aboutsummaryrefslogtreecommitdiff
path: root/engines/hopkins
diff options
context:
space:
mode:
Diffstat (limited to 'engines/hopkins')
-rw-r--r--engines/hopkins/anim.cpp804
-rw-r--r--engines/hopkins/anim.h78
-rw-r--r--engines/hopkins/computer.cpp1222
-rw-r--r--engines/hopkins/computer.h106
-rw-r--r--engines/hopkins/debugger.cpp67
-rw-r--r--engines/hopkins/debugger.h48
-rw-r--r--engines/hopkins/detection.cpp191
-rw-r--r--engines/hopkins/detection_tables.h247
-rw-r--r--engines/hopkins/dialogs.cpp781
-rw-r--r--engines/hopkins/dialogs.h77
-rw-r--r--engines/hopkins/events.cpp542
-rw-r--r--engines/hopkins/events.h94
-rw-r--r--engines/hopkins/files.cpp271
-rw-r--r--engines/hopkins/files.h58
-rw-r--r--engines/hopkins/font.cpp495
-rw-r--r--engines/hopkins/font.h98
-rw-r--r--engines/hopkins/globals.cpp215
-rw-r--r--engines/hopkins/globals.h225
-rw-r--r--engines/hopkins/graphics.cpp1855
-rw-r--r--engines/hopkins/graphics.h188
-rw-r--r--engines/hopkins/hopkins.cpp2861
-rw-r--r--engines/hopkins/hopkins.h197
-rw-r--r--engines/hopkins/lines.cpp2914
-rw-r--r--engines/hopkins/lines.h196
-rw-r--r--engines/hopkins/menu.cpp168
-rw-r--r--engines/hopkins/menu.h46
-rw-r--r--engines/hopkins/module.mk29
-rw-r--r--engines/hopkins/objects.cpp4058
-rw-r--r--engines/hopkins/objects.h338
-rw-r--r--engines/hopkins/saveload.cpp333
-rw-r--r--engines/hopkins/saveload.h78
-rw-r--r--engines/hopkins/script.cpp2624
-rw-r--r--engines/hopkins/script.h50
-rw-r--r--engines/hopkins/sound.cpp916
-rw-r--r--engines/hopkins/sound.h138
-rw-r--r--engines/hopkins/talk.cpp1081
-rw-r--r--engines/hopkins/talk.h78
37 files changed, 23767 insertions, 0 deletions
diff --git a/engines/hopkins/anim.cpp b/engines/hopkins/anim.cpp
new file mode 100644
index 0000000000..007197090f
--- /dev/null
+++ b/engines/hopkins/anim.cpp
@@ -0,0 +1,804 @@
+/* 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/anim.h"
+
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "common/file.h"
+#include "common/rect.h"
+#include "engines/util.h"
+
+namespace Hopkins {
+
+AnimationManager::AnimationManager(HopkinsEngine *vm) {
+ _vm = vm;
+ _clearAnimationFl = false;
+ for (int i = 0; i < 8; ++i)
+ Common::fill((byte *)&Bank[i], (byte *)&Bank[i] + sizeof(BankItem), 0);
+ for (int i = 0; i < 35; ++i)
+ Common::fill((byte *)&_animBqe[i], (byte *)&_animBqe[i] + sizeof(BqeAnimItem), 0);
+}
+
+void AnimationManager::clearAll() {
+ initAnimBqe();
+}
+
+/**
+ * Play Animation
+ * @param filename Filename of animation to play
+ * @param rate1 Delay amount before starting animation
+ * @param rate2 Delay amount between animation frames
+ * @param rate3 Delay amount after animation finishes
+ */
+void AnimationManager::playAnim(const Common::String &filename, uint32 rate1, uint32 rate2, uint32 rate3, bool skipSeqFl) {
+ Common::File f;
+
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_events->mouseOff();
+
+ byte *screenP = _vm->_graphicsMan->_backBuffer;
+
+ Common::String tmpStr;
+ // The Windows 95 demo only contains the interlaced version of the BOMBE1 and BOMBE2 videos
+ if (_vm->getPlatform() == Common::kPlatformWindows && _vm->getIsDemo() && filename == "BOMBE1A.ANM")
+ tmpStr = "BOMBE1.ANM";
+ else if (_vm->getPlatform() == Common::kPlatformWindows && _vm->getIsDemo() && filename == "BOMBE2A.ANM")
+ tmpStr = "BOMBE2.ANM";
+ else
+ tmpStr = filename;
+ if (!f.open(tmpStr))
+ error("File not found - %s", tmpStr.c_str());
+
+ f.skip(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ size_t nbytes = f.readUint32LE();
+ f.skip(14);
+ f.read(screenP, nbytes);
+
+ if (_clearAnimationFl)
+ _vm->_graphicsMan->clearScreen();
+
+ if (skipSeqFl) {
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ } else {
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->display8BitRect(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ }
+ _vm->_events->_rateCounter = 0;
+ _vm->_events->_escKeyFl = false;
+ _vm->_soundMan->loadAnimSound();
+
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ // Do pre-animation delay
+ do {
+ if (_vm->_events->_escKeyFl)
+ break;
+
+ _vm->_events->refreshEvents();
+ } while (!_vm->shouldQuit() && _vm->_events->_rateCounter < rate1);
+ }
+
+ if (!_vm->_events->_escKeyFl) {
+ _vm->_events->_rateCounter = 0;
+ int frameNumber = 0;
+ while (!_vm->shouldQuit()) {
+ ++frameNumber;
+ _vm->_soundMan->playAnimSound(frameNumber);
+
+ byte imageStr[17];
+ // Read frame header
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ do {
+ if (_vm->_events->_escKeyFl)
+ break;
+
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (!_vm->shouldQuit() && _vm->_events->_rateCounter < rate2);
+ }
+
+ if (!_vm->_events->_escKeyFl) {
+ _vm->_events->_rateCounter = 0;
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyVideoVbe16(screenP);
+
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ _vm->_soundMan->checkSoundEnd();
+ }
+ }
+ }
+
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE && !_vm->_events->_escKeyFl) {
+ // Do post-animation delay
+ do {
+ if (_vm->_events->_escKeyFl)
+ break;
+
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (_vm->_events->_rateCounter < rate3);
+ }
+
+ if (!_vm->_events->_escKeyFl) {
+ _vm->_events->_rateCounter = 0;
+ _vm->_soundMan->checkSoundEnd();
+ }
+
+ if (_vm->_graphicsMan->_fadingFl) {
+ byte *screenCopy = _vm->_globals->allocMemory(307200);
+
+ f.seek(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ nbytes = f.readUint32LE();
+ f.skip(14);
+ f.read(screenP, nbytes);
+
+ memcpy(screenCopy, screenP, 307200);
+
+ for (;;) {
+ byte imageStr[17];
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyWinscanVbe3(screenP, screenCopy);
+ }
+ _vm->_graphicsMan->fadeOutDefaultLength(screenCopy);
+ _vm->_globals->freeMemory(screenCopy);
+ }
+
+ _vm->_graphicsMan->_fadingFl = false;
+ f.close();
+ _vm->_graphicsMan->_skipVideoLockFl = false;
+
+ _vm->_events->mouseOn();
+}
+
+/**
+ * Play Animation, type 2
+ */
+void AnimationManager::playAnim2(const Common::String &filename, uint32 rate1, uint32 rate2, uint32 rate3) {
+ int oldScrollPosX = 0;
+ byte *screenP = NULL;
+ Common::File f;
+
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_events->mouseOff();
+
+ while (!_vm->shouldQuit()) {
+ memcpy(_vm->_graphicsMan->_oldPalette, _vm->_graphicsMan->_palette, 769);
+
+ _vm->_graphicsMan->backupScreen();
+
+ if (!_vm->_graphicsMan->_lineNbr)
+ _vm->_graphicsMan->_scrollOffset = 0;
+
+ screenP = _vm->_graphicsMan->_backBuffer;
+ if (!f.open(filename))
+ error("Error opening file - %s", filename.c_str());
+
+ f.skip(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ size_t nbytes = f.readUint32LE();
+ f.skip(14);
+
+ f.read(screenP, nbytes);
+
+ _vm->_graphicsMan->clearPalette();
+ oldScrollPosX = _vm->_graphicsMan->_scrollPosX;
+ _vm->_graphicsMan->setScreenWidth(SCREEN_WIDTH);
+ _vm->_graphicsMan->scrollScreen(0);
+ _vm->_graphicsMan->clearScreen();
+ _vm->_graphicsMan->_maxX = SCREEN_WIDTH;
+
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->display8BitRect(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+
+ _vm->_events->_rateCounter = 0;
+ _vm->_events->_escKeyFl = false;
+ _vm->_soundMan->loadAnimSound();
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ while (!_vm->_events->_escKeyFl && _vm->_events->_rateCounter < rate1) {
+ _vm->_events->refreshEvents();
+ }
+ }
+ break;
+ }
+
+ if (!_vm->_events->_escKeyFl) {
+ _vm->_events->_rateCounter = 0;
+ int frameNumber = 0;
+ for (;;) {
+ if (_vm->_events->_escKeyFl)
+ break;
+ ++frameNumber;
+ _vm->_soundMan->playAnimSound(frameNumber);
+ byte imageStr[17];
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ while (!_vm->_events->_escKeyFl && _vm->_events->_rateCounter < rate2) {
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ }
+ }
+
+ _vm->_events->_rateCounter = 0;
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyVideoVbe16(screenP);
+
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ _vm->_soundMan->checkSoundEnd();
+ }
+
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ while (!_vm->_events->_escKeyFl && _vm->_events->_rateCounter < rate3) {
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ }
+ }
+ }
+
+ _vm->_graphicsMan->_skipVideoLockFl = false;
+ f.close();
+
+ if (_vm->_graphicsMan->_fadingFl) {
+ f.seek(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ size_t nbytes = f.readUint32LE();
+ f.skip(14);
+ f.read(screenP, nbytes);
+ byte *ptra = _vm->_globals->allocMemory(307200);
+ memcpy(ptra, screenP, 307200);
+
+ for (;;) {
+ byte imageStr[17];
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyWinscanVbe3(screenP, ptra);
+ }
+ _vm->_graphicsMan->fadeOutDefaultLength(ptra);
+ ptra = _vm->_globals->freeMemory(ptra);
+ }
+ _vm->_graphicsMan->_fadingFl = false;
+
+ _vm->_graphicsMan->restoreScreen();
+
+ memcpy(_vm->_graphicsMan->_palette, _vm->_graphicsMan->_oldPalette, 769);
+ _vm->_graphicsMan->clearPalette();
+ _vm->_graphicsMan->clearScreen();
+
+ _vm->_graphicsMan->_scrollPosX = oldScrollPosX;
+ _vm->_graphicsMan->scrollScreen(oldScrollPosX);
+ if (_vm->_graphicsMan->_largeScreenFl) {
+ _vm->_graphicsMan->setScreenWidth(2 * SCREEN_WIDTH);
+ _vm->_graphicsMan->_maxX = 2 * SCREEN_WIDTH;
+ _vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_frontBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ } else {
+ _vm->_graphicsMan->setScreenWidth(SCREEN_WIDTH);
+ _vm->_graphicsMan->_maxX = SCREEN_WIDTH;
+ _vm->_graphicsMan->clearScreen();
+ _vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_frontBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ }
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ _vm->_graphicsMan->fadeInShort();
+ _vm->_graphicsMan->updateScreen();
+
+ _vm->_events->mouseOn();
+}
+
+/**
+ * Load Animation
+ */
+void AnimationManager::loadAnim(const Common::String &animName) {
+ clearAnim();
+
+ Common::String filename = animName + ".ANI";
+ Common::File f;
+ if (!f.open(filename))
+ error("Failed to open %s", filename.c_str());
+
+ int filesize = f.size();
+ int nbytes = filesize - 115;
+
+ char header[10];
+ char dummyBuf[15];
+ char filename1[15];
+ char filename2[15];
+ char filename3[15];
+ char filename4[15];
+ char filename5[15];
+ char filename6[15];
+
+ f.read(header, 10);
+ f.read(dummyBuf, 15);
+ f.read(filename1, 15);
+ f.read(filename2, 15);
+ f.read(filename3, 15);
+ f.read(filename4, 15);
+ f.read(filename5, 15);
+ f.read(filename6, 15);
+
+ if (READ_BE_UINT32(header) != MKTAG('A', 'N', 'I', 'S'))
+ error("Invalid animation File: %s", filename.c_str());
+
+ const char *files[6] = { &filename1[0], &filename2[0], &filename3[0], &filename4[0],
+ &filename5[0], &filename6[0] };
+
+ for (int idx = 0; idx <= 5; ++idx) {
+ if (files[idx][0]) {
+ if (!f.exists(files[idx]))
+ error("Missing file %s in animation File: %s", files[idx], filename.c_str());
+ if (loadSpriteBank(idx + 1, files[idx]))
+ error("Invalid sprite bank in animation File: %s", filename.c_str());
+ }
+ }
+
+ byte *data = _vm->_globals->allocMemory(nbytes + 1);
+ f.read(data, nbytes);
+ f.close();
+
+ for (int idx = 1; idx <= 20; ++idx)
+ searchAnim(data, idx, nbytes);
+
+ _vm->_globals->freeMemory(data);
+}
+
+/**
+ * Clear animation
+ */
+void AnimationManager::clearAnim() {
+ for (int idx = 0; idx < 35; ++idx) {
+ _animBqe[idx]._data = _vm->_globals->freeMemory(_animBqe[idx]._data);
+ _animBqe[idx]._enabledFl = false;
+ }
+
+ for (int idx = 0; idx < 8; ++idx) {
+ Bank[idx]._data = _vm->_globals->freeMemory(Bank[idx]._data);
+ Bank[idx]._loadedFl = false;
+ Bank[idx]._filename = "";
+ Bank[idx]._fileHeader = 0;
+ }
+}
+
+/**
+ * Load Sprite Bank
+ */
+int AnimationManager::loadSpriteBank(int idx, const Common::String &filename) {
+ int result = 0;
+ Bank[idx]._loadedFl = true;
+ Bank[idx]._filename = filename;
+
+ byte *fileDataPtr = _vm->_fileIO->loadFile(filename);
+
+ Bank[idx]._fileHeader = 0;
+ if (fileDataPtr[1] == 'L' && fileDataPtr[2] == 'E')
+ Bank[idx]._fileHeader = 1;
+ else if (fileDataPtr[1] == 'O' && fileDataPtr[2] == 'R')
+ Bank[idx]._fileHeader = 2;
+
+ if (!Bank[idx]._fileHeader) {
+ _vm->_globals->freeMemory(fileDataPtr);
+ Bank[idx]._loadedFl = false;
+ result = -1;
+ }
+
+ Bank[idx]._data = fileDataPtr;
+
+ int objectDataIdx = 0;
+ for(objectDataIdx = 0; objectDataIdx <= 249; objectDataIdx++) {
+ int width = _vm->_objectsMan->getWidth(fileDataPtr, objectDataIdx);
+ int height = _vm->_objectsMan->getHeight(fileDataPtr, objectDataIdx);
+ if (!width && !height)
+ break;
+ }
+
+ if (objectDataIdx > 249) {
+ _vm->_globals->freeMemory(fileDataPtr);
+ Bank[idx]._loadedFl = false;
+ result = -2;
+ }
+ Bank[idx]._objDataIdx = objectDataIdx;
+
+ Common::String ofsFilename = Bank[idx]._filename;
+ char ch;
+ do {
+ ch = ofsFilename.lastChar();
+ ofsFilename.deleteLastChar();
+ } while (ch != '.');
+ ofsFilename += ".OFS";
+
+ Common::File f;
+ if (f.exists(ofsFilename)) {
+ byte *ofsData = _vm->_fileIO->loadFile(ofsFilename);
+ byte *curOfsData = ofsData;
+ for (int objIdx = 0; objIdx < Bank[idx]._objDataIdx; ++objIdx, curOfsData += 8) {
+ int x1 = READ_LE_INT16(curOfsData);
+ int y1 = READ_LE_INT16(curOfsData + 2);
+ int x2 = READ_LE_INT16(curOfsData + 4);
+ int y2 = READ_LE_INT16(curOfsData + 6);
+
+ _vm->_objectsMan->setOffsetXY(Bank[idx]._data, objIdx, x1, y1, 0);
+ if (Bank[idx]._fileHeader == 2)
+ _vm->_objectsMan->setOffsetXY(Bank[idx]._data, objIdx, x2, y2, 1);
+ }
+
+ _vm->_globals->freeMemory(ofsData);
+ result = 0;
+ }
+
+ return result;
+}
+
+/**
+ * Search Animation
+ */
+void AnimationManager::searchAnim(const byte *data, int animIndex, int bufSize) {
+ for (int dataIdx = 0; dataIdx <= bufSize; dataIdx++) {
+ if (READ_BE_UINT32(&data[dataIdx]) == MKTAG('A', 'N', 'I', 'M')) {
+ int entryIndex = data[dataIdx + 4];
+ if (animIndex == entryIndex) {
+ int curBufferPos = dataIdx + 5;
+ int count = 0;
+ bool innerLoopCond = false;
+ do {
+ if (READ_BE_UINT32(&data[curBufferPos]) == MKTAG('A', 'N', 'I', 'M') || READ_BE_UINT24(&data[curBufferPos]) == MKTAG24('F', 'I', 'N'))
+ innerLoopCond = true;
+ if (bufSize < curBufferPos) {
+ _animBqe[animIndex]._enabledFl = false;
+ _animBqe[animIndex]._data = NULL;
+ return;
+ }
+ ++curBufferPos;
+ ++count;
+ } while (!innerLoopCond);
+ _animBqe[animIndex]._data = _vm->_globals->allocMemory(count + 50);
+ _animBqe[animIndex]._enabledFl = true;
+ memcpy(_animBqe[animIndex]._data, data + dataIdx + 5, 20);
+
+ byte *dataP = _animBqe[animIndex]._data;
+ int curDestDataIndx = 20;
+ int curSrcDataIndx = dataIdx + 25;
+
+ for (int i = 0; i <= 4999; i++) {
+ memcpy(dataP + curDestDataIndx, data + curSrcDataIndx, 10);
+ if (!READ_LE_UINT16(data + curSrcDataIndx + 4))
+ break;
+ curDestDataIndx += 10;
+ curSrcDataIndx += 10;
+ }
+ break;
+ }
+ }
+ if (READ_BE_UINT24(&data[dataIdx]) == MKTAG24('F', 'I', 'N'))
+ break;
+ }
+}
+
+/**
+ * Play sequence
+ */
+void AnimationManager::playSequence(const Common::String &file, uint32 rate1, uint32 rate2, uint32 rate3, bool skipEscFl, bool skipSeqFl, bool noColFl) {
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_events->_mouseFl = false;
+ if (!noColFl) {
+ _vm->_events->refreshScreenAndEvents();
+
+ _vm->_graphicsMan->backupScreen();
+
+ if (!_vm->_graphicsMan->_lineNbr)
+ _vm->_graphicsMan->_scrollOffset = 0;
+ }
+ byte *screenP = _vm->_graphicsMan->_backBuffer;
+ Common::File f;
+ if (!f.open(file))
+ error("Error opening file - %s", file.c_str());
+
+ f.skip(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ size_t nbytes = f.readUint32LE();
+ f.skip(14);
+ f.read(screenP, nbytes);
+
+ if (skipSeqFl) {
+ if (!_vm->getIsDemo()) {
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+ }
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ } else {
+ _vm->_graphicsMan->display8BitRect(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ }
+ bool skipFl = false;
+ if (noColFl)
+ _vm->_graphicsMan->fadeInDefaultLength(screenP);
+ _vm->_events->_rateCounter = 0;
+ _vm->_events->_escKeyFl = false;
+ _vm->_soundMan->loadAnimSound();
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ do {
+ if (_vm->shouldQuit() || (_vm->_events->_escKeyFl && !skipEscFl)) {
+ skipFl = true;
+ break;
+ }
+
+ _vm->_events->_escKeyFl = false;
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (_vm->_events->_rateCounter < rate1);
+ }
+ _vm->_events->_rateCounter = 0;
+ if (!skipFl) {
+ int soundNumber = 0;
+ for (;;) {
+ ++soundNumber;
+ _vm->_soundMan->playAnimSound(soundNumber);
+ byte imageStr[17];
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ do {
+ if (_vm->shouldQuit() || (_vm->_events->_escKeyFl && !skipEscFl)) {
+ skipFl = true;
+ break;
+ }
+
+ _vm->_events->_escKeyFl = false;
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (_vm->_events->_rateCounter < rate2);
+ }
+
+ if (skipFl)
+ break;
+
+ _vm->_events->_rateCounter = 0;
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyVideoVbe16a(screenP);
+
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ _vm->_soundMan->checkSoundEnd();
+ }
+ }
+
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE && !skipFl) {
+ do {
+ if (_vm->shouldQuit() || (_vm->_events->_escKeyFl && !skipEscFl)) {
+ skipFl = true;
+ break;
+ }
+
+ _vm->_events->_escKeyFl = false;
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (_vm->_events->_rateCounter < rate3);
+ }
+
+ if (!skipFl)
+ _vm->_events->_rateCounter = 0;
+
+ _vm->_graphicsMan->_skipVideoLockFl = false;
+ f.close();
+
+ if (!noColFl) {
+ _vm->_graphicsMan->restoreScreen();
+
+ _vm->_events->_mouseFl = true;
+ }
+}
+
+/**
+ * Play Sequence type 2
+ */
+void AnimationManager::playSequence2(const Common::String &file, uint32 rate1, uint32 rate2, uint32 rate3, bool skipSeqFl) {
+ byte *screenP;
+ int frameNumber;
+ Common::File f;
+
+ for (;;) {
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_events->_mouseFl = false;
+ screenP = _vm->_graphicsMan->_backBuffer;
+
+ if (!f.open(file))
+ error("File not found - %s", file.c_str());
+
+ f.skip(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ size_t nbytes = f.readUint32LE();
+ f.skip(14);
+ f.read(screenP, nbytes);
+
+ if (skipSeqFl) {
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ } else {
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->display8BitRect(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ }
+ _vm->_events->_rateCounter = 0;
+ _vm->_events->_escKeyFl = false;
+ _vm->_soundMan->loadAnimSound();
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ do {
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (!_vm->shouldQuit() && !_vm->_events->_escKeyFl && _vm->_events->_rateCounter < rate1);
+ }
+ break;
+ }
+
+ if (!_vm->_events->_escKeyFl) {
+ _vm->_events->_rateCounter = 0;
+ frameNumber = 0;
+ while (!_vm->shouldQuit()) {
+ _vm->_soundMan->playAnimSound(frameNumber++);
+
+ byte imageStr[17];
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ do {
+ _vm->_events->refreshEvents();
+ } while (!_vm->shouldQuit() && !_vm->_events->_escKeyFl && _vm->_events->_rateCounter < rate2);
+ }
+
+ _vm->_events->_rateCounter = 0;
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyVideoVbe16a(screenP);
+
+ _vm->_graphicsMan->addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_graphicsMan->updateScreen();
+ _vm->_soundMan->checkSoundEnd();
+ }
+ }
+
+ if (_vm->_globals->_eventMode == EVENTMODE_IGNORE) {
+ // Wait for third rate delay
+ do {
+ _vm->_events->refreshEvents();
+ _vm->_soundMan->checkSoundEnd();
+ } while (!_vm->shouldQuit() && !_vm->_events->_escKeyFl && _vm->_events->_rateCounter < rate3);
+ }
+
+ _vm->_events->_rateCounter = 0;
+
+ if (_vm->_graphicsMan->_fadingFl) {
+ byte *ptra = _vm->_globals->allocMemory(307200);
+
+ f.seek(6);
+ f.read(_vm->_graphicsMan->_palette, 800);
+ f.skip(4);
+ size_t nbytes = f.readUint32LE();
+ f.skip(14);
+ f.read(screenP, nbytes);
+
+ memcpy(ptra, screenP, 307200);
+ for (;;) {
+ byte imageStr[17];
+ if (f.read(imageStr, 16) != 16)
+ break;
+ imageStr[16] = 0;
+
+ if (strncmp((const char *)imageStr, "IMAGE=", 6))
+ break;
+
+ f.read(screenP, READ_LE_UINT32(imageStr + 8));
+ if (*screenP != kByteStop)
+ _vm->_graphicsMan->copyWinscanVbe(screenP, ptra);
+ }
+ _vm->_graphicsMan->fadeOutDefaultLength(ptra);
+ ptra = _vm->_globals->freeMemory(ptra);
+ }
+ _vm->_graphicsMan->_fadingFl = false;
+
+ f.close();
+ _vm->_events->_mouseFl = true;
+}
+
+void AnimationManager::initAnimBqe() {
+ for (int idx = 0; idx < 35; ++idx) {
+ _animBqe[idx]._data = NULL;
+ _animBqe[idx]._enabledFl = false;
+ }
+
+ for (int idx = 0; idx < 8; ++idx) {
+ Bank[idx]._data = NULL;
+ Bank[idx]._loadedFl = false;
+ Bank[idx]._filename = "";
+ Bank[idx]._fileHeader = 0;
+ }
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/anim.h b/engines/hopkins/anim.h
new file mode 100644
index 0000000000..22f725681a
--- /dev/null
+++ b/engines/hopkins/anim.h
@@ -0,0 +1,78 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_ANIM_H
+#define HOPKINS_ANIM_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/str.h"
+#include "graphics/surface.h"
+
+namespace Hopkins {
+
+struct BankItem {
+ byte *_data;
+ bool _loadedFl;
+ Common::String _filename;
+ int _fileHeader;
+ int _objDataIdx;
+};
+
+struct BqeAnimItem {
+ byte *_data;
+ bool _enabledFl;
+};
+
+class HopkinsEngine;
+
+class AnimationManager {
+private:
+ bool _clearAnimationFl;
+
+ HopkinsEngine *_vm;
+
+ void initAnimBqe();
+ int loadSpriteBank(int idx, const Common::String &filename);
+ void searchAnim(const byte *data, int animIndex, int count);
+
+public:
+ BqeAnimItem _animBqe[35];
+ BankItem Bank[8];
+
+ AnimationManager(HopkinsEngine *vm);
+ void clearAll();
+
+ void loadAnim(const Common::String &animName);
+ void clearAnim();
+ void playAnim(const Common::String &filename, uint32 rate1, uint32 rate2, uint32 rate3, bool skipSeqFl = false);
+ void playAnim2(const Common::String &filename, uint32 rate1, uint32 rate2, uint32 rate3);
+ void playSequence(const Common::String &file, uint32 rate1, uint32 rate2, uint32 rate3, bool skipEscFl, bool skipSeqFl, bool noColFl = false);
+ void playSequence2(const Common::String &file, uint32 rate1, uint32 rate2, uint32 rate3, bool skipSeqFl = false);
+
+ void setClearAnimFlag() { _clearAnimationFl = true; }
+ void unsetClearAnimFlag() { _clearAnimationFl = false; }
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_ANIM_H */
diff --git a/engines/hopkins/computer.cpp b/engines/hopkins/computer.cpp
new file mode 100644
index 0000000000..467153e4dd
--- /dev/null
+++ b/engines/hopkins/computer.cpp
@@ -0,0 +1,1222 @@
+/* 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/computer.h"
+
+#include "hopkins/font.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/file.h"
+#include "common/textconsole.h"
+
+namespace Hopkins {
+
+ComputerManager::ComputerManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ for (int i = 0; i < 50; i++) {
+ _menuText[i]._actvFl = false;
+ _menuText[i]._lineSize = 0;
+ memset(_menuText[i]._line, 0, 90);
+ }
+ Common::fill(&_inputBuf[0], &_inputBuf[200], '\0');
+ _breakoutSpr = NULL;
+ _textColor = 0;
+ _breakoutLevel = (int16 *)NULL;
+ _breakoutBrickNbr = 0;
+ _breakoutScore = 0;
+ _breakoutLives = 0;
+ _breakoutSpeed = 0;
+ _ballRightFl = false;
+ _ballUpFl = false;
+ _breakoutLevelNbr = 0;
+ _padPositionX = 0;
+ _minBreakoutMoveSpeed = 0;
+ _maxBreakoutMoveSpeed = 0;
+ _lastBreakoutMoveSpeed = 0;
+ _breakoutHiscore = 0;
+}
+
+/**
+ * Sets up textual entry mode. Used by the code for Hopkins computer.
+ */
+void ComputerManager::setVideoMode() {
+ setTextMode();
+}
+
+/**
+ * Sets up Textual entry mode
+ */
+void ComputerManager::setTextMode() {
+ _vm->_graphicsMan->clearPalette();
+ _vm->_graphicsMan->clearScreen();
+
+ _vm->_graphicsMan->_lineNbr = SCREEN_WIDTH;
+ _vm->_fontMan->_font = _vm->_globals->freeMemory(_vm->_fontMan->_font);
+
+ Common::String filename = "STFONT.SPR";
+ Common::File f;
+ if (!f.exists(filename))
+ filename = "FONTE.SPR"; // Used by the BeOS and OS/2 versions as an alternative
+ _vm->_fontMan->_font = _vm->_fileIO->loadFile(filename);
+ _vm->_fontMan->_fontFixedWidth = 8;
+ _vm->_fontMan->_fontFixedHeight = 8;
+
+ _vm->_graphicsMan->loadImage("WINTEXT");
+ _vm->_graphicsMan->fadeInLong();
+ loadMenu();
+ _vm->_events->_mouseFl = false;
+}
+
+/**
+ * Clear the screen
+ */
+void ComputerManager::clearScreen() {
+ _vm->_graphicsMan->loadImage("WINTEXT");
+ _vm->_graphicsMan->fadeInLong();
+}
+
+/**
+ * Sets the text mode color
+ */
+void ComputerManager::setTextColor(int col) {
+ _textColor = col;
+}
+
+/**
+ * Sets the text position.
+ * @param yp Y position
+ * @param xp X position
+ * @remarks Yes, the reverse co-ordinate pair is really like that in the original game.
+ */
+void ComputerManager::setTextPosition(int yp, int xp) {
+ _textPosition.x = xp << 3;
+ _textPosition.y = yp << 4;
+}
+
+/**
+ * Show a computer in the FBI office
+ * @param mode Which computer to display
+ */
+void ComputerManager::showComputer(ComputerEnum mode) {
+ _vm->_events->_escKeyFl = false;
+ _vm->_graphicsMan->resetDirtyRects();
+ setVideoMode();
+ setTextColor(4);
+ setTextPosition(2, 4);
+ if (mode == COMPUTER_HOPKINS)
+ outText(Common::String(_menuText[0]._line));
+ else if (mode == COMPUTER_SAMANTHA)
+ outText(Common::String(_menuText[1]._line));
+ else // COMPUTER_PUBLIC
+ outText(Common::String(_menuText[2]._line));
+
+ setTextColor(1);
+ if (mode == COMPUTER_PUBLIC) {
+ setTextPosition(10, 8);
+ outText(Common::String(_menuText[3]._line));
+ }
+ setTextPosition(12, 28);
+ outText(Common::String(_menuText[4]._line));
+ setTextPosition(14, 35);
+
+ displayMessage(280, 224, 8);
+ bool passwordMatch = false;
+ if ((mode == COMPUTER_HOPKINS) && !strcmp(_inputBuf, "HOPKINS"))
+ passwordMatch = true;
+ else if ((mode == COMPUTER_SAMANTHA) && !strcmp(_inputBuf, "328MHZA"))
+ passwordMatch = true;
+ else if ((mode == COMPUTER_PUBLIC) && !strcmp(_inputBuf, "ALLFREE"))
+ passwordMatch = true;
+
+ if (passwordMatch) {
+ while (!_vm->shouldQuit()) {
+ _vm->_events->_escKeyFl = false;
+ clearScreen();
+ setTextColor(4);
+ setTextPosition(2, 4);
+ if (mode == COMPUTER_HOPKINS)
+ outText(Common::String(_menuText[0]._line));
+ else if (mode == COMPUTER_SAMANTHA)
+ outText(Common::String(_menuText[1]._line));
+ else if (mode == COMPUTER_PUBLIC)
+ outText(Common::String(_menuText[2]._line));
+ setTextColor(15);
+ setTextPosition(8, 25);
+ setTextColor(15);
+ outText2(Common::String(_menuText[6]._line));
+ setTextPosition(20, 25);
+ outText2(Common::String(_menuText[7]._line));
+ if (mode == COMPUTER_HOPKINS) {
+ setTextPosition(10, 25);
+ outText2(Common::String(_menuText[8]._line));
+ setTextPosition(12, 25);
+ outText2(Common::String(_menuText[9]._line));
+ setTextPosition(14, 25);
+ outText2(Common::String(_menuText[10]._line));
+ setTextPosition(16, 25);
+ outText2(Common::String(_menuText[11]._line));
+ } else if (mode == COMPUTER_SAMANTHA) {
+ setTextPosition(10, 25);
+// outText2(Common::String(_menuText[0x95A])); <=== CHECKME: Unexpected value! replaced by the following line, for consistancy
+ outText2(Common::String(_menuText[12]._line));
+ setTextPosition(12, 25);
+ outText2(Common::String(_menuText[13]._line));
+ setTextPosition(14, 25);
+ outText2(Common::String(_menuText[14]._line));
+ setTextPosition(16, 25);
+ outText2(Common::String(_menuText[15]._line));
+ setTextPosition(18, 25);
+ outText2(Common::String(_menuText[16]._line));
+ }
+
+ bool numericFlag = false;
+ char keyPressed;
+ do {
+ keyPressed = _vm->_events->waitKeyPress();
+ if (_vm->shouldQuit())
+ return;
+
+ if ((keyPressed >= '0') && (keyPressed <= '9'))
+ numericFlag = true;
+ } while (!numericFlag);
+
+ // 0 - Quit
+ if (keyPressed == '0')
+ break;
+ // 1 - Games
+ if (keyPressed == '1') {
+ displayGamesSubMenu();
+ } else if (mode == COMPUTER_HOPKINS) {
+ clearScreen();
+ setTextColor(4);
+ setTextPosition(2, 4);
+ outText(Common::String(_menuText[0]._line));
+ setTextColor(15);
+ switch (keyPressed) {
+ case '2':
+ readText(1);
+ break;
+ case '3':
+ readText(2);
+ break;
+ case '4':
+ readText(3);
+ break;
+ case '5':
+ readText(4);
+ break;
+ }
+ } else if (mode == COMPUTER_SAMANTHA) {
+ clearScreen();
+ setTextColor(4);
+ setTextPosition(2, 4);
+ outText(Common::String(_menuText[1]._line));
+ setTextColor(15);
+ switch (keyPressed) {
+ case '2':
+ readText(6);
+ break;
+ case '3':
+ readText(7);
+ break;
+ case '4':
+ readText(8);
+ break;
+ case '5':
+ readText(9);
+ break;
+ case '6':
+ readText(10);
+ _vm->_globals->_saveData->_data[svField270] = 4;
+ break;
+ }
+ }
+ }
+ _vm->_graphicsMan->clearScreen();
+ _vm->_graphicsMan->updateScreen();
+ restoreFBIRoom();
+ } else {
+ // Password doesn't match - Access Denied
+ setTextColor(4);
+ setTextPosition(16, 25);
+ outText(Common::String(_menuText[5]._line));
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->delay(1000);
+
+ memset(_vm->_graphicsMan->_frontBuffer, 0, 307199);
+ _vm->_graphicsMan->clearScreen();
+ _vm->_graphicsMan->updateScreen();
+ restoreFBIRoom();
+ _vm->_events->mouseOff();
+ }
+
+ if (mode == COMPUTER_HOPKINS)
+ _vm->_globals->_exitId = 13;
+ else // Free access or Samantha
+ _vm->_globals->_exitId = 14;
+
+ _vm->_graphicsMan->resetDirtyRects();
+}
+
+static const char _englishText[] =
+"% ****** FBI COMPUTER NUMBER 4985 ****** J.HOPKINS COMPUTER ******\n"
+"% ****** FBI COMPUTER NUMBER 4998 ****** S.COLLINS COMPUTER ******\n"
+"% ****** FBI COMPUTER NUMBER 4997 ****** ACCES FREE COMPUTER ******\n"
+"% PASSWORD IS: ALLFREE\n% ENTER CURRENT PASSWORD\n"
+"% ****** ACCES DENIED ******\n"
+"% 1) *** GAME ***\n"
+"% 0) QUIT COMPUTER\n"
+"% 2) STRANGE CADAVER\n"
+"% 3) STRANGE CADAVER\n"
+"% 4) SENATOR FERGUSSON\n"
+"% 5) DOG KILLER\n"
+"% 2) SCIENTIST KIDNAPPED.\n"
+"% 3) SCIENTIST KIDNAPPED (next).\n"
+"% 4) SCIENTIST KIDNAPPED (next).\n"
+"% 5) SCIENTIST KIDNAPPED (next).\n"
+"% 6) SCIENTIST KIDNAPPED (next).\n"
+"%% fin\n";
+
+static const char _frenchText[] =
+"% ****** FBI COMPUTER NUMBER 4985 ****** J.HOPKINS COMPUTER ******\n"
+"% ****** FBI COMPUTER NUMBER 4998 ****** S.COLLINS COMPUTER ******\n"
+"% ****** FBI COMPUTER NUMBER 4997 ****** ACCES FREE COMPUTER ******\n"
+"% PASSWORD IS: ALLFREE\n"
+"% ENTER CURRENT PASSWORD\n"
+"% ****** ACCES DENIED ******\n"
+"% 1) *** CASSE BRIQUE ***\n"
+"% 0) QUITTER L'ORDINATEUR\n"
+"% 2) CADAVRE SANS TETE\n"
+"% 3) CADAVRE SANS TETE\n"
+"% 4) AGRESSION DU SENATEUR\n"
+"% 5) LES CHIENS TUEURS\n"
+"% 2) DISPARITIONS DE CHERCHEURS.\n"
+"% 3) DISPARITIONS (suite).\n"
+"% 4) DISPARITIONS (suite).\n"
+"% 5) DISPARITIONS (suite).\n"
+"% 6) DISPARITIONS (suite).\n"
+"%% fin\n";
+
+static const char _spanishText[] =
+"% **** ORDENADOR DEL FBI NUMERO 4985 **** ORDENADOR J.HOPKINS *****\n"
+"% **** ORDENADOR DEL FBI NUMERO 4998 **** ORDENADOR S.COLLINS *****\n"
+"% *** ORDENADOR DEL FBI NUMERO 4997 *** ORDENADOR DE ACCESO LIBRE ***\n"
+"% LA CONTRASE¥A ES: ALLFREE\n"
+"% ESCRIBE CONTRASE¥A ACTUAL\n"
+"% **** ACCESO DENEGADO ****\n"
+"% 1) *** JUEGO ***\n"
+"% 0) SALIR DEL ORDENADOR\n"
+"% 2) CADAVER EXTRA¥O\n"
+"% 3) CADAVER EXTRA¥O\n"
+"% 4) SENADOR FERGUSSON\n"
+"% 5) MATAPERROS\n"
+"% 2) CIENTIFICO SECUESTRADO.\n"
+"% 3) CIENTIFICO SECUESTRADO (siguiente).\n"
+"% 4) CIENTIFICO SECUESTRADO (siguiente).\n"
+"% 5) CIENTIFICO SECUESTRADO (siguiente).\n"
+"% 6) CIENTIFICO SECUESTRADO (siguiente).\n"
+"%% fin\n";
+
+/**
+ * Load Menu data
+ */
+void ComputerManager::loadMenu() {
+ char *ptr;
+ if (_vm->_fileIO->fileExists("COMPUTAN.TXT")) {
+ ptr = (char *)_vm->_fileIO->loadFile("COMPUTAN.TXT");
+ } else if (_vm->_globals->_language == LANG_FR) {
+ ptr = (char *)_vm->_globals->allocMemory(sizeof(_frenchText));
+ strcpy(ptr, _frenchText);
+ } else if (_vm->_globals->_language == LANG_SP) {
+ ptr = (char *)_vm->_globals->allocMemory(sizeof(_spanishText));
+ strcpy(ptr, _spanishText);
+ } else {
+ ptr = (char *)_vm->_globals->allocMemory(sizeof(_englishText));
+ strcpy(ptr, _englishText);
+ }
+
+ char *tmpPtr = ptr;
+ int lineNum = 0;
+ int strPos;
+ bool loopCond = false;
+
+ do {
+ if (tmpPtr[0] == '%') {
+ if (tmpPtr[1] == '%') {
+ loopCond = true;
+ break;
+ }
+ _menuText[lineNum]._actvFl = 1;
+ strPos = 0;
+ while (strPos <= 89) {
+ char curChar = tmpPtr[strPos + 2];
+ if (curChar == '%' || curChar == 10)
+ break;
+ _menuText[lineNum]._line[strPos++] = curChar;
+ }
+ if (strPos <= 89) {
+ _menuText[lineNum]._line[strPos] = 0;
+ _menuText[lineNum]._lineSize = strPos - 1;
+ }
+ ++lineNum;
+ }
+ ++tmpPtr;
+ } while (!loopCond);
+ _vm->_globals->freeMemory((byte *)ptr);
+}
+
+void ComputerManager::displayMessage(int xp, int yp, int textIdx) {
+ char curChar;
+
+ int x1 = xp;
+ int x2 = 0;
+
+ int textIndex = 0;
+ bool oldMouseFlag = _vm->_events->_mouseFl;
+ _vm->_events->_mouseFl = false;
+
+ _vm->_fontMan->displayTextVesa(xp, yp, "_", 252);
+ do {
+ curChar = _vm->_events->waitKeyPress();
+ if (_vm->shouldQuit())
+ return;
+
+ char mappedChar = '*';
+
+ if ((curChar == '-') || ((curChar >= '0') && (curChar <= '9')) || ((curChar >= 'A') && (curChar <= 'Z')))
+ mappedChar = curChar;
+ else if ((curChar >= 'a') && (curChar <= 'z'))
+ mappedChar = curChar - 32;
+
+ // BackSpace
+ if (curChar == 8 && textIndex > 0) {
+ _inputBuf[textIndex--] = 0;
+ x1 -= _vm->_fontMan->_fontFixedWidth;
+ x2 = x1 + 2 * _vm->_fontMan->_fontFixedWidth;
+ _vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, 3 * _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp);
+ _vm->_graphicsMan->addDirtyRect(x1, yp, x2, yp + 12);
+ _vm->_fontMan->displayTextVesa(x1, yp, "_", 252);
+ }
+ if (mappedChar != '*') {
+ char newChar = mappedChar;
+ _vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp);
+ _vm->_graphicsMan->addDirtyRect(x1, yp, _vm->_fontMan->_fontFixedWidth + x1, yp + 12);
+ _inputBuf[textIndex] = newChar;
+
+ Common::String charString = Common::String::format("%c_", newChar);
+ _vm->_fontMan->displayTextVesa(x1, yp, charString, 252);
+ ++textIndex;
+ x1 += _vm->_fontMan->_fontFixedWidth;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ } while (textIndex != textIdx && curChar != 13);
+
+ _vm->_graphicsMan->copyRect(_vm->_graphicsMan->_backBuffer, x1, yp, _vm->_fontMan->_fontFixedWidth, 12, _vm->_graphicsMan->_frontBuffer, x1, yp);
+ _vm->_graphicsMan->addDirtyRect(x1, yp, _vm->_fontMan->_fontFixedWidth + x1, yp + 12);
+
+ _vm->_events->refreshScreenAndEvents();
+ _inputBuf[textIndex] = 0;
+ _vm->_events->_mouseFl = oldMouseFlag;
+}
+
+/**
+ * Outputs a text string
+ */
+void ComputerManager::outText(const Common::String &msg) {
+ _vm->_fontMan->renderTextDisplay(_textPosition.x, _textPosition.y, msg, _textColor);
+}
+
+/**
+ * Outputs a text string
+ */
+void ComputerManager::outText2(const Common::String &msg) {
+ _vm->_fontMan->displayTextVesa(_textPosition.x, _textPosition.y, msg, _textColor);
+}
+
+/**
+ * Restores the scene for the FBI headquarters room
+ */
+void ComputerManager::restoreFBIRoom() {
+ _vm->_graphicsMan->fadeOutShort();
+
+ _vm->_globals->freeMemory(_vm->_fontMan->_font);
+ _vm->_fontMan->_font = _vm->_fileIO->loadFile("FONTE3.SPR");
+ _vm->_fontMan->_fontFixedWidth = 12;
+ _vm->_fontMan->_fontFixedHeight = 21;
+
+ _vm->_events->_mouseFl = true;
+}
+
+/**
+ * Display texts for the given menu entry
+ */
+void ComputerManager::readText(int idx) {
+ _vm->_events->_escKeyFl = false;
+
+ Common::String filename;
+ if (_vm->_globals->_language == LANG_EN)
+ filename = "THOPKAN.TXT";
+ else if (_vm->_globals->_language == LANG_FR)
+ filename = "THOPK.TXT";
+ else if (_vm->_globals->_language == LANG_SP)
+ filename = "THOPKES.TXT";
+
+ byte *ptr = _vm->_fileIO->loadFile(filename);
+ uint16 fileSize = _vm->_fileIO->fileSize(filename);
+ int pos;
+ for (pos = 0; pos < fileSize; pos++) {
+ if (ptr[pos] == '%') {
+ Common::String numStr = Common::String::format("%c%c", ptr[pos + 1], ptr[pos + 2]);
+ if (idx == atol(numStr.c_str()))
+ break;
+ }
+ }
+ if (pos > fileSize - 3)
+ error("Error with Hopkins computer file");
+
+ pos += 3;
+ int lineNum = 5;
+ Common::String curStr = "";
+ byte curChar;
+ do {
+ curChar = ptr[pos];
+ if (curChar == 13) {
+ setTextPosition(lineNum, 1);
+ outText(curStr);
+
+ ++lineNum;
+ _vm->_events->refreshScreenAndEvents();
+ curStr = "";
+ } else if (curChar != '%') {
+ curStr += curChar;
+ }
+ ++pos;
+ assert(pos <= fileSize);
+ } while (curChar != '%');
+
+ _vm->_events->waitKeyPress();
+ ptr = _vm->_globals->freeMemory(ptr);
+}
+
+/**
+ * Display breakout when Games sub-menu is selected
+ */
+void ComputerManager::displayGamesSubMenu() {
+ const byte *oldSpriteData = _vm->_objectsMan->_sprite[0]._spriteData;
+ uint oldSpeed = _vm->_globals->_speed;
+
+ _vm->_globals->_speed = 1;
+ _vm->_events->changeMouseCursor(0);
+ _breakoutSpr = NULL;
+ _vm->_events->_breakoutFl = true;
+ _breakoutLevel = (int16 *)NULL;
+ _breakoutBrickNbr = 0;
+ _breakoutScore = 0;
+ _breakoutLives = 5;
+ _breakoutSpeed = 1;
+ _ballRightFl = false;
+ _ballUpFl = false;
+ _breakoutLevelNbr = 0;
+ _vm->_graphicsMan->_minY = 0;
+ _vm->_graphicsMan->_maxX = 320;
+ _vm->_graphicsMan->_maxY = 200;
+ _vm->_soundMan->loadSample(1, "SOUND37.WAV");
+ _vm->_soundMan->loadSample(2, "SOUND38.WAV");
+ _vm->_soundMan->loadSample(3, "SOUND39.WAV");
+ _breakoutSpr = _vm->_fileIO->loadFile("CASSE.SPR");
+ loadHiscore();
+ setModeVGA256();
+
+ newLevel();
+ _vm->_graphicsMan->updateScreen();
+
+ playBreakout();
+ _vm->_graphicsMan->resetDirtyRects();
+ _breakoutSpr = _vm->_globals->freeMemory(_breakoutSpr);
+ _breakoutLevel = (int16 *)_vm->_globals->freeMemory((byte *)_breakoutLevel);
+ _vm->_objectsMan->_sprite[0]._spriteData = oldSpriteData;
+
+ _vm->_soundMan->removeSample(1);
+ _vm->_soundMan->removeSample(2);
+ _vm->_soundMan->removeSample(3);
+ _vm->_globals->_speed = oldSpeed;
+ _vm->_events->_breakoutFl = false;
+ setVideoMode();
+ setTextColor(15);
+ clearScreen();
+ _vm->_graphicsMan->_maxX = 680;
+ _vm->_graphicsMan->_minY = 0;
+ _vm->_graphicsMan->_maxY = 460;
+}
+
+/**
+ * Load Highscore from file
+ */
+void ComputerManager::loadHiscore() {
+ byte *ptr = _vm->_globals->allocMemory(100);
+ _vm->_saveLoad->load("HISCORE.DAT", ptr);
+
+ for (int scoreIndex = 0; scoreIndex < 6; ++scoreIndex) {
+ for (int i = 0; i < 5; ++i) {
+ char nextChar = ptr[(16 * scoreIndex) + i];
+ if (!nextChar)
+ nextChar = ' ';
+ _score[scoreIndex]._name += nextChar;
+ }
+
+ for (int i = 0; i < 9; ++i) {
+ char nextChar = ptr[(scoreIndex * 16) + 6 + i];
+ if (!nextChar)
+ nextChar = '0';
+ _score[scoreIndex]._score += nextChar;
+ }
+ }
+
+ _vm->_globals->freeMemory(ptr);
+ _breakoutHiscore = atol(_score[5]._score.c_str());
+}
+
+/**
+ * VGA 256 col
+ */
+void ComputerManager::setModeVGA256() {
+ _vm->_graphicsMan->clearScreen();
+ _vm->_graphicsMan->clearPalette();
+ _vm->_graphicsMan->setScreenWidth(320);
+}
+
+/**
+ * Load new level
+ */
+void ComputerManager::newLevel() {
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->removeSprite(1);
+ ++_breakoutLives;
+ if (_breakoutLives > 11)
+ _breakoutLives = 11;
+ _vm->_graphicsMan->loadVgaImage("CASSEF.PCX");
+ displayLives();
+ _breakoutLevel = (int16 *)_vm->_globals->freeMemory((byte *)_breakoutLevel);
+
+ ++_breakoutLevelNbr;
+ Common::String file;
+ Common::File f;
+ while (!_vm->shouldQuit()) {
+ file = Common::String::format("TAB%d.TAB", _breakoutLevelNbr);
+ if (f.open(file))
+ break;
+
+ _breakoutLevelNbr = 1;
+ }
+ f.close();
+
+ _breakoutLevel = (int16 *)_vm->_fileIO->loadFile(file);
+ displayBricks();
+
+ _vm->_objectsMan->addStaticSprite(_breakoutSpr, Common::Point(150, 192), 0, 13, 0, false, 0, 0);
+ _vm->_objectsMan->addStaticSprite(_breakoutSpr, Common::Point(164, 187), 1, 14, 0, false, 0, 0);
+
+ _ballPosition = Common::Point(164, 187);
+ _padPositionX = 150;
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->animateSprite(1);
+
+ _vm->_events->mouseOn();
+ _vm->_soundMan->playSample(3, 5);
+}
+
+/**
+ * Display bricks in breakout game
+ */
+void ComputerManager::displayBricks() {
+ _breakoutBrickNbr = 0;
+ _breakoutSpeed = 1;
+ int16 *level = _breakoutLevel;
+
+ int cellLeft;
+ int cellTop;
+ int cellType;
+ for (int levelIdx = 0; ; levelIdx += 6) {
+ cellLeft = (int16)FROM_LE_16(level[levelIdx]);
+ if (cellLeft == -1)
+ break;
+ cellTop = FROM_LE_16(level[levelIdx + 1]);
+ cellType = FROM_LE_16(level[levelIdx + 4]);
+
+ if (cellType <= 6)
+ ++_breakoutBrickNbr;
+
+ switch (cellType) {
+ case 1:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 21);
+ break;
+ case 2:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 22);
+ break;
+ case 3:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 17);
+ break;
+ case 4:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 20);
+ break;
+ case 5:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 19);
+ break;
+ case 6:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 18);
+ break;
+ case 31:
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellTop, 23);
+ break;
+ }
+ }
+
+ displayScore();
+}
+
+/**
+ * Display Lives in breakout game
+ */
+void ComputerManager::displayLives() {
+ for (int i = 0, xp = 10; i <= 11; i++, xp += 7)
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 10, 15);
+
+ for (int i = 0, xp = 10; i < _breakoutLives - 1; i++, xp += 7)
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 10, 14);
+
+ _vm->_graphicsMan->updateScreen();
+}
+
+/**
+ * Main function for breakout game
+ */
+void ComputerManager::playBreakout() {
+ int lastBreakoutEvent = 0;
+ while (!_vm->shouldQuit()) {
+ while (!_vm->shouldQuit()) {
+ // Set up the racket and ball
+ _vm->_events->mouseOff();
+ _ballPosition = Common::Point(_padPositionX + 14, 187);
+ _vm->_objectsMan->setSpriteY(1, 187);
+ _vm->_objectsMan->setSpriteX(1, _ballPosition.x);
+
+ _vm->_graphicsMan->resetDirtyRects();
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->fadeInBreakout();
+
+ // Wait for mouse press to start playing
+ do {
+ _padPositionX = _vm->_events->getMouseX();
+ if (_vm->_events->_mousePos.x <= 4)
+ _padPositionX = 5;
+ if (_padPositionX > 282)
+ _padPositionX = 282;
+ _vm->_objectsMan->setSpriteX(0, _padPositionX);
+ _vm->_objectsMan->setSpriteX(1, _padPositionX + 14);
+ _vm->_objectsMan->setSpriteY(1, 187);
+ _vm->_events->refreshScreenAndEvents();
+ } while (!_vm->shouldQuit() && _vm->_events->getMouseButton() != 1);
+
+ _breakoutSpeed = 1;
+ _ballPosition = Common::Point(_padPositionX + 14, 187);
+ _ballRightFl = (_padPositionX > 135);
+ _ballUpFl = false;
+
+ // Play loop
+ do {
+ _vm->_soundMan->checkSounds();
+
+ _padPositionX = _vm->_events->getMouseX();
+ if (_vm->_events->_mousePos.x <= 4)
+ _padPositionX = 5;
+ if (_padPositionX > 282)
+ _padPositionX = 282;
+ _vm->_objectsMan->setSpriteX(0, _padPositionX);
+ lastBreakoutEvent = moveBall();
+ _vm->_events->refreshScreenAndEvents();
+ } while (!_vm->shouldQuit() && !lastBreakoutEvent);
+ if (lastBreakoutEvent != 1)
+ break;
+
+ --_breakoutLives;
+
+ if (_breakoutLives) {
+ displayLives();
+ if (_breakoutLives)
+ continue;
+ }
+
+ _vm->_graphicsMan->fadeOutBreakout();
+ _vm->_events->mouseOn();
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->removeSprite(1);
+ if (_breakoutScore > _breakoutHiscore)
+ getScoreName();
+ if (displayHiscores() != 1)
+ break;
+
+ _breakoutBrickNbr = 0;
+ _breakoutScore = 0;
+ _breakoutLives = 4;
+ _breakoutSpeed = 1;
+ _ballRightFl = false;
+ _ballUpFl = false;
+ _breakoutLevelNbr = 0;
+ loadHiscore();
+ newLevel();
+ }
+ if (lastBreakoutEvent != 2)
+ return;
+ _vm->_graphicsMan->fadeOutBreakout();
+ newLevel();
+ }
+}
+
+/**
+ * Show the high scores for the Breakout game
+ * @return The selected button index: 1 = Game, 2 = Quit
+ */
+int ComputerManager::displayHiscores() {
+ _vm->_graphicsMan->resetDirtyRects();
+ loadHiscore();
+ _vm->_graphicsMan->loadVgaImage("HISCORE.PCX");
+ byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR");
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+
+ int yp;
+ int xp;
+ // Loop for displaying the scores
+ for (int scoreIndex = 0; scoreIndex <= 5; scoreIndex++) {
+ yp = 19 * scoreIndex;
+ yp += 46;
+
+ // Display the characters of the name
+ for (int i = 0; i <= 5; i++)
+ displayHiscoreLine(ptr, 9 * i + 69, yp, _score[scoreIndex]._name[i]);
+
+ // Display the digits of the score
+ for (int i = 0; i <= 8; i++)
+ displayHiscoreLine(ptr, 9 * i + 199, yp, _score[scoreIndex]._score[i]);
+ }
+
+ _vm->_graphicsMan->fadeInBreakout();
+ _vm->_graphicsMan->resetDirtyRects();
+ int buttonIndex = 0;
+ do {
+ _vm->_events->refreshEvents();
+ xp = _vm->_events->getMouseX();
+ yp = _vm->_events->getMouseY();
+
+ if (_vm->_events->getMouseButton() == 1 && ABS(xp - 79) <= 33 && ABS(yp - 396) <= 13)
+ buttonIndex = 1;
+ else if (_vm->_events->getMouseButton() == 1 && ABS(xp - 583) <= 32 && ABS(yp - 396) <= 13)
+ buttonIndex = 2;
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (!buttonIndex && !_vm->shouldQuit());
+
+ _vm->_events->mouseOff();
+ _vm->_graphicsMan->fadeOutBreakout();
+ _vm->_globals->freeMemory(ptr);
+ return buttonIndex;
+}
+
+/**
+ * Display a screen to enter player name in the case of a new hiscore
+ */
+void ComputerManager::getScoreName() {
+ _vm->_graphicsMan->loadVgaImage("NAME.PCX");
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+ byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR");
+ _vm->_graphicsMan->fadeInBreakout();
+ for (int strPos = 0; strPos <= 4; strPos++) {
+ displayHiscoreLine(ptr, 9 * strPos + 140, 78, 1);
+
+ char curChar = toupper(_vm->_events->waitKeyPress());
+ if ((curChar < '0') || (curChar > 'Z'))
+ curChar = ' ';
+ if ((curChar > '9') && (curChar < 'A'))
+ curChar = ' ';
+
+ _score[5]._name.setChar(curChar, strPos);
+ displayHiscoreLine(ptr, 9 * strPos + 140, 78, curChar);
+
+ for (int idx = 0; idx < 12; ++idx)
+ _vm->_events->refreshScreenAndEvents();
+ }
+ _score[5]._score = " ";
+
+ char score[16];
+ sprintf(score, "%d", _breakoutScore);
+ int scoreLen = 0;
+ do
+ ++scoreLen;
+ while (score[scoreLen]);
+
+ for (int i = scoreLen, scorePos = 8; i >= 0; i--) {
+ _score[5]._score.setChar(score[i], scorePos--);
+ }
+ _vm->_graphicsMan->fadeOutBreakout();
+ _vm->_globals->freeMemory(ptr);
+ saveScore();
+}
+
+/**
+ * Display current score
+ */
+void ComputerManager::displayScore() {
+ Common::String scoreStr = Common::String::format("%d", _breakoutScore);
+ int strSize = scoreStr.size();
+ for (int i = strSize - 1, idx = 0; i >= 0; i--) {
+ displayScoreChar(idx++, scoreStr[i]);
+ }
+}
+
+/**
+ * Display a character of the score
+ */
+void ComputerManager::displayScoreChar(int charPos, int charDisp) {
+ int xp;
+ switch (charPos) {
+ case 1:
+ xp = 190;
+ break;
+ case 2:
+ xp = 180;
+ break;
+ case 3:
+ xp = 167;
+ break;
+ case 4:
+ xp = 157;
+ break;
+ case 5:
+ xp = 147;
+ break;
+ case 9:
+ xp = 134;
+ break;
+ default:
+ xp = 200;
+ break;
+ }
+
+ int idx = 3;
+ if (charDisp >= '0' && charDisp <= '9')
+ idx = charDisp - 45;
+
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, xp, 11, idx);
+}
+
+/**
+ * Save Hiscore in file
+ */
+void ComputerManager::saveScore() {
+ int scores[6];
+ // Load high scores in an array
+ for (int i = 0; i <= 5; i++) {
+ scores[i] = atol(_score[i]._score.c_str());
+ if (!scores[i])
+ scores[i] = 5;
+ }
+
+ int scorePlace[6];
+ // order high scores
+ for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) {
+ for(int i = 0;;i++) {
+ int curScore = scores[i];
+ if (curScore && scores[0] <= curScore && scores[1] <= curScore && scores[2] <= curScore && scores[3] <= curScore
+ && scores[4] <= curScore && scores[5] <= curScore) {
+ scorePlace[scorePlaceIdx] = i;
+ scores[i] = 0;
+ break;
+ }
+ }
+ }
+
+ byte *ptr = _vm->_globals->allocMemory(100);
+ memset(ptr, 0, 99);
+ for (int scorePlaceIdx = 0; scorePlaceIdx <= 5; scorePlaceIdx++) {
+ int curBufPtr = 16 * scorePlaceIdx;
+ for (int namePos = 0; namePos <= 4; namePos++) {
+ char curChar = _score[scorePlace[scorePlaceIdx]]._name[namePos];
+ if (!curChar)
+ curChar = ' ';
+ ptr[curBufPtr + namePos] = curChar;
+ };
+
+ ptr[curBufPtr + 5] = 0;
+
+ for (int scorePos = 0; scorePos <= 8; scorePos++) {
+ char curChar = _score[scorePlace[scorePlaceIdx]]._score[scorePos];
+ if (!curChar)
+ curChar = '0';
+ ptr[curBufPtr + 6 + scorePos] = curChar;
+ };
+ ptr[curBufPtr + 15] = 0;
+ }
+
+ _vm->_saveLoad->saveFile("HISCORE.DAT", ptr, 100);
+ _vm->_globals->freeMemory(ptr);
+}
+
+/**
+ * Display parts of the hiscore line
+ */
+void ComputerManager::displayHiscoreLine(const byte *objectData, int x, int y, int curChar) {
+ int idx = 36;
+
+ if (curChar == 100)
+ idx = 0;
+ else if (curChar >= '0' && curChar <= '9')
+ idx = curChar - '0';
+ else if (curChar >= 'A' && curChar <= 'Z')
+ idx = curChar - 'A' + 10;
+ else if (curChar == 1)
+ idx = 37;
+ _vm->_graphicsMan->fastDisplay2(objectData, x, y, idx);
+}
+
+/**
+ * Handle ball moves
+ */
+int ComputerManager::moveBall() {
+ //(signed int)(6.0 * (long double)_vm->getRandomNumber( rand() / 2147483648.0) + 1;
+ // TODO: Figure out random number
+ int randVal = _vm->getRandomNumber(6);
+ switch (_breakoutSpeed) {
+ case 1:
+ _minBreakoutMoveSpeed = 1;
+ _maxBreakoutMoveSpeed = 1;
+ break;
+ case 2:
+ _minBreakoutMoveSpeed = 1;
+ _maxBreakoutMoveSpeed = 2;
+ break;
+ case 3:
+ _minBreakoutMoveSpeed = 2;
+ _maxBreakoutMoveSpeed = 2;
+ break;
+ case 4:
+ _minBreakoutMoveSpeed = 3;
+ _maxBreakoutMoveSpeed = 2;
+ break;
+ }
+
+ int moveSpeed = _minBreakoutMoveSpeed;
+ if (_lastBreakoutMoveSpeed == _minBreakoutMoveSpeed)
+ moveSpeed = _maxBreakoutMoveSpeed;
+
+ if (_ballUpFl)
+ _ballPosition.y += moveSpeed;
+ else
+ _ballPosition.y -= moveSpeed;
+
+ if (_ballRightFl)
+ _ballPosition.x += moveSpeed;
+ else
+ _ballPosition.x -= moveSpeed;
+
+ _lastBreakoutMoveSpeed = moveSpeed;
+ if (_ballPosition.x <= 6) {
+ _vm->_soundMan->playSample(2, 6);
+ _ballPosition.x = randVal + 6;
+ _ballRightFl = !_ballRightFl;
+ } else if (_ballPosition.x > 307) {
+ _vm->_soundMan->playSample(2, 6);
+ _ballPosition.x = 307 - randVal;
+ _ballRightFl = !_ballRightFl;
+ }
+
+ if (_ballPosition.y <= 6) {
+ _vm->_soundMan->playSample(2, 6);
+ _ballPosition.y = randVal + 7;
+ _ballUpFl = !_ballUpFl;
+ } else if (_ballPosition.y >= 186 && _ballPosition.y <= 194) {
+ _vm->_soundMan->playSample(2, 6);
+ int ballPosXRight = _ballPosition.x + 6;
+ if ((_ballPosition.x > _padPositionX - 2) && (ballPosXRight < _padPositionX + 36)) {
+ _ballUpFl = false;
+ if (ballPosXRight <= _padPositionX + 15) {
+ _ballRightFl = false;
+ if (_ballPosition.x >= _padPositionX && ballPosXRight <= _padPositionX + 5)
+ _ballPosition.x -= 4;
+ if (_ballPosition.x >= _padPositionX + 5 && _ballPosition.x + 6 <= _padPositionX + 10)
+ _ballPosition.x -= 2;
+ }
+ if (_ballPosition.x >= _padPositionX + 19 && _ballPosition.x + 6 <= _padPositionX + 36) {
+ _ballRightFl = true;
+ if (_ballPosition.x >= _padPositionX + 29)
+ _ballPosition.x += 4;
+ if (_ballPosition.x >= _padPositionX + 24 && _ballPosition.x + 6 <= _padPositionX + 29)
+ _ballPosition.x += 2;
+ }
+ }
+ }
+
+ int retVal = 0;
+ if (_ballPosition.y > 194)
+ retVal = 1;
+ checkBallCollisions();
+ _vm->_objectsMan->setSpriteX(1, _ballPosition.x);
+ _vm->_objectsMan->setSpriteY(1, _ballPosition.y);
+ if (!_breakoutBrickNbr)
+ retVal = 2;
+ return retVal;
+}
+
+/**
+ * Check ball collision with bricks
+ */
+void ComputerManager::checkBallCollisions() {
+ int cellLeft;
+
+ bool brickDestroyedFl = false;
+ // TODO: Check if correct
+ int randVal = _vm->getRandomNumber(6) + 1;
+ int ballLeft = _ballPosition.x;
+ int ballTop = _ballPosition.y;
+ int ballRight = _ballPosition.x + 6;
+ int ballBottom = _ballPosition.y + 6;
+ int16 *level = _breakoutLevel;
+ uint16 levelIdx = 0;
+ do {
+ cellLeft = level[levelIdx];
+ int cellUp = level[levelIdx + 1];
+ int cellRight = level[levelIdx + 2];
+ int cellBottom = level[levelIdx + 3];
+ int cellType = level[levelIdx + 4];
+ if (level[levelIdx + 5] == 1 && cellLeft != -1) {
+ bool collisionFl = false;
+ if (ballTop <= cellBottom && ballBottom >= cellBottom) {
+ if (ballLeft >= cellLeft && ballRight <= cellRight) {
+ collisionFl = true;
+ _ballUpFl = true;
+ }
+ if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) {
+ collisionFl = true;
+ _ballUpFl = true;
+ _ballRightFl = false;
+ if (cellType == 31)
+ _ballPosition.x -= randVal;
+ }
+ if ((ballLeft <= cellRight) && (ballRight >= cellRight)) {
+ collisionFl = true;
+ _ballUpFl = true;
+ _ballRightFl = true;
+ if (cellType == 31)
+ _ballPosition.x += randVal;
+ }
+ }
+ if (ballBottom >= cellUp && ballTop <= cellUp) {
+ if (ballLeft >= cellLeft && ballRight <= cellRight) {
+ collisionFl = true;
+ _ballUpFl = false;
+ }
+ if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) {
+ collisionFl = true;
+ _ballUpFl = false;
+ _ballRightFl = false;
+ if (cellType == 31)
+ _ballPosition.x -= 2;
+ }
+ if ((ballLeft <= cellRight) && (ballRight >= cellRight)) {
+ collisionFl = true;
+ _ballUpFl = false;
+ _ballRightFl = true;
+ if (cellType == 31)
+ _ballPosition.x += randVal;
+ }
+ }
+ if ((ballTop >= cellUp) && (ballBottom <= cellBottom)) {
+ if ((ballRight >= cellLeft) && (ballLeft <= cellLeft)) {
+ collisionFl = true;
+ _ballRightFl = false;
+ if (cellType == 31)
+ _ballPosition.x -= randVal;
+ }
+ if ((ballLeft <= cellRight) && (ballRight >= cellRight)) {
+ collisionFl = true;
+ _ballRightFl = true;
+ if (cellType == 31)
+ _ballPosition.x += randVal;
+ }
+ }
+ if (collisionFl) {
+ if (cellType == 31) {
+ _vm->_soundMan->playSample(2, 6);
+ } else {
+ _vm->_soundMan->playSample(1, 5);
+ _vm->_graphicsMan->fastDisplay2(_breakoutSpr, cellLeft, cellUp, 16);
+ switch (cellType) {
+ case 1:
+ _breakoutScore += 10;
+ break;
+ case 2:
+ _breakoutScore += 5;
+ break;
+ case 3:
+ _breakoutScore += 50;
+ if (_breakoutSpeed <= 1)
+ _breakoutSpeed = 2;
+ if (_breakoutBrickNbr <= 19)
+ _breakoutSpeed = 3;
+ break;
+ case 4:
+ _breakoutScore += 20;
+ break;
+ case 5:
+ _breakoutScore += 30;
+ if (_breakoutSpeed <= 1)
+ _breakoutSpeed = 2;
+ break;
+ case 6:
+ _breakoutScore += 40;
+ break;
+ }
+ displayScore();
+ --_breakoutBrickNbr;
+ level[levelIdx + 5] = 0;
+ brickDestroyedFl = true;
+ }
+ }
+ }
+
+ if (brickDestroyedFl)
+ cellLeft = -1;
+ levelIdx += 6;
+ } while (cellLeft != -1);
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/computer.h b/engines/hopkins/computer.h
new file mode 100644
index 0000000000..cdd653f793
--- /dev/null
+++ b/engines/hopkins/computer.h
@@ -0,0 +1,106 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_COMPUTER_H
+#define HOPKINS_COMPUTER_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/rect.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+struct MenuItem {
+ bool _actvFl;
+ int _lineSize;
+ char _line[90];
+};
+
+struct ScoreItem {
+ Common::String _name;
+ Common::String _score;
+};
+
+enum ComputerEnum { COMPUTER_HOPKINS = 1, COMPUTER_SAMANTHA = 2, COMPUTER_PUBLIC = 3 };
+
+class ComputerManager {
+private:
+ HopkinsEngine *_vm;
+ MenuItem _menuText[50];
+ char _inputBuf[200];
+ ScoreItem _score[6];
+ int _textColor;
+ Common::Point _textPosition;
+ Common::Point _ballPosition;
+ byte *_breakoutSpr;
+ int16 *_breakoutLevel;
+ int _breakoutBrickNbr;
+ int _breakoutScore;
+ int _breakoutLives;
+ int _breakoutSpeed;
+ bool _ballRightFl;
+ bool _ballUpFl;
+ int _breakoutLevelNbr;
+ int _padPositionX;
+ int _breakoutHiscore;
+ int _minBreakoutMoveSpeed;
+ int _maxBreakoutMoveSpeed;
+ int _lastBreakoutMoveSpeed;
+
+ void loadMenu();
+ void restoreFBIRoom();
+ void setVideoMode();
+ void setTextMode();
+ void clearScreen();
+ void setTextColor(int col);
+ void setTextPosition(int yp, int xp);
+ void outText(const Common::String &msg);
+ void outText2(const Common::String &msg);
+ void readText(int idx);
+ void loadHiscore();
+ void newLevel();
+ void setModeVGA256();
+ void displayLives();
+ void displayBricks();
+ void displayGamesSubMenu();
+ int displayHiscores();
+ void displayHiscoreLine(const byte *objectData, int x, int y, int curChar);
+ void displayMessage(int xp, int yp, int textIdx);
+ void displayScore();
+ void displayScoreChar(int charPos, int charDisp);
+ void getScoreName();
+ void playBreakout();
+ int moveBall();
+ void saveScore();
+ void checkBallCollisions();
+
+public:
+ ComputerManager(HopkinsEngine *vm);
+
+ void showComputer(ComputerEnum mode);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_COMPUTER_H */
diff --git a/engines/hopkins/debugger.cpp b/engines/hopkins/debugger.cpp
new file mode 100644
index 0000000000..246270c1c2
--- /dev/null
+++ b/engines/hopkins/debugger.cpp
@@ -0,0 +1,67 @@
+/* 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/debugger.h"
+
+#include "hopkins/globals.h"
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+
+namespace Hopkins {
+
+Debugger::Debugger(HopkinsEngine *vm) : GUI::Debugger() {
+ _vm = vm;
+ DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
+ DCmd_Register("rects", WRAP_METHOD(Debugger, cmd_DirtyRects));
+ DCmd_Register("teleport", WRAP_METHOD(Debugger, cmd_Teleport));
+ DCmd_Register("show_room", WRAP_METHOD(Debugger, cmd_ShowCurrentRoom));
+}
+
+// Turns dirty rects on or off
+bool Debugger::cmd_DirtyRects(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("%s: [on | off]\n", argv[0]);
+ return true;
+ } else {
+ _vm->_graphicsMan->_showDirtyRects = !strcmp(argv[1], "on");
+ return false;
+ }
+}
+
+// Change room number
+bool Debugger::cmd_Teleport(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("%s: [Room number]\n", argv[0]);
+ return true;
+ } else {
+ _vm->_globals->_exitId = atoi(argv[1]);
+ return false;
+ }
+}
+
+// Display room number
+bool Debugger::cmd_ShowCurrentRoom(int argc, const char **argv) {
+ DebugPrintf("Current room: %d\n", _vm->_globals->_curRoomNum);
+ return true;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/debugger.h b/engines/hopkins/debugger.h
new file mode 100644
index 0000000000..7f7bffd755
--- /dev/null
+++ b/engines/hopkins/debugger.h
@@ -0,0 +1,48 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_DEBUGGER_H
+#define HOPKINS_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+class Debugger : public GUI::Debugger {
+private:
+ HopkinsEngine *_vm;
+
+public:
+ Debugger(HopkinsEngine *vm);
+ virtual ~Debugger() {}
+
+ bool cmd_DirtyRects(int argc, const char **argv);
+ bool cmd_Teleport(int argc, const char **argv);
+ bool cmd_ShowCurrentRoom(int argc, const char **argv);
+};
+
+} // End of namespace Hopkins
+
+#endif
diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp
new file mode 100644
index 0000000000..a42597415b
--- /dev/null
+++ b/engines/hopkins/detection.cpp
@@ -0,0 +1,191 @@
+/* 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/hopkins.h"
+
+#include "base/plugins.h"
+#include "common/savefile.h"
+#include "common/str-array.h"
+#include "common/memstream.h"
+#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "graphics/colormasks.h"
+#include "graphics/surface.h"
+
+#define MAX_SAVES 99
+
+namespace Hopkins {
+
+struct HopkinsGameDescription {
+ ADGameDescription desc;
+};
+
+uint32 HopkinsEngine::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
+
+Common::Language HopkinsEngine::getLanguage() const {
+ return _gameDescription->desc.language;
+}
+
+Common::Platform HopkinsEngine::getPlatform() const {
+ return _gameDescription->desc.platform;
+}
+
+bool HopkinsEngine::getIsDemo() const {
+ return _gameDescription->desc.flags & ADGF_DEMO;
+}
+
+} // End of namespace Hopkins
+
+static const PlainGameDescriptor hopkinsGames[] = {
+ {"hopkins", "Hopkins FBI"},
+ {0, 0}
+};
+
+#include "hopkins/detection_tables.h"
+
+const static char *directoryGlobs[] = {
+ "voice",
+ 0
+};
+
+class HopkinsMetaEngine : public AdvancedMetaEngine {
+public:
+ HopkinsMetaEngine() : AdvancedMetaEngine(Hopkins::gameDescriptions, sizeof(Hopkins::HopkinsGameDescription), hopkinsGames) {
+ _maxScanDepth = 3;
+ _directoryGlobs = directoryGlobs;
+ }
+
+ virtual const char *getName() const {
+ return "Hopkins Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Hopkins FBI (c)1997-2003 MP Entertainment";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual void removeSaveState(const char *target, int slot) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+};
+
+bool HopkinsMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail);
+}
+
+bool Hopkins::HopkinsEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+bool HopkinsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ const Hopkins::HopkinsGameDescription *gd = (const Hopkins::HopkinsGameDescription *)desc;
+ if (gd) {
+ *engine = new Hopkins::HopkinsEngine(syst, gd);
+ }
+ return gd != 0;
+}
+
+SaveStateList HopkinsMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String saveDesc;
+ Common::String pattern = Common::String::format("%s.0??", target);
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
+
+ Hopkins::hopkinsSavegameHeader header;
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ const char *ext = strrchr(file->c_str(), '.');
+ int slot = ext ? atoi(ext + 1) : -1;
+
+ if (slot >= 0 && slot < MAX_SAVES) {
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
+
+ if (in) {
+ if (Hopkins::SaveLoadManager::readSavegameHeader(in, header)) {
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+int HopkinsMetaEngine::getMaximumSaveSlot() const {
+ return MAX_SAVES;
+}
+
+void HopkinsMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(filename);
+}
+
+SaveStateDescriptor HopkinsMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename);
+
+ if (f) {
+ Hopkins::hopkinsSavegameHeader header;
+ Hopkins::SaveLoadManager::readSavegameHeader(f, header);
+ delete f;
+
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header._saveName);
+ desc.setThumbnail(header._thumbnail);
+ desc.setSaveDate(header._year, header._month, header._day);
+ desc.setSaveTime(header._hour, header._minute);
+ desc.setPlayTime(header._totalFrames * GAME_FRAME_TIME);
+
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+
+#if PLUGIN_ENABLED_DYNAMIC(HOPKINS)
+REGISTER_PLUGIN_DYNAMIC(HOPKINS, PLUGIN_TYPE_ENGINE, HopkinsMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(HOPKINS, PLUGIN_TYPE_ENGINE, HopkinsMetaEngine);
+#endif
diff --git a/engines/hopkins/detection_tables.h b/engines/hopkins/detection_tables.h
new file mode 100644
index 0000000000..e1937372d2
--- /dev/null
+++ b/engines/hopkins/detection_tables.h
@@ -0,0 +1,247 @@
+/* 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.
+ *
+ */
+
+namespace Hopkins {
+
+static const HopkinsGameDescription gameDescriptions[] = {
+ {
+ // Hopkins FBI Linux Demo 1.00
+ {
+ "hopkins",
+ "Linux Demo v1.00",
+ {
+ {"Hopkins-PDemo.bin", 0, "88b4d6e14b9b1407083cb3d1213c0fa7", 272027},
+ {"RES_VAN.RES", 0, "29414c05be8f9fe794c61572a65def12", 16060544},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformLinux,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ {
+ // Hopkins FBI Linux Demo 1.02
+ {
+ "hopkins",
+ "Linux Demo v1.02",
+ {
+ {"Hopkins-PDemo.bin", 0, "f82f4e698f3a189419351be0de2b2f8e", 273760},
+ {"RES_VAN.RES", 0, "29414c05be8f9fe794c61572a65def12", 16060544},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformLinux,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ {
+ // Hopkins FBI OS/2, provided by Strangerke
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.exe", 0, "63d45f882278e5a9fa1027066223e5d9", 292864},
+ {"ENG_VOI.RES", 0, "fa5789d1d8c19d160bce44a33e742fdf", 66860711},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformOS2,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Win95 Demo, provided by Strangerke
+ // CHECKME: No voice! a second file is required though... Also, it has multi-language support
+ {
+ "hopkins",
+ "Win95 Demo",
+ {
+ {"Hopkins.exe", 0, "0c9ebfe371f4dcf84a49f333f04839a0", 376897},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Win95 Polish Demo, provided by Strangerke
+ {
+ "hopkins",
+ "Win95 Demo",
+ {
+ {"Hopkins.exe", 0, "7595c0b9374739b212ee9f8f412ac716", 307200},
+ {"RES_VAN.RES", 0, "8262cfba261c200af4451902689dffe0", 12233202},
+ AD_LISTEND
+ },
+ Common::PL_POL,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Win95 Spanish
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.exe", 0, "31c837378bb2e0b2573befea44956d3f", 421386},
+ {"RES_VES.RES", 0, "77ee08896466ae88cc1af3bf1a0bf78c", 32882302},
+ AD_LISTEND
+ },
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Win95, provided by Strangerke
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.exe", 0, "277a5c144bf9ec7d8450ae37afb85090", 419281},
+ {"RES_VAN.RES", 0, "f1693ac0b0859c8ecd8cb30ff43cf55f", 38296346},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Win95, provided by alexbevi
+ // Dec 15 1998 hopkins.exe
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.exe", 0, "a587762dd50d5933e1c89f9975180764", 378694},
+ {"RES_VAN.RES", 0, "f1693ac0b0859c8ecd8cb30ff43cf55f", 38296346},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Linux, provided by Strangerke
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.bin", 0, "71611380cb31744bf909b8319a65e6e6", 275844},
+ {"RES_VFR.RES", 0, "0490d4d1aa71075ebf71cc79e5dc7894", 39817945},
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformLinux,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Hopkins FBI Linux, provided by Strangerke
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.bin", 0, "71611380cb31744bf909b8319a65e6e6", 275844},
+ {"RES_VAN.RES", 0, "29414c05be8f9fe794c61572a65def12", 38832455},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformLinux,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ {
+ // Hopkins FBI BeOS, provided by Strangerke
+ {
+ "hopkins",
+ 0,
+ {
+ {"ENG_VOI.RES", 0, "fa5789d1d8c19d160bce44a33e742fdf", 66860711},
+ {"Hopkins_ FBI", 0, "8940ce2e618c42691b66aad5d6c223b0", 757936},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformBeOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ {
+ // Hopkins FBI BeOS, uninstalled, provided by eriktorbjorn
+ {
+ "hopkins",
+ 0,
+ {
+ {"ENG_VOI.RES", 0, "fa5789d1d8c19d160bce44a33e742fdf", 66860711},
+ {"Hopkins.pkg", 0, "72f97806dd3d5fc0c0eb24196f180618", 285017},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformBeOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ },
+
+ {
+ // Hopkins FBI Win32, French uninstalled, provided by SylvainTV
+ {
+ "hopkins",
+ 0,
+ {
+ {"Hopkins.exe", 0, "277a5c144bf9ec7d8450ae37afb85090", 419281},
+ {"RES_VFR.RES", 0, "b8a3849063c9eeefe80e82cfce1ad3cd", 39269361},
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ },
+
+
+ { AD_TABLE_END_MARKER }
+};
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/dialogs.cpp b/engines/hopkins/dialogs.cpp
new file mode 100644
index 0000000000..5b9fb8afc2
--- /dev/null
+++ b/engines/hopkins/dialogs.cpp
@@ -0,0 +1,781 @@
+/* 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/dialogs.h"
+
+#include "hopkins/events.h"
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+#include "hopkins/sound.h"
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/util.h"
+
+namespace Hopkins {
+
+DialogsManager::DialogsManager(HopkinsEngine *vm) {
+ _vm = vm;
+ _inventFl = false;
+ _inventDisplayedFl = false;
+ _removeInventFl = false;
+ _inventX = _inventY = 0;
+ _oldInventX = 0;
+ _inventWidth = _inventHeight = 0;
+ _inventWin1 = NULL;
+ _inventBuf2 = NULL;
+ _inventoryIcons = NULL;
+}
+
+DialogsManager::~DialogsManager() {
+ _vm->_globals->freeMemory(_inventWin1);
+ _vm->_globals->freeMemory(_inventBuf2);
+ _vm->_globals->freeMemory(_inventoryIcons);
+}
+
+void DialogsManager::clearAll() {
+ _inventWin1 = NULL;
+ _inventBuf2 = NULL;
+}
+
+void DialogsManager::loadIcons() {
+ _inventoryIcons = _vm->_fileIO->loadFile("ICONE.SPR");
+}
+
+void DialogsManager::drawInvent(Common::Point oldBorder, int oldBorderSpriteIndex, Common::Point newBorder, int newBorderSpriteIndex) {
+ if (!_inventDisplayedFl)
+ return;
+
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, _inventWin1, _inventX, _inventY, _inventWidth, _inventHeight);
+ if (oldBorder.x && oldBorder.y)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _inventBuf2, oldBorder.x + 300, oldBorder.y + 300, oldBorderSpriteIndex + 1);
+ if (newBorder.x && newBorder.y)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _inventBuf2, newBorder.x + 300, newBorder.y + 300, newBorderSpriteIndex);
+ _vm->_graphicsMan->addDirtyRect(_inventX, _inventY, _inventX + _inventWidth, _inventY + _inventHeight);
+}
+
+void DialogsManager::showOptionsDialog() {
+ _vm->_events->changeMouseCursor(0);
+ _vm->_events->refreshScreenAndEvents();
+ Common::String filename;
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ filename = "OPTION.SPR";
+ else {
+ if (_vm->_globals->_language == LANG_FR)
+ filename = "OPTIFR.SPR";
+ else if (_vm->_globals->_language == LANG_EN)
+ filename = "OPTIAN.SPR";
+ else if (_vm->_globals->_language == LANG_SP)
+ filename = "OPTIES.SPR";
+ }
+
+ _vm->_globals->_optionDialogSpr = _vm->_fileIO->loadFile(filename);
+ _vm->_globals->_optionDialogFl = true;
+
+ int scrollOffset = _vm->_graphicsMan->_scrollOffset;
+ bool doneFlag = false;
+ do {
+ if (_vm->_events->getMouseButton()) {
+ Common::Point mousePos(_vm->_events->getMouseX(), _vm->_events->getMouseY());
+
+ if (!_vm->_soundMan->_musicOffFl) {
+ if (mousePos.x >= scrollOffset + 300 && mousePos.y > 113 && mousePos.x <= scrollOffset + 327 && mousePos.y <= 138) {
+ // Change the music volume
+ ++_vm->_soundMan->_musicVolume;
+
+ if (_vm->_soundMan->_musicVolume <= 12)
+ _vm->_soundMan->playSoundFile("bruit2.wav");
+ else
+ _vm->_soundMan->_musicVolume = 12;
+ _vm->_soundMan->setMODMusicVolume(_vm->_soundMan->_musicVolume);
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+
+ if (!_vm->_soundMan->_musicOffFl && mousePos.x >= scrollOffset + 331 && mousePos.y > 113 && mousePos.x <= scrollOffset + 358 && mousePos.y <= 138) {
+ --_vm->_soundMan->_musicVolume;
+ if (_vm->_soundMan->_musicVolume >= 0)
+ _vm->_soundMan->playSoundFile("bruit2.wav");
+ else
+ _vm->_soundMan->_musicVolume = 0;
+
+ _vm->_soundMan->setMODMusicVolume(_vm->_soundMan->_musicVolume);
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+ }
+ if (!_vm->_soundMan->_soundOffFl) {
+ // increase volume
+ if (mousePos.x >= scrollOffset + 300 && mousePos.y > 140 && mousePos.x <= scrollOffset + 327 && mousePos.y <= 165) {
+ ++_vm->_soundMan->_soundVolume;
+ if (_vm->_soundMan->_soundVolume <= 16)
+ _vm->_soundMan->playSoundFile("bruit2.wav");
+ else
+ _vm->_soundMan->_soundVolume = 16;
+ _vm->_soundMan->setMODSampleVolume();
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+
+ // Decrease volume
+ if (!_vm->_soundMan->_soundOffFl && mousePos.x >= scrollOffset + 331 && mousePos.y > 140 && mousePos.x <= scrollOffset + 358 && mousePos.y <= 165) {
+ --_vm->_soundMan->_soundVolume;
+ if (_vm->_soundMan->_soundVolume >= 0)
+ _vm->_soundMan->playSoundFile("bruit2.wav");
+ else
+ _vm->_soundMan->_soundVolume = 0;
+ _vm->_soundMan->setMODSampleVolume();
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+ }
+
+ if (!_vm->_soundMan->_voiceOffFl) {
+ if (mousePos.x >= scrollOffset + 300 && mousePos.y > 167 && mousePos.x <= scrollOffset + 327 && mousePos.y <= 192) {
+ ++_vm->_soundMan->_voiceVolume;
+
+ if (_vm->_soundMan->_voiceVolume <= 16)
+ _vm->_soundMan->playSoundFile("bruit2.wav");
+ else
+ _vm->_soundMan->_voiceVolume = 16;
+ _vm->_soundMan->setMODVoiceVolume();
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+
+ if (!_vm->_soundMan->_voiceOffFl && mousePos.x >= scrollOffset + 331 && mousePos.y > 167 && mousePos.x <= scrollOffset + 358 && mousePos.y <= 192) {
+ --_vm->_soundMan->_voiceVolume;
+ if (_vm->_soundMan->_voiceVolume >= 0)
+ _vm->_soundMan->playSoundFile("bruit2.wav");
+ else
+ _vm->_soundMan->_voiceVolume = 0;
+ _vm->_soundMan->setMODVoiceVolume();
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+ }
+
+ if (mousePos.x >= scrollOffset + 431) {
+ if (mousePos.y > 194 && mousePos.x <= scrollOffset + 489 && mousePos.y <= 219)
+ _vm->_soundMan->_textOffFl = !_vm->_soundMan->_textOffFl;
+
+ if (mousePos.x >= scrollOffset + 431) {
+ if (mousePos.y > 167 && mousePos.x <= scrollOffset + 489 && mousePos.y <= 192) {
+ _vm->_soundMan->_voiceOffFl = !_vm->_soundMan->_voiceOffFl;
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+ if (mousePos.x >= scrollOffset + 431) {
+ if (mousePos.y > 113 && mousePos.x <= scrollOffset + 489 && mousePos.y <= 138) {
+ if (_vm->_soundMan->_musicOffFl) {
+ _vm->_soundMan->_musicOffFl = false;
+ _vm->_soundMan->setMODMusicVolume(_vm->_soundMan->_musicVolume);
+ } else {
+ _vm->_soundMan->_musicOffFl = true;
+ _vm->_soundMan->setMODMusicVolume(0);
+ }
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+
+ if (mousePos.x >= scrollOffset + 431 && mousePos.y > 140 && mousePos.x <= scrollOffset + 489 && mousePos.y <= 165) {
+ _vm->_soundMan->_soundOffFl = !_vm->_soundMan->_soundOffFl;
+
+ _vm->_soundMan->updateScummVMSoundSettings();
+ }
+ }
+ }
+ }
+
+ if (mousePos.x >= scrollOffset + 175 && mousePos.y > 285 && mousePos.x <= scrollOffset + 281 && mousePos.y <= 310) {
+ _vm->_globals->_exitId = 300;
+ doneFlag = true;
+ }
+ if (mousePos.x >= scrollOffset + 355 && mousePos.y > 285 && mousePos.x <= scrollOffset + 490 && mousePos.y <= 310)
+ doneFlag = true;
+ if (mousePos.x >= scrollOffset + 300 && mousePos.y > 194 && mousePos.x <= scrollOffset + 358 && mousePos.y <= 219) {
+ switch (_vm->_graphicsMan->_scrollSpeed) {
+ case 1:
+ _vm->_graphicsMan->_scrollSpeed = 2;
+ break;
+ case 2:
+ _vm->_graphicsMan->_scrollSpeed = 4;
+ break;
+ case 4:
+ _vm->_graphicsMan->_scrollSpeed = 8;
+ break;
+ case 8:
+ _vm->_graphicsMan->_scrollSpeed = 16;
+ break;
+ case 16:
+ _vm->_graphicsMan->_scrollSpeed = 32;
+ break;
+ case 32:
+ _vm->_graphicsMan->_scrollSpeed = 48;
+ break;
+ case 48:
+ _vm->_graphicsMan->_scrollSpeed = 64;
+ break;
+ case 64:
+ _vm->_graphicsMan->_scrollSpeed = 128;
+ break;
+ case 128:
+ _vm->_graphicsMan->_scrollSpeed = 160;
+ break;
+ case 160:
+ _vm->_graphicsMan->_scrollSpeed = 320;
+ break;
+ case 320:
+ _vm->_graphicsMan->_scrollSpeed = 1;
+ break;
+ }
+ }
+
+ // Values are blocked, thus handling the zone is useless
+ //if (mousePos.x >= _vm->_graphicsManager->ofscroll + 348 && mousePos.y > 248 && mousePos.x <= _vm->_graphicsManager->ofscroll + 394 && mousePos.y <= 273)
+ // _vm->_globals->_speed = 2;
+
+ if ( mousePos.x < scrollOffset + 165 || mousePos.x > scrollOffset + 496
+ || mousePos.y < 107 || mousePos.y > 318)
+ doneFlag = true;
+ }
+
+ if (_vm->_globals->_speed == 1)
+ _vm->_globals->_menuSpeed = 6;
+ else if (_vm->_globals->_speed == 2)
+ _vm->_globals->_menuSpeed = 5;
+ else if (_vm->_globals->_speed == 3)
+ _vm->_globals->_menuSpeed = 4;
+
+ _vm->_globals->_menuTextOff = !_vm->_soundMan->_textOffFl ? 7 : 8;
+ _vm->_globals->_menuVoiceOff = !_vm->_soundMan->_voiceOffFl ? 7 : 8;
+ _vm->_globals->_menuSoundOff = !_vm->_soundMan->_soundOffFl ? 7 : 8;
+ _vm->_globals->_menuMusicOff = !_vm->_soundMan->_musicOffFl ? 7 : 8;
+
+ _vm->_globals->_menuDisplayType = 9;
+
+ switch (_vm->_graphicsMan->_scrollSpeed) {
+ case 1:
+ _vm->_globals->_menuScrollSpeed = 12;
+ break;
+ case 2:
+ _vm->_globals->_menuScrollSpeed = 13;
+ break;
+ case 4:
+ _vm->_globals->_menuScrollSpeed = 14;
+ break;
+ case 8:
+ _vm->_globals->_menuScrollSpeed = 15;
+ break;
+ case 16:
+ _vm->_globals->_menuScrollSpeed = 16;
+ break;
+ case 32:
+ _vm->_globals->_menuScrollSpeed = 17;
+ break;
+ case 48:
+ _vm->_globals->_menuScrollSpeed = 18;
+ break;
+ case 64:
+ _vm->_globals->_menuScrollSpeed = 19;
+ break;
+ case 128:
+ _vm->_globals->_menuScrollSpeed = 20;
+ break;
+ case 160:
+ _vm->_globals->_menuScrollSpeed = 21;
+ break;
+ case 320:
+ _vm->_globals->_menuScrollSpeed = 22;
+ break;
+ case 640:
+ _vm->_globals->_menuScrollSpeed = 23;
+ break;
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (!doneFlag);
+
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, scrollOffset + 164,
+ 107, 335, 215, _vm->_graphicsMan->_frontBuffer, scrollOffset + 164, 107);
+ _vm->_graphicsMan->addDirtyRect(scrollOffset + 164, 107, scrollOffset + 498, 320);
+
+ _vm->_globals->_optionDialogSpr = _vm->_globals->freeMemory(_vm->_globals->_optionDialogSpr);
+ _vm->_globals->_optionDialogFl = false;
+}
+
+void DialogsManager::showInventory() {
+ if (_removeInventFl || _inventDisplayedFl || _vm->_globals->_disableInventFl)
+ return;
+
+ _vm->_graphicsMan->_scrollStatus = 1;
+ _vm->_objectsMan->_eraseVisibleCounter = 4;
+ _vm->_objectsMan->_visibleFl = false;
+ for (int i = 0; i <= 1; i++) {
+ inventAnim();
+ _vm->_events->getMouseX();
+ _vm->_events->getMouseY();
+ _vm->_events->refreshScreenAndEvents();
+ }
+ _inventWin1 = NULL;
+
+ bool loopFl;
+ do {
+ loopFl = false;
+ _vm->_events->_curMouseButton = 0;
+ _vm->_events->_mouseButton = 0;
+ _vm->_globals->_disableInventFl = true;
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+
+ Common::String filename;
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ filename = "INVENT.SPR";
+ else {
+ switch (_vm->_globals->_language) {
+ case LANG_EN:
+ filename = "INVENTAN.SPR";
+ break;
+ case LANG_FR:
+ filename = "INVENTFR.SPR";
+ break;
+ case LANG_SP:
+ filename = "INVENTES.SPR";
+ break;
+ }
+ }
+
+ Common::File f;
+ if (!f.open(filename))
+ error("Error opening file - %s", filename.c_str());
+
+ size_t filesize = f.size();
+ _inventWin1 = _vm->_globals->allocMemory(filesize);
+ _vm->_fileIO->readStream(f, _inventWin1, filesize);
+ f.close();
+
+ _inventBuf2 = _vm->_fileIO->loadFile("INVENT2.SPR");
+
+ _inventX = _vm->_graphicsMan->_scrollOffset + 152;
+ _inventY = 114;
+ _inventWidth = _vm->_objectsMan->getWidth(_inventWin1, 0);
+ _inventHeight = _vm->_objectsMan->getHeight(_inventWin1, 0);
+
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, _inventWin1, _inventX + 300, 414, 0, 0, 0, false);
+ int curPosY = 0;
+ int inventCount = 0;
+ for (int inventLine = 1; inventLine <= 5; inventLine++) {
+ int curPosX = 0;
+ for (int inventCol = 1; inventCol <= 6; inventCol++) {
+ ++inventCount;
+ int inventIdx = _vm->_globals->_inventory[inventCount];
+ // The last two zones are not reserved for the inventory: Options and Save/Load
+ if (inventIdx && inventCount <= 29) {
+ byte *obj = _vm->_objectsMan->loadObjectFromFile(inventIdx, false);
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, obj, _inventX + curPosX + 6,
+ curPosY + 120, _vm->_objectsMan->getObjectWidth(), _vm->_objectsMan->getObjectHeight());
+ _vm->_globals->freeMemory(obj);
+ }
+ curPosX += 54;
+ };
+ curPosY += 38;
+ }
+ _vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_frontBuffer, _inventWin1, _inventX, _inventY, _inventWidth, _inventHeight);
+ _vm->_events->_curMouseButton = 0;
+ int newInventoryItem = 0;
+
+ // Main loop to select an inventory item
+ while (!_vm->shouldQuit()) {
+ // Turn on drawing the inventory dialog in the event manager
+ _inventDisplayedFl = true;
+
+ int mousePosX = _vm->_events->getMouseX();
+ int mousePosY = _vm->_events->getMouseY();
+ int mouseButton = _vm->_events->getMouseButton();
+ int oldInventoryItem = newInventoryItem;
+ newInventoryItem = _vm->_linesMan->checkInventoryHotspots(mousePosX, mousePosY);
+ if (newInventoryItem != oldInventoryItem)
+ _vm->_objectsMan->initBorder(newInventoryItem);
+ int cursorId = _vm->_events->_mouseCursorId;
+ if (cursorId != 1 && cursorId != 2 && cursorId != 3 && cursorId != 16) {
+ if (mouseButton == 2) {
+ _vm->_objectsMan->nextObjectIcon(newInventoryItem);
+ if (cursorId != 23)
+ _vm->_events->changeMouseCursor(cursorId);
+ }
+ }
+ cursorId = _vm->_events->_mouseCursorId;
+ if (mouseButton == 1) {
+ if (cursorId == 1 || cursorId == 2 || cursorId == 3 || cursorId == 16 || !cursorId)
+ break;
+ _vm->_objectsMan->takeInventoryObject(_vm->_globals->_inventory[newInventoryItem]);
+ if (_vm->_events->_mouseCursorId == 8)
+ break;
+
+ _vm->_script->_tempObjectFl = true;
+ _vm->_globals->_saveData->_data[svLastObjectIndex] = _vm->_objectsMan->_curObjectIndex;
+ _vm->_globals->_saveData->_data[svLastInventoryItem] = _vm->_globals->_inventory[newInventoryItem];
+ _vm->_globals->_saveData->_data[svLastInvMouseCursor] = _vm->_events->_mouseCursorId;
+ _vm->_objectsMan->loadObjectIniFile();
+ _vm->_script->_tempObjectFl = false;
+
+ if (_vm->_soundMan->_voiceOffFl) {
+ do
+ _vm->_events->refreshScreenAndEvents();
+ while (!_vm->_globals->_exitId && _vm->_events->getMouseButton() != 1);
+ _vm->_fontMan->hideText(9);
+ }
+ if (_vm->_globals->_exitId) {
+ if (_vm->_globals->_exitId == 2) {
+ _vm->_globals->_exitId = 0;
+ break;
+ }
+
+ _vm->_globals->_exitId = 0;
+ _inventBuf2 = _vm->_globals->freeMemory(_inventBuf2);
+ _inventWin1 = _vm->_globals->freeMemory(_inventWin1);
+ loopFl = true;
+ break;
+ } else
+ _inventDisplayedFl = true;
+ }
+ if (_removeInventFl)
+ break;
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_globals->_screenId >= 35 && _vm->_globals->_screenId <= 40)
+ _vm->_objectsMan->handleSpecialGames();
+ }
+ } while (loopFl);
+
+ _vm->_fontMan->hideText(9);
+ if (_inventDisplayedFl) {
+ _inventDisplayedFl = false;
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, _inventX, 114, _inventWidth, _inventHeight, _vm->_graphicsMan->_frontBuffer, _inventX, 114);
+ _vm->_graphicsMan->addDirtyRect(_inventX, 114, _inventX + _inventWidth, _inventWidth + 114);
+ _vm->_objectsMan->_refreshBobMode10Fl = true;
+ }
+
+ _inventWin1 = _vm->_globals->freeMemory(_inventWin1);
+ _inventBuf2 = _vm->_globals->freeMemory(_inventBuf2);
+
+ int cursorId = _vm->_events->_mouseCursorId;
+ if (cursorId == 1)
+ showOptionsDialog();
+ else if (cursorId == 3)
+ showLoadGame();
+ else if (cursorId == 2)
+ showSaveGame();
+
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(4);
+ _vm->_objectsMan->_oldBorderPos = Common::Point(0, 0);
+ _vm->_objectsMan->_borderPos = Common::Point(0, 0);
+ _vm->_globals->_disableInventFl = false;
+ _vm->_graphicsMan->_scrollStatus = 0;
+}
+
+/**
+ * Inventory Animations
+ */
+void DialogsManager::inventAnim() {
+ if (_vm->_globals->_disableInventFl)
+ return;
+
+ if (_vm->_objectsMan->_eraseVisibleCounter && !_vm->_objectsMan->_visibleFl) {
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, _oldInventX, 27, 48, 38,
+ _vm->_graphicsMan->_frontBuffer, _oldInventX, 27);
+ _vm->_graphicsMan->addDirtyRect(_oldInventX, 27, _oldInventX + 48, 65);
+ --_vm->_objectsMan->_eraseVisibleCounter;
+ }
+
+ if (_vm->_objectsMan->_visibleFl) {
+ if (_oldInventX <= 1)
+ _oldInventX = 2;
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, _oldInventX, 27, 48, 38,
+ _vm->_graphicsMan->_frontBuffer, _oldInventX, 27);
+
+ _vm->_graphicsMan->addDirtyRect(_oldInventX, 27, _oldInventX + 48, 65);
+ int newOffset = _vm->_graphicsMan->_scrollOffset + 2;
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _inventoryIcons, newOffset + 300, 327, 0);
+ _vm->_graphicsMan->addDirtyRect(newOffset, 27, newOffset + 45, 62);
+ _oldInventX = newOffset;
+ }
+
+ if (_vm->_globals->_saveData->_data[svField357] == 1) {
+ if (_vm->_globals->_saveData->_data[svField353] == 1)
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_headSprites, 832, 325, 0, 0, 0, false);
+ if (_vm->_globals->_saveData->_data[svField355] == 1)
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_headSprites, 866, 325, 1, 0, 0, false);
+ _vm->_graphicsMan->addDirtyRect(532, 25, 560, 60);
+ _vm->_graphicsMan->addDirtyRect(566, 25, 594, 60);
+ }
+ if (_vm->_globals->_saveData->_data[svField356] == 1) {
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_headSprites, 832, 325, 0, 0, 0, false);
+ _vm->_graphicsMan->addDirtyRect(532, 25, 560, 60);
+ }
+
+ if (_vm->_globals->_saveData->_data[svField354] == 1) {
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_headSprites, 832, 325, 0, 0, 0, false);
+ _vm->_graphicsMan->addDirtyRect(532, 25, 560, 60);
+ }
+}
+
+/**
+ * Test dialog opening
+ */
+void DialogsManager::testDialogOpening() {
+ if (_vm->_globals->_cityMapEnabledFl)
+ _vm->_events->_gameKey = KEY_NONE;
+
+ if ((_vm->_events->_gameKey == KEY_NONE) || _inventFl)
+ return;
+
+ DIALOG_KEY key = _vm->_events->_gameKey;
+ _vm->_events->_gameKey = KEY_NONE;
+ _inventFl = true;
+
+ switch (key) {
+ case KEY_INVENTORY:
+ showInventory();
+ break;
+ case KEY_OPTIONS:
+ _vm->_graphicsMan->_scrollStatus = 1;
+ showOptionsDialog();
+ _vm->_graphicsMan->_scrollStatus = 0;
+ break;
+ case KEY_LOAD:
+ _vm->_graphicsMan->_scrollStatus = 1;
+ showLoadGame();
+ _vm->_graphicsMan->_scrollStatus = 0;
+ break;
+ case KEY_SAVE:
+ _vm->_graphicsMan->_scrollStatus = 1;
+ showSaveGame();
+ _vm->_graphicsMan->_scrollStatus = 0;
+ break;
+ default:
+ break;
+ }
+
+ _inventFl = false;
+ _vm->_events->_gameKey = KEY_NONE;
+}
+
+/**
+ * Load Game dialog
+ */
+void DialogsManager::showLoadGame() {
+ _vm->_events->refreshScreenAndEvents();
+ showSaveLoad(MODE_LOAD);
+
+ int slotNumber;
+ do {
+ slotNumber = searchSavegames();
+ _vm->_events->refreshScreenAndEvents();
+ } while (!_vm->shouldQuit() && (!slotNumber || _vm->_events->getMouseButton() != 1));
+ _vm->_objectsMan->_saveLoadFl = false;
+ int16 startPosX = _vm->_events->_startPos.x + 183;
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, startPosX, 60, 274, 353, _vm->_graphicsMan->_frontBuffer, startPosX, 60);
+ _vm->_graphicsMan->addDirtyRect(startPosX, 60, startPosX + 274, 413);
+ _vm->_objectsMan->_refreshBobMode10Fl = true;
+ _vm->_objectsMan->_saveLoadSprite = _vm->_globals->freeMemory(_vm->_objectsMan->_saveLoadSprite);
+ _vm->_objectsMan->_saveLoadSprite2 = _vm->_globals->freeMemory(_vm->_objectsMan->_saveLoadSprite2);
+ _vm->_objectsMan->_saveLoadX = 0;
+ _vm->_objectsMan->_saveLoadY = 0;
+
+ if (slotNumber != 7) {
+ _vm->_saveLoad->loadGame(slotNumber);
+ }
+
+ _vm->_objectsMan->changeObject(14);
+}
+
+/**
+ * Save Game dialog
+ */
+void DialogsManager::showSaveGame() {
+ _vm->_events->refreshScreenAndEvents();
+
+ showSaveLoad(MODE_SAVE);
+ int slotNumber;
+ do {
+ slotNumber = searchSavegames();
+ _vm->_events->refreshScreenAndEvents();
+ } while (!_vm->shouldQuit() && (!slotNumber || _vm->_events->getMouseButton() != 1));
+
+ _vm->_objectsMan->_saveLoadFl = false;
+ int16 startPosX = _vm->_events->_startPos.x + 183;
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, startPosX, 60, 274, 353, _vm->_graphicsMan->_frontBuffer, startPosX, 60);
+ _vm->_graphicsMan->addDirtyRect(startPosX, 60, startPosX + 274, 413);
+ _vm->_objectsMan->_refreshBobMode10Fl = true;
+ _vm->_objectsMan->_saveLoadSprite = _vm->_globals->freeMemory(_vm->_objectsMan->_saveLoadSprite);
+ _vm->_objectsMan->_saveLoadSprite2 = _vm->_globals->freeMemory(_vm->_objectsMan->_saveLoadSprite2);
+ _vm->_objectsMan->_saveLoadX = 0;
+ _vm->_objectsMan->_saveLoadY = 0;
+
+ if (slotNumber != 7) {
+ // Since the original GUI doesn't support save names, use a default name
+ Common::String saveName = Common::String::format("Save #%d", slotNumber);
+
+ // Save the game
+ _vm->_saveLoad->saveGame(slotNumber, saveName);
+ }
+}
+
+/**
+ * Load/Save dialog
+ */
+void DialogsManager::showSaveLoad(SaveLoadMode mode) {
+ Common::String filename;
+
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ filename = "SAVE.SPR";
+ else {
+ switch (_vm->_globals->_language) {
+ case LANG_EN:
+ filename = "SAVEAN.SPR";
+ break;
+ case LANG_FR:
+ filename = "SAVEFR.SPR";
+ break;
+ case LANG_SP:
+ filename = "SAVEES.SPR";
+ break;
+ }
+ }
+
+ _vm->_objectsMan->_saveLoadSprite = _vm->_objectsMan->loadSprite(filename);
+ _vm->_objectsMan->_saveLoadSprite2 = _vm->_objectsMan->loadSprite("SAVE2.SPR");
+ int16 startPosX = _vm->_events->_startPos.x;
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_saveLoadSprite, startPosX + 483, 360, 0);
+
+ if (_vm->_globals->_language == LANG_FR) {
+ if (mode == MODE_SAVE)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_saveLoadSprite, startPosX + 525, 375, 1);
+ else if (mode == MODE_LOAD)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_saveLoadSprite, startPosX + 515, 375, 2);
+ } else {
+ if (mode == MODE_SAVE)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_saveLoadSprite, startPosX + 535, 372, 1);
+ else if (mode == MODE_LOAD)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_saveLoadSprite, startPosX + 539, 372, 2);
+ }
+
+ for (int slotNumber = 1; slotNumber <= 6; ++slotNumber) {
+ hopkinsSavegameHeader header;
+ if (_vm->_saveLoad->readSavegameHeader(slotNumber, header)) {
+ Graphics::Surface thumb8;
+ _vm->_saveLoad->convertThumb16To8(header._thumbnail, &thumb8);
+
+ byte *thumb = (byte *)thumb8.pixels;
+
+ int16 startPosX_ = _vm->_events->_startPos.x;
+ switch (slotNumber) {
+ case 1:
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, thumb, startPosX_ + 190, 112, 128, 87);
+ break;
+ case 2:
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, thumb, startPosX_ + 323, 112, 128, 87);
+ break;
+ case 3:
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, thumb, startPosX_ + 190, 203, 128, 87);
+ break;
+ case 4:
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, thumb, startPosX_ + 323, 203, 128, 87);
+ break;
+ case 5:
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, thumb, startPosX_ + 190, 294, 128, 87);
+ break;
+ case 6:
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, thumb, startPosX_ + 323, 294, 128, 87);
+ break;
+ }
+
+ thumb8.free();
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+ }
+
+ _vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_frontBuffer, _vm->_objectsMan->_saveLoadSprite, _vm->_events->_startPos.x + 183, 60, 274, 353);
+ _vm->_objectsMan->_saveLoadFl = true;
+ _vm->_objectsMan->_saveLoadX = 0;
+ _vm->_objectsMan->_saveLoadY = 0;
+}
+
+/**
+ * Search savegames
+ */
+int DialogsManager::searchSavegames() {
+ int xp = _vm->_events->getMouseX();
+ int yp = _vm->_events->getMouseY();
+
+ int16 startPosX = _vm->_graphicsMan->_scrollOffset = _vm->_events->_startPos.x;
+
+ int slotNumber = 0;
+ if (yp >= 112 && yp <= 198) {
+ if (xp > startPosX + 189 && xp < startPosX + 318) {
+ slotNumber = 1;
+ _vm->_objectsMan->_saveLoadX = 189;
+ _vm->_objectsMan->_saveLoadY = 111;
+ } else if (xp > startPosX + 322 && xp < startPosX + 452) {
+ slotNumber = 2;
+ _vm->_objectsMan->_saveLoadX = 322;
+ _vm->_objectsMan->_saveLoadY = 111;
+ }
+ } else if (yp >= 203 && yp <= 289) {
+ if (xp > startPosX + 189 && xp < startPosX + 318) {
+ slotNumber = 3;
+ _vm->_objectsMan->_saveLoadX = 189;
+ _vm->_objectsMan->_saveLoadY = 202;
+ } else if (xp > startPosX + 322 && xp < startPosX + 452) {
+ slotNumber = 4;
+ _vm->_objectsMan->_saveLoadX = 322;
+ _vm->_objectsMan->_saveLoadY = 202;
+ }
+ } else if (yp >= 294 && yp <= 380) {
+ if (xp > startPosX + 189 && xp < startPosX + 318) {
+ slotNumber = 5;
+ _vm->_objectsMan->_saveLoadX = 189;
+ _vm->_objectsMan->_saveLoadY = 293;
+ } else if (xp > startPosX + 322 && xp < startPosX + 452) {
+ slotNumber = 6;
+ _vm->_objectsMan->_saveLoadX = 322;
+ _vm->_objectsMan->_saveLoadY = 293;
+ }
+ } else if (yp >= 388 && yp <= 404 && xp > startPosX + 273 && xp < startPosX + 355) {
+ slotNumber = 7;
+ _vm->_objectsMan->_saveLoadX = 0;
+ _vm->_objectsMan->_saveLoadY = 0;
+ } else {
+ slotNumber = 0;
+ _vm->_objectsMan->_saveLoadX = 0;
+ _vm->_objectsMan->_saveLoadY = 0;
+ }
+
+ return slotNumber;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/dialogs.h b/engines/hopkins/dialogs.h
new file mode 100644
index 0000000000..246b80cd3e
--- /dev/null
+++ b/engines/hopkins/dialogs.h
@@ -0,0 +1,77 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_DIALOGS_H
+#define HOPKINS_DIALOGS_H
+
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/error.h"
+#include "common/rect.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+enum SaveLoadMode { MODE_SAVE = 1, MODE_LOAD = 2 };
+
+/**
+ * Class for manging game dialogs
+ */
+class DialogsManager {
+private:
+ byte *_inventWin1;
+ byte *_inventBuf2;
+ byte *_inventoryIcons;
+ bool _inventDisplayedFl;
+ bool _removeInventFl;
+ int _inventX, _inventY;
+ int _inventWidth, _inventHeight;
+ int _oldInventX;
+
+ HopkinsEngine *_vm;
+
+ void showSaveLoad(SaveLoadMode mode);
+ int searchSavegames();
+public:
+ bool _inventFl;
+
+ DialogsManager(HopkinsEngine *vm);
+ ~DialogsManager();
+ void inventAnim();
+ void showInventory();
+ void showLoadGame();
+ void showSaveGame();
+ void showOptionsDialog();
+ void testDialogOpening();
+ void clearAll();
+
+ void drawInvent(Common::Point oldBorder, int oldBorderSpriteIndex, Common::Point newBorder, int newBorderSpriteIndex);
+ void loadIcons();
+
+ void disableInvent() { _removeInventFl = true; }
+ void enableInvent() { _removeInventFl = false; }
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_MENU_H */
diff --git a/engines/hopkins/events.cpp b/engines/hopkins/events.cpp
new file mode 100644
index 0000000000..58389ef2e9
--- /dev/null
+++ b/engines/hopkins/events.cpp
@@ -0,0 +1,542 @@
+/* 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/events.h"
+
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/hopkins.h"
+#include "hopkins/sound.h"
+
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "graphics/cursorman.h"
+
+namespace Hopkins {
+
+EventsManager::EventsManager(HopkinsEngine *vm) {
+ _vm = vm;
+ _mouseFl = false;
+ _mouseLinuxFl = false;
+ _mouseSizeX = _mouseSizeY = 0;
+ _mouseOffset.x = _mouseOffset.y = 0;
+ _startPos.x = _startPos.y = 0;
+ _breakoutFl = false;
+ _mouseSpriteId = 0;
+ _curMouseButton = 0;
+ _mouseButton = 0;
+ _mouseCursor = NULL;
+ _gameCounter = 0;
+ _rateCounter = 0;
+ _escKeyFl = false;
+ _gameKey = KEY_NONE;
+ _mouseCursorId = 0;
+ _oldIconId = 0;
+ _objectBuf = NULL;
+
+ Common::fill(&_keyState[0], &_keyState[256], false);
+ _priorCounterTime = _priorFrameTime = g_system->getMillis();
+}
+
+EventsManager::~EventsManager() {
+ _vm->_globals->freeMemory(_objectBuf);
+ _vm->_globals->freeMemory(_mouseCursor);
+}
+
+void EventsManager::clearAll() {
+ _vm->_globals->freeMemory(_objectBuf);
+ _objectBuf = _vm->_globals->allocMemory(2500);
+}
+
+void EventsManager::initMouseData() {
+ if (_vm->getPlatform() == Common::kPlatformLinux)
+ _mouseLinuxFl = true;
+ else
+ _mouseLinuxFl = false;
+
+ if (_mouseLinuxFl) {
+ _mouseSizeX = 52;
+ _mouseSizeY = 32;
+ } else {
+ _mouseSizeX = 34;
+ _mouseSizeY = 20;
+ }
+
+ switch (_vm->_globals->_language) {
+ case LANG_EN:
+ if (!_mouseLinuxFl)
+ _mouseCursor = _vm->_fileIO->loadFile("SOUAN.SPR");
+ else
+ _mouseCursor = _vm->_fileIO->loadFile("LSOUAN.SPR");
+ break;
+ case LANG_FR:
+ if (!_mouseLinuxFl)
+ _mouseCursor = _vm->_fileIO->loadFile("SOUFR.SPR");
+ else
+ _mouseCursor = _vm->_fileIO->loadFile("LSOUFR.SPR");
+ break;
+ case LANG_SP:
+ _mouseCursor = _vm->_fileIO->loadFile("SOUES.SPR");
+ break;
+ }
+}
+
+// Mouse On
+void EventsManager::setMouseOn() {
+ _mouseFl = true;
+
+ if (_mouseLinuxFl) {
+ _mouseSizeX = 52;
+ _mouseSizeY = 32;
+ } else {
+ _mouseSizeX = 34;
+ _mouseSizeY = 20;
+ }
+
+ _mouseOffset.x = 0;
+ _mouseOffset.y = 0;
+
+ if (!_breakoutFl)
+ setMouseXY(300, 200);
+ else
+ setMouseXY(150, 100);
+}
+
+/**
+ * Set Mouse position
+ */
+void EventsManager::setMouseXY(Common::Point pos) {
+ g_system->warpMouse(pos.x, pos.y);
+}
+
+/**
+ * Set Mouse position
+ */
+void EventsManager::setMouseXY(int xp, int yp) {
+ g_system->warpMouse(xp, yp);
+}
+
+/**
+ * Get Mouse X
+ */
+int EventsManager::getMouseX() {
+ _mousePos.x = _startPos.x + g_system->getEventManager()->getMousePos().x;
+ _mousePos.y = g_system->getEventManager()->getMousePos().y;
+
+ return _mousePos.x + _mouseOffset.x;
+}
+
+/**
+ * Get Mouse Y
+ */
+int EventsManager::getMouseY() {
+ _mousePos.x = _startPos.x + g_system->getEventManager()->getMousePos().x;
+ _mousePos.y = g_system->getEventManager()->getMousePos().y;
+
+ return _mousePos.y + _mouseOffset.y;
+}
+
+/**
+ * Get Mouse Button
+ */
+int EventsManager::getMouseButton() {
+ refreshEvents();
+ return _curMouseButton;
+}
+
+/**
+ * Mouse Off
+ */
+void EventsManager::mouseOff() {
+ _mouseFl = false;
+ CursorMan.showMouse(false);
+}
+
+/**
+ * Mouse On
+ */
+void EventsManager::mouseOn() {
+ setMouseOn();
+ _mouseFl = true;
+ CursorMan.showMouse(true);
+}
+
+/**
+ * Change Mouse Cursor
+ */
+void EventsManager::changeMouseCursor(int id) {
+ int cursorId = id;
+
+ if (_mouseCursorId == 23)
+ return;
+
+ if (id == 4 && _mouseCursorId == 4 && _vm->_globals->_freezeCharacterFl)
+ cursorId = 0;
+ if (cursorId == 25)
+ cursorId = 5;
+
+ if (_oldIconId != cursorId || !cursorId) {
+ _oldIconId = cursorId;
+ _mouseSpriteId = cursorId;
+
+ updateCursor();
+ }
+}
+
+/**
+ * Check Events
+ */
+void EventsManager::refreshEvents() {
+ _vm->_soundMan->checkSounds();
+
+ pollEvents();
+}
+
+void EventsManager::checkForNextFrameCounter() {
+ int32 delayAmount = 10 - (g_system->getMillis() - _priorCounterTime);
+ if (delayAmount > 0)
+ _vm->_system->delayMillis(delayAmount);
+
+ // Check for whether to increment the game counter
+ uint32 milli = g_system->getMillis();
+ while ((milli - _priorCounterTime) >= 10) {
+ _priorCounterTime += 10;
+ _rateCounter += 3;
+ }
+
+ // Check for next game frame
+ if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
+ ++_gameCounter;
+ _priorFrameTime = milli;
+ _vm->_graphicsMan->updateScreen();
+
+ // Signal the ScummVM debugger
+ _vm->_debug->onFrame();
+ }
+}
+
+void EventsManager::delay(int totalMilli) {
+ uint32 delayEnd = g_system->getMillis() + totalMilli;
+
+ while (!g_system->getEventManager()->shouldQuit() && g_system->getMillis() < delayEnd) {
+ g_system->delayMillis(10);
+ }
+}
+
+void EventsManager::pollEvents() {
+ checkForNextFrameCounter();
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ // Handle keypress
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ return;
+
+ case Common::EVENT_KEYDOWN:
+ _keyState[(byte)toupper(event.kbd.ascii)] = true;
+ handleKey(event);
+ return;
+ case Common::EVENT_KEYUP:
+ _keyState[(byte)toupper(event.kbd.ascii)] = false;
+ return;
+ case Common::EVENT_LBUTTONDOWN:
+ _mouseButton = 1;
+ return;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButton = 2;
+ return;
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ _mouseButton = 0;
+ return;
+ default:
+ break;
+ }
+ }
+
+ for (char chr = 'A'; chr <= 'Z'; chr++)
+ _keyState[(byte)chr] = false;
+
+ for (char chr = '0'; chr <= '9'; chr++)
+ _keyState[(byte)chr] = false;
+}
+
+void EventsManager::handleKey(const Common::Event &event) {
+ _escKeyFl = (event.kbd.keycode == Common::KEYCODE_ESCAPE);
+
+ if (event.kbd.keycode == Common::KEYCODE_i || event.kbd.keycode == Common::KEYCODE_TAB)
+ _gameKey = KEY_INVENTORY;
+ else if (event.kbd.keycode == Common::KEYCODE_F5)
+ _gameKey = KEY_SAVE;
+ else if (event.kbd.keycode == Common::KEYCODE_F7)
+ _gameKey = KEY_LOAD;
+ else if (event.kbd.keycode == Common::KEYCODE_F1 || event.kbd.keycode == Common::KEYCODE_o)
+ _gameKey = KEY_OPTIONS;
+
+ // Check for debugger
+ if ((event.kbd.keycode == Common::KEYCODE_d) && (event.kbd.flags & Common::KBD_CTRL)) {
+ // Attach to the debugger
+ _vm->_debug->attach();
+ _vm->_debug->onFrame();
+ }
+
+}
+
+/**
+ * Waits for a keypress, ignoring mouse events
+ * @return Keypress, or -1 if game quit was requested
+ */
+int EventsManager::waitKeyPress() {
+ char foundChar = '\0';
+
+ while (!foundChar) {
+ if (_vm->shouldQuit())
+ return -1;
+
+ for (char ch = 'A'; ch <= 'Z'; ++ch) {
+ if (_keyState[(byte)ch]) {
+ foundChar = ch;
+ break;
+ }
+ }
+
+ for (char ch = '0'; ch <= '9'; ++ch) {
+ if (_keyState[(byte)ch]) {
+ foundChar = ch;
+ break;
+ }
+ }
+
+ if (_keyState[(byte)'.'])
+ foundChar = '.';
+ else if (_keyState[8])
+ // BACKSPACE
+ foundChar = 8;
+ else if (_keyState[13])
+ // ENTER
+ foundChar = 13;
+ else if (_keyState[(byte)' '])
+ foundChar = ' ';
+
+ refreshScreenAndEvents();
+ }
+
+ // Wait for keypress release
+ while (_keyState[(byte)foundChar] && !_vm->shouldQuit()) {
+ refreshScreenAndEvents();
+ g_system->delayMillis(10);
+ }
+
+ // Return character
+ return foundChar;
+}
+
+void EventsManager::refreshScreenAndEvents() {
+ int bottom = 0;
+ int right = 0;
+ int height = 0;
+ int width = 0;
+ int xp = 0;
+ int yp = 0;
+
+ if (_mouseFl) {
+ int mouseWidth = 20;
+ if (!_mouseLinuxFl)
+ mouseWidth = 10;
+ int mouseHeight = 20;
+ if (!_mouseLinuxFl)
+ mouseHeight = 15;
+ xp = _mousePos.x - mouseWidth;
+ yp = _mousePos.y;
+ width = _mouseSizeX;
+ height = _mouseSizeY;
+ if (_mouseCursorId == 23) {
+ width = _vm->_objectsMan->getObjectWidth();
+ height = _vm->_objectsMan->getObjectHeight();
+ } else {
+ if (_breakoutFl) {
+ if (xp < _vm->_graphicsMan->_minX)
+ xp = _vm->_graphicsMan->_minX;
+ if (_mousePos.y < _vm->_graphicsMan->_minY)
+ yp = _vm->_graphicsMan->_minY;
+ if (_mouseSizeX + xp >= _vm->_graphicsMan->_maxX)
+ width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsMan->_maxX);
+ if (yp + _mouseSizeY >= _vm->_graphicsMan->_maxY)
+ height = _vm->_graphicsMan->_maxY - yp;
+ } else {
+ if (xp < _vm->_graphicsMan->_minX)
+ xp = _vm->_graphicsMan->_minX - mouseWidth;
+ mouseHeight = (int16)mouseHeight;
+ if (_mousePos.y < _vm->_graphicsMan->_minY - mouseHeight)
+ yp = _vm->_graphicsMan->_minY - mouseHeight;
+ if (_mouseSizeX + xp >= _vm->_graphicsMan->_maxX)
+ width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsMan->_maxX - mouseWidth);
+ if (yp + _mouseSizeY >= mouseHeight + _vm->_graphicsMan->_maxY)
+ height = _vm->_graphicsMan->_maxY - mouseHeight - yp;
+ }
+ right = xp + width;
+ bottom = yp + height;
+ }
+ }
+
+ if (!_vm->_globals->_linuxEndDemoFl)
+ _vm->_objectsMan->displaySprite();
+ if (!_mouseFl) {
+ updateCursor();
+ } else if (_mouseCursorId == 23) {
+ if (yp < _vm->_graphicsMan->_maxY && xp < _vm->_graphicsMan->_maxX) {
+ if (width + xp > _vm->_graphicsMan->_maxX)
+ width = _vm->_graphicsMan->_maxX - xp;
+ if (yp + height > _vm->_graphicsMan->_maxY)
+ height = _vm->_graphicsMan->_maxY - yp;
+ if (width > 1 && height > 1) {
+ updateCursor();
+ }
+ }
+ } else if (yp < _vm->_graphicsMan->_maxY && xp < _vm->_graphicsMan->_maxX && width > 1 && height > 1) {
+ updateCursor();
+ _vm->_graphicsMan->addDirtyRect(xp, yp, right, bottom);
+ }
+
+ _vm->_globals->_speed = 2;
+ bool externalLoopFl = false;
+ do {
+ while (!_vm->shouldQuit()) {
+ checkForNextFrameCounter();
+ bool innerLoopFl = false;
+
+ while (!_vm->shouldQuit() && (_breakoutFl || _vm->_globals->_eventMode != EVENTMODE_IGNORE)) {
+ checkForNextFrameCounter();
+
+ if (!_breakoutFl) {
+ innerLoopFl = true;
+ break;
+ }
+ if (_rateCounter > 1) {
+ externalLoopFl = true;
+ break;
+ }
+ }
+ if (innerLoopFl || _vm->_globals->_speed != 2)
+ break;
+ if (externalLoopFl ||_rateCounter > 9) {
+ externalLoopFl = true;
+ break;
+ }
+ }
+ if (externalLoopFl)
+ break;
+ } while (!_vm->shouldQuit() && _vm->_globals->_eventMode == EVENTMODE_CREDITS && _rateCounter <= 15);
+ _vm->_globals->_speed = 2;
+ _rateCounter = 0;
+ if (!_vm->_graphicsMan->_largeScreenFl || _vm->_graphicsMan->_scrollStatus == 1) {
+ _vm->_graphicsMan->displayDirtyRects();
+ } else {
+ if (_vm->_graphicsMan->_scrollStatus != 2) {
+ if (getMouseX() > _vm->_graphicsMan->_scrollPosX + 620)
+ _vm->_graphicsMan->_scrollPosX += _vm->_graphicsMan->_scrollSpeed;
+ if (getMouseX() < _vm->_graphicsMan->_scrollPosX + 10)
+ _vm->_graphicsMan->_scrollPosX -= _vm->_graphicsMan->_scrollSpeed;
+ }
+ _vm->_graphicsMan->_scrollPosX = CLIP(_vm->_graphicsMan->_scrollPosX, 0, SCREEN_WIDTH);
+ if (_vm->_graphicsMan->_oldScrollPosX == _vm->_graphicsMan->_scrollPosX) {
+ _vm->_graphicsMan->displayDirtyRects();
+ } else {
+ _vm->_fontMan->hideText(9);
+ _vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_scrollPosX, 20, SCREEN_WIDTH, 440, 0, 20);
+ _vm->_graphicsMan->resetRefreshRects();
+ _vm->_graphicsMan->addRefreshRect(0, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 20);
+
+ _vm->_graphicsMan->resetDirtyRects();
+
+ _startPos.x = _vm->_graphicsMan->_scrollPosX;
+ _vm->_graphicsMan->_scrollOffset = _vm->_graphicsMan->_scrollPosX;
+ }
+ _vm->_graphicsMan->_oldScrollPosX = _vm->_graphicsMan->_scrollPosX;
+ _startPos.x = _vm->_graphicsMan->_scrollPosX;
+ _vm->_graphicsMan->_scrollOffset = _vm->_graphicsMan->_scrollPosX;
+ }
+ _curMouseButton = _mouseButton;
+ _mouseButton = 0;
+ _vm->_soundMan->checkSoundEnd();
+ refreshEvents();
+}
+
+void EventsManager::updateCursor() {
+ // Backup the current sprite clipping bounds and reset them
+ Common::Rect clipBounds(_vm->_graphicsMan->_minX, _vm->_graphicsMan->_minY,
+ _vm->_graphicsMan->_maxX, _vm->_graphicsMan->_maxY);
+ _vm->_graphicsMan->_minX = _vm->_graphicsMan->_minY = 0;
+ _vm->_graphicsMan->_maxX = _vm->_objectsMan->getObjectWidth();
+ _vm->_graphicsMan->_maxY = _vm->_objectsMan->getObjectHeight();
+ int pitch = _vm->_graphicsMan->_lineNbr2;
+ _vm->_graphicsMan->_lineNbr2 = _vm->_objectsMan->getObjectWidth();
+
+ // Create the temporary cursor surface
+ byte *cursorSurface = new byte[_vm->_objectsMan->getObjectHeight() * _vm->_objectsMan->getObjectWidth()];
+ Common::fill(cursorSurface, cursorSurface + _vm->_objectsMan->getObjectHeight() * _vm->_objectsMan->getObjectWidth(), 0);
+
+ if (_mouseCursorId != 23) {
+ // Draw standard cursor
+ _vm->_graphicsMan->drawVesaSprite(cursorSurface, _mouseCursor, 300, 300, _mouseSpriteId);
+ } else {
+ // Draw the active inventory object
+ _vm->_graphicsMan->drawCompressedSprite(cursorSurface, _objectBuf, 300, 300, 0, 0, 0, false);
+ }
+
+ // Reset the clipping bounds
+ _vm->_graphicsMan->_minX = clipBounds.left;
+ _vm->_graphicsMan->_minY = clipBounds.top;
+ _vm->_graphicsMan->_maxX = clipBounds.right;
+ _vm->_graphicsMan->_maxY = clipBounds.bottom;
+ _vm->_graphicsMan->_lineNbr2 = pitch;
+
+ // Create a cursor palette
+ Graphics::PixelFormat pixelFormat = g_system->getScreenFormat();
+
+ byte *cursorPalette = new byte[3 * PALETTE_SIZE];
+ uint16 *paletteColors = (uint16 *)_vm->_graphicsMan->_palettePixels;
+
+ for (int i = 0; i < PALETTE_SIZE; i++) {
+ uint8 r, g, b;
+ pixelFormat.colorToRGB(READ_LE_UINT16(&paletteColors[i]), r, g, b);
+ cursorPalette[3 * i] = r;
+ cursorPalette[3 * i + 1] = g;
+ cursorPalette[3 * i + 2] = b;
+ }
+
+ // Calculate the X offset within the pointer image to the actual cursor data
+ int xOffset = !_mouseLinuxFl ? 10 : 20;
+
+ // Set the ScummVM cursor from the surface
+ CursorMan.replaceCursorPalette(cursorPalette, 0, PALETTE_SIZE - 1);
+ CursorMan.replaceCursor(cursorSurface, _vm->_objectsMan->getObjectWidth(), _vm->_objectsMan->getObjectHeight(),
+ xOffset, 0, 0, true);
+
+ // Delete the cursor surface and palette
+ delete[] cursorPalette;
+ delete[] cursorSurface;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/events.h b/engines/hopkins/events.h
new file mode 100644
index 0000000000..f4dedce1c5
--- /dev/null
+++ b/engines/hopkins/events.h
@@ -0,0 +1,94 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_EVENTS_H
+#define HOPKINS_EVENTS_H
+
+#include "common/scummsys.h"
+#include "common/events.h"
+#include "common/str.h"
+
+namespace Hopkins {
+
+#define GAME_FRAME_RATE 50
+#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
+
+class HopkinsEngine;
+
+enum DIALOG_KEY { KEY_NONE = 0, KEY_INVENTORY = 1, KEY_OPTIONS = 2, KEY_SAVE = 3, KEY_LOAD = 4 };
+
+class EventsManager {
+private:
+ int _oldIconId;
+ uint32 _priorCounterTime;
+ uint32 _priorFrameTime;
+ bool _keyState[256];
+ bool _mouseLinuxFl;
+ int _mouseSizeX, _mouseSizeY;
+
+ HopkinsEngine *_vm;
+
+ void pollEvents();
+ void handleKey(const Common::Event &event);
+ void checkForNextFrameCounter();
+ void updateCursor();
+
+public:
+ DIALOG_KEY _gameKey;
+ uint32 _rateCounter;
+ uint32 _gameCounter;
+ bool _escKeyFl;
+ bool _mouseFl;
+ bool _breakoutFl;
+ Common::Point _startPos;
+ Common::Point _mousePos;
+ Common::Point _mouseOffset;
+ int _mouseSpriteId;
+ int _curMouseButton;
+ int _mouseButton;
+ int _mouseCursorId;
+ byte *_objectBuf;
+ byte *_mouseCursor;
+
+ EventsManager(HopkinsEngine *vm);
+ ~EventsManager();
+ void clearAll();
+ void initMouseData();
+
+ void delay(int totalMilli);
+ void changeMouseCursor(int id);
+ void refreshEvents();
+ int waitKeyPress();
+ int getMouseX();
+ int getMouseY();
+ int getMouseButton();
+ void setMouseXY(Common::Point pos);
+ void setMouseXY(int xp, int yp);
+ void mouseOn();
+ void mouseOff();
+ void setMouseOn();
+ void refreshScreenAndEvents();
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_EVENTS_H */
diff --git a/engines/hopkins/files.cpp b/engines/hopkins/files.cpp
new file mode 100644
index 0000000000..2390ebbdf8
--- /dev/null
+++ b/engines/hopkins/files.cpp
@@ -0,0 +1,271 @@
+/* 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/files.h"
+
+#include "hopkins/hopkins.h"
+#include "hopkins/globals.h"
+
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/str.h"
+#include "common/savefile.h"
+
+namespace Hopkins {
+
+FileManager::FileManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ _catalogPos = 0;
+ _catalogSize = 0;
+}
+
+/**
+ * Load a file
+ */
+byte *FileManager::loadFile(const Common::String &file) {
+ Common::File f;
+ if (!f.open(file))
+ error("Error opening %s", file.c_str());
+
+ // Allocate space for the file contents
+ size_t filesize = f.size();
+ byte *data = _vm->_globals->allocMemory(filesize);
+ if (!data)
+ error("Error allocating space for file being loaded - %s", file.c_str());
+
+ readStream(f, data, filesize);
+ f.close();
+
+ return data;
+}
+
+/**
+ * Read a given number of bytes from a Stream into a pre-allocated buffer
+ */
+int FileManager::readStream(Common::ReadStream &stream, void *buf, size_t nbytes) {
+ return stream.read(buf, nbytes);
+}
+
+/**
+ * Initialize censorship based on blood.dat file
+ */
+void FileManager::initCensorship() {
+ _vm->_globals->_censorshipFl = false;
+
+ // If file doesn't exist, fallback to uncensored
+ if (fileExists("BLOOD.DAT")) {
+ char *data = (char *)loadFile("BLOOD.DAT");
+
+ if ((data[6] == 'u' && data[7] == 'k') || (data[6] == 'U' && data[7] == 'K'))
+ _vm->_globals->_censorshipFl = true;
+
+ _vm->_globals->freeMemory((byte *)data);
+ }
+}
+
+/**
+ * Check if a file is present
+ */
+bool FileManager::fileExists(const Common::String &file) {
+ Common::File f;
+
+ return f.exists(file);
+}
+
+/**
+ * Search file in Cat file
+ */
+byte *FileManager::searchCat(const Common::String &file, CatMode mode, bool &fileFoundFl) {
+ byte *ptr = NULL;
+ fileFoundFl = true;
+ Common::File f;
+
+ Common::String filename = file;
+ Common::String secondaryFilename = "";
+ filename.toUppercase();
+
+ switch (mode) {
+ case RES_INI:
+ if (!f.exists("RES_INI.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("RES_INI.CAT");
+ secondaryFilename = "RES_INI.RES";
+ break;
+
+ case RES_REP:
+ if (!f.exists("RES_REP.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("RES_REP.CAT");
+ secondaryFilename = "RES_REP.RES";
+ break;
+
+ case RES_LIN:
+ if (!f.exists("RES_LIN.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("RES_LIN.CAT");
+ secondaryFilename = "RES_LIN.RES";
+ break;
+
+ case RES_PER:
+ if (!f.exists("RES_PER.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("RES_PER.CAT");
+ secondaryFilename = "RES_PER.RES";
+ break;
+
+ case RES_PIC:
+ if (!f.exists("PIC.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("PIC.CAT");
+ break;
+
+ case RES_SAN:
+ if (!f.exists("RES_SAN.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("RES_SAN.CAT");
+ break;
+
+ case RES_SLI:
+ if (!f.exists("RES_SLI.CAT")) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile("RES_SLI.CAT");
+ break;
+
+ case RES_VOI: {
+ Common::String tmpFilename;
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ tmpFilename = "ENG_VOI.CAT";
+ // Win95 and Linux versions uses another set of names
+ else {
+ switch (_vm->_globals->_language) {
+ case LANG_EN:
+ tmpFilename = "RES_VAN.CAT";
+ break;
+ case LANG_FR:
+ tmpFilename = "RES_VFR.CAT";
+ break;
+ case LANG_SP:
+ tmpFilename = "RES_VES.CAT";
+ break;
+ }
+ }
+
+ if (!f.exists(tmpFilename)) {
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ ptr = loadFile(tmpFilename);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Scan for an entry in the catalogue
+ byte *result;
+ bool matchFlag = false;
+ int offsetVal = 0;
+
+ while (!matchFlag) {
+ Common::String name = (const char *)ptr + offsetVal;
+
+ if (name == filename) {
+ // Found entry for file, so get it's details from the catalogue entry
+ const byte *pData = ptr + offsetVal;
+ _catalogPos = READ_LE_UINT32(pData + 15);
+ _catalogSize = READ_LE_UINT32(pData + 19);
+ matchFlag = true;
+ }
+
+ if (name == "FINIS") {
+ _vm->_globals->freeMemory(ptr);
+ fileFoundFl = false;
+ return NULL;
+ }
+
+ offsetVal += 23;
+ }
+
+ _vm->_globals->freeMemory(ptr);
+
+ if (secondaryFilename != "") {
+ if (!f.open(secondaryFilename))
+ error("CHARGE_FICHIER");
+
+ f.seek(_catalogPos);
+
+ byte *catData = _vm->_globals->allocMemory(_catalogSize);
+ if (catData == NULL)
+ error("CHARGE_FICHIER");
+
+ readStream(f, catData, _catalogSize);
+ f.close();
+ result = catData;
+ } else {
+ result = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * Returns the size of a file. Throws an error if the file can't be found
+ */
+uint32 FileManager::fileSize(const Common::String &filename) {
+ Common::File f;
+ uint32 size;
+
+ if (!f.open(filename))
+ error("Could not find file %s", filename.c_str());
+
+ size = f.size();
+ f.close();
+
+ return size;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/files.h b/engines/hopkins/files.h
new file mode 100644
index 0000000000..5e5eaa755c
--- /dev/null
+++ b/engines/hopkins/files.h
@@ -0,0 +1,58 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_FILES_H
+#define HOPKINS_FILES_H
+
+#include "common/scummsys.h"
+#include "common/hash-str.h"
+#include "common/str.h"
+#include "common/stream.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+// RES_ANI = 4 has been removed because it's not used
+enum CatMode { RES_INI = 1, RES_REP = 2, RES_LIN = 3, RES_PER = 5,
+ RES_PIC = 6, RES_SAN = 7, RES_SLI = 8, RES_VOI = 9 };
+
+class FileManager {
+public:
+ uint32 _catalogPos;
+ uint32 _catalogSize;
+
+ HopkinsEngine *_vm;
+
+ FileManager(HopkinsEngine *vm);
+
+ bool fileExists(const Common::String &file);
+ byte *loadFile(const Common::String &file);
+ int readStream(Common::ReadStream &stream, void *buf, size_t nbytes);
+ void initCensorship();
+ byte *searchCat(const Common::String &file, CatMode mode, bool &fileFoundFl);
+ uint32 fileSize(const Common::String &filename);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_GLOBALS_H */
diff --git a/engines/hopkins/font.cpp b/engines/hopkins/font.cpp
new file mode 100644
index 0000000000..611327e9a8
--- /dev/null
+++ b/engines/hopkins/font.cpp
@@ -0,0 +1,495 @@
+/* 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/font.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/file.h"
+#include "common/textconsole.h"
+
+namespace Hopkins {
+
+FontManager::FontManager(HopkinsEngine *vm) {
+ _vm = vm;
+ clearAll();
+}
+
+FontManager::~FontManager() {
+ _vm->_globals->freeMemory(_font);
+ _vm->_globals->freeMemory(_zoneText);
+}
+
+void FontManager::loadZoneText() {
+ switch (_vm->_globals->_language) {
+ case LANG_EN:
+ _zoneText = _vm->_fileIO->loadFile("ZONEAN.TXT");
+ break;
+ case LANG_FR:
+ _zoneText = _vm->_fileIO->loadFile("ZONE01.TXT");
+ break;
+ case LANG_SP:
+ _zoneText = _vm->_fileIO->loadFile("ZONEES.TXT");
+ break;
+ }
+}
+
+void FontManager::clearAll() {
+ _font = NULL;
+ _fontFixedHeight = 0;
+ _fontFixedWidth = 0;
+
+ for (int idx = 0; idx < 12; ++idx) {
+ Common::fill((byte *)&_text[idx], (byte *)&_text[idx] + sizeof(TxtItem), 0);
+
+ _textList[idx]._enabledFl = false;
+ _textList[idx]._height = 0;
+ _textList[idx]._width = 0;
+ _textList[idx]._pos.x = 0;
+ _textList[idx]._pos.y = 0;
+ }
+
+ for (int idx = 0; idx < 21; idx++)
+ _textSortArray[idx] = 0;
+
+ _oldName = Common::String("");
+ _indexName = Common::String("");
+
+ for (int idx = 0; idx < 4048; idx++)
+ _index[idx] = 0;
+
+ _tempText = NULL;
+ _zoneText = NULL;
+
+ _boxWidth = 240;
+}
+
+void FontManager::initData() {
+ _font = _vm->_fileIO->loadFile("FONTE3.SPR");
+ _fontFixedWidth = 12;
+ _fontFixedHeight = 21;
+ loadZoneText();
+}
+/**
+ * Display Text
+ */
+void FontManager::showText(int idx) {
+ if ((idx - 5) > MAX_TEXT)
+ error("Attempted to display text > MAX_TEXT.");
+
+ TxtItem &txt = _text[idx - 5];
+ txt._textOnFl = true;
+ txt._textLoadedFl = false;
+
+ txt._textBlock = _vm->_globals->freeMemory(txt._textBlock);
+}
+
+/**
+ * Hide text
+ */
+void FontManager::hideText(int idx) {
+ if ((idx - 5) > MAX_TEXT)
+ error("Attempted to display text > MAX_TEXT.");
+
+ TxtItem &txt = _text[idx - 5];
+ txt._textOnFl = false;
+ txt._textLoadedFl = false;
+ txt._textBlock = _vm->_globals->freeMemory(txt._textBlock);
+}
+
+/**
+ * Set Text Color
+ */
+void FontManager::setTextColor(int idx, byte colByte) {
+ _text[idx - 5]._color = colByte;
+}
+
+/**
+ * Set Text Optimal Color
+ */
+void FontManager::setOptimalColor(int idx1, int idx2, int idx3, int idx4) {
+ setTextColor(idx1, 255);
+ setTextColor(idx2, 255);
+ setTextColor(idx3, 255);
+ setTextColor(idx4, 253);
+}
+
+/**
+ * Init text structure
+ */
+void FontManager::initTextBuffers(int idx, int messageId, const Common::String &filename, int xp, int yp, int textType, int length, int color) {
+ assert(idx - 5 >= 0 && (idx - 5) <= MAX_TEXT);
+
+ TxtItem &txt = _text[idx - 5];
+ txt._textOnFl = false;
+ txt._filename = filename;
+ txt._pos.x = xp;
+ txt._pos.y = yp;
+ txt._messageId = messageId;
+ txt._textType = textType;
+ txt._length = length;
+ txt._color = color;
+}
+
+// Box
+void FontManager::box(int idx, int messageId, const Common::String &filename, int xp, int yp) {
+ int textPosX = xp;
+ if (idx < 0)
+ error("Bad number for text");
+ _fontFixedWidth = 11;
+
+ _boxWidth = 11 * _text[idx]._length;
+ if (_text[idx]._textLoadedFl) {
+ int textType = _text[idx]._textType;
+ if (textType != 6 && textType != 1 && textType != 3 && textType != 5) {
+ int yCurrent = yp + 5;
+ for (int lineNum = 0; lineNum < _text[idx]._lineCount; ++lineNum) {
+ displayText(xp + 5, yCurrent, _text[idx]._lines[lineNum], _text[idx]._color);
+ yCurrent += _fontFixedHeight + 1;
+ }
+ } else {
+ int height = _text[idx]._height;
+ int width = _text[idx]._width;
+ _vm->_graphicsMan->restoreSurfaceRect(
+ _vm->_graphicsMan->_frontBuffer,
+ _text[idx]._textBlock,
+ xp,
+ yp,
+ _text[idx]._width,
+ _text[idx]._height);
+ _vm->_graphicsMan->addDirtyRect(xp, yp, xp + width, yp + height);
+ }
+ } else {
+ int lineCount = 0;
+ for (int i = 0; i <= 19; i++)
+ _textSortArray[i] = 0;
+
+ _text[idx]._textLoadedFl = true;
+ Common::String file = filename;
+ if (strncmp(file.c_str(), _oldName.c_str(), strlen(file.c_str())) != 0) {
+ // Starting to access a new file, so read in the index file for the file
+ _oldName = file;
+ _indexName = Common::String(file.c_str(), file.size() - 3);
+ _indexName += "IND";
+
+ Common::File f;
+ if (!f.open(_indexName))
+ error("Error opening file - %s", _indexName.c_str());
+ int filesize = f.size();
+ for (int i = 0; i < (filesize / 4); ++i)
+ _index[i] = f.readUint32LE();
+ f.close();
+ }
+ int bufSize;
+ if (filename[0] != 'Z' || filename[1] != 'O') {
+ Common::File f;
+ if (!f.open(file))
+ error("Error opening file - %s", _indexName.c_str());
+
+ bufSize = 2048;
+ f.seek(_index[messageId]);
+
+ _tempText = _vm->_globals->allocMemory(2058);
+ if (_tempText == NULL)
+ error("Error allocating text");
+
+ Common::fill(&_tempText[0], &_tempText[2058], 0);
+ f.read(_tempText, 2048);
+ f.close();
+ } else {
+ bufSize = 100;
+ _tempText = _vm->_globals->allocMemory(110);
+ Common::fill(&_tempText[0], &_tempText[110], 0);
+ memcpy(_tempText, _zoneText + _index[messageId], 96);
+ WRITE_LE_UINT16((uint16 *)_tempText + 48, READ_LE_INT16(_zoneText + _index[messageId] + 96));
+ }
+ byte *curTempTextPtr = _tempText;
+ for (int i = 0; i < bufSize; i++) {
+ byte curChar = *curTempTextPtr;
+ if ((byte)(*curTempTextPtr + 46) > 27) {
+ if ((byte)(curChar + 80) > 27) {
+ if ((byte)(curChar - 65) <= 25 || (byte)(curChar - 97) <= 25)
+ curChar = 32;
+ } else {
+ curChar -= 79;
+ }
+ } else {
+ curChar += 111;
+ }
+ *curTempTextPtr = curChar;
+ curTempTextPtr++;
+ };
+
+ int textLength;
+ for (textLength = 0; textLength < bufSize; textLength++) {
+ byte curChar = _tempText[textLength];
+ if (curChar == '\r' || curChar == '\n') {
+ _tempText[textLength] = 0;
+ if (!_text[idx]._length)
+ break;
+ }
+ }
+
+ if (bufSize && bufSize > textLength) {
+ _text[idx]._length = textLength;
+ _boxWidth = 0;
+
+ for (int curStrIdx = 0; curStrIdx < textLength + 1; curStrIdx++) {
+ byte curChar = _tempText[curStrIdx];
+ if (curChar <= 31)
+ curChar = ' ';
+ _boxWidth += _vm->_objectsMan->getWidth(_font, curChar - 32);
+ }
+
+ _boxWidth += 2;
+ _text[idx]._pos.x = 320 - abs(_boxWidth / 2);
+ textPosX = _vm->_events->_startPos.x + _text[idx]._pos.x;
+ lineCount = 1;
+ _text[idx]._lines[0] = Common::String((const char *)_tempText, textLength);
+ } else {
+ if (!_boxWidth)
+ _boxWidth = 240;
+ int tempTextIdx = 0;
+ int lineSize;
+ byte curChar;
+ do {
+ int curLineSize = 0;
+ int ptrb = _boxWidth - 4;
+ for (;;) {
+ lineSize = curLineSize;
+ do
+ curChar = _tempText[tempTextIdx + curLineSize++];
+ while (curChar != ' ' && curChar != '%');
+ if (curLineSize >= ptrb / _fontFixedWidth) {
+ if (curChar == '%')
+ curChar = ' ';
+ break;
+ }
+ if (curChar == '%') {
+ lineSize = curLineSize;
+ break;
+ }
+ }
+
+ // WORKAROUND: Perhaps due to the usage of ScummVM strings here, recalculate what the
+ // actual length of the line to be copied will be. Otherwise, you can see artifacts,
+ // such as a single character beyond the end of string NULL.
+ int actualSize = 0;
+ while (actualSize < lineSize && _tempText[tempTextIdx + actualSize])
+ ++actualSize;
+
+ _text[idx]._lines[lineCount] = Common::String((const char *)_tempText + tempTextIdx, actualSize);
+ _textSortArray[lineCount++] = lineSize;
+
+ tempTextIdx += lineSize;
+ } while (curChar != '%');
+
+ for (int i = 0; i <= 19; i++) {
+ if (_textSortArray[i] <= 0) {
+ _textSortArray[i] = 0;
+ } else {
+ int ptrc = 0;
+ for (int curIdx = 0; curIdx < _textSortArray[i] - 1; curIdx++) {
+ Common::String &line = _text[idx]._lines[i];
+ byte curChar2 = (curIdx >= (int)line.size()) ? '\0' : line.c_str()[curIdx];
+ if (curChar2 <= 31)
+ curChar2 = ' ';
+ ptrc += _vm->_objectsMan->getWidth(_font, (byte)curChar2 - 32);
+ }
+ _textSortArray[i] = ptrc;
+ }
+ }
+ for (int i = 0; i <= 19; i++) {
+ for (int j = i + 1; j != i; j = (j + 1) % 20) {
+ if (_textSortArray[i] < _textSortArray[j])
+ _textSortArray[i] = 0;
+ }
+ };
+
+ for (int i = 0; i <= 19; i++) {
+ if (_textSortArray[i])
+ _boxWidth = _textSortArray[i];
+ }
+
+ if ((_text[idx]._textType < 2) || (_text[idx]._textType > 3)) {
+ int i;
+ for (i = xp - _vm->_events->_startPos.x; _boxWidth + i > 638 && i > -2 && _text[idx]._textType; i -= 2)
+ ;
+ _text[idx]._pos.x = i;
+ textPosX = _vm->_events->_startPos.x + i;
+ } else {
+ _text[idx]._pos.x = textPosX;
+ }
+ }
+ int posX = textPosX;
+ int posY = yp;
+ int saveWidth = _boxWidth + 10;
+ int saveHeight = (_fontFixedHeight + 1) * lineCount + 12;
+ if (_text[idx]._textType == 6) {
+ _text[idx]._pos.x = 315 - abs(saveWidth / 2);
+ textPosX = posX = _vm->_events->_startPos.x + _text[idx]._pos.x;
+ _text[idx]._pos.y = posY = 50;
+ }
+ int textType = _text[idx]._textType;
+ if (textType == 1 || textType == 3 || textType == 5 || textType == 6) {
+ int size = saveHeight * saveWidth;
+ byte *ptrd = _vm->_globals->allocMemory(size);
+ if (ptrd == NULL)
+ error("Cutting a block for text box (%d)", size);
+
+ _vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_frontBuffer, ptrd, posX, posY, saveWidth, saveHeight);
+ _vm->_graphicsMan->fillSurface(ptrd, _vm->_graphicsMan->_colorTable, size);
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, ptrd, posX, posY, saveWidth, saveHeight);
+ _vm->_globals->freeMemory(ptrd);
+
+ _vm->_graphicsMan->drawHorizontalLine(_vm->_graphicsMan->_frontBuffer, posX, posY, saveWidth, (byte)-2);
+ _vm->_graphicsMan->drawHorizontalLine(_vm->_graphicsMan->_frontBuffer, posX, saveHeight + posY, saveWidth, (byte)-2);
+ _vm->_graphicsMan->drawVerticalLine(_vm->_graphicsMan->_frontBuffer, posX, posY, saveHeight, (byte)-2);
+ _vm->_graphicsMan->drawVerticalLine(_vm->_graphicsMan->_frontBuffer, saveWidth + posX, posY, saveHeight, (byte)-2);
+ }
+ _text[idx]._lineCount = lineCount;
+ int textPosY = posY + 5;
+
+ for (int lineNum = 0; lineNum < lineCount; ++lineNum) {
+ displayText(textPosX + 5, textPosY, _text[idx]._lines[lineNum], _text[idx]._color);
+ textPosY += _fontFixedHeight + 1;
+ }
+
+ int blockWidth = saveWidth + 1;
+ int blockHeight = saveHeight + 1;
+
+ _text[idx]._width = blockWidth;
+ _text[idx]._height = blockHeight;
+ textType = _text[idx]._textType;
+ if (textType == 6 || textType == 1 || textType == 3 || textType == 5) {
+ _text[idx]._textBlock = _vm->_globals->freeMemory(_text[idx]._textBlock);
+ int blockSize = blockHeight * blockWidth;
+ byte *ptre = _vm->_globals->allocMemory(blockSize + 20);
+ if (ptre == NULL)
+ error("Cutting a block for text box (%d)", blockSize);
+
+ _text[idx]._textBlock = ptre;
+ _text[idx]._width = blockWidth;
+ _text[idx]._height = blockHeight;
+ _vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_frontBuffer, _text[idx]._textBlock, posX, posY, _text[idx]._width, blockHeight);
+ }
+ _tempText = _vm->_globals->freeMemory(_tempText);
+ }
+}
+
+/**
+ * Directly display text (using a VESA segment)
+ */
+void FontManager::displayTextVesa(int xp, int yp, const Common::String &message, int col) {
+ int charIndex;
+ int currentX = xp;
+
+ const char *srcP = message.c_str();
+ for (;;) {
+ byte currChar = *srcP++;
+ if (!currChar)
+ break;
+ if (currChar >= 32) {
+ charIndex = currChar - 32;
+ _vm->_graphicsMan->displayFont(_vm->_graphicsMan->_frontBuffer, _font, currentX, yp, currChar - 32, col);
+ currentX += _vm->_objectsMan->getWidth(_font, charIndex);
+ }
+ }
+
+ _vm->_graphicsMan->addDirtyRect(xp, yp, currentX, yp + 12);
+}
+
+/**
+ * Directly display text
+ */
+void FontManager::displayText(int xp, int yp, const Common::String &message, int col) {
+ for (uint idx = 0; idx < message.size(); ++idx) {
+ byte currentChar = (byte)message[idx];
+
+ if (currentChar > 31) {
+ int characterIndex = currentChar - 32;
+ _vm->_graphicsMan->displayFont(_vm->_graphicsMan->_frontBuffer, _font, xp, yp, characterIndex, col);
+ xp += _vm->_objectsMan->getWidth(_font, characterIndex);
+ }
+ }
+}
+
+/**
+ * Compute character width and render text using variable width fonts
+ */
+void FontManager::renderTextDisplay(int xp, int yp, const Common::String &msg, int col) {
+ const char *srcP = msg.c_str();
+ int charEndPosX = xp;
+ int fontCol = col;
+ byte curChar = *srcP++;
+ while (curChar) {
+ if (curChar == '&') {
+ fontCol = 2;
+ curChar = *srcP++;
+ }
+ if (curChar == '$') {
+ fontCol = 4;
+ curChar = *srcP++;
+ }
+ if (!curChar)
+ break;
+ if (curChar >= 32) {
+ byte printChar = curChar - 32;
+ _vm->_graphicsMan->displayFont(_vm->_graphicsMan->_frontBuffer, _font, charEndPosX, yp, printChar, fontCol);
+
+ // UGLY HACK: For some obscure reason, the BeOS and OS/2 versions use another font file, which doesn't have variable width.
+ // All the fonts have a length of 9, which results in completely broken text in the computer.
+ // This horrible workaround fixes the English versions of the game. So far, no other languages are known for those platforms.
+ // Just in case, all the accentuated characters are handled properly, which *should* be OK for the other languages too.
+ int charWidth;
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
+ if ((curChar >= 'A' && curChar <= 'Z') || (curChar >= 'a' && curChar <= 'z' && curChar != 'm' && curChar != 'w') || (curChar >= '0' && curChar <= '9') || curChar == '*' || (curChar >= 128 && curChar <= 168))
+ charWidth = _vm->_objectsMan->getWidth(_font, printChar) - 1;
+ else if (curChar == 'm' || curChar == 'w')
+ charWidth = _vm->_objectsMan->getWidth(_font, printChar);
+ else
+ charWidth = 6;
+ } else
+ charWidth = _vm->_objectsMan->getWidth(_font, printChar);
+
+ int charStartPosX = charEndPosX;
+ charEndPosX += charWidth;
+ _vm->_graphicsMan->addDirtyRect(charStartPosX, yp, charEndPosX, yp + 12);
+ if (_vm->_events->_escKeyFl) {
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ _vm->_events->refreshScreenAndEvents();
+ } else {
+ _vm->_globals->_eventMode = EVENTMODE_ALT;
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ }
+ }
+ curChar = *srcP++;
+ }
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/font.h b/engines/hopkins/font.h
new file mode 100644
index 0000000000..93e807ea4b
--- /dev/null
+++ b/engines/hopkins/font.h
@@ -0,0 +1,98 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_FONT_H
+#define HOPKINS_FONT_H
+
+#include "common/scummsys.h"
+#include "common/events.h"
+#include "common/str.h"
+
+namespace Hopkins {
+
+#define MAX_TEXT 11
+
+class HopkinsEngine;
+
+struct TxtItem {
+ bool _textOnFl;
+ Common::String _filename;
+ Common::Point _pos;
+ int _messageId;
+ int _lineCount;
+ Common::String _lines[10];
+ int _textType;
+ int _length;
+ byte *_textBlock;
+ int16 _width;
+ int16 _height;
+ bool _textLoadedFl;
+ int _color;
+};
+
+struct TxtItemList {
+ bool _enabledFl;
+ Common::Point _pos;
+ int16 _width;
+ int16 _height;
+};
+
+class FontManager {
+private:
+ HopkinsEngine *_vm;
+
+ void setTextColor(int idx, byte colByte);
+
+ int _textSortArray[21];
+ Common::String _oldName;
+ Common::String _indexName;
+ int _index[4048];
+ byte *_tempText;
+ byte *_zoneText;
+ int _boxWidth;
+
+ void loadZoneText();
+public:
+ byte *_font;
+ int _fontFixedWidth;
+ int _fontFixedHeight;
+ TxtItem _text[12];
+ TxtItemList _textList[12];
+
+ FontManager(HopkinsEngine *vm);
+ ~FontManager();
+ void clearAll();
+ void initData();
+
+ void showText(int idx);
+ void hideText(int idx);
+ void initTextBuffers(int idx, int messageId, const Common::String &filename, int xp, int yp, int textType, int length, int color);
+ void displayText(int xp, int yp, const Common::String &message, int col);
+ void displayTextVesa(int xp, int yp, const Common::String &message, int col);
+ void renderTextDisplay(int xp, int yp, const Common::String &msg, int col);
+ void setOptimalColor(int idx1, int idx2, int idx3, int idx4);
+ void box(int idx, int messageId, const Common::String &filename, int xp, int yp);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_FONT_H */
diff --git a/engines/hopkins/globals.cpp b/engines/hopkins/globals.cpp
new file mode 100644
index 0000000000..2e7a2195d1
--- /dev/null
+++ b/engines/hopkins/globals.cpp
@@ -0,0 +1,215 @@
+/* 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/globals.h"
+
+#include "hopkins/files.h"
+#include "hopkins/font.h"
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+
+#include "common/textconsole.h"
+#include "common/file.h"
+
+namespace Hopkins {
+
+// Default data for the Hopkins array
+
+const int HOPKINS_PERSO_0[] = {
+ 0, -2, 0, -3, 0, -6, 0, -1, 0, -3, 0, -3, 0, -5, 0, -3, 0, -6, 0, -3, 0, -3, 0, -3,
+ 9, -4, 8, -4, 6, -2, 9, -2, 9, -3, 9, -3, 9, -4, 9, -2, 9, -2, 8, -2, 9, -3, 9, -2,
+ 13, 0, 13, 0, 13, 0, 13, 0, 14, 0, 13, 0, 13, 0, 12, 0, 12, 0, 14, 0, 13, 0, 14, 0,
+ 10, 3, 9, 3, 10, 4, 8, 2, 7, 1, 10, 2, 9, 2, 7, 4, 7, 3, 8, 0, 9, 1, 9, 1, 0, 4, 0,
+ 4, 0, 6, 0, 3, 0, 4, 0, 3, 0, 4, 0, 4, 0, 6, 0, 3, 0, 3, 0, 3
+};
+
+const int HOPKINS_PERSO_1[] = {
+ 0, -2, 0, -2, 0, -5, 0, -1, 0, -2, 0, -2, 0, -4, 0, -2, 0, -5, 0, -2, 0, -2, 0, -2,
+ 11, 0, 10, 0, 11, 0, 11, 0, 11, 0, 11, 0, 12, 0, 11, 0, 9, 0, 10, 0, 11, 0, 11, 0,
+ 11, 0, 10, 0, 11, 0, 11, 0, 11, 0, 11, 0, 12, 0, 11, 0, 9, 0, 10, 0, 11, 0, 11, 0,
+ 11, 0, 10, 0, 11, 0, 11, 0, 11, 0, 11, 0, 12, 0, 11, 0, 9, 0, 10, 0, 11, 0, 11, 0,
+ 0, 3, 0, 3, 0, 5, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 5, 0, 3, 0, 3, 0, 3
+};
+
+const int HOPKINS_PERSO_2[] = {
+ 0, -2, 0, 0, 0, -3, 0, -2, 0, -2, 0, -1, 0, -2, 0, -1, 0, -3, 0, -2, 0, -2, 0, -2,
+ 8, 0, 9, 0, 5, 0, 9, 0, 7, 0, 7, 0, 7, 0, 7, 0, 6, 0, 7, 0, 6, 0, 9, 0, 8, 0, 9, 0,
+ 5, 0, 9, 0, 7, 0, 7, 0, 7, 0, 7, 0, 6, 0, 7, 0, 6, 0, 9, 0, 8, 0, 9, 0, 5, 0, 9, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 6, 0, 7, 0, 6, 0, 9, 0, 0, 2, 0, 0, 0, 2, 0, 1, 0, 2, 0, 2,
+ 0, 2, 0, 2, 0, 2, 0, 1, 0, 2, 0, 2
+};
+
+Globals::Globals(HopkinsEngine *vm) {
+ _vm = vm;
+
+ // Initialize array properties
+ for (int i = 0; i < 500; ++i)
+ _spriteSize[i] = 0;
+ for (int i = 0; i < 70; ++i)
+ Common::fill((byte *)&_hopkinsItem[i], (byte *)&_hopkinsItem[i] + sizeof(HopkinsItem), 0);
+
+ for (int i = 0; i < 36; ++i)
+ _inventory[i] = 0;
+
+ // Initialize fields
+ _language = LANG_EN;
+
+ _linuxEndDemoFl = false;
+ _speed = 1;
+ _eventMode = EVENTMODE_DEFAULT;
+ _exitId = 0;
+ _characterSpriteBuf = 0;
+ _screenId = 0;
+ _prevScreenId = 0;
+ _characterMaxPosY = 0;
+ _menuScrollSpeed = 0;
+ _menuSpeed = 0;
+ _menuSoundOff = 0;
+ _menuVoiceOff = 0;
+ _menuMusicOff = 0;
+ _menuTextOff = 0;
+ _menuDisplayType = 0;
+ _checkDistanceFl = false;
+ _characterType = 0;
+ _actionMoveTo = false;
+ _actionDirection = DIR_NONE;
+
+ _creditsStartX = -1;
+ _creditsEndX = -1;
+ _creditsStartY = -1;
+ _creditsEndY = -1;
+ _creditsPosY = 0;
+ _creditsLineNumb = 0;
+ memset(_creditsItem, 0, 12000);
+ _creditsStep = 0;
+
+ _oceanDirection = DIR_NONE;
+
+ // Initialize pointers
+ _levelSpriteBuf = NULL;
+ _saveData = NULL;
+ _answerBuffer = NULL;
+ _characterSpriteBuf = NULL;
+ _optionDialogSpr = NULL;
+
+ // Reset flags
+ _censorshipFl = false;
+ _disableInventFl = false;
+ _freezeCharacterFl = false;
+ _optionDialogFl = false;
+ _introSpeechOffFl = false;
+ _cityMapEnabledFl = false;
+
+ _baseMapColor = 50;
+ _curRoomNum = 0;
+}
+
+Globals::~Globals() {
+ freeMemory(_levelSpriteBuf);
+ freeMemory((byte *)_saveData);
+ freeMemory(_answerBuffer);
+ freeMemory(_characterSpriteBuf);
+ free(NULL);
+}
+
+void Globals::setConfig() {
+ // CHECKME: Should be in Globals() but it doesn't work
+ // The Polish version is a translation of the English version. The filenames are the same.
+ switch (_vm->getLanguage()) {
+ case Common::EN_ANY:
+ case Common::PL_POL:
+ _language = LANG_EN;
+ break;
+ case Common::FR_FRA:
+ _language = LANG_FR;
+ break;
+ case Common::ES_ESP:
+ _language = LANG_SP;
+ break;
+ default:
+ warning("Unknown language in internal language mapping");
+ break;
+ }
+ // End of CHECKME
+
+ switch (_language) {
+ case LANG_EN:
+ _zoneFilename = "ZONEAN.TXT";
+ _textFilename = "TEXTEAN.TXT";
+ break;
+ case LANG_FR:
+ _zoneFilename = "ZONE01.TXT";
+ _textFilename = "TEXTE01.TXT";
+ break;
+ case LANG_SP:
+ _zoneFilename = "ZONEES.TXT";
+ _textFilename = "TEXTEES.TXT";
+ break;
+ }
+}
+
+void Globals::clearAll() {
+ _vm->_fontMan->clearAll();
+ _vm->_dialog->clearAll();
+ _answerBuffer = NULL;
+ _levelSpriteBuf = NULL;
+ _saveData = NULL;
+ _vm->_objectsMan->_curObjectIndex = 0;
+
+ _vm->_linesMan->clearAll();
+ _vm->_objectsMan->clearAll();
+
+ _saveData = (Savegame *)malloc(sizeof(Savegame));
+ memset(_saveData, 0, sizeof(Savegame));
+
+ _vm->_events->clearAll();
+}
+
+void Globals::loadCharacterData() {
+ assert(_characterType >= 0 && _characterType <= 2);
+
+ const int *srcList[] = { HOPKINS_PERSO_0, HOPKINS_PERSO_1, HOPKINS_PERSO_2 };
+ const int *srcP = srcList[_characterType];
+
+ for (int idx = 0; idx < 240 / 4; ++idx) {
+ _hopkinsItem[idx]._speedX = *srcP++;
+ _hopkinsItem[idx]._speedY = *srcP++;
+ }
+
+ _vm->_objectsMan->resetOldFrameIndex();
+ _vm->_objectsMan->resetOldDirection();
+}
+
+byte *Globals::allocMemory(int count) {
+ byte *result = (byte *)malloc(count);
+ if (!result)
+ result = NULL;
+ return result;
+}
+
+byte *Globals::freeMemory(byte *p) {
+ if (p)
+ free(p);
+ return NULL;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/globals.h b/engines/hopkins/globals.h
new file mode 100644
index 0000000000..f86a810c28
--- /dev/null
+++ b/engines/hopkins/globals.h
@@ -0,0 +1,225 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_GLOBALS_H
+#define HOPKINS_GLOBALS_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/events.h"
+
+namespace Hopkins {
+
+struct HopkinsItem {
+ int _speedX;
+ int _speedY;
+};
+
+struct CharacterLocation {
+ Common::Point _pos;
+ int _startSpriteIndex;
+ int _location;
+ int _zoomFactor;
+};
+
+enum SauvegardeOffset {
+ svLastMouseCursor = 1
+ , svLastZoneNum = 2
+ , svLastObjectIndex = 3
+ , svDialogField4 = 4
+ , svLastScreenId = 5
+ , svLastPrevScreenId = 6
+ , svLastInventoryItem = 8
+ , svLastInvMouseCursor = 9
+ , svLastSavegameSlot = 10
+ , svFreedHostageFl = 80
+ , svField94 = 94
+ , svField95 = 95
+ , svForestAvailableFl = 113
+ , svHutBurningFl = 117
+ , svHopkinsCloneFl = 121
+ , svAlternateSpriteFl = 122
+ , svHeavenGuardGoneFl = 123
+ , svField132 = 132
+ , svField133 = 133
+ , svGameWonFl = 135
+ , svCinemaCurtainCond1 = 166
+ , svCinemaCurtainCond2 = 167
+ , svBankAttackAnimPlayedFl = 170
+ , svCopCall1PlayedFl = 171
+ , svCopCall2PlayedFl = 172
+ , svField173 = 173
+ , svField176 = 176
+ , svPoolDogGoneFl = 177
+ , svCinemaDogGoneFl = 181
+ , svField183 = 183
+ , svField184 = 184
+ , svField186 = 186
+ , svField188 = 188
+ , svField200 = 200
+ , svField214 = 214
+ , svBombBoxOpenedFl = 220
+ , svBombDisarmedFl = 225
+ , svField228 = 228
+ , svField231 = 231
+ , svField253 = 253
+ , svField261 = 261
+ , svField270 = 270
+ , svField300 = 300
+ , svBaseElevatorCond1 = 311
+ , svBaseFireFl = 312
+ , svSecondElevatorAvailableFl = 318
+ , svField320 = 320
+ , svEscapeLeftJailFl = 330
+ , svField333 = 333
+ , svField338 = 338
+ , svField339 = 339
+ , svField340 = 340
+ , svField341 = 341
+ , svField352 = 352
+ , svField353 = 353
+ , svField354 = 354
+ , svField355 = 355
+ , svField356 = 356
+ , svField357 = 357
+ , svField399 = 399
+ , svField401 = 401
+};
+
+// As Script engine directly access savegame fields,
+// refactoring it in separated fields properly named is impossible
+struct Savegame {
+ byte _data[2050];
+ CharacterLocation _cloneHopkins;
+ CharacterLocation _realHopkins;
+ CharacterLocation _samantha;
+ int16 _inventory[35]; // Originally at offset 1300 of data array
+ int16 _mapCarPosX;
+ int16 _mapCarPosY;
+};
+
+struct CreditItem {
+ bool _actvFl;
+ int _color;
+ int _linePosY;
+ int _lineSize;
+ byte _line[50];
+};
+
+enum Language { LANG_EN = 0, LANG_FR = 1, LANG_SP = 2};
+
+enum PlayerCharacter { CHARACTER_HOPKINS = 0, CHARACTER_HOPKINS_CLONE = 1, CHARACTER_SAMANTHA = 2 };
+
+enum Directions {
+ DIR_NONE = -1,
+ DIR_UP = 1,
+ DIR_UP_RIGHT = 2,
+ DIR_RIGHT = 3,
+ DIR_DOWN_RIGHT = 4,
+ DIR_DOWN = 5,
+ DIR_DOWN_LEFT = 6,
+ DIR_LEFT = 7,
+ DIR_UP_LEFT = 8
+};
+
+enum EventMode {
+ EVENTMODE_DEFAULT = 0,
+ EVENTMODE_IGNORE = 1,
+ EVENTMODE_CREDITS = 3,
+ EVENTMODE_ALT = 4
+};
+
+class HopkinsEngine;
+
+/**
+ * Engine Globals
+ */
+class Globals {
+private:
+ HopkinsEngine *_vm;
+
+public:
+ bool _disableInventFl;
+ bool _cityMapEnabledFl;
+ bool _linuxEndDemoFl;
+ bool _censorshipFl;
+ bool _introSpeechOffFl;
+ int _exitId;
+ Directions _oceanDirection;
+ int _actionDirection;
+ int _inventory[36];
+ int _screenId;
+ int _prevScreenId;
+ int _characterMaxPosY;
+ int _baseMapColor;
+ int _spriteSize[500];
+ int _characterType;
+ uint _speed;
+ byte *_answerBuffer;
+ Savegame *_saveData;
+ Language _language;
+ HopkinsItem _hopkinsItem[70];
+
+ CreditItem _creditsItem[200];
+ int _creditsLineNumb;
+ int _creditsStep;
+ int _creditsPosY;
+ int _creditsStartX;
+ int _creditsEndX;
+ int _creditsStartY;
+ int _creditsEndY;
+
+ int _menuSpeed;
+ int _menuSoundOff;
+ int _menuTextOff;
+ int _menuVoiceOff;
+ int _menuMusicOff;
+ int _menuDisplayType;
+ int _menuScrollSpeed;
+
+ byte *_optionDialogSpr;
+ bool _optionDialogFl;
+
+ bool _actionMoveTo;
+ bool _freezeCharacterFl;
+ bool _checkDistanceFl;
+ byte *_characterSpriteBuf;
+ Common::String _zoneFilename;
+ Common::String _textFilename;
+ byte *_levelSpriteBuf;
+
+ EventMode _eventMode;
+
+ Globals(HopkinsEngine *vm);
+ ~Globals();
+ byte *allocMemory(int count);
+ byte *freeMemory(byte *p);
+ void setConfig();
+ void clearAll();
+ void loadCharacterData();
+
+ int _curRoomNum;
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_GLOBALS_H */
diff --git a/engines/hopkins/graphics.cpp b/engines/hopkins/graphics.cpp
new file mode 100644
index 0000000000..f978a5803f
--- /dev/null
+++ b/engines/hopkins/graphics.cpp
@@ -0,0 +1,1855 @@
+/* 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/graphics.h"
+
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/hopkins.h"
+
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "graphics/decoders/pcx.h"
+#include "common/file.h"
+#include "common/rect.h"
+#include "engines/util.h"
+
+namespace Hopkins {
+
+GraphicsManager::GraphicsManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ _lockCounter = 0;
+ _initGraphicsFl = false;
+ _screenWidth = _screenHeight = 0;
+ _screenLineSize = 0;
+ _palettePixels = NULL;
+ _lineNbr = 0;
+ _videoPtr = NULL;
+ _scrollOffset = 0;
+ _scrollPosX = 0;
+ _largeScreenFl = false;
+ _oldScrollPosX = 0;
+ _backBuffer = NULL;
+ _frontBuffer = NULL;
+ _screenBuffer = NULL;
+ _backupScreen = NULL;
+ _showDirtyRects = false;
+
+ _lineNbr2 = 0;
+ _enlargedX = _enlargedY = 0;
+ _enlargedXFl = _enlargedYFl = false;
+ _fadeDefaultSpeed = 15;
+ _fadingFl = false;
+ _skipVideoLockFl = false;
+ _scrollStatus = 0;
+ _minX = 0;
+ _minY = 20;
+ _maxX = SCREEN_WIDTH * 2;
+ _maxY = SCREEN_HEIGHT - 20;
+ _posXClipped = _posYClipped = 0;
+ _clipX1 = _clipY1 = 0;
+ _clipFl = false;
+ _reduceX = _reducedY = 0;
+ _zoomOutFactor = 0;
+ _width = 0;
+ _specialWidth = 0;
+
+ Common::fill(&_paletteBuffer[0], &_paletteBuffer[PALETTE_SIZE * 2], 0);
+ Common::fill(&_colorTable[0], &_colorTable[PALETTE_EXT_BLOCK_SIZE], 0);
+ Common::fill(&_palette[0], &_palette[PALETTE_EXT_BLOCK_SIZE], 0);
+ Common::fill(&_oldPalette[0], &_oldPalette[PALETTE_EXT_BLOCK_SIZE], 0);
+
+ if (_vm->getIsDemo()) {
+ if (_vm->getPlatform() == Common::kPlatformLinux)
+ // CHECKME: Should be false?
+ _manualScroll = true;
+ else
+ _manualScroll = false;
+ _scrollSpeed = 16;
+ } else {
+ _manualScroll = false;
+ _scrollSpeed = 32;
+ }
+
+ _noFadingFl = false;
+}
+
+GraphicsManager::~GraphicsManager() {
+ _vm->_globals->freeMemory(_backBuffer);
+ _vm->_globals->freeMemory(_frontBuffer);
+ _vm->_globals->freeMemory(_screenBuffer);
+ _vm->_globals->freeMemory(_backupScreen);
+}
+
+void GraphicsManager::setGraphicalMode(int width, int height) {
+ if (!_initGraphicsFl) {
+ Graphics::PixelFormat pixelFormat16(2, 5, 6, 5, 0, 11, 5, 0, 0);
+ initGraphics(width, height, true, &pixelFormat16);
+
+ // Init surfaces
+ _backBuffer = _vm->_globals->allocMemory(SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+ _frontBuffer = _vm->_globals->allocMemory(SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+ _screenBuffer = _vm->_globals->allocMemory(SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+
+ _videoPtr = NULL;
+ _screenWidth = width;
+ _screenHeight = height;
+
+ _screenLineSize = SCREEN_WIDTH * 2;
+ _palettePixels = _paletteBuffer;
+ _lineNbr = width;
+
+ _initGraphicsFl = true;
+ } else {
+ error("setGraphicalMode called multiple times");
+ }
+}
+
+/**
+ * (try to) Lock Screen
+ */
+void GraphicsManager::lockScreen() {
+ if (!_skipVideoLockFl) {
+ if (_lockCounter++ == 0) {
+ _videoPtr = _screenBuffer;
+ _screenLineSize = SCREEN_WIDTH * 2;
+ }
+ }
+}
+
+/**
+ * (try to) Unlock Screen
+ */
+void GraphicsManager::unlockScreen() {
+ assert(_videoPtr);
+ if (--_lockCounter == 0) {
+ _videoPtr = NULL;
+ }
+}
+
+/**
+ * Clear Screen
+ */
+void GraphicsManager::clearScreen() {
+ lockScreen();
+ assert(_videoPtr);
+
+ Common::fill(_screenBuffer, _screenBuffer + _screenLineSize * _screenHeight, 0);
+ addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ unlockScreen();
+}
+
+void GraphicsManager::clearVesaScreen() {
+ Common::fill(_backBuffer, _backBuffer + _screenLineSize * _screenHeight, 0);
+ Common::fill(_frontBuffer, _frontBuffer + _screenLineSize * _screenHeight, 0);
+ addDirtyRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+}
+
+/**
+ * Load Image
+ */
+void GraphicsManager::loadImage(const Common::String &file) {
+ Common::String filename = Common::String::format("%s.PCX", file.c_str());
+ loadScreen(filename);
+ initColorTable(165, 170, _palette);
+}
+
+/**
+ * Load VGA Image
+ */
+void GraphicsManager::loadVgaImage(const Common::String &file) {
+ setScreenWidth(SCREEN_WIDTH);
+ clearScreen();
+ loadPCX320(_backBuffer, file, _palette);
+ memcpy(_frontBuffer, _backBuffer, 64000);
+ setScreenWidth(320);
+ _maxX = 320;
+
+ copy16bFromSurfaceScaleX2(_frontBuffer);
+ addRefreshRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ fadeInBreakout();
+}
+
+/**
+ * Load Screen
+ */
+void GraphicsManager::loadScreen(const Common::String &file) {
+ Common::File f;
+ assert(!_videoPtr);
+
+ bool flag = true;
+ bool fileFoundFl = false;
+ _vm->_fileIO->searchCat(file, RES_PIC, fileFoundFl);
+ if (!fileFoundFl) {
+ if (!f.open(file))
+ error("loadScreen - %s", file.c_str());
+
+ f.seek(0, SEEK_END);
+ f.close();
+ flag = false;
+ }
+
+ scrollScreen(0);
+ loadPCX640(_backBuffer, file, _palette, flag);
+
+ _scrollPosX = 0;
+ _oldScrollPosX = 0;
+ clearPalette();
+
+ if (!_largeScreenFl) {
+ setScreenWidth(SCREEN_WIDTH);
+ _maxX = SCREEN_WIDTH;
+ clearScreen();
+
+ display8BitRect(_backBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ } else {
+ setScreenWidth(SCREEN_WIDTH * 2);
+ _maxX = SCREEN_WIDTH * 2;
+ clearScreen();
+
+ if (_manualScroll)
+ display8BitRect(_backBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ }
+
+ memcpy(_frontBuffer, _backBuffer, SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+}
+
+void GraphicsManager::initColorTable(int minIndex, int maxIndex, byte *palette) {
+ for (int idx = 0; idx < 256; ++idx)
+ _colorTable[idx] = idx;
+
+ translateSurface(_colorTable, palette, 256, minIndex, maxIndex);
+
+ for (int idx = 0; idx < 256; ++idx) {
+ byte v = _colorTable[idx];
+ if (v > 27 || !v)
+ _colorTable[idx] = 0;
+ }
+
+ _colorTable[0] = 1;
+}
+
+/**
+ * Scroll Screen
+ */
+void GraphicsManager::scrollScreen(int amount) {
+ int result = CLIP(amount, 0, SCREEN_WIDTH);
+ _vm->_events->_startPos.x = result;
+ _scrollOffset = result;
+ _scrollPosX = result;
+}
+
+void GraphicsManager::translateSurface(byte *destP, const byte *srcP, int count, int minThreshold, int maxThreshold) {
+ byte *destPosP = destP;
+ for (int idx = 0; idx < count; ++idx) {
+ int palIndex = *destPosP;
+ int srcOffset = 3 * palIndex;
+ int col1 = srcP[srcOffset] + srcP[srcOffset + 1] + srcP[srcOffset + 2];
+
+ for (int idx2 = 0; idx2 < 38; ++idx2) {
+ srcOffset = 3 * idx2;
+ int col2 = srcP[srcOffset] + srcP[srcOffset + 1] + srcP[srcOffset + 2];
+
+ col2 += minThreshold;
+ if (col2 < col1)
+ continue;
+
+ col2 -= maxThreshold;
+ if (col2 > col1)
+ continue;
+
+ *destPosP = (idx2 == 0) ? 1 : idx2;
+ break;
+ }
+ destPosP++;
+ }
+}
+
+void GraphicsManager::fillSurface(byte *surface, byte *col, int size) {
+ byte dataVal;
+
+ byte *dataP = surface;
+ for (int count = size - 1; count; count--){
+ dataVal = *dataP;
+ *dataP = col[dataVal];
+ dataP++;
+ }
+}
+
+void GraphicsManager::loadPCX640(byte *surface, const Common::String &file, byte *palette, bool typeFlag) {
+ Common::File f;
+ Graphics::PCXDecoder pcxDecoder;
+
+ // Clear the passed surface
+ memset(surface, 0, SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+
+ if (typeFlag) {
+ // Load PCX from within the PIC resource
+ if (!f.open("PIC.RES"))
+ error("Error opening PIC.RES.");
+ f.seek(_vm->_fileIO->_catalogPos);
+ } else {
+ // Load stand alone PCX file
+ if (!f.open(file))
+ error("Error opening PCX %s.", file.c_str());
+ }
+
+ // Decode the PCX
+ if (!pcxDecoder.loadStream(f))
+ error("Error decoding PCX %s", file.c_str());
+
+ const Graphics::Surface *s = pcxDecoder.getSurface();
+
+ // Copy out the dimensions and pixels of the decoded surface
+ _largeScreenFl = s->w > SCREEN_WIDTH;
+ Common::copy((byte *)s->pixels, (byte *)s->pixels + (s->pitch * s->h), surface);
+
+ // Copy out the palette
+ const byte *palSrc = pcxDecoder.getPalette();
+ Common::copy((const byte *)palSrc, (const byte *)palSrc + PALETTE_BLOCK_SIZE, palette);
+
+ f.close();
+}
+
+void GraphicsManager::loadPCX320(byte *surface, const Common::String &file, byte *palette) {
+ Common::File f;
+ if (!f.open(file))
+ error("File not found - %s", file.c_str());
+
+ size_t filesize = f.size();
+
+ f.read(surface, 128);
+ int imageSize = filesize - 896;
+ byte *ptr = _vm->_globals->allocMemory(65024);
+ size_t curBufSize;
+ int imageNumb;
+ int imageDataSize;
+ if (imageSize >= 64000) {
+ imageNumb = imageSize / 64000 + 1;
+ imageDataSize = abs(64000 * (imageSize / 64000) - imageSize);
+ f.read(ptr, 64000);
+ curBufSize = 64000;
+ } else {
+ imageNumb = 1;
+ imageDataSize = imageSize;
+ f.read(ptr, imageSize);
+ curBufSize = imageSize;
+ }
+ imageNumb--;
+ size_t curByteIdx = 0;
+ for (int i = 0; i < 64000; i++) {
+ if (curByteIdx == curBufSize) {
+ curByteIdx = 0;
+ --imageNumb;
+ curBufSize = 64000;
+ if (!imageNumb)
+ curBufSize = imageDataSize;
+ f.read(ptr, curBufSize);
+ }
+ byte curByte = ptr[curByteIdx++];
+ if (curByte > 192) {
+ int repeatCount = curByte - 192;
+ if (curByteIdx == curBufSize) {
+ curByteIdx = 0;
+ --imageNumb;
+ curBufSize = 64000;
+ if (imageNumb == 1)
+ curBufSize = imageDataSize;
+ f.read(ptr, curBufSize);
+ }
+ curByte = ptr[curByteIdx++];
+ for (; repeatCount; repeatCount--)
+ surface[i++] = curByte;
+
+ --i;
+ } else {
+ surface[i] = curByte;
+ }
+ }
+
+ f.seek(filesize - 768);
+ f.read(palette, 768);
+ f.close();
+
+ _vm->_globals->freeMemory(ptr);
+}
+
+// Clear Palette
+void GraphicsManager::clearPalette() {
+ // As weird as it sounds, this is what the original Linux executable does,
+ // and not a full array clear.
+ _paletteBuffer[0] = 0;
+}
+
+void GraphicsManager::setScreenWidth(int pitch) {
+ _lineNbr = _lineNbr2 = pitch;
+}
+
+/**
+ * Copies data from a 8-bit palette surface into the 16-bit screen
+ */
+void GraphicsManager::display8BitRect(const byte *surface, int xs, int ys, int width, int height, int destX, int destY) {
+ lockScreen();
+
+ assert(_videoPtr);
+ const byte *srcP = xs + _lineNbr2 * ys + surface;
+ byte *destP = (byte *)_videoPtr + destX * 2 + _screenLineSize * destY;
+
+ for (int yp = 0; yp < height; ++yp) {
+ // Copy over the line, using the source pixels as lookups into the pixels palette
+ const byte *lineSrcP = srcP;
+ byte *lineDestP = destP;
+
+ for (int xp = 0; xp < width; ++xp) {
+ lineDestP[0] = _palettePixels[lineSrcP[0] * 2];
+ lineDestP[1] = _palettePixels[(lineSrcP[0] * 2) + 1];
+ lineDestP += 2;
+ lineSrcP++;
+ }
+ // Move to the start of the next line
+ srcP += _lineNbr2;
+ destP += _screenLineSize;
+ }
+
+ unlockScreen();
+ addRefreshRect(destX, destY, destX + width, destY + height);
+}
+
+void GraphicsManager::displayScaled8BitRect(const byte *surface, int xp, int yp, int width, int height, int destX, int destY) {
+ int xCtr;
+ const byte *palette;
+ int savedXCount;
+ byte *loopDestP;
+ const byte *loopSrcP;
+ int yCtr;
+
+ assert(_videoPtr);
+ const byte *srcP = surface + xp + 320 * yp;
+ byte *destP = (byte *)_videoPtr + 30 * _screenLineSize + destX + destX + destX + destX + _screenLineSize * 2 * destY;
+ int yCount = height;
+ int xCount = width;
+
+ do {
+ yCtr = yCount;
+ xCtr = xCount;
+ loopSrcP = srcP;
+ loopDestP = destP;
+ savedXCount = xCount;
+ palette = _palettePixels;
+
+ do {
+ destP[0] = destP[2] = destP[_screenLineSize] = destP[_screenLineSize + 2] = palette[2 * srcP[0]];
+ destP[1] = destP[3] = destP[_screenLineSize + 1] = destP[_screenLineSize + 3] = palette[(2 * srcP[0]) + 1];
+ ++srcP;
+ destP += 4;
+ --xCtr;
+ } while (xCtr);
+
+ xCount = savedXCount;
+ destP = loopDestP + _screenLineSize * 2;
+ srcP = loopSrcP + 320;
+ yCount = yCtr - 1;
+ } while (yCtr != 1);
+
+ addRefreshRect(destX, destY, destX + width, destY + width);
+}
+
+/**
+ * Fade in. the step number is determine by parameter.
+ */
+void GraphicsManager::fadeIn(const byte *palette, int step, const byte *surface) {
+ byte palData2[PALETTE_BLOCK_SIZE];
+ int fadeStep;
+ if (step > 1)
+ fadeStep = step;
+ else
+ fadeStep = 2;
+ // Initialize temporary palette
+ Common::fill(&palData2[0], &palData2[PALETTE_BLOCK_SIZE], 0);
+
+ // Set current palette to black
+ setPaletteVGA256(palData2);
+
+ // Loop through fading in the palette
+ for (int fadeIndex = 0; fadeIndex < fadeStep; ++fadeIndex) {
+ for (int palOffset = 0; palOffset < PALETTE_BLOCK_SIZE; palOffset += 3) {
+ palData2[palOffset + 0] = fadeIndex * palette[palOffset + 0] / (fadeStep - 1);
+ palData2[palOffset + 1] = fadeIndex * palette[palOffset + 1] / (fadeStep - 1);
+ palData2[palOffset + 2] = fadeIndex * palette[palOffset + 2] / (fadeStep - 1);
+ }
+
+ // Set the transition palette and refresh the screen
+ setPaletteVGA256(palData2);
+ display8BitRect(surface, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ updateScreen();
+
+ // Added a delay in order to see the fading
+ _vm->_events->delay(20);
+ }
+
+ // Set the final palette
+ setPaletteVGA256(palette);
+
+ // Refresh the screen
+ display8BitRect(surface, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ updateScreen();
+}
+
+/**
+ * Fade out. the step number is determine by parameter.
+ */
+void GraphicsManager::fadeOut(const byte *palette, int step, const byte *surface) {
+ byte palData[PALETTE_BLOCK_SIZE];
+ if ((step > 1) && (palette) && (!_vm->_events->_escKeyFl)) {
+ int fadeStep = step;
+ for (int fadeIndex = 0; fadeIndex < fadeStep; fadeIndex++) {
+ for (int palOffset = 0; palOffset < PALETTE_BLOCK_SIZE; palOffset += 3) {
+ palData[palOffset + 0] = (fadeStep - fadeIndex - 1) * palette[palOffset + 0] / (fadeStep - 1);
+ palData[palOffset + 1] = (fadeStep - fadeIndex - 1) * palette[palOffset + 1] / (fadeStep - 1);
+ palData[palOffset + 2] = (fadeStep - fadeIndex - 1) * palette[palOffset + 2] / (fadeStep - 1);
+ }
+
+ setPaletteVGA256(palData);
+ display8BitRect(surface, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ updateScreen();
+
+ _vm->_events->delay(20);
+ }
+ }
+
+ // No initial palette, or end of fading
+ for (int i = 0; i < PALETTE_BLOCK_SIZE; i++)
+ palData[i] = 0;
+
+ setPaletteVGA256(palData);
+ display8BitRect(surface, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+
+ updateScreen();
+}
+
+/**
+ * Short fade in. The step number is 1, the default step number is also set to 1.
+ */
+void GraphicsManager::fadeInShort() {
+ _fadeDefaultSpeed = 1;
+ fadeIn(_palette, 1, (const byte *)_frontBuffer);
+}
+
+/**
+ * Short fade out. The step number is 1, the default step number is also set to 1.
+ */
+void GraphicsManager::fadeOutShort() {
+ _fadeDefaultSpeed = 1;
+ fadeOut(_palette, 1, (const byte *)_frontBuffer);
+}
+
+/**
+ * Long fade in. The step number is 20, the default step number is also set to 15.
+ */
+void GraphicsManager::fadeInLong() {
+ _fadeDefaultSpeed = 15;
+ fadeIn(_palette, 20, (const byte *)_frontBuffer);
+}
+
+/**
+ * Long fade out. The step number is 20, the default step number is also set to 15.
+ */
+void GraphicsManager::fadeOutLong() {
+ _fadeDefaultSpeed = 15;
+ fadeOut(_palette, 20, (const byte *)_frontBuffer);
+}
+
+/**
+ * Fade in. The step number used is the default step number.
+ */
+void GraphicsManager::fadeInDefaultLength(const byte *surface) {
+ assert(surface);
+ fadeIn(_palette, _fadeDefaultSpeed, surface);
+}
+
+/**
+ * Fade out. The step number used is the default step number.
+ */
+void GraphicsManager::fadeOutDefaultLength(const byte *surface) {
+ assert(surface);
+ fadeOut(_palette, _fadeDefaultSpeed, surface);
+}
+
+/**
+ * Fade in used by for the breakout mini-game
+ */
+void GraphicsManager::fadeInBreakout() {
+ setPaletteVGA256(_palette);
+ copy16bFromSurfaceScaleX2(_frontBuffer);
+ updateScreen();
+}
+
+/**
+ * Fade out used by for the breakout mini-game
+ */
+void GraphicsManager::fadeOutBreakout() {
+ byte palette[PALETTE_EXT_BLOCK_SIZE];
+
+ memset(palette, 0, PALETTE_EXT_BLOCK_SIZE);
+ setPaletteVGA256(palette);
+ copy16bFromSurfaceScaleX2(_frontBuffer);
+ updateScreen();
+}
+
+void GraphicsManager::setPaletteVGA256(const byte *palette) {
+ changePalette(palette);
+}
+
+void GraphicsManager::setPaletteVGA256WithRefresh(const byte *palette, const byte *surface) {
+ changePalette(palette);
+ display8BitRect(surface, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ updateScreen();
+}
+
+void GraphicsManager::setColorPercentage(int palIndex, int r, int g, int b) {
+ int palOffset = 3 * palIndex;
+ _palette[palOffset] = 255 * r / 100;
+ _palette[palOffset + 1] = 255 * g / 100;
+ _palette[palOffset + 2] = 255 * b / 100;
+}
+
+void GraphicsManager::setColorPercentage2(int palIndex, int r, int g, int b) {
+ int rv = 255 * r / 100;
+ int gv = 255 * g / 100;
+ int bv = 255 * b / 100;
+
+ int palOffset = 3 * palIndex;
+ _palette[palOffset] = rv;
+ _palette[palOffset + 1] = gv;
+ _palette[palOffset + 2] = bv;
+
+ WRITE_UINT16(&_paletteBuffer[2 * palIndex], mapRGB(rv, gv, bv));
+}
+
+void GraphicsManager::changePalette(const byte *palette) {
+ const byte *srcP = &palette[0];
+ for (int idx = 0; idx < PALETTE_SIZE; ++idx, srcP += 3) {
+ WRITE_UINT16(&_paletteBuffer[2 * idx], mapRGB(srcP[0], srcP[1], srcP[2]));
+ }
+}
+
+uint16 GraphicsManager::mapRGB(byte r, byte g, byte b) {
+ Graphics::PixelFormat format = g_system->getScreenFormat();
+
+ return (r >> format.rLoss) << format.rShift
+ | (g >> format.gLoss) << format.gShift
+ | (b >> format.bLoss) << format.bShift;
+}
+
+void GraphicsManager::updateScreen() {
+ // TODO: Is this okay here?
+ // Display any aras of the screen that need refreshing
+ displayDirtyRects();
+ displayRefreshRects();
+
+ // Update the screen
+ g_system->updateScreen();
+}
+
+void GraphicsManager::copyWinscanVbe3(const byte *srcData, byte *destSurface) {
+ byte srcByte;
+ byte destLen1;
+ byte *destSlice1P;
+ byte destLen2;
+ byte *destSlice2P;
+
+ int rleValue = 0;
+ int destOffset = 0;
+ const byte *srcP = srcData;
+ for (;;) {
+ srcByte = srcP[0];
+ if (srcByte == kByteStop)
+ return;
+ if (srcByte == 211) {
+ destLen1 = srcP[1];
+ rleValue = srcP[2];
+ destSlice1P = destOffset + destSurface;
+ destOffset += destLen1;
+ memset(destSlice1P, rleValue, destLen1);
+ srcP += 3;
+ } else if (srcByte < 222) {
+ if (srcByte > 211) {
+ destLen2 = (byte)(srcP[0] + 45);
+ rleValue = srcP[1];
+ destSlice2P = destOffset + destSurface;
+ destOffset += destLen2;
+ memset(destSlice2P, rleValue, destLen2);
+ srcP += 2;
+ } else {
+ destSurface[destOffset] = srcByte;
+ ++srcP;
+ ++destOffset;
+ }
+ } else if (srcByte < kSetOffset) {
+ destOffset += (byte)(srcP[0] + 35);
+ srcP++;
+ } else if (srcByte == k8bVal) {
+ destOffset += srcP[1];
+ srcP += 2;
+ } else if (srcByte == k16bVal) {
+ destOffset += READ_LE_UINT16(srcP + 1);
+ srcP += 3;
+ } else {
+ destOffset += READ_LE_UINT32(srcP + 1);
+ srcP += 5;
+ }
+ }
+}
+
+void GraphicsManager::copyVideoVbe16(const byte *srcData) {
+ const byte *srcP = srcData;
+ int destOffset = 0;
+
+ lockScreen();
+ assert(_videoPtr);
+
+ for (;;) {
+ byte srcByte = srcP[0];
+ if (srcByte >= 222) {
+ if (srcByte == kByteStop)
+ break;
+
+ if (srcByte < kSetOffset) {
+ destOffset += srcByte - 221;
+ srcByte = *++srcP;
+ } else if (srcByte == k8bVal) {
+ destOffset += srcP[1];
+ srcByte = srcP[2];
+ srcP += 2;
+ } else if (srcByte == k16bVal) {
+ destOffset += READ_LE_UINT16(srcP + 1);
+ srcByte = srcP[3];
+ srcP += 3;
+ } else {
+ destOffset += READ_LE_UINT32(srcP + 1);
+ srcByte = srcP[5];
+ srcP += 5;
+ }
+ }
+
+ if (destOffset > SCREEN_WIDTH * SCREEN_HEIGHT) {
+ warning("HACK: Stopping anim, out of bounds - 0x%x %d", srcByte, destOffset);
+ break;
+ }
+
+ if (srcByte > 210) {
+ if (srcByte == 211) {
+ int pixelCount = srcP[1];
+ int pixelIndex = srcP[2];
+ byte *destP = (byte *)_videoPtr + destOffset * 2;
+ destOffset += pixelCount;
+
+ while (pixelCount--) {
+ destP[0] = _palettePixels[2 * pixelIndex];
+ destP[1] = _palettePixels[(2 * pixelIndex) + 1];
+ destP += 2;
+ }
+
+ srcP += 3;
+ } else {
+ int pixelCount = srcByte - 211;
+ int pixelIndex = srcP[1];
+ byte *destP = (byte *)_videoPtr + destOffset * 2;
+ destOffset += pixelCount;
+
+ while (pixelCount--) {
+ destP[0] = _palettePixels[2 * pixelIndex];
+ destP[1] = _palettePixels[(2 * pixelIndex) + 1];
+ destP += 2;
+ }
+
+ srcP += 2;
+ }
+ } else {
+ byte *destP = (byte *)_videoPtr + destOffset * 2;
+ destP[0] = _palettePixels[2 * srcByte];
+ destP[1] = _palettePixels[(2 * srcByte) + 1];
+ ++srcP;
+ ++destOffset;
+ }
+ }
+ unlockScreen();
+}
+
+void GraphicsManager::copyVideoVbe16a(const byte *srcData) {
+ byte srcByte;
+ int destOffset = 0;
+ const byte *srcP = srcData;
+
+ lockScreen();
+ for (;;) {
+ srcByte = srcP[0];
+ if (srcByte == kByteStop)
+ break;
+ if (srcP[0] > kByteStop) {
+ if (srcByte == k8bVal) {
+ destOffset += srcP[1];
+ srcByte = srcP[2];
+ srcP += 2;
+ } else if (srcByte == k16bVal) {
+ destOffset += READ_LE_UINT16(srcP + 1);
+ srcByte = srcP[3];
+ srcP += 3;
+ } else {
+ destOffset += READ_LE_UINT32(srcP + 1);
+ srcByte = srcP[5];
+ srcP += 5;
+ }
+ }
+
+ WRITE_LE_UINT16((byte *)_videoPtr + destOffset * 2, READ_LE_UINT16(_palettePixels + 2 * srcByte));
+ ++srcP;
+ ++destOffset;
+ }
+ unlockScreen();
+}
+
+void GraphicsManager::copySurfaceRect(const byte *srcSurface, byte *destSurface, int xs, int ys, int width, int height) {
+ const byte *srcP;
+ byte *destP;
+ int rowCount;
+ int rowCount2;
+
+ // TODO: This code in the original is potentially dangerous, as it doesn't clip the area to within
+ // the screen, and so thus can read areas outside of the allocated surface buffer
+ srcP = xs + _lineNbr2 * ys + srcSurface;
+ destP = destSurface;
+ rowCount = height;
+ do {
+ rowCount2 = rowCount;
+ if (width & 1) {
+ memcpy(destP, srcP, width);
+ srcP += width;
+ destP += width;
+ } else if (width & 2) {
+ for (int i = width >> 1; i; --i) {
+ destP[0] = srcP[0];
+ destP[1] = srcP[1];
+ srcP += 2;
+ destP += 2;
+ }
+ } else {
+ memcpy(destP, srcP, 4 * (width >> 2));
+ srcP += 4 * (width >> 2);
+ destP += 4 * (width >> 2);
+ }
+ srcP = _lineNbr2 + srcP - width;
+ rowCount = rowCount2 - 1;
+ } while (rowCount2 != 1);
+}
+
+/**
+ * Draws a sprite onto the screen
+ * @param surface Destination surface
+ * @param spriteData The raw data for a sprite set
+ * @param xp X co-ordinate. For some reason, starts from 300 = first column
+ * @param yp Y co-ordinate. FOr some reason, starts from 300 = top row
+ * @param spriteIndex Index of the sprite to draw
+ */
+void GraphicsManager::drawVesaSprite(byte *surface, const byte *spriteData, int xp, int yp, int spriteIndex) {
+ // Get a pointer to the start of the desired sprite
+ const byte *spriteP = spriteData + 3;
+ for (int i = spriteIndex; i; --i)
+ spriteP += READ_LE_UINT32(spriteP) + 16;
+
+ _posXClipped = 0;
+ _posYClipped = 0;
+ _clipFl = false;
+
+ spriteP += 4;
+ int width = READ_LE_UINT16(spriteP);
+ spriteP += 2;
+ int height = READ_LE_UINT16(spriteP);
+
+ // Clip X
+ _clipX1 = width;
+ if ((xp + width) <= _minX + 300)
+ return;
+ if (xp < _minX + 300) {
+ _posXClipped = _minX + 300 - xp;
+ _clipFl = true;
+ }
+
+ // Clip Y
+ _clipY1 = height;
+ if (yp <= 0)
+ return;
+ if (yp < _minY + 300) {
+ _posYClipped = _minY + 300 - yp;
+ _clipFl = true;
+ }
+
+ // Clip X1
+ if (xp >= _maxX + 300)
+ return;
+ if (xp + width > _maxX + 300) {
+ int xAmount = width + 10 - (xp + width - (_maxX + 300));
+ if (xAmount <= 10)
+ return;
+
+ _clipX1 = xAmount - 10;
+ _clipFl = true;
+ }
+
+ // Clip Y1
+ if (yp >= _maxY + 300)
+ return;
+ if (yp + height > _maxY + 300) {
+ int yAmount = height + 10 - (yp + height - (_maxY + 300));
+ if (yAmount <= 10)
+ return;
+
+ // _clipY1 is always positive thanks to the previous check
+ _clipY1 = yAmount - 10;
+ _clipFl = true;
+ }
+
+ // Sprite display
+
+ // Set up source
+ spriteP += 6;
+ int srcOffset = READ_LE_UINT16(spriteP);
+ spriteP += 4;
+ const byte *srcP = spriteP;
+ spriteP += srcOffset;
+
+ // Set up surface destination
+ byte *destP = surface + (yp - 300) * _lineNbr2 + (xp - 300);
+
+ // Handling for clipped versus non-clipped
+ if (_clipFl) {
+ // Clipped version
+ for (int yc = 0; yc < _clipY1; ++yc, destP += _lineNbr2) {
+ byte *tempDestP = destP;
+ byte byteVal;
+ int xc = 0;
+
+ while ((byteVal = *srcP) != 253) {
+ ++srcP;
+ width = READ_LE_UINT16(srcP);
+ srcP += 2;
+
+ if (byteVal == 254) {
+ // Copy pixel range
+ for (int xv = 0; xv < width; ++xv, ++xc, ++spriteP, ++tempDestP) {
+ if (_posYClipped == 0 && xc >= _posXClipped && xc < _clipX1)
+ *tempDestP = *spriteP;
+ }
+ } else {
+ // Skip over bytes
+ tempDestP += width;
+ xc += width;
+ }
+ }
+
+ if (_posYClipped > 0)
+ --_posYClipped;
+ srcP += 3;
+ }
+ } else {
+ // Non-clipped
+ for (int yc = 0; yc < height; ++yc, destP += _lineNbr2) {
+ byte *tempDestP = destP;
+ byte byteVal;
+
+ while ((byteVal = *srcP) != 253) {
+ ++srcP;
+ width = READ_LE_UINT16(srcP);
+ srcP += 2;
+
+ if (byteVal == 254) {
+ // Copy pixel range
+ Common::copy(spriteP, spriteP + width, tempDestP);
+ spriteP += width;
+ }
+
+ tempDestP += width;
+ }
+
+ // Skip over control byte and width
+ srcP += 3;
+ }
+ }
+}
+
+void GraphicsManager::endDisplayBob() {
+ for (int idx = 1; idx <= 20; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->hideBob(idx);
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->refreshScreenAndEvents();
+
+ for (int idx = 1; idx <= 20; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->resetBob(idx);
+ }
+
+ for (int idx = 1; idx <= 29; ++idx) {
+ _vm->_objectsMan->_lockedAnims[idx]._enableFl = false;
+ }
+
+ for (int idx = 1; idx <= 20; ++idx) {
+ _vm->_animMan->_animBqe[idx]._enabledFl = false;
+ }
+}
+
+void GraphicsManager::displayAllBob() {
+ for (int idx = 1; idx <= 20; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->displayBob(idx);
+ }
+}
+
+void GraphicsManager::resetDirtyRects() {
+ _dirtyRects.clear();
+}
+
+void GraphicsManager::resetRefreshRects() {
+ _refreshRects.clear();
+}
+
+// Add a game area dirty rectangle
+void GraphicsManager::addDirtyRect(int x1, int y1, int x2, int y2) {
+ x1 = CLIP(x1, _minX, _maxX);
+ y1 = CLIP(y1, _minY, _maxY);
+ x2 = CLIP(x2, _minX, _maxX);
+ y2 = CLIP(y2, _minY, _maxY);
+
+ if ((x2 > x1) && (y2 > y1))
+ addRectToArray(_dirtyRects, Common::Rect(x1, y1, x2, y2));
+}
+
+// Add a refresh rect
+void GraphicsManager::addRefreshRect(int x1, int y1, int x2, int y2) {
+ x1 = MAX(x1, 0);
+ y1 = MAX(y1, 0);
+ x2 = MIN(x2, SCREEN_WIDTH);
+ y2 = MIN(y2, SCREEN_HEIGHT);
+
+ if ((x2 > x1) && (y2 > y1))
+ addRectToArray(_refreshRects, Common::Rect(x1, y1, x2, y2));
+}
+
+void GraphicsManager::addRectToArray(Common::Array<Common::Rect> &rects, const Common::Rect &newRect) {
+ // Scan for an intersection with existing rects
+ uint rectIndex;
+ for (rectIndex = 0; rectIndex < rects.size(); ++rectIndex) {
+ Common::Rect &r = rects[rectIndex];
+
+ if (r.intersects(newRect)) {
+ // Rect either intersects or is completely inside existing one, so extend existing one as necessary
+ r.extend(newRect);
+ break;
+ }
+ }
+ if (rectIndex == rects.size()) {
+ // Rect not intersecting any existing one, so add it in
+ assert(rects.size() < DIRTY_RECTS_SIZE);
+ rects.push_back(newRect);
+ }
+
+ // Take care of merging the existing rect list. This is done as a separate check even if
+ // a previous extending above has been done, since the merging of the new rect above may
+ // result in further rects now able to be merged
+
+ for (int srcIndex = rects.size() - 1; srcIndex > 0; --srcIndex) {
+ const Common::Rect &srcRect = rects[srcIndex];
+
+ // Loop through all the other rects to see if it intersects them
+ for (int destIndex = srcIndex - 1; destIndex >= 0; --destIndex) {
+ if (rects[destIndex].intersects(srcRect)) {
+ // Found an intersection, so extend the found one, and delete the original
+ rects[destIndex].extend(srcRect);
+ rects.remove_at(srcIndex);
+ break;
+ }
+ }
+ }
+}
+
+// Draw any game dirty rects onto the screen intermediate surface
+void GraphicsManager::displayDirtyRects() {
+ if (_dirtyRects.size() == 0)
+ return;
+
+ lockScreen();
+
+ // Refresh the entire screen
+ for (uint idx = 0; idx < _dirtyRects.size(); ++idx) {
+ Common::Rect &r = _dirtyRects[idx];
+ Common::Rect dstRect;
+
+ if (_vm->_events->_breakoutFl) {
+ displayScaled8BitRect(_frontBuffer, r.left, r.top, r.right - r.left, r.bottom - r.top, r.left, r.top);
+ dstRect.left = r.left * 2;
+ dstRect.top = r.top * 2 + 30;
+ dstRect.setWidth((r.right - r.left) * 2);
+ dstRect.setHeight((r.bottom - r.top) * 2);
+ } else if (r.right > _vm->_events->_startPos.x && r.left < _vm->_events->_startPos.x + SCREEN_WIDTH) {
+ r.left = MAX<int16>(r.left, _vm->_events->_startPos.x);
+ r.right = MIN<int16>(r.right, (int16)_vm->_events->_startPos.x + SCREEN_WIDTH);
+
+ display8BitRect(_frontBuffer, r.left, r.top, r.right - r.left, r.bottom - r.top, r.left - _vm->_events->_startPos.x, r.top);
+
+ dstRect.left = r.left - _vm->_events->_startPos.x;
+ dstRect.top = r.top;
+ dstRect.setWidth(r.right - r.left);
+ dstRect.setHeight(r.bottom - r.top);
+ }
+
+ // If it's a valid rect, then add it to the list of areas to refresh on the screen
+ if (dstRect.isValidRect() && dstRect.width() > 0 && dstRect.height() > 0)
+ addRectToArray(_refreshRects, dstRect);
+ }
+
+ unlockScreen();
+ resetDirtyRects();
+}
+
+void GraphicsManager::displayRefreshRects() {
+ Graphics::Surface *screenSurface = NULL;
+ if (_showDirtyRects) {
+ screenSurface = g_system->lockScreen();
+ g_system->copyRectToScreen(_screenBuffer, _screenLineSize, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ }
+ // Loop through copying over any specified rects to the screen
+ for (uint idx = 0; idx < _refreshRects.size(); ++idx) {
+ const Common::Rect &r = _refreshRects[idx];
+
+ byte *srcP = _screenBuffer + _screenLineSize * r.top + (r.left * 2);
+ g_system->copyRectToScreen(srcP, _screenLineSize, r.left, r.top, r.width(), r.height());
+
+ if (_showDirtyRects)
+ screenSurface->frameRect(r, 0xffffff);
+ }
+
+ if (_showDirtyRects)
+ g_system->unlockScreen();
+
+ resetRefreshRects();
+}
+
+
+/**
+ * Fast Display of either a compressed or vesa sprite
+ */
+void GraphicsManager::fastDisplay(const byte *spriteData, int xp, int yp, int spriteIndex, bool addSegment) {
+ int width = _vm->_objectsMan->getWidth(spriteData, spriteIndex);
+ int height = _vm->_objectsMan->getHeight(spriteData, spriteIndex);
+
+ if (*spriteData == 78) {
+ drawCompressedSprite(_backBuffer, spriteData, xp + 300, yp + 300, spriteIndex, 0, 0, false);
+ drawCompressedSprite(_frontBuffer, spriteData, xp + 300, yp + 300, spriteIndex, 0, 0, false);
+ } else {
+ drawVesaSprite(_frontBuffer, spriteData, xp + 300, yp + 300, spriteIndex);
+ drawVesaSprite(_backBuffer, spriteData, xp + 300, yp + 300, spriteIndex);
+ }
+ if (addSegment)
+ addDirtyRect(xp, yp, xp + width, yp + height);
+}
+
+void GraphicsManager::fastDisplay2(const byte *objectData, int xp, int yp, int idx, bool addSegment) {
+ int width = _vm->_objectsMan->getWidth(objectData, idx);
+ int height = _vm->_objectsMan->getHeight(objectData, idx);
+ if (*objectData == 78) {
+ drawCompressedSprite(_backBuffer, objectData, xp + 300, yp + 300, idx, 0, 0, false);
+ drawCompressedSprite(_frontBuffer, objectData, xp + 300, yp + 300, idx, 0, 0, false);
+ } else {
+ drawVesaSprite(_frontBuffer, objectData, xp + 300, yp + 300, idx);
+ drawVesaSprite(_backBuffer, objectData, xp + 300, yp + 300, idx);
+ }
+ if (addSegment)
+ addDirtyRect(xp, yp, xp + width, yp + height);
+}
+
+/**
+ * Copy from surface to video buffer, scale 2x.
+ */
+void GraphicsManager::copy16bFromSurfaceScaleX2(const byte *surface) {
+ byte *palPtr;
+ int curPixel;
+
+ lockScreen();
+
+ assert(_videoPtr);
+ const byte *curSurface = surface;
+ byte *destPtr = 30 * _screenLineSize + (byte *)_videoPtr;
+ for (int y = 200; y; y--) {
+ byte *oldDestPtr = destPtr;
+ for (int x = 320; x; x--) {
+ curPixel = 2 * *curSurface;
+ palPtr = _palettePixels + curPixel;
+ destPtr[0] = destPtr[2] = destPtr[_screenLineSize] = destPtr[_screenLineSize + 2] = palPtr[0];
+ destPtr[1] = destPtr[3] = destPtr[_screenLineSize + 1] = destPtr[_screenLineSize + 3] = palPtr[1];
+ ++curSurface;
+ destPtr += 4;
+ }
+ destPtr = _screenLineSize * 2 + oldDestPtr;
+ }
+
+ unlockScreen();
+}
+
+void GraphicsManager::restoreSurfaceRect(byte *destSurface, const byte *src, int xp, int yp, int width, int height) {
+ int yCtr;
+
+ byte *destP = xp + _lineNbr2 * yp + destSurface;
+ int yNext = height;
+ const byte *srcP = src;
+ do {
+ yCtr = yNext;
+ if (width & 1) {
+ memcpy(destP, srcP, width);
+ srcP += width;
+ destP += width;
+ } else if (width & 2) {
+ for (int i = width >> 1; i; --i) {
+ destP[0] = srcP[0];
+ destP[1] = srcP[1];
+ srcP += 2;
+ destP += 2;
+ }
+ } else {
+ memcpy(destP, srcP, 4 * (width >> 2));
+ srcP += 4 * (width >> 2);
+ destP += 4 * (width >> 2);
+ }
+ destP = _lineNbr2 + destP - width;
+ yNext = yCtr - 1;
+ } while (yCtr != 1);
+}
+
+/**
+ * Compute the value of a parameter plus a given percentage
+ */
+int GraphicsManager::zoomIn(int val, int percentage) {
+ if (val)
+ val += percentage * (long int)val / 100;
+
+ return val;
+}
+
+/**
+ * Compute the value of a parameter minus a given percentage
+ */
+int GraphicsManager::zoomOut(int val, int percentage) {
+ if (val)
+ val -= percentage * (long int)val / 100;
+
+ return val;
+}
+
+// Display 'Perfect?'
+void GraphicsManager::drawCompressedSprite(byte *surface, const byte *srcData, int xp300, int yp300, int frameIndex, int zoom1, int zoom2, bool flipFl) {
+ const byte *spriteStartP = srcData + 3;
+ for (int i = frameIndex; i; --i)
+ spriteStartP += READ_LE_UINT32(spriteStartP) + 16;
+
+ const byte *spriteSizeP = spriteStartP + 4;
+ int spriteWidth = READ_LE_INT16(spriteSizeP);
+ spriteSizeP += 2;
+ int spriteHeight2 = READ_LE_INT16(spriteSizeP);
+ int spriteHeight1 = spriteHeight2;
+ const byte *spritePixelsP = spriteSizeP + 10;
+ _posXClipped = 0;
+ _posYClipped = 0;
+ _clipX1 = 0;
+ _clipY1 = 0;
+ if ((xp300 <= _minX) || (yp300 <= _minY) || (xp300 >= _maxX + 300) || (yp300 >= _maxY + 300))
+ return;
+
+ // Clipped values are greater or equal to zero, thanks to the previous test
+ _clipX1 = _maxX + 300 - xp300;
+ _clipY1 = _maxY + 300 - yp300;
+
+ // _minX is never negative, and should be always 0
+ // The previous check insures that xp300 it's always greater to it
+ // After this check, posXClipped is always positive
+ if (xp300 < _minX + 300)
+ _posXClipped = _minX + 300 - xp300;
+
+ // Ditto.
+ if (yp300 < _minY + 300)
+ _posYClipped = _minY + 300 - yp300;
+
+ byte *dest1P = xp300 + _lineNbr2 * (yp300 - 300) - 300 + surface;
+ if (zoom2) {
+ _enlargedX = 0;
+ _enlargedY = 0;
+ _enlargedYFl = false;
+ _enlargedXFl = false;
+ _width = spriteWidth;
+ int zoomedWidth = zoomIn(spriteWidth, zoom2);
+ int zoomedHeight = zoomIn(spriteHeight1, zoom2);
+ if (flipFl) {
+ byte *clippedDestP = zoomedWidth + dest1P;
+ if (_posYClipped) {
+ if (_posYClipped < 0 || _posYClipped >= zoomedHeight)
+ return;
+ int hiddenHeight = 0;
+ while (zoomIn(++hiddenHeight, zoom2) < _posYClipped)
+ ;
+ spritePixelsP += _width * hiddenHeight;
+ clippedDestP += _lineNbr2 * _posYClipped;
+ zoomedHeight -= _posYClipped;
+ }
+ if (zoomedHeight > _clipY1)
+ zoomedHeight = _clipY1;
+ if (_posXClipped) {
+ if (_posXClipped >= zoomedWidth)
+ return;
+ zoomedWidth -= _posXClipped;
+ }
+ if (zoomedWidth > _clipX1) {
+ int clippedZoomedWidth = zoomedWidth - _clipX1;
+ clippedDestP -= clippedZoomedWidth;
+ int closestWidth = 0;
+ while (zoomIn(++closestWidth, zoom2) < clippedZoomedWidth)
+ ;
+ spritePixelsP += closestWidth;
+ zoomedWidth = _clipX1;
+ }
+ int curHeight;
+ do {
+ for (;;) {
+ curHeight = zoomedHeight;
+ byte *oldDestP = clippedDestP;
+ const byte *oldSpritePixelsP = spritePixelsP;
+ _enlargedXFl = false;
+ _enlargedX = 0;
+ for (int i = zoomedWidth; i; _enlargedXFl = false, i--) {
+ for (;;) {
+ if (*spritePixelsP)
+ *clippedDestP = *spritePixelsP;
+ --clippedDestP;
+ ++spritePixelsP;
+ if (!_enlargedXFl)
+ _enlargedX += zoom2;
+ if (_enlargedX >= 0 && _enlargedX < 100)
+ break;
+ _enlargedX -= 100;
+ --spritePixelsP;
+ _enlargedXFl = true;
+ --i;
+ if (!i)
+ break;
+ }
+ }
+ spritePixelsP = _width + oldSpritePixelsP;
+ clippedDestP = _lineNbr2 + oldDestP;
+ if (!_enlargedYFl)
+ _enlargedY += zoom2;
+ if (_enlargedY >= 0 && _enlargedY < 100)
+ break;
+ _enlargedY -= 100;
+ spritePixelsP = oldSpritePixelsP;
+ _enlargedYFl = true;
+ zoomedHeight = curHeight - 1;
+ if (curHeight == 1)
+ return;
+ }
+ _enlargedYFl = false;
+ zoomedHeight = curHeight - 1;
+ } while (curHeight != 1);
+ } else {
+ if (_posYClipped) {
+ if (_posYClipped >= zoomedHeight)
+ return;
+ int closerHeight = 0;
+ while (zoomIn(++closerHeight, zoom2) < _posYClipped)
+ ;
+ spritePixelsP += _width * closerHeight;
+ dest1P += _lineNbr2 * _posYClipped;
+ zoomedHeight -= _posYClipped;
+ }
+ if (zoomedHeight > _clipY1)
+ zoomedHeight = _clipY1;
+ if (_posXClipped) {
+ if (_posXClipped >= zoomedWidth)
+ return;
+ int closerWidth = 0;
+ while (zoomIn(++closerWidth, zoom2) < _posXClipped)
+ ;
+ spritePixelsP += closerWidth;
+ dest1P += _posXClipped;
+ zoomedWidth = zoomedWidth - _posXClipped;
+ }
+ if (zoomedWidth > _clipX1)
+ zoomedWidth = _clipX1;
+
+ int curHeight;
+ do {
+ for (;;) {
+ curHeight = zoomedHeight;
+ byte *oldDest1P = dest1P;
+ const byte *oldSpritePixelsP = spritePixelsP;
+ _enlargedXFl = false;
+ _enlargedX = 0;
+ for (int i = zoomedWidth; i; _enlargedXFl = false, i--) {
+ for (;;) {
+ if (*spritePixelsP)
+ *dest1P = *spritePixelsP;
+ ++dest1P;
+ ++spritePixelsP;
+ if (!_enlargedXFl)
+ _enlargedX += zoom2;
+ if (_enlargedX >= 0 && _enlargedX < 100)
+ break;
+ _enlargedX -= 100;
+ --spritePixelsP;
+ _enlargedXFl = true;
+ --i;
+ if (!i)
+ break;
+ }
+ }
+ spritePixelsP = _width + oldSpritePixelsP;
+ dest1P = _lineNbr2 + oldDest1P;
+ if (!_enlargedYFl)
+ _enlargedY += zoom2;
+ if (_enlargedY >= 0 && _enlargedY < 100)
+ break;
+ _enlargedY -= 100;
+ spritePixelsP = oldSpritePixelsP;
+ _enlargedYFl = true;
+ zoomedHeight = curHeight - 1;
+ if (curHeight == 1)
+ return;
+ }
+ _enlargedYFl = false;
+ zoomedHeight = curHeight - 1;
+ } while (curHeight != 1);
+ }
+ } else if (zoom1) {
+ _reduceX = 0;
+ _reducedY = 0;
+ _width = spriteWidth;
+ _zoomOutFactor = zoom1;
+ if (zoom1 < 100) {
+ int zoomedSpriteWidth = zoomOut(spriteWidth, _zoomOutFactor);
+ if (flipFl) {
+ byte *curDestP = zoomedSpriteWidth + dest1P;
+ do {
+ byte *oldDestP = curDestP;
+ _reducedY += _zoomOutFactor;
+ if (_reducedY >= 0 && _reducedY < 100) {
+ _reduceX = 0;
+ int curWidth = zoomedSpriteWidth;
+ for (int i = _width; i; i--) {
+ _reduceX += _zoomOutFactor;
+ if (_reduceX >= 0 && _reduceX < 100) {
+ if (curWidth >= _posXClipped && curWidth < _clipX1 && *spritePixelsP)
+ *curDestP = *spritePixelsP;
+ --curDestP;
+ ++spritePixelsP;
+ --curWidth;
+ } else {
+ _reduceX -= 100;
+ ++spritePixelsP;
+ }
+ }
+ curDestP = _lineNbr2 + oldDestP;
+ } else {
+ _reducedY -= 100;
+ spritePixelsP += _width;
+ }
+ --spriteHeight2;
+ } while (spriteHeight2);
+ } else {
+ do {
+ int oldSpriteHeight = spriteHeight2;
+ byte *oldDest1P = dest1P;
+ _reducedY += _zoomOutFactor;
+ if (_reducedY >= 0 && _reducedY < 100) {
+ _reduceX = 0;
+ int curX = 0;
+ for (int i = _width; i; i--) {
+ _reduceX += _zoomOutFactor;
+ if (_reduceX >= 0 && _reduceX < 100) {
+ if (curX >= _posXClipped && curX < _clipX1 && *spritePixelsP)
+ *dest1P = *spritePixelsP;
+ ++dest1P;
+ ++spritePixelsP;
+ ++curX;
+ } else {
+ _reduceX -= 100;
+ ++spritePixelsP;
+ }
+ }
+ spriteHeight2 = oldSpriteHeight;
+ dest1P = _lineNbr2 + oldDest1P;
+ } else {
+ _reducedY -= 100;
+ spritePixelsP += _width;
+ }
+ --spriteHeight2;
+ } while (spriteHeight2);
+ }
+ }
+ } else {
+ _width = spriteWidth;
+ if (flipFl) {
+ byte *dest2P = spriteWidth + dest1P;
+ _specialWidth = spriteWidth;
+ if (_posYClipped) {
+ if (_posYClipped >= spriteHeight1 || spriteHeight1 < 0)
+ return;
+ spritePixelsP += spriteWidth * _posYClipped;
+ dest2P += _lineNbr2 * _posYClipped;
+ spriteHeight1 -= _posYClipped;
+ }
+ if (spriteHeight1 > _clipY1)
+ spriteHeight1 = _clipY1;
+
+ if (_posXClipped >= spriteWidth)
+ return;
+ spriteWidth -= _posXClipped;
+
+ if (spriteWidth > _clipX1) {
+ int clippedWidth = spriteWidth - _clipX1;
+ spritePixelsP += clippedWidth;
+ dest2P -= clippedWidth;
+ spriteWidth = _clipX1;
+ }
+ int yCtr2;
+ do {
+ yCtr2 = spriteHeight1;
+ byte *destCopy2P = dest2P;
+ const byte *spritePixelsCopy2P = spritePixelsP;
+ for (int xCtr2 = spriteWidth; xCtr2; xCtr2--) {
+ if (*spritePixelsP)
+ *dest2P = *spritePixelsP;
+ ++spritePixelsP;
+ --dest2P;
+ }
+ spritePixelsP = _specialWidth + spritePixelsCopy2P;
+ dest2P = _lineNbr2 + destCopy2P;
+ spriteHeight1 = yCtr2 - 1;
+ } while (yCtr2 != 1);
+ } else {
+ _specialWidth = spriteWidth;
+ if (_posYClipped) {
+ if (_posYClipped >= spriteHeight1 || spriteHeight1 < 0)
+ return;
+ spritePixelsP += spriteWidth * _posYClipped;
+ dest1P += _lineNbr2 * _posYClipped;
+ spriteHeight1 -= _posYClipped;
+ }
+ if (spriteHeight1 > _clipY1)
+ spriteHeight1 = _clipY1;
+ if (_posXClipped) {
+ if (_posXClipped >= spriteWidth)
+ return;
+ spritePixelsP += _posXClipped;
+ dest1P += _posXClipped;
+ spriteWidth -= _posXClipped;
+ }
+ if (spriteWidth > _clipX1)
+ spriteWidth = _clipX1;
+ int yCtr1;
+ do {
+ yCtr1 = spriteHeight1;
+ byte *dest1CopyP = dest1P;
+ const byte *spritePixelsCopyP = spritePixelsP;
+ for (int xCtr1 = spriteWidth; xCtr1; xCtr1--) {
+ if (*spritePixelsP)
+ *dest1P = *spritePixelsP;
+ ++dest1P;
+ ++spritePixelsP;
+ }
+ spritePixelsP = _specialWidth + spritePixelsCopyP;
+ dest1P = _lineNbr2 + dest1CopyP;
+ spriteHeight1 = yCtr1 - 1;
+ } while (yCtr1 != 1);
+ }
+ }
+}
+
+void GraphicsManager::copySurface(const byte *surface, int x1, int y1, int width, int height, byte *destSurface, int destX, int destY) {
+ int left = x1;
+ int top = y1;
+ int croppedWidth = width;
+ int croppedHeight = height;
+
+ if (x1 < _minX) {
+ croppedWidth = width - (_minX - x1);
+ left = _minX;
+ }
+ if (y1 < _minY) {
+ croppedHeight = height - (_minY - y1);
+ top = _minY;
+ }
+
+ if (top + croppedHeight > _maxY)
+ croppedHeight = _maxY - top;
+ if (left + croppedWidth > _maxX)
+ croppedWidth = _maxX - left;
+
+ if (croppedWidth > 0 && croppedHeight > 0) {
+ int height2 = croppedHeight;
+ copyRect(surface, left, top, croppedWidth, croppedHeight, destSurface, destX, destY);
+ addDirtyRect(left, top, left + croppedWidth, top + height2);
+ }
+}
+
+void GraphicsManager::copyRect(const byte *srcSurface, int x1, int y1, uint16 width, int height, byte *destSurface, int destX, int destY) {
+ const byte *srcP = x1 + _lineNbr2 * y1 + srcSurface;
+ byte *destP = destX + _lineNbr2 * destY + destSurface;
+ int yp = height;
+ int yCurrent;
+ do {
+ yCurrent = yp;
+ memcpy(destP, srcP, 4 * (width >> 2));
+ const byte *src2P = (srcP + 4 * (width >> 2));
+ byte *dest2P = (destP + 4 * (width >> 2));
+ int pitch = width - 4 * (width >> 2);
+ memcpy(dest2P, src2P, pitch);
+ destP = (dest2P + pitch + _lineNbr2 - width);
+ srcP = (src2P + pitch + _lineNbr2 - width);
+ yp = yCurrent - 1;
+ } while (yCurrent != 1);
+}
+
+// Display Font
+void GraphicsManager::displayFont(byte *surface, const byte *spriteData, int xp, int yp, int characterIndex, int color) {
+ const byte *spriteDataP = spriteData + 3;
+ for (int i = characterIndex; i; --i)
+ spriteDataP += READ_LE_UINT32(spriteDataP) + 16;
+
+ int spriteWidth = 0;
+ int spriteHeight = 0;
+ const byte *spriteSizeP = spriteDataP + 4;
+ spriteWidth = READ_LE_INT16(spriteSizeP);
+ spriteSizeP += 2;
+ spriteHeight = READ_LE_INT16(spriteSizeP);
+ const byte *spritePixelsP = spriteSizeP + 10;
+ byte *destP = surface + xp + _lineNbr2 * yp;
+ _width = spriteWidth;
+
+ int yCtr;
+ do {
+ yCtr = spriteHeight;
+ byte *destLineP = destP;
+ for (int xCtr = spriteWidth; xCtr; xCtr--) {
+ byte destByte = *spritePixelsP;
+ if (*spritePixelsP) {
+ if (destByte == 252)
+ destByte = color;
+ *destP = destByte;
+ }
+
+ ++destP;
+ ++spritePixelsP;
+ }
+ destP = _lineNbr2 + destLineP;
+ spriteHeight = yCtr - 1;
+ } while (yCtr != 1);
+}
+
+void GraphicsManager::initScreen(const Common::String &file, int mode, bool initializeScreen) {
+ Common::String filename = file + ".ini";
+ bool fileFoundFl = false;
+
+ byte *ptr = _vm->_fileIO->searchCat(filename, RES_INI, fileFoundFl);
+
+ if (!fileFoundFl) {
+ ptr = _vm->_fileIO->loadFile(filename);
+ }
+
+ if (!mode) {
+ filename = file + ".spr";
+ _vm->_globals->_levelSpriteBuf = _vm->_globals->freeMemory(_vm->_globals->_levelSpriteBuf);
+ if (initializeScreen) {
+ fileFoundFl = false;
+ _vm->_globals->_levelSpriteBuf = _vm->_fileIO->searchCat(filename, RES_SLI, fileFoundFl);
+ if (!fileFoundFl) {
+ _vm->_globals->_levelSpriteBuf = _vm->_fileIO->loadFile(filename);
+ } else {
+ _vm->_globals->_levelSpriteBuf = _vm->_fileIO->loadFile("RES_SLI.RES");
+ }
+ }
+ }
+ if (READ_BE_UINT24(ptr) != MKTAG24('I', 'N', 'I')) {
+ error("Invalid INI File %s", file.c_str());
+ } else {
+ bool doneFlag = false;
+ int dataOffset = 1;
+
+ do {
+ int dataVal1 = _vm->_script->handleOpcode(ptr + 20 * dataOffset);
+ if (_vm->shouldQuit())
+ return;
+
+ if (dataVal1 == 2)
+ dataOffset = _vm->_script->handleGoto((ptr + 20 * dataOffset));
+ if (dataVal1 == 3)
+ dataOffset = _vm->_script->handleIf(ptr, dataOffset);
+ if (dataOffset == -1)
+ error("Error, defective IFF");
+ if (dataVal1 == 1 || dataVal1 == 4)
+ ++dataOffset;
+ if (!dataVal1 || dataVal1 == 5)
+ doneFlag = true;
+ } while (!doneFlag);
+ }
+ _vm->_globals->freeMemory(ptr);
+ _vm->_globals->_answerBuffer = _vm->_globals->freeMemory(_vm->_globals->_answerBuffer);
+
+ filename = file + ".rep";
+ fileFoundFl = false;
+ byte *dataP = _vm->_fileIO->searchCat(filename, RES_REP, fileFoundFl);
+ if (!fileFoundFl)
+ dataP = _vm->_fileIO->loadFile(filename);
+
+ _vm->_globals->_answerBuffer = dataP;
+ _vm->_objectsMan->_forceZoneFl = true;
+ _vm->_objectsMan->_changeVerbFl = false;
+}
+
+void GraphicsManager::displayScreen(bool initPalette) {
+ if (initPalette)
+ initColorTable(50, 65, _palette);
+
+ if (_lineNbr == SCREEN_WIDTH)
+ fillSurface(_frontBuffer, _colorTable, SCREEN_WIDTH * SCREEN_HEIGHT);
+ else if (_lineNbr == (SCREEN_WIDTH * 2))
+ fillSurface(_frontBuffer, _colorTable, SCREEN_WIDTH * SCREEN_HEIGHT * 2);
+
+ display8BitRect(_frontBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ memcpy(_backBuffer, _frontBuffer, 614399);
+ updateScreen();
+}
+
+void GraphicsManager::copyWinscanVbe(const byte *src, byte *dest) {
+ int destOffset = 0;
+ const byte *srcPtr = src;
+ for (;;) {
+ byte byteVal = *srcPtr;
+ if (byteVal == kByteStop)
+ return;
+ if (*srcPtr > kByteStop) {
+ if (byteVal == k8bVal) {
+ destOffset += srcPtr[1];
+ byteVal = srcPtr[2];
+ srcPtr += 2;
+ } else if (byteVal == k16bVal) {
+ destOffset += READ_LE_UINT16(srcPtr + 1);
+ byteVal = srcPtr[3];
+ srcPtr += 3;
+ } else {
+ destOffset += READ_LE_UINT32(srcPtr + 1);
+ byteVal = srcPtr[5];
+ srcPtr += 5;
+ }
+ }
+ dest[destOffset] = byteVal;
+ ++srcPtr;
+ ++destOffset;
+ }
+}
+
+// Reduce Screen
+void GraphicsManager::reduceScreenPart(const byte *srcSurface, byte *destSurface, int xp, int yp, int width, int height, int zoom) {
+ const byte *srcP = xp + _lineNbr2 * yp + srcSurface;
+ byte *destP = destSurface;
+ _zoomOutFactor = zoom;
+ _width = width;
+ _reduceX = 0;
+ _reducedY = 0;
+ if (zoom < 100) {
+ for (int yCtr = 0; yCtr < height; ++yCtr, srcP += _lineNbr2) {
+ _reducedY += _zoomOutFactor;
+ if (_reducedY < 100) {
+ _reduceX = 0;
+ const byte *lineSrcP = srcP;
+
+ for (int xCtr = 0; xCtr < _width; ++xCtr) {
+ _reduceX += _zoomOutFactor;
+ if (_reduceX < 100) {
+ *destP++ = *lineSrcP++;
+ } else {
+ _reduceX -= 100;
+ ++lineSrcP;
+ }
+ }
+ } else {
+ _reducedY -= 100;
+ }
+ }
+ }
+}
+
+/**
+ * Draw horizontal line
+ */
+void GraphicsManager::drawHorizontalLine(byte *surface, int xp, int yp, uint16 width, byte col) {
+ memset(surface + xp + _lineNbr2 * yp, col, width);
+}
+
+/**
+ * Draw vertical line
+ */
+void GraphicsManager::drawVerticalLine(byte *surface, int xp, int yp, int height, byte col) {
+ byte *destP = surface + xp + _lineNbr2 * yp;
+
+ for (int yCtr = height; yCtr; yCtr--) {
+ *destP = col;
+ destP += _lineNbr2;
+ }
+}
+
+/**
+ * Backup the current screen
+ */
+void GraphicsManager::backupScreen() {
+ // Allocate a new data block for the screen, if necessary
+ if (_vm->_graphicsMan->_backupScreen == NULL)
+ _vm->_graphicsMan->_backupScreen = _vm->_globals->allocMemory(SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+
+ // Backup the screen
+ Common::copy(_vm->_graphicsMan->_backBuffer, _vm->_graphicsMan->_backBuffer +
+ SCREEN_WIDTH * 2 * SCREEN_HEIGHT, _vm->_graphicsMan->_backupScreen);
+}
+
+/**
+ * Restore a previously backed up screen
+ */
+void GraphicsManager::restoreScreen() {
+ assert(_vm->_graphicsMan->_backupScreen);
+
+ // Restore the screen and free the buffer
+ Common::copy(_vm->_graphicsMan->_backupScreen, _vm->_graphicsMan->_backupScreen +
+ SCREEN_WIDTH * 2 * SCREEN_HEIGHT, _vm->_graphicsMan->_backBuffer);
+ _vm->_globals->freeMemory(_vm->_graphicsMan->_backupScreen);
+ _backupScreen = NULL;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/graphics.h b/engines/hopkins/graphics.h
new file mode 100644
index 0000000000..b7d7eaa86f
--- /dev/null
+++ b/engines/hopkins/graphics.h
@@ -0,0 +1,188 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_GRAPHICS_H
+#define HOPKINS_GRAPHICS_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/endian.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "graphics/surface.h"
+
+namespace Hopkins {
+
+#define DIRTY_RECTS_SIZE 250
+#define PALETTE_SIZE 256
+#define PALETTE_BLOCK_SIZE (PALETTE_SIZE * 3)
+#define PALETTE_EXT_BLOCK_SIZE 800
+static const byte kSetOffset = 251;
+static const byte kByteStop = 252;
+static const byte k8bVal = 253;
+static const byte k16bVal = 254;
+
+struct RGB8 {
+ byte r;
+ byte g;
+ byte b;
+};
+
+class HopkinsEngine;
+
+class GraphicsManager {
+private:
+ HopkinsEngine *_vm;
+
+ int _lockCounter;
+ bool _initGraphicsFl;
+ int _screenWidth;
+ int _screenHeight;
+ byte *_videoPtr;
+ int _width;
+ int _posXClipped, _posYClipped;
+ bool _clipFl;
+ int _specialWidth;
+
+ int _enlargedX, _enlargedY;
+ bool _enlargedXFl, _enlargedYFl;
+ int _clipX1, _clipY1;
+ int _reduceX, _reducedY;
+ int _zoomOutFactor;
+
+ bool _manualScroll;
+
+ void loadScreen(const Common::String &file);
+ void loadPCX640(byte *surface, const Common::String &file, byte *palette, bool typeFlag);
+ void loadPCX320(byte *surface, const Common::String &file, byte *palette);
+ void fadeIn(const byte *palette, int step, const byte *surface);
+ void fadeOut(const byte *palette, int step, const byte *surface);
+ void changePalette(const byte *palette);
+ uint16 mapRGB(byte r, byte g, byte b);
+ void copy16bFromSurfaceScaleX2(const byte *surface);
+
+ void translateSurface(byte *destP, const byte *srcP, int count, int minThreshold, int maxThreshold);
+ void displayScaled8BitRect(const byte *surface, int xp, int yp, int width, int height, int destX, int destY);
+
+ void lockScreen();
+ void unlockScreen();
+public:
+ byte _paletteBuffer[PALETTE_SIZE * 2];
+ byte _colorTable[PALETTE_EXT_BLOCK_SIZE];
+ byte _palette[PALETTE_EXT_BLOCK_SIZE];
+ byte _oldPalette[PALETTE_EXT_BLOCK_SIZE];
+ byte *_backBuffer;
+ byte *_frontBuffer;
+ byte *_screenBuffer;
+ byte *_backupScreen;
+ bool _largeScreenFl;
+ bool _noFadingFl;
+ bool _fadingFl;
+ bool _skipVideoLockFl;
+ int _scrollOffset;
+ int _scrollPosX;
+ int _oldScrollPosX;
+ int _scrollSpeed;
+ int _lineNbr;
+ int _lineNbr2;
+ int _minX, _minY;
+ int _maxX, _maxY;
+ int _scrollStatus;
+ int _fadeDefaultSpeed;
+ int _screenLineSize;
+
+ /**
+ * The _dirtyRects list contains paletted game areas that need to be redrawn.
+ * The _dstrect array is the list of areas of the screen that ScummVM needs to be redrawn.
+ * Some areas, such as the animation managers, skip the _dirtyRects and use _dstrec directly.
+ */
+ Common::Array<Common::Rect> _dirtyRects;
+ Common::Array<Common::Rect> _refreshRects;
+ bool _showDirtyRects;
+
+ byte *_palettePixels;
+public:
+ GraphicsManager(HopkinsEngine *vm);
+ ~GraphicsManager();
+
+ void clearPalette();
+ void clearScreen();
+ void clearVesaScreen();
+ void resetDirtyRects();
+ void resetRefreshRects();
+ void addDirtyRect(int x1, int y1, int x2, int y2);
+ void addDirtyRect(const Common::Rect &r) { addDirtyRect(r.left, r.top, r.right, r.bottom); }
+ void addRefreshRect(int x1, int y1, int x2, int y2);
+ void addRectToArray(Common::Array<Common::Rect> &rects, const Common::Rect &newRect);
+ void displayDirtyRects();
+ void displayRefreshRects();
+ void copySurface(const byte *surface, int x1, int y1, int width, int height, byte *destSurface, int destX, int destY);
+ void loadImage(const Common::String &file);
+ void loadVgaImage(const Common::String &file);
+ void fadeInLong();
+ void fadeInBreakout();
+ void fadeInDefaultLength(const byte *surface);
+ void fadeInShort();
+ void fadeOutDefaultLength(const byte *surface);
+ void fadeOutBreakout();
+ void fadeOutLong();
+ void fadeOutShort();
+ void copyWinscanVbe3(const byte *srcData, byte *destSurface);
+ void copyWinscanVbe(const byte *srcP, byte *destP);
+ void copyVideoVbe16(const byte *srcData);
+ void copyVideoVbe16a(const byte *srcData);
+ void copySurfaceRect(const byte *srcSurface, byte *destSurface, int xs, int ys, int width, int height);
+ void restoreSurfaceRect(byte *destSurface, const byte *src, int xp, int yp, int width, int height);
+ void displayFont(byte *surface, const byte *spriteData, int xp, int yp, int characterIndex, int color);
+ void drawHorizontalLine(byte *surface, int xp, int yp, uint16 width, byte col);
+ void drawVerticalLine(byte *surface, int xp, int yp, int height, byte col);
+ void initColorTable(int minIndex, int maxIndex, byte *palette);
+ void setGraphicalMode(int width, int height);
+ void setPaletteVGA256(const byte *palette);
+ void setPaletteVGA256WithRefresh(const byte *palette, const byte *surface);
+ void scrollScreen(int amount);
+ int zoomIn(int v, int percentage);
+ int zoomOut(int v, int percentage);
+ void initScreen(const Common::String &file, int mode, bool initializeScreen);
+ void displayAllBob();
+ void endDisplayBob();
+ void updateScreen();
+ void reduceScreenPart(const byte *srcSruface, byte *destSurface, int xp, int yp, int width, int height, int zoom);
+ void setScreenWidth(int pitch);
+
+ void setColorPercentage(int palIndex, int r, int g, int b);
+ void setColorPercentage2(int palIndex, int r, int g, int b);
+ void fastDisplay(const byte *spriteData, int xp, int yp, int spriteIndex, bool addSegment = true);
+ void fastDisplay2(const byte *objectData, int xp, int yp, int idx, bool addSegment = true);
+ void drawCompressedSprite(byte *surface, const byte *srcData, int xp300, int yp300, int frameIndex, int zoom1, int zoom2, bool flipFl);
+ void copyRect(const byte *srcSurface, int x1, int y1, uint16 width, int height, byte *destSurface, int destX, int destY);
+ void drawVesaSprite(byte *surface, const byte *spriteData, int xp, int yp, int spriteIndex);
+ void display8BitRect(const byte *surface, int xs, int ys, int width, int height, int destX, int destY);
+ void fillSurface(byte *surface, byte *col, int size);
+ void displayScreen(bool initPalette);
+ void backupScreen();
+ void restoreScreen();
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_GRAPHICS_H */
diff --git a/engines/hopkins/hopkins.cpp b/engines/hopkins/hopkins.cpp
new file mode 100644
index 0000000000..bf9509c0d4
--- /dev/null
+++ b/engines/hopkins/hopkins.cpp
@@ -0,0 +1,2861 @@
+/* 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/hopkins.h"
+#include "hopkins/graphics.h"
+#include "hopkins/files.h"
+#include "hopkins/saveload.h"
+#include "hopkins/sound.h"
+#include "hopkins/talk.h"
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/events.h"
+#include "common/file.h"
+
+namespace Hopkins {
+
+HopkinsEngine *g_vm;
+
+HopkinsEngine::HopkinsEngine(OSystem *syst, const HopkinsGameDescription *gameDesc) : Engine(syst),
+ _gameDescription(gameDesc), _randomSource("Hopkins") {
+ g_vm = this;
+ _animMan = new AnimationManager(this);
+ _computer = new ComputerManager(this);
+ _dialog = new DialogsManager(this);
+ _debug = new Debugger(this);
+ _events = new EventsManager(this);
+ _fileIO = new FileManager(this);
+ _fontMan = new FontManager(this);
+ _globals = new Globals(this);
+ _graphicsMan = new GraphicsManager(this);
+ _linesMan = new LinesManager(this);
+ _menuMan = new MenuManager(this);
+ _objectsMan = new ObjectsManager(this);
+ _saveLoad = new SaveLoadManager(this);
+ _script = new ScriptManager(this);
+ _soundMan = new SoundManager(this);
+ _talkMan = new TalkManager(this);
+
+ _startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+}
+
+HopkinsEngine::~HopkinsEngine() {
+ delete _talkMan;
+ delete _soundMan;
+ delete _script;
+ delete _saveLoad;
+ delete _objectsMan;
+ delete _menuMan;
+ delete _linesMan;
+ delete _graphicsMan;
+ delete _globals;
+ delete _fontMan;
+ delete _fileIO;
+ delete _events;
+ delete _debug;
+ delete _dialog;
+ delete _computer;
+ delete _animMan;
+}
+
+Common::String HopkinsEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+/**
+ * Returns true if it is currently okay to restore a game
+ */
+bool HopkinsEngine::canLoadGameStateCurrently() {
+ return !_globals->_exitId && !_globals->_cityMapEnabledFl && _events->_mouseFl;
+}
+
+/**
+ * Returns true if it is currently okay to save the game
+ */
+bool HopkinsEngine::canSaveGameStateCurrently() {
+ return !_globals->_exitId && !_globals->_cityMapEnabledFl && _events->_mouseFl;
+}
+
+/**
+ * Load the savegame at the specified slot index
+ */
+Common::Error HopkinsEngine::loadGameState(int slot) {
+ return _saveLoad->loadGame(slot);
+}
+
+/**
+ * Save the game to the given slot index, and with the given name
+ */
+Common::Error HopkinsEngine::saveGameState(int slot, const Common::String &desc) {
+ return _saveLoad->saveGame(slot, desc);
+}
+
+Common::Error HopkinsEngine::run() {
+ _saveLoad->initSaves();
+
+ _globals->setConfig();
+ _fileIO->initCensorship();
+ initializeSystem();
+
+ if (!getIsDemo())
+ runFull();
+ else if (getPlatform() == Common::kPlatformLinux)
+ runLinuxDemo();
+ else if (getPlatform() == Common::kPlatformWindows)
+ runWin95Demo();
+ else {
+ warning("Unhandled version, switching to Linux demo. Please report this version to ScummVM developers");
+ runLinuxDemo();
+ }
+
+ return Common::kNoError;
+}
+
+bool HopkinsEngine::runWin95Demo() {
+ _objectsMan->loadObjects();
+ _objectsMan->changeObject(14);
+ _objectsMan->addObject(14);
+ _objectsMan->_helicopterFl = false;
+
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+
+ if (_startGameSlot == -1) {
+ _graphicsMan->loadImage("H2");
+ _graphicsMan->fadeInLong();
+
+ if (!_events->_escKeyFl)
+ playIntro();
+ }
+
+ _events->_rateCounter = 0;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _globals->_speed = 1;
+
+ for (int i = 1; i < 50; i++) {
+ _graphicsMan->copySurface(_graphicsMan->_backBuffer, 0, 0, 640, 440, _graphicsMan->_frontBuffer, 0, 0);
+ _events->refreshScreenAndEvents();
+ }
+
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ if (_events->_rateCounter > 475)
+ _globals->_speed = 2;
+ if (_events->_rateCounter > 700)
+ _globals->_speed = 3;
+
+ if (_startGameSlot == -1) {
+ _graphicsMan->fadeOutLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR");
+ }
+
+ _globals->_characterType = 0;
+ _objectsMan->_mapCarPosX = _objectsMan->_mapCarPosY = 0;
+ memset(_globals->_saveData, 0, 2000);
+ _globals->_exitId = 0;
+
+ if (_startGameSlot != -1)
+ _saveLoad->loadGame(_startGameSlot);
+
+ if (getLanguage() != Common::PL_POL)
+ if (!displayAdultDisclaimer())
+ return Common::kNoError;
+
+ for (;;) {
+ if (_globals->_exitId == 300)
+ _globals->_exitId = 0;
+
+ if (!_globals->_exitId) {
+ _globals->_exitId = _menuMan->menu();
+ if (_globals->_exitId == -1) {
+ _globals->_characterSpriteBuf = _globals->freeMemory(_globals->_characterSpriteBuf);
+ restoreSystem();
+ return false;
+ }
+ }
+
+ if (shouldQuit())
+ return false;
+
+ _globals->_curRoomNum = _globals->_exitId;
+
+ switch (_globals->_exitId) {
+ case 1:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM01", "IM01", "ANIM01", "IM01", 2, true);
+ break;
+
+ case 3:
+ if (!_globals->_saveData->_data[svBankAttackAnimPlayedFl]) {
+ _soundMan->playSound(3);
+ if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS)
+ _graphicsMan->loadImage("fond");
+ else {
+ if (_globals->_language == LANG_FR)
+ _graphicsMan->loadImage("fondfr");
+ else if (_globals->_language == LANG_EN)
+ _graphicsMan->loadImage("fondan");
+ else if (_globals->_language == LANG_SP)
+ _graphicsMan->loadImage("fondes");
+ }
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->_specialSoundNum = 2;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ if (!_globals->_censorshipFl)
+ _animMan->playAnim("BANQUE.ANM", 200, 28, 200);
+ else
+ _animMan->playAnim("BANKUK.ANM", 200, 28, 200);
+ _soundMan->_specialSoundNum = 0;
+ _soundMan->removeSample(1);
+ _soundMan->removeSample(2);
+ _soundMan->removeSample(3);
+ _soundMan->removeSample(4);
+ _graphicsMan->fadeOutLong();
+ _globals->_saveData->_data[svBankAttackAnimPlayedFl] = 1;
+ }
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM03", "IM03", "ANIM03", "IM03", 2, false);
+ break;
+
+ case 4:
+ _globals->_disableInventFl = true;
+ _objectsMan->handleCityMap();
+ _globals->_disableInventFl = false;
+ break;
+
+ case 5:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 455;
+
+ if (_globals->_saveData->_data[svFreedHostageFl]) {
+ if (_globals->_saveData->_data[svFreedHostageFl] == 1)
+ _objectsMan->sceneControl2("IM05", "IM05A", "ANIM05B", "IM05", 3, false);
+ } else {
+ _objectsMan->sceneControl2("IM05", "IM05", "ANIM05", "IM05", 3, false);
+ }
+ break;
+
+ case 6:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 460;
+ _objectsMan->sceneControl2("IM06", "IM06", "ANIM06", "IM06", 2, true);
+ break;
+
+ case 7:
+ if (_globals->_saveData->_data[svBombBoxOpenedFl])
+ _objectsMan->sceneControl("BOMBEB", "BOMBE", "BOMBE", "BOMBE", 2, true);
+ else
+ _objectsMan->sceneControl("BOMBEA", "BOMBE", "BOMBE", "BOMBE", 2, true);
+ break;
+
+ case 8:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM08", "IM08", "ANIM08", "IM08", 2, true);
+ break;
+
+ case 9:
+ _globals->_characterMaxPosY = 440;
+ _linesMan->setMaxLineIdx(20);
+ if (_globals->_saveData->_data[svBombDisarmedFl])
+ _objectsMan->sceneControl2("IM09", "IM09", "ANIM09", "IM09", 10, true);
+ else
+ bombExplosion();
+ break;
+
+ case 10:
+ _objectsMan->sceneControl("IM10", "IM10", "ANIM10", "IM10", 9, false);
+ break;
+
+ case 11:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM11", "IM11", "ANIM11", "IM11", 2, false);
+ break;
+
+ case 12:
+ _globals->_characterMaxPosY = 450;
+ _linesMan->setMaxLineIdx(20);
+ if (_globals->_saveData->_data[svBombDisarmedFl]) {
+ if (_globals->_language == LANG_FR)
+ _graphicsMan->loadImage("ENDFR");
+ else
+ _graphicsMan->loadImage("ENDUK");
+ _graphicsMan->fadeInLong();
+ _events->mouseOn();
+ do
+ _events->refreshScreenAndEvents();
+ while (_events->getMouseButton() != 1);
+ _graphicsMan->fadeOutLong();
+ restoreSystem();
+ } else
+ bombExplosion();
+ break;
+
+ case 13:
+ case 14:
+ case 15:
+ handleNotAvailable(11);
+ break;
+
+ case 16:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 33:
+ case 32:
+ case 34:
+ handleNotAvailable(4);
+ break;
+
+ case 17:
+ handleNotAvailable(1);
+ break;
+
+ case 111:
+ _objectsMan->sceneControl("IM111", "IM111", "ANIM111", "IM111", 10, false);
+ break;
+
+ case 112:
+ _objectsMan->sceneControl("IM112", "IM112", "ANIM112", "IM112", 10, false);
+ break;
+
+ case 113:
+ _globals->_exitId = 0;
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_screenId;
+ _globals->_screenId = 113;
+ _globals->_saveData->_data[svLastScreenId] = _globals->_screenId;
+ _computer->showComputer(COMPUTER_HOPKINS);
+ _graphicsMan->clearScreen();
+ _graphicsMan->updateScreen();
+ memset(_graphicsMan->_frontBuffer, 0, 307200);
+ memset(_graphicsMan->_backBuffer, 0, 307200);
+ _graphicsMan->clearPalette();
+ _graphicsMan->resetDirtyRects();
+ break;
+
+ case 114:
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_screenId;
+ _globals->_screenId = 114;
+ _globals->_saveData->_data[svLastScreenId] = _globals->_screenId;
+ _globals->_exitId = 0;
+ _computer->showComputer(COMPUTER_SAMANTHA);
+ _graphicsMan->clearScreen();
+ break;
+
+ case 115:
+ _globals->_exitId = 0;
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_screenId;
+ _globals->_screenId = 115;
+ _globals->_saveData->_data[svLastScreenId] = _globals->_screenId;
+ _computer->showComputer(COMPUTER_PUBLIC);
+ _graphicsMan->clearScreen();
+ break;
+
+ case 150:
+ _soundMan->playSound(28);
+ _globals->_eventMode = EVENTMODE_ALT; // CHECKME!
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _animMan->playAnim("JOUR1A.anm", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+
+ case 151:
+ _soundMan->playSound(28);
+ _globals->_eventMode = EVENTMODE_ALT; // CHECKME!
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _graphicsMan->loadImage("njour3a");
+ _graphicsMan->fadeInLong();
+ _events->delay(5000);
+ _graphicsMan->fadeOutLong();
+ _globals->_exitId = 300;
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ break;
+
+ case 152:
+ _soundMan->playSound(28);
+ _globals->_eventMode = EVENTMODE_ALT; // CHECKME!
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _animMan->playAnim("JOUR4A.anm", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+ }
+ }
+ return true;
+}
+
+bool HopkinsEngine::runLinuxDemo() {
+ _objectsMan->loadObjects();
+ _objectsMan->changeObject(14);
+ _objectsMan->addObject(14);
+ _objectsMan->_helicopterFl = false;
+
+ _events->mouseOff();
+
+ _graphicsMan->clearScreen();
+
+ if (_startGameSlot == -1) {
+ _graphicsMan->loadImage("LINUX");
+ _graphicsMan->fadeInLong();
+ _events->delay(1500);
+ _graphicsMan->fadeOutLong();
+
+ _graphicsMan->loadImage("H2");
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+
+ if (!_events->_escKeyFl)
+ playIntro();
+ }
+
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR");
+ _globals->_characterType = 0;
+ _objectsMan->_mapCarPosX = _objectsMan->_mapCarPosY = 0;
+ memset(_globals->_saveData, 0, 2000);
+ _globals->_exitId = 0;
+
+ if (_startGameSlot != -1)
+ _saveLoad->loadGame(_startGameSlot);
+
+ for (;;) {
+ if (_globals->_exitId == 300)
+ _globals->_exitId = 0;
+
+ if (!_globals->_exitId) {
+ _globals->_exitId = _menuMan->menu();
+ if (_globals->_exitId == -1) {
+ if (!shouldQuit())
+ endLinuxDemo();
+ _globals->_characterSpriteBuf = _globals->freeMemory(_globals->_characterSpriteBuf);
+ restoreSystem();
+ }
+ }
+
+ if (shouldQuit())
+ return false;
+
+ _globals->_curRoomNum = _globals->_exitId;
+
+ switch (_globals->_exitId) {
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 22:
+ case 23:
+ case 24:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 34:
+ case 38:
+ displayNotAvailable();
+ break;
+
+ case 1:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM01", "IM01", "ANIM01", "IM01", 1, true);
+ break;
+
+ case 3:
+ if (!_globals->_saveData->_data[svBankAttackAnimPlayedFl]) {
+ _soundMan->playSound(3);
+ if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS)
+ _graphicsMan->loadImage("fond");
+ else {
+ if (_globals->_language == LANG_FR)
+ _graphicsMan->loadImage("fondfr");
+ else if (_globals->_language == LANG_EN)
+ _graphicsMan->loadImage("fondan");
+ else if (_globals->_language == LANG_SP)
+ _graphicsMan->loadImage("fondes");
+ }
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->_specialSoundNum = 2;
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _graphicsMan->_fadingFl = true;
+
+ if (!_globals->_censorshipFl)
+ _animMan->playAnim("BANQUE.ANM", 200, 28, 200);
+ else
+ _animMan->playAnim("BANKUK.ANM", 200, 28, 200);
+ _soundMan->_specialSoundNum = 0;
+ _soundMan->removeSample(1);
+ _soundMan->removeSample(2);
+ _soundMan->removeSample(3);
+ _soundMan->removeSample(4);
+ _globals->_saveData->_data[svBankAttackAnimPlayedFl] = 1;
+ }
+
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM03", "IM03", "ANIM03", "IM03", 2, false);
+ break;
+
+ case 4:
+ _globals->_disableInventFl = true;
+ _objectsMan->handleCityMap();
+ _globals->_disableInventFl = false;
+ break;
+
+ case 5:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 455;
+ if (_globals->_saveData->_data[svFreedHostageFl] == 1)
+ _objectsMan->sceneControl2("IM05", "IM05A", "ANIM05B", "IM05", 3, false);
+ else
+ _objectsMan->sceneControl2("IM05", "IM05", "ANIM05", "IM05", 3, false);
+ break;
+
+ case 6:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 460;
+ _objectsMan->sceneControl2("IM06", "IM06", "ANIM06", "IM06", 2, true);
+ break;
+
+ case 7:
+ if (_globals->_saveData->_data[svBombBoxOpenedFl])
+ _objectsMan->sceneControl("BOMBEB", "BOMBE", "BOMBE", "BOMBE", 2, true);
+ else
+ _objectsMan->sceneControl("BOMBEA", "BOMBE", "BOMBE", "BOMBE", 2, true);
+ break;
+
+ case 8:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM08", "IM08", "ANIM08", "IM08", 2, true);
+ break;
+
+ case 9:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 440;
+
+ if (!_globals->_saveData->_data[svBombDisarmedFl])
+ bombExplosion();
+ else
+ _objectsMan->sceneControl2("IM09", "IM09", "ANIM09", "IM09", 10, true);
+ break;
+
+ case 10:
+ _objectsMan->sceneControl("IM10", "IM10", "ANIM10", "IM10", 9, false);
+ break;
+
+ case 11:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM11", "IM11", "ANIM11", "IM11", 2, false);
+ break;
+
+ case 12:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 450;
+ if (_globals->_saveData->_data[svBombDisarmedFl])
+ _objectsMan->sceneControl2("IM12", "IM12", "ANIM12", "IM12", 1, false);
+ else
+ bombExplosion();
+ break;
+
+ case 13:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM13", "IM13", "ANIM13", "IM13", 1, true);
+ break;
+
+ case 14:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM14", "IM14", "ANIM14", "IM14", 1, true);
+ break;
+
+ case 15:
+ _objectsMan->sceneControl("IM15", "IM15", "ANIM15", "IM15", 29, false);
+ break;
+
+ case 16:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+
+ if (_globals->_saveData->_data[svForestAvailableFl] == 1) {
+ _objectsMan->sceneControl2("IM16", "IM16A", "ANIM16", "IM16", 7, true);
+ } else if (!_globals->_saveData->_data[svForestAvailableFl]) {
+ _objectsMan->sceneControl2("IM16", "IM16", "ANIM16", "IM16", 7, true);
+ }
+ break;
+
+ case 25:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM25", "IM25", "ANIM25", "IM25", 30, true);
+ break;
+
+ case 26:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM26", "IM26", "ANIM26", "IM26", 30, true);
+
+ case 33:
+ _objectsMan->sceneControl("IM33", "IM33", "ANIM33", "IM33", 8, false);
+ break;
+
+ case 35:
+ displayEndDemo();
+ break;
+
+ case 111:
+ _objectsMan->sceneControl("IM111", "IM111", "ANIM111", "IM111", 10, false);
+ break;
+
+ case 112:
+ _objectsMan->sceneControl("IM112", "IM112", "ANIM112", "IM112", 10, false);
+ break;
+
+ case 113:
+ _globals->_exitId = 0;
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_screenId;
+ _globals->_screenId = 113;
+ _globals->_saveData->_data[svLastScreenId] = 113;
+ _computer->showComputer(COMPUTER_HOPKINS);
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->updateScreen();
+ memset(_graphicsMan->_frontBuffer, 0, 307200);
+ memset(_graphicsMan->_backBuffer, 0, 307200);
+ _graphicsMan->clearPalette();
+ _graphicsMan->resetDirtyRects();
+ break;
+
+ case 114:
+ _globals->_exitId = 0;
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_screenId;
+ _globals->_screenId = 114;
+ _globals->_saveData->_data[svLastScreenId] = 114;
+ _computer->showComputer(COMPUTER_SAMANTHA);
+ _graphicsMan->clearScreen();
+ break;
+
+ case 115:
+ _globals->_exitId = 0;
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_screenId;
+ _globals->_screenId = 115;
+ _globals->_saveData->_data[svLastScreenId] = 115;
+ _computer->showComputer(COMPUTER_PUBLIC);
+ _graphicsMan->clearScreen();
+ break;
+
+ case 150:
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR1A.anm", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+
+ case 151:
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR3A.anm", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+
+ case 152:
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR4A.anm", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+ }
+ }
+ return true;
+}
+
+bool HopkinsEngine::runFull() {
+ if (_startGameSlot == -1 && getPlatform() == Common::kPlatformLinux)
+ _soundMan->playSound(16);
+
+ _objectsMan->loadObjects();
+ _objectsMan->changeObject(14);
+ _objectsMan->addObject(14);
+
+ if (getPlatform() == Common::kPlatformLinux) {
+ _objectsMan->_helicopterFl = false;
+ _events->mouseOff();
+ // No code has been added to display the version as it's wrong
+ // in my copy: it mentions a Win95 version v4 using DirectDraw (Strangerke)
+ } else if (getPlatform() == Common::kPlatformWindows) {
+ _objectsMan->_helicopterFl = false;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ // This code displays the game version.
+ // It wasn't present in the original and could be put in the debugger
+ // It has been added there for debug purposes
+ if (_startGameSlot == -1) {
+ _graphicsMan->loadImage("VERSW");
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ }
+ _graphicsMan->clearVesaScreen();
+ } else {
+ // This piece of code, though named "display_version" in the original,
+ // displays a "loading please wait" screen.
+ if (_startGameSlot == -1) {
+ _graphicsMan->loadImage("VERSW");
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ }
+ _graphicsMan->clearVesaScreen();
+
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ }
+
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+
+ if (_startGameSlot == -1) {
+ if (getPlatform() == Common::kPlatformLinux) {
+ _graphicsMan->loadImage("H2");
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ _globals->_speed = 2;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("MP.ANM", 10, 16, 200);
+ } else {
+ _animMan->playAnim("MP.ANM", 10, 16, 200);
+ _graphicsMan->fadeOutLong();
+ }
+ }
+
+ if (!_events->_escKeyFl && _startGameSlot == -1) {
+ playIntro();
+ if (shouldQuit())
+ return false;
+ }
+ if (getPlatform() != Common::kPlatformLinux && _startGameSlot == -1) {
+ _graphicsMan->fadeOutShort();
+ _graphicsMan->loadImage("H2");
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ }
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR");
+ _globals->_characterType = 0;
+ _objectsMan->_mapCarPosX = _objectsMan->_mapCarPosY = 0;
+ memset(_globals->_saveData, 0, 2000);
+
+ _globals->_exitId = 0;
+
+ if (_startGameSlot != -1)
+ _saveLoad->loadGame(_startGameSlot);
+
+ for (;;) {
+ if (_globals->_exitId == 300)
+ _globals->_exitId = 0;
+ if (!_globals->_exitId) {
+ _globals->_exitId = _menuMan->menu();
+ if (_globals->_exitId == -1) {
+ _globals->_characterSpriteBuf = _globals->freeMemory(_globals->_characterSpriteBuf);
+ restoreSystem();
+ return false;
+ }
+ }
+
+ if (shouldQuit())
+ return false;
+
+ _globals->_curRoomNum = _globals->_exitId;
+
+ switch (_globals->_exitId) {
+ case 1:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM01", "IM01", "ANIM01", "IM01", 1, true);
+ break;
+
+ case 3:
+ if (!_globals->_saveData->_data[svBankAttackAnimPlayedFl]) {
+ // Play the bank attack animation
+ _soundMan->playSound(3);
+ if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS)
+ _graphicsMan->loadImage("fond");
+ else {
+ if (_globals->_language == LANG_FR)
+ _graphicsMan->loadImage("fondfr");
+ else if (_globals->_language == LANG_EN)
+ _graphicsMan->loadImage("fondan");
+ else if (_globals->_language == LANG_SP)
+ _graphicsMan->loadImage("fondes");
+ }
+ _graphicsMan->fadeInLong();
+ _events->delay(500);
+ _graphicsMan->fadeOutLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->_specialSoundNum = 2;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) {
+ if (getPlatform() == Common::kPlatformLinux)
+ _graphicsMan->_fadingFl = true;
+
+ if (!_globals->_censorshipFl)
+ _animMan->playAnim("BANQUE.ANM", 200, 28, 200);
+ else
+ _animMan->playAnim("BANKUK.ANM", 200, 28, 200);
+ } else {
+ _animMan->playAnim("BANQUE.ANM", 200, 28, 200);
+ }
+
+ _soundMan->_specialSoundNum = 0;
+ _soundMan->removeSample(1);
+ _soundMan->removeSample(2);
+ _soundMan->removeSample(3);
+ _soundMan->removeSample(4);
+
+ if (getPlatform() != Common::kPlatformLinux) {
+ // Copy the end of the animation into the secondary buffer and fade out the screen
+ Common::fill(_graphicsMan->_frontBuffer, _graphicsMan->_frontBuffer +
+ SCREEN_WIDTH * 2 * SCREEN_HEIGHT, 0);
+ _graphicsMan->fadeOutLong();
+ }
+
+ _globals->_saveData->_data[svBankAttackAnimPlayedFl] = 1;
+ }
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM03", "IM03", "ANIM03", "IM03", 2, false);
+ break;
+
+ case 4:
+ _globals->_disableInventFl = true;
+ _objectsMan->handleCityMap();
+ _globals->_disableInventFl = false;
+ break;
+
+ case 5:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 455;
+ if (_globals->_saveData->_data[svFreedHostageFl] == 1)
+ _objectsMan->sceneControl2("IM05", "IM05A", "ANIM05B", "IM05", 3, false);
+ else
+ _objectsMan->sceneControl2("IM05", "IM05", "ANIM05", "IM05", 3, false);
+ break;
+
+ case 6:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 460;
+ _objectsMan->sceneControl2("IM06", "IM06", "ANIM06", "IM06", 2, true);
+ break;
+
+ case 7:
+ if (_globals->_saveData->_data[svBombBoxOpenedFl])
+ _objectsMan->sceneControl("BOMBEB", "BOMBE", "BOMBE", "BOMBE", 2, true);
+ else
+ _objectsMan->sceneControl("BOMBEA", "BOMBE", "BOMBE", "BOMBE", 2, true);
+ break;
+
+ case 8:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM08", "IM08", "ANIM08", "IM08", 2, true);
+ break;
+
+ case 9:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 440;
+ if (_globals->_saveData->_data[svBombDisarmedFl])
+ _objectsMan->sceneControl2("IM09", "IM09", "ANIM09", "IM09", 10, true);
+ else
+ bombExplosion();
+ break;
+
+ case 10:
+ _objectsMan->sceneControl("IM10", "IM10", "ANIM10", "IM10", 9, false);
+ break;
+
+ case 11:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 450;
+ _objectsMan->sceneControl2("IM11", "IM11", "ANIM11", "IM11", 2, false);
+ break;
+
+ case 12:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 450;
+ if (_globals->_saveData->_data[svBombDisarmedFl])
+ _objectsMan->sceneControl2("IM12", "IM12", "ANIM12", "IM12", 1, false);
+ else
+ bombExplosion();
+ break;
+
+ case 13:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM13", "IM13", "ANIM13", "IM13", 1, true);
+ break;
+
+ case 14:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM14", "IM14", "ANIM14", "IM14", 1, true);
+ break;
+
+ case 15:
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows)
+ _objectsMan->sceneControl("IM15", "IM15", "ANIM15", "IM15", 29, false);
+ else
+ _objectsMan->sceneControl("IM15", "IM15", "ANIM15", "IM15", 18, false);
+ break;
+
+ case 16:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ if (_globals->_saveData->_data[svForestAvailableFl] == 1)
+ _objectsMan->sceneControl2("IM16", "IM16A", "ANIM16", "IM16", 7, true);
+ else
+ _objectsMan->sceneControl2("IM16", "IM16", "ANIM16", "IM16", 7, true);
+ break;
+
+ case 17:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 440;
+ if (_globals->_saveData->_data[svHutBurningFl] == 1)
+ _objectsMan->sceneControl2("IM17", "IM17A", "ANIM17", "IM17", 11, true);
+ else if (!_globals->_saveData->_data[svHutBurningFl])
+ _objectsMan->sceneControl2("IM17", "IM17", "ANIM17", "IM17", 11, true);
+ if (_globals->_exitId == 18) {
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _soundMan->stopSound();
+ if (getPlatform() == Common::kPlatformLinux) {
+ _soundMan->playSound(29);
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("PURG1A.ANM", 12, 18, 50);
+ } else if (getPlatform() == Common::kPlatformWindows) {
+ _soundMan->playSound(29);
+ _animMan->playAnim("PURG1A.ANM", 12, 18, 50);
+ _graphicsMan->fadeOutShort();
+ } else {
+ _soundMan->playSound(6);
+ _animMan->playAnim("PURG1A.ANM", 12, 18, 50);
+ _graphicsMan->fadeOutShort();
+ }
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ }
+ break;
+
+ case 18:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows)
+ _objectsMan->sceneControl2("IM18", "IM18", "ANIM18", "IM18", 29, false);
+ else
+ _objectsMan->sceneControl2("IM18", "IM18", "ANIM18", "IM18", 6, false);
+ break;
+
+ case 19:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 440;
+ if (_globals->_saveData->_data[svHeavenGuardGoneFl])
+ _objectsMan->sceneControl2("IM19", "IM19A", "ANIM19", "IM19", 6, true);
+ else
+ _objectsMan->sceneControl2("IM19", "IM19", "ANIM19", "IM19", 6, true);
+ break;
+
+ case 20:
+ _linesMan->setMaxLineIdx(10);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM20", "IM20", "ANIM20", "IM20", 6, true);
+ if (_globals->_exitId == 17) {
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->stopSound();
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _soundMan->playSound(6);
+ if (getPlatform() == Common::kPlatformLinux)
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("PURG2A.ANM", 12, 18, 50);
+ if (getPlatform() != Common::kPlatformLinux)
+ _graphicsMan->fadeOutShort();
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ }
+ break;
+
+ case 22:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM22", "IM22", "ANIM22", "IM22", 6, true);
+ break;
+
+ case 23:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM23", "IM23", "ANIM23", "IM23", 6, true);
+ break;
+
+ case 24:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ if (_globals->_saveData->_data[svCinemaDogGoneFl] == 1)
+ _objectsMan->sceneControl2("IM24", "IM24A", "ANIM24", "IM24", 1, true);
+ else
+ _objectsMan->sceneControl2("IM24", "IM24", "ANIM24", "IM24", 1, true);
+ break;
+
+ case 25:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 445;
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows)
+ _objectsMan->sceneControl2("IM25", "IM25", "ANIM25", "IM25", 30, true);
+ else
+ _objectsMan->sceneControl2("IM25", "IM25", "ANIM25", "IM25", 8, true);
+ break;
+
+ case 26:
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 435;
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows)
+ _objectsMan->sceneControl2("IM26", "IM26", "ANIM26", "IM26", 30, true);
+ else
+ _objectsMan->sceneControl2("IM26", "IM26", "ANIM26", "IM26", 8, true);
+ break;
+
+ case 27:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 440;
+ if (_globals->_saveData->_data[svPoolDogGoneFl] == 1)
+ _objectsMan->sceneControl2("IM27", "IM27A", "ANIM27", "IM27", 27, true);
+ else
+ _objectsMan->sceneControl2("IM27", "IM27", "ANIM27", "IM27", 27, true);
+ break;
+
+ case 28:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 450;
+ if (_globals->_saveData->_data[svCinemaCurtainCond1] != 1 || _globals->_saveData->_data[svCinemaCurtainCond2] != 1)
+ _objectsMan->sceneControl2("IM28", "IM28", "ANIM28", "IM28", 1, false);
+ else
+ _objectsMan->sceneControl2("IM28A", "IM28", "ANIM28", "IM28", 1, false);
+ break;
+
+ case 29:
+ _linesMan->setMaxLineIdx(50);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM29", "IM29", "ANIM29", "IM29", 1, true);
+ break;
+
+ case 30:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM30", "IM30", "ANIM30", "IM30", 24, false);
+ break;
+
+ case 31:
+ _objectsMan->sceneControl("IM31", "IM31", "ANIM31", "IM31", 10, true);
+ break;
+
+ case 32:
+ _linesMan->setMaxLineIdx(20);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM32", "IM32", "ANIM32", "IM32", 2, true);
+ break;
+
+ case 33:
+ _objectsMan->sceneControl("IM33", "IM33", "ANIM33", "IM33", 8, false);
+ break;
+
+ case 34:
+ _objectsMan->sceneControl("IM34", "IM34", "ANIM34", "IM34", 2, false);
+ break;
+
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41: {
+ _linesMan->setMaxLineIdx(40);
+ _globals->_characterMaxPosY = 435;
+ _globals->_disableInventFl = false;
+ _objectsMan->_forestFl = true;
+ Common::String im = Common::String::format("IM%d", _globals->_exitId);
+ _soundMan->playSound(13);
+ if (_objectsMan->_forestSprite == NULL) {
+ _objectsMan->_forestSprite = _objectsMan->loadSprite("HOPDEG.SPR");
+ _soundMan->loadSample(1, "SOUND41.WAV");
+ }
+ _objectsMan->sceneControl2(im, im, "BANDIT", im, 13, false);
+ if (_globals->_exitId < 35 || _globals->_exitId > 49) {
+ _objectsMan->_forestSprite = _globals->freeMemory(_objectsMan->_forestSprite);
+ _objectsMan->_forestFl = false;
+ _soundMan->removeSample(1);
+ }
+ break;
+ }
+
+ case 50:
+ playPlaneCutscene();
+ _globals->_exitId = 51;
+ break;
+
+ case 51:
+ _linesMan->setMaxLineIdx(10);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM51", "IM51", "ANIM51", "IM51", 14, true);
+ break;
+
+ case 52:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM52", "IM52", "ANIM52", "IM52", 14, true);
+ break;
+
+ case 54:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM54", "IM54", "ANIM54", "IM54", 14, true);
+ break;
+
+ case 55:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 460;
+ _objectsMan->sceneControl2("IM55", "IM55", "ANIM55", "IM55", 14, false);
+ break;
+
+ case 56:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM56", "IM56", "ANIM56", "IM56", 14, false);
+ break;
+
+ case 57:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM57", "IM57", "ANIM57", "IM57", 14, true);
+ break;
+
+ case 58:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM58", "IM58", "ANIM58", "IM58", 14, false);
+ break;
+
+ case 59:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM59", "IM59", "ANIM59", "IM59", 21, false);
+ break;
+
+ case 60:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM60", "IM60", "ANIM60", "IM60", 21, false);
+ break;
+
+ case 61:
+ if (_globals->_saveData->_data[svBaseElevatorCond1] == 1 && !_globals->_saveData->_data[svBaseFireFl])
+ handleConflagration();
+ _objectsMan->sceneControl("IM61", "IM61", "ANIM61", "IM61", 21, false);
+ break;
+
+ case 62:
+ _linesMan->setMaxLineIdx(8);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM62", "IM62", NULL, "IM62", 21, false);
+ break;
+
+ case 63:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM63", "IM63", "ANIM63", "IM63", 21, false);
+ break;
+
+ case 64:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM64", "IM64", "ANIM64", "IM64", 21, true);
+ break;
+
+ case 65:
+ _linesMan->setMaxLineIdx(30);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM65", "IM65", "ANIM65", "IM65", 21, false);
+ break;
+
+ case 66:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM66", "IM66", "ANIM66", "IM66", 21, false);
+ break;
+
+ case 67:
+ _linesMan->setMaxLineIdx(8);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM67", "IM67", NULL, "IM67", 21, false);
+ break;
+
+ case 68:
+ _linesMan->setMaxLineIdx(8);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM68", "IM68", "ANIM68", "IM68", 21, true);
+ break;
+
+ case 69:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM69", "IM69", "ANIM69", "IM69", 21, false);
+ break;
+
+ case 70:
+ _linesMan->setMaxLineIdx(8);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM70", "IM70", NULL, "IM70", 21, false);
+ break;
+
+ case 71:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 445;
+ _objectsMan->sceneControl2("IM71", "IM71", "ANIM71", "IM71", 21, false);
+ break;
+
+ case 73:
+ _linesMan->setMaxLineIdx(15);
+ _globals->_characterMaxPosY = 445;
+ if (_globals->_saveData->_data[svSecondElevatorAvailableFl] == 1)
+ _objectsMan->sceneControl2("IM73", "IM73A", "ANIM73", "IM73", 21, true);
+ else
+ _objectsMan->sceneControl2("IM73", "IM73", "ANIM73", "IM73", 21, true);
+ break;
+
+ case 75:
+ playSubmarineCutscene();
+ break;
+
+ case 77:
+ handleOceanMaze(77, "OCEAN01", DIR_RIGHT, 0, 84, 0, 0, 25);
+ break;
+
+ case 78:
+ handleOceanMaze(78, "OCEAN02", DIR_UP, 0, 91, 84, 0, 25);
+ break;
+
+ case 79:
+ handleOceanMaze(79, "OCEAN03", DIR_LEFT, 87, 0, 0, 83, 25);
+ break;
+
+ case 80:
+ handleOceanMaze(80, "OCEAN04", DIR_UP, 86, 88, 0, 81, 25);
+ break;
+
+ case 81:
+ handleOceanMaze(81, "OCEAN05", DIR_UP, 91, 82, 80, 85, 25);
+ break;
+
+ case 82:
+ handleOceanMaze(82, "OCEAN06", DIR_LEFT, 81, 0, 88, 0, 25);
+ break;
+
+ case 83:
+ handleOceanMaze(83, "OCEAN07", DIR_UP, 89, 0, 79, 88, 25);
+ break;
+
+ case 84:
+ handleOceanMaze(84, "OCEAN08", DIR_UP, 77, 0, 0, 78, 25);
+ break;
+
+ case 85:
+ handleOceanMaze(85, "OCEAN09", DIR_UP, 0, 0, 81, 0, 25);
+ break;
+
+ case 86:
+ handleOceanMaze(86, "OCEAN10", DIR_UP, 0, 80, 0, 91, 25);
+ break;
+
+ case 87:
+ handleOceanMaze(87, "OCEAN11", DIR_RIGHT, 0, 79, 90, 0, 25);
+ break;
+
+ case 88:
+ handleOceanMaze(88, "OCEAN12", DIR_UP, 80, 0, 83, 82, 25);
+ break;
+
+ case 89:
+ handleOceanMaze(89, "OCEAN13", DIR_RIGHT, 0, 83, 0, 0, 25);
+ break;
+
+ case 90:
+ playUnderwaterBaseCutscene();
+ break;
+
+ case 91:
+ handleOceanMaze(91, "OCEAN15", DIR_RIGHT, 78, 81, 86, 0, 25);
+ break;
+
+ case 93:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 445;
+ if (_globals->_saveData->_data[svEscapeLeftJailFl]) {
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows)
+ _objectsMan->sceneControl2("IM93", "IM93C", "ANIM93", "IM93", 29, true);
+ else
+ _objectsMan->sceneControl2("IM93", "IM93C", "ANIM93", "IM93", 26, true);
+ } else {
+ if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows)
+ _objectsMan->sceneControl2("IM93", "IM93", "ANIM93", "IM93", 29, true);
+ else
+ _objectsMan->sceneControl2("IM93", "IM93", "ANIM93", "IM93", 26, true);
+ }
+ break;
+
+ case 94:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 440;
+ _objectsMan->sceneControl2("IM94", "IM94", "ANIM94", "IM94", 19, true);
+ break;
+
+ case 95:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM95", "IM95", "ANIM95", "IM95", 19, false);
+ break;
+
+ case 96:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM96", "IM96", "ANIM96", "IM96", 19, false);
+ break;
+
+ case 97:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM97", "IM97", "ANIM97", "IM97", 19, false);
+ if (_globals->_exitId == 18) {
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->stopSound();
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _soundMan->playSound(6);
+ _animMan->playAnim("PURG1A.ANM", 12, 18, 50);
+ _graphicsMan->fadeOutShort();
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ }
+ break;
+
+ case 98:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM98", "IM98", "ANIM98", "IM98", 19, true);
+ break;
+
+ case 99:
+ _linesMan->setMaxLineIdx(5);
+ _globals->_characterMaxPosY = 435;
+ _objectsMan->sceneControl2("IM99", "IM99", "ANIM99", "IM99", 19, true);
+ break;
+
+ case 100:
+ playEnding();
+ break;
+
+ case 111:
+ _objectsMan->sceneControl("IM111", "IM111", "ANIM111", "IM111", 10, false);
+ break;
+
+ case 112:
+ _objectsMan->sceneControl("IM112", "IM112", "ANIM112", "IM112", 10, false);
+ break;
+
+ case 113:
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_screenId = 113;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_prevScreenId;
+ _globals->_saveData->_data[svLastScreenId] = _globals->_screenId;
+ _globals->_exitId = 0;
+ _computer->showComputer(COMPUTER_HOPKINS);
+ _graphicsMan->clearScreen();
+ _graphicsMan->updateScreen();
+ memset(_graphicsMan->_frontBuffer, 0, 307200);
+ memset(_graphicsMan->_backBuffer, 0, 307200);
+ _graphicsMan->clearPalette();
+ _graphicsMan->resetDirtyRects();
+ break;
+
+ case 114:
+ _globals->_exitId = 0;
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_screenId = 114;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_prevScreenId;
+ _globals->_saveData->_data[svLastScreenId] = _globals->_screenId;
+ _computer->showComputer(COMPUTER_SAMANTHA);
+ _graphicsMan->clearScreen();
+ break;
+
+ case 115:
+ _globals->_prevScreenId = _globals->_screenId;
+ _globals->_screenId = 115;
+ _globals->_saveData->_data[svLastPrevScreenId] = _globals->_prevScreenId;
+ _globals->_saveData->_data[svLastScreenId] = _globals->_screenId;
+ _globals->_exitId = 0;
+ _computer->showComputer(COMPUTER_PUBLIC);
+ _graphicsMan->clearScreen();
+ break;
+
+ case 150:
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ if (getPlatform() == Common::kPlatformLinux)
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR1A.ANM", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+
+ case 151:
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ if (getPlatform() == Common::kPlatformLinux)
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR3A.ANM", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+
+ case 152:
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ if (getPlatform() == Common::kPlatformLinux)
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR4A.ANM", 12, 12, 2000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ break;
+
+ case 194:
+ case 195:
+ case 196:
+ case 197:
+ case 198:
+ case 199:
+ _globals->_characterSpriteBuf = _globals->freeMemory(_globals->_characterSpriteBuf);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->stopSound();
+ _soundMan->playSound(23);
+ _globals->_exitId = handleBaseMap(); // Handles the base map (non-Windows)
+ //_globals->_exitId = WBASE(); // Handles the 3D Doom level (Windows)
+ _soundMan->stopSound();
+ _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR");
+ _globals->_characterType = 0;
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _graphicsMan->_lineNbr = SCREEN_WIDTH;
+ break;
+ }
+ }
+ _globals->_characterSpriteBuf = _globals->freeMemory(_globals->_characterSpriteBuf);
+ restoreSystem();
+ return true;
+}
+
+bool HopkinsEngine::shouldQuit() const {
+ return g_system->getEventManager()->shouldQuit();
+}
+
+int HopkinsEngine::getRandomNumber(int maxNumber) {
+ return _randomSource.getRandomNumber(maxNumber);
+}
+
+void HopkinsEngine::initializeSystem() {
+ // Set graphics mode
+ _graphicsMan->setGraphicalMode(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ // Synchronize the sound settings from ScummVM
+ _soundMan->syncSoundSettings();
+
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "SYSTEM");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "LINK");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "BUFFER");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "ANIM");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "ANM");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "BASE");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "MUSIC");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "SEQ");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "SAVE");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "SOUND");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "SVGA");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "VOICE");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "TSVGA");
+
+ _globals->clearAll();
+
+ _events->initMouseData();
+ _fontMan->initData();
+
+ _dialog->loadIcons();
+ _objectsMan->_headSprites = _fileIO->loadFile("TETE.SPR");
+
+ _events->setMouseOn();
+ _events->_mouseFl = false;
+
+ _globals->loadCharacterData();
+
+ _events->_mouseOffset.x = 0;
+ _events->_mouseOffset.y = 0;
+}
+
+/**
+ * Play the intro of the game
+ */
+void HopkinsEngine::playIntro() {
+ // Win95 EN demo doesn't include the intro
+ if ((getLanguage() == Common::EN_ANY) && (getPlatform() == Common::kPlatformWindows) && (getIsDemo()))
+ return;
+
+ byte paletteData[PALETTE_EXT_BLOCK_SIZE];
+ byte paletteData2[PALETTE_EXT_BLOCK_SIZE];
+
+ memset(&paletteData, 0, PALETTE_EXT_BLOCK_SIZE);
+ _events->refreshScreenAndEvents();
+ _events->_mouseFl = false;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _events->refreshScreenAndEvents();
+ _soundMan->playSound(16);
+ _animMan->setClearAnimFlag();
+ _animMan->playAnim("J1.anm", 12, 12, 50);
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _soundMan->mixVoice(1, 3);
+ _animMan->playAnim("J2.anm", 12, 12, 50);
+
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _soundMan->mixVoice(2, 3);
+ _animMan->playAnim("J3.anm", 12, 12, 50);
+
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _soundMan->mixVoice(3, 3);
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _graphicsMan->updateScreen();
+ _soundMan->playSound(11);
+ _graphicsMan->loadImage("intro1");
+ _graphicsMan->scrollScreen(0);
+ _graphicsMan->_scrollOffset = 0;
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+ for (int i = 0; i <= 4; i++)
+ _events->refreshScreenAndEvents();
+
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->fadeInLong();
+ if (_graphicsMan->_largeScreenFl) {
+ _graphicsMan->_scrollStatus = 2;
+ _graphicsMan->_scrollPosX = 0;
+
+ bool loopCond = false;
+ do {
+ _graphicsMan->_scrollPosX += 2;
+ if (_graphicsMan->_scrollPosX > (SCREEN_WIDTH - 2)) {
+ _graphicsMan->_scrollPosX = SCREEN_WIDTH;
+ loopCond = true;
+ }
+
+ if (_events->getMouseX() < _graphicsMan->_scrollPosX + 10)
+ _events->setMouseXY(_events->_mousePos.x + 4, _events->getMouseY());
+ _events->refreshScreenAndEvents();
+ } while (!shouldQuit() && !loopCond && _graphicsMan->_scrollPosX != SCREEN_WIDTH);
+
+ _events->refreshScreenAndEvents();
+ _graphicsMan->_scrollStatus = 0;
+
+ if (shouldQuit())
+ return;
+ }
+
+ _soundMan->mixVoice(4, 3);
+ _graphicsMan->fadeOutLong();
+ _graphicsMan->_scrollStatus = 0;
+ _graphicsMan->loadImage("intro2");
+ _graphicsMan->scrollScreen(0);
+ _animMan->loadAnim("INTRO2");
+ _graphicsMan->displayAllBob();
+ _soundMan->playSound(23);
+ _objectsMan->stopBobAnimation(3);
+ _objectsMan->stopBobAnimation(5);
+ _graphicsMan->_scrollOffset = 0;
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+
+ for (int i = 0; i <= 4; i++)
+ _events->refreshScreenAndEvents();
+
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->fadeInLong();
+ for (uint i = 0; i < 200 / _globals->_speed; ++i)
+ _events->refreshScreenAndEvents();
+
+ _objectsMan->setBobAnimation(3);
+ _soundMan->mixVoice(5, 3);
+ _objectsMan->stopBobAnimation(3);
+ _events->refreshScreenAndEvents();
+ memcpy(&paletteData2, _graphicsMan->_palette, 796);
+
+ _graphicsMan->setPaletteVGA256WithRefresh(paletteData, _graphicsMan->_frontBuffer);
+ _graphicsMan->endDisplayBob();
+
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _soundMan->_specialSoundNum = 5;
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("ELEC.ANM", 10, 26, 200);
+ _soundMan->_specialSoundNum = 0;
+
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _graphicsMan->loadImage("intro2");
+ _graphicsMan->scrollScreen(0);
+ _animMan->loadAnim("INTRO2");
+ _graphicsMan->displayAllBob();
+ _soundMan->playSound(23);
+ _objectsMan->stopBobAnimation(3);
+ _objectsMan->stopBobAnimation(5);
+ _objectsMan->stopBobAnimation(1);
+ _graphicsMan->_scrollOffset = 0;
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+
+ for (int i = 0; i <= 3; i++)
+ _events->refreshScreenAndEvents();
+
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->setPaletteVGA256WithRefresh(paletteData2, _graphicsMan->_frontBuffer);
+
+ int introIndex = 0;
+ while (!shouldQuit() && !_events->_escKeyFl) {
+ if (introIndex == 12) {
+ _objectsMan->setBobAnimation(3);
+ _events->refreshScreenAndEvents();
+ _soundMan->mixVoice(6, 3);
+ _events->refreshScreenAndEvents();
+ _objectsMan->stopBobAnimation(3);
+ }
+
+ Common::copy(&paletteData2[0], &paletteData2[PALETTE_BLOCK_SIZE], &_graphicsMan->_palette[0]);
+
+ for (int i = 1, maxPalVal = 4 * introIndex; i <= PALETTE_BLOCK_SIZE; i++) {
+ if (_graphicsMan->_palette[i] > maxPalVal)
+ _graphicsMan->_palette[i] -= maxPalVal;
+ }
+
+ _graphicsMan->setPaletteVGA256WithRefresh(_graphicsMan->_palette, _graphicsMan->_frontBuffer);
+
+ for (int i = 1; i < 2 * introIndex; i++)
+ _events->refreshScreenAndEvents();
+
+ _graphicsMan->setPaletteVGA256WithRefresh(paletteData2, _graphicsMan->_frontBuffer);
+
+ for (int i = 1; i < 20 - introIndex; i++)
+ _events->refreshScreenAndEvents();
+
+ introIndex += 2;
+ if (introIndex > 15) {
+ _graphicsMan->setPaletteVGA256WithRefresh(paletteData, _graphicsMan->_frontBuffer);
+ for (uint j = 1; j < 100 / _globals->_speed; ++j)
+ _events->refreshScreenAndEvents();
+
+ _objectsMan->setBobAnimation(3);
+ _soundMan->mixVoice(7, 3);
+ _objectsMan->stopBobAnimation(3);
+
+ for (uint k = 1; k < 60 / _globals->_speed; ++k)
+ _events->refreshScreenAndEvents();
+ _objectsMan->setBobAnimation(5);
+ for (uint l = 0; l < 20 / _globals->_speed; ++l)
+ _events->refreshScreenAndEvents();
+
+ Common::copy(&paletteData2[0], &paletteData2[PALETTE_BLOCK_SIZE], &_graphicsMan->_palette[0]);
+ _graphicsMan->setPaletteVGA256WithRefresh(_graphicsMan->_palette, _graphicsMan->_frontBuffer);
+
+ for (uint m = 0; m < 50 / _globals->_speed; ++m) {
+ if (m == 30 / _globals->_speed) {
+ _objectsMan->setBobAnimation(3);
+ _soundMan->mixVoice(8, 3);
+ _objectsMan->stopBobAnimation(3);
+ }
+
+ _events->refreshScreenAndEvents();
+ }
+
+ _graphicsMan->fadeOutLong();
+ _graphicsMan->endDisplayBob();
+ _soundMan->playSound(3);
+ _soundMan->_specialSoundNum = 1;
+ _animMan->setClearAnimFlag();
+ _animMan->playAnim("INTRO1.anm", 10, 24, 18);
+ _soundMan->_specialSoundNum = 0;
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _animMan->playAnim("INTRO2.anm", 10, 24, 18);
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _animMan->playAnim("INTRO3.anm", 10, 24, 200);
+ if (shouldQuit() || _events->_escKeyFl)
+ return;
+
+ _graphicsMan->_fadingFl = true;
+ _animMan->unsetClearAnimFlag();
+ _animMan->playAnim("J4.anm", 12, 12, 1000);
+ break;
+ }
+ }
+
+ _events->_escKeyFl = false;
+}
+
+/**
+ * If in demo, displays a 'not available' screen and returns to the city map
+ */
+void HopkinsEngine::displayNotAvailable() {
+ if (!getIsDemo())
+ return;
+
+ if (_globals->_language == LANG_FR)
+ _graphicsMan->loadImage("ndfr");
+ else
+ _graphicsMan->loadImage("nduk");
+
+ _graphicsMan->fadeInLong();
+ if (_soundMan->_voiceOffFl)
+ _events->delay(500);
+ else
+ _soundMan->mixVoice(628, 4);
+
+ _graphicsMan->fadeOutLong();
+ _globals->_exitId = 4;
+}
+
+void HopkinsEngine::handleNotAvailable(int nextScreen) {
+ // Use the code of the Linux demo instead of the code of the Windows demo.
+ // The behavior is somewhat better, and common code is easier to maintain.
+ displayNotAvailable();
+ _globals->_exitId = nextScreen;
+}
+
+void HopkinsEngine::displayEndDemo() {
+ _soundMan->playSound(28);
+ if (_globals->_language == LANG_FR)
+ _graphicsMan->loadImage("endfr");
+ else
+ _graphicsMan->loadImage("enduk");
+
+ _graphicsMan->fadeInLong();
+ _events->delay(1500);
+ _graphicsMan->fadeOutLong();
+ _globals->_exitId = 0;
+}
+
+void HopkinsEngine::bombExplosion() {
+ _graphicsMan->_lineNbr = SCREEN_WIDTH;
+ _graphicsMan->setScreenWidth(SCREEN_WIDTH);
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->_specialSoundNum = 199;
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("BOMBE2A.ANM", 50, 14, 500);
+ _soundMan->_specialSoundNum = 0;
+ _graphicsMan->loadImage("IM15");
+ _animMan->loadAnim("ANIM15");
+ _graphicsMan->displayAllBob();
+ _objectsMan->stopBobAnimation(7);
+
+ for (int idx = 0; idx < 5; ++idx) {
+ _events->refreshScreenAndEvents();
+ }
+
+ _graphicsMan->fadeInLong();
+ _events->mouseOff();
+
+ for (int idx = 0; idx < 20; ++idx) {
+ _events->refreshScreenAndEvents();
+ }
+
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startStaticCharacterDialogue("vire.pe2");
+ _globals->_introSpeechOffFl = false;
+ _objectsMan->setBobAnimation(7);
+
+ for (int idx = 0; idx < 100; ++idx) {
+ _events->refreshScreenAndEvents();
+ }
+
+ _graphicsMan->fadeOutLong();
+ _graphicsMan->endDisplayBob();
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 151;
+}
+
+void HopkinsEngine::restoreSystem() {
+ quitGame();
+ _events->refreshEvents();
+}
+
+void HopkinsEngine::endLinuxDemo() {
+ _globals->_linuxEndDemoFl = true;
+ _graphicsMan->resetDirtyRects();
+ _objectsMan->_forestFl = false;
+ _events->_breakoutFl = false;
+ _globals->_disableInventFl = true;
+ _graphicsMan->loadImage("BOX");
+ _soundMan->playSound(28);
+ _graphicsMan->fadeInLong();
+ _events->mouseOn();
+ _events->changeMouseCursor(0);
+ _events->_mouseCursorId = 0;
+ _events->_mouseSpriteId = 0;
+
+ bool mouseClicked = false;
+
+ do {
+ _events->refreshScreenAndEvents();
+
+ if (_events->getMouseButton() == 1)
+ mouseClicked = true;
+ } while (!mouseClicked && !shouldQuit());
+
+ // Original tried to open a web browser link here. Since ScummVM doesn't support
+ // that, it's being skipped in favor of simply exiting
+
+ _graphicsMan->fadeOutLong();
+}
+
+void HopkinsEngine::handleConflagration() {
+ _globals->_disableInventFl = true;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->loadImage("IM71");
+ _animMan->loadAnim("ANIM71");
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+ _graphicsMan->displayAllBob();
+
+ for (int cpt = 0; cpt <= 4; cpt++)
+ _events->refreshScreenAndEvents();
+
+ _graphicsMan->fadeInLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ for (int cpt = 0; cpt <= 249; cpt++)
+ _events->refreshScreenAndEvents();
+
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startAnimatedCharacterDialogue("SVGARD1.pe2");
+ _globals->_introSpeechOffFl = false;
+
+ for (int cpt = 0; cpt <= 49; cpt++)
+ _events->refreshScreenAndEvents();
+
+ _graphicsMan->fadeOutLong();
+ _graphicsMan->endDisplayBob();
+ _globals->_saveData->_data[svBaseFireFl] = 1;
+ _globals->_disableInventFl = false;
+}
+
+void HopkinsEngine::playSubmarineCutscene() {
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->_lineNbr = SCREEN_WIDTH;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _soundMan->playSound(25);
+ _animMan->setClearAnimFlag();
+ _animMan->playAnim("base00a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("base05a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("base10a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("base20a.anm", 10, 18, 18);
+ // CHECKME: The original code was doing the opposite test, which was a bug.
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("base30a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("base40a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("base50a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("OC00a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("OC05a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("OC10a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("OC20a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl) {
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("OC30a.anm", 10, 18, 18);
+ }
+
+ _events->_escKeyFl = false;
+ _animMan->unsetClearAnimFlag();
+ _globals->_exitId = 85;
+}
+
+void HopkinsEngine::playUnderwaterBaseCutscene() {
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _soundMan->playSound(26);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _globals->_disableInventFl = true;
+ _graphicsMan->_fadingFl = true;
+ _animMan->playSequence("abase.seq", 50, 15, 50, false, false, true);
+ _graphicsMan->loadImage("IM92");
+ _animMan->loadAnim("ANIM92");
+ _graphicsMan->displayAllBob();
+ _objectsMan->loadLinkFile("IM92");
+/*
+ for (int cpt = 0; cpt <= 4 && !shouldQuit(); cpt++)
+ _eventsManager->refreshScreenAndEvents();
+*/
+ _graphicsMan->fadeInLong();
+ _objectsMan->enableHidingBehavior();
+
+ do
+ _events->refreshScreenAndEvents();
+ while (!shouldQuit() && _objectsMan->getBobAnimDataIdx(8) != 22);
+
+ if (!shouldQuit()) {
+ _graphicsMan->fadeOutLong();
+ _graphicsMan->endDisplayBob();
+ _objectsMan->resetHidingItems();
+ _globals->_disableInventFl = false;
+ _globals->_exitId = 93;
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ }
+}
+
+void HopkinsEngine::playEnding() {
+ _globals->_characterSpriteBuf = _globals->freeMemory(_globals->_characterSpriteBuf);
+ _dialog->disableInvent();
+ _globals->_disableInventFl = true;
+ _graphicsMan->_scrollOffset = 0;
+ _globals->_cityMapEnabledFl = false;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->playSound(26);
+ _linesMan->_route = NULL;
+ _globals->_freezeCharacterFl = true;
+ _globals->_exitId = 0;
+ _soundMan->loadSample(1, "SOUND90.WAV");
+ _graphicsMan->loadImage("IM100");
+ _animMan->loadAnim("ANIM100");
+ _graphicsMan->displayAllBob();
+ _events->mouseOn();
+ _objectsMan->stopBobAnimation(7);
+ _objectsMan->stopBobAnimation(8);
+ _objectsMan->stopBobAnimation(9);
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+ _events->changeMouseCursor(0);
+
+ for (int cpt = 0; cpt <= 4; cpt++)
+ _events->refreshScreenAndEvents();
+
+ _graphicsMan->fadeInLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(6) != 54);
+
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startAnimatedCharacterDialogue("GM4.PE2");
+ _globals->_disableInventFl = true;
+ _objectsMan->stopBobAnimation(6);
+ _objectsMan->stopBobAnimation(10);
+ _objectsMan->setBobAnimation(9);
+ _objectsMan->setBobAnimation(7);
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(7) != 54);
+
+ _soundMan->playSample(1);
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(7) != 65);
+
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startAnimatedCharacterDialogue("DUELB4.PE2");
+ _events->mouseOff();
+ _globals->_disableInventFl = true;
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(7) != 72);
+
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startAnimatedCharacterDialogue("DUELH1.PE2");
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(7) != 81);
+
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startAnimatedCharacterDialogue("DUELB5.PE2");
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(7) != 120);
+
+ _objectsMan->stopBobAnimation(7);
+ if (_globals->_saveData->_data[svGameWonFl] == 1) {
+ _soundMan->_specialSoundNum = 200;
+ _soundMan->_skipRefreshFl = true;
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("BERM.ANM", 100, 24, 300);
+ _graphicsMan->endDisplayBob();
+ _soundMan->removeSample(1);
+ _graphicsMan->loadImage("PLAN3");
+ _graphicsMan->fadeInLong();
+
+ _events->_rateCounter = 0;
+ if (!_events->_escKeyFl) {
+ do
+ _events->refreshEvents();
+ while (_events->_rateCounter < 2000 / _globals->_speed && !_events->_escKeyFl);
+ }
+ _events->_escKeyFl = false;
+ _graphicsMan->fadeOutLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->_specialSoundNum = 0;
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("JOUR2A.anm", 12, 12, 1000);
+ _soundMan->playSound(11);
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+ _animMan->playAnim("FF1a.anm", 18, 18, 9);
+ _animMan->playAnim("FF1a.anm", 9, 18, 9);
+ _animMan->playAnim("FF1a.anm", 9, 18, 18);
+ _animMan->playAnim("FF1a.anm", 9, 18, 9);
+ _animMan->playAnim("FF2a.anm", 24, 24, 100);
+ displayCredits();
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ _dialog->enableInvent();
+ _globals->_disableInventFl = false;
+ } else {
+ _soundMan->_specialSoundNum = 200;
+ _soundMan->_skipRefreshFl = true;
+ _animMan->playAnim2("BERM.ANM", 100, 24, 300);
+ _objectsMan->stopBobAnimation(7);
+ _objectsMan->setBobAnimation(8);
+ _globals->_introSpeechOffFl = true;
+ _talkMan->startAnimatedCharacterDialogue("GM5.PE2");
+ _globals->_disableInventFl = true;
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(8) != 5);
+
+ _soundMan->directPlayWav("SOUND41.WAV");
+
+ do
+ _events->refreshScreenAndEvents();
+ while (_objectsMan->getBobAnimDataIdx(8) != 21);
+
+ _graphicsMan->fadeOutLong();
+ _graphicsMan->endDisplayBob();
+ _soundMan->removeSample(1);
+ _soundMan->playSound(16);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _soundMan->_specialSoundNum = 0;
+ _dialog->enableInvent();
+ _globals->_disableInventFl = false;
+ _animMan->playAnim("JOUR4A.anm", 12, 12, 1000);
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+ _globals->_exitId = 300;
+ }
+ _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR");
+ _globals->_characterType = 0;
+ _globals->_eventMode = EVENTMODE_DEFAULT;
+}
+
+void HopkinsEngine::playPlaneCutscene() {
+ _soundMan->playSound(28);
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _graphicsMan->clearScreen();
+ _graphicsMan->clearPalette();
+
+ _animMan->unsetClearAnimFlag();
+ _animMan->playAnim("aerop00a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("serop10a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("aerop20a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("aerop30a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("aerop40a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("aerop50a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("aerop60a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("aerop70a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("trans00a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("trans10a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("trans15a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("trans20a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("trans30a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl)
+ _animMan->playAnim("trans40a.anm", 10, 18, 18);
+ if (!_events->_escKeyFl) {
+ _graphicsMan->_fadingFl = true;
+ _animMan->playAnim("PARA00a.anm", 9, 9, 9);
+ }
+
+ _events->_escKeyFl = false;
+ _animMan->unsetClearAnimFlag();
+}
+
+void HopkinsEngine::loadBaseMap() {
+ Common::String filename = Common::String::format("%s.PCX", "PBASE");
+ Common::File f;
+
+ if (f.exists(filename)) {
+ // PBASE file exists, so go ahead and load it
+ _graphicsMan->loadImage("PBASE");
+ } else {
+ // PBASE file doesn't exist, so draw a substitute screen
+ drawBaseMap();
+ }
+}
+
+void HopkinsEngine::drawBaseMap() {
+ memset(_graphicsMan->_backBuffer, 0, SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+
+ // List of rectangle areas to draw for exit points
+ const int rects[] = {
+ 181, 66, 181 + 16, 66 + 22,
+ 353, 116, 353 + 22, 116 + 16,
+ 483, 250, 483 + 20, 250 + 25,
+ 471, 326, 471 + 27, 326 + 20,
+ 162, 365, 162 + 21, 365 + 23,
+ 106, 267, 106 + 20, 267 + 26
+ };
+
+ // Loop through displaying
+ const int *rectP = &rects[0];
+ for (int rectIndex = 0; rectIndex < 6; ++rectIndex, rectP += 4) {
+ Common::Rect r(rectP[0], rectP[1], rectP[2], rectP[3]);
+
+ for (int yp = r.top; yp <= r.bottom; ++yp) {
+ byte *pDest = _graphicsMan->_backBuffer + yp * SCREEN_WIDTH + r.left;
+ Common::fill(pDest, pDest + r.width(), 0xff);
+ }
+ }
+
+ // Copy the calculated screen
+ memcpy(_graphicsMan->_frontBuffer, _graphicsMan->_backBuffer, SCREEN_WIDTH * 2 * SCREEN_HEIGHT);
+
+ // Write some explanatory text
+ _fontMan->displayText(40, 200, "ScummVM base map - select a square for different rooms", 255);
+}
+
+int HopkinsEngine::handleBaseMap() {
+ _globals->_disableInventFl = true;
+
+ // Load the map image
+ loadBaseMap();
+
+ // Set needed colors
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+ _events->changeMouseCursor(0);
+ _graphicsMan->fadeInLong();
+ bool loopCond = false;
+ int zone;
+ do {
+ if (shouldQuit())
+ return 0;
+
+ int mouseButton = _events->getMouseButton();
+ int posX = _events->getMouseX();
+ int posY = _events->getMouseY();
+ zone = 0;
+ if ((posX - 181 <= 16) && (posY - 66 <= 22) &&
+ (posX - 181 >= 0) && (posY - 66 >= 0))
+ zone = 1;
+ if ((posX - 353 <= 22) && (posY - 116 <= 19) &&
+ (posX - 353 >= 0) && (posY - 116 >= 0))
+ zone = 2;
+ if ((posX - 483 <= 20) && (posY - 250 <= 25) &&
+ (posX - 483 >= 0) && (posY - 250 >= 0))
+ zone = 3;
+ if ((posX - 471 <= 27) && (posY - 326 <= 20) &&
+ (posX - 471 >= 0) && (posY - 326 >= 0))
+ zone = 4;
+ if ((posX - 162 <= 21) && (posY - 365 <= 23) &&
+ (posX - 162 >= 0) && (posY - 365 >= 0))
+ zone = 5;
+ if ((posX - 106 <= 20) && (posY - 267 <= 26) &&
+ (posX - 106 >= 0) && (posY - 267 >= 0))
+ zone = 6;
+ if (zone) {
+ _events->changeMouseCursor(4);
+ _globals->_baseMapColor += 25;
+ if (_globals->_baseMapColor > 100)
+ _globals->_baseMapColor = 0;
+ _graphicsMan->setColorPercentage2(251, _globals->_baseMapColor, _globals->_baseMapColor, _globals->_baseMapColor);
+ } else {
+ _events->changeMouseCursor(0);
+ _graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ }
+ _events->refreshScreenAndEvents();
+ if ((mouseButton == 1) && zone)
+ loopCond = true;
+ } while (!loopCond);
+
+ _globals->_disableInventFl = false;
+ _graphicsMan->fadeOutLong();
+
+ int result;
+ switch (zone) {
+ case 1:
+ result = 94;
+ break;
+ case 2:
+ result = 95;
+ break;
+ case 3:
+ result = 96;
+ break;
+ case 4:
+ result = 97;
+ break;
+ case 5:
+ result = 98;
+ break;
+ case 6:
+ result = 99;
+ break;
+ default:
+ result = 0;
+ break;
+ }
+ return result;
+}
+
+void HopkinsEngine::loadCredits() {
+ _globals->_creditsPosY = 440;
+ _globals->_creditsStep = 45;
+ byte *bufPtr;
+ switch (_globals->_language) {
+ case LANG_EN:
+ bufPtr = _fileIO->loadFile("CREAN.TXT");
+ break;
+ case LANG_FR:
+ bufPtr = _fileIO->loadFile("CREFR.TXT");
+ break;
+ case LANG_SP:
+ bufPtr = _fileIO->loadFile("CREES.TXT");
+ break;
+ default:
+ error("Unhandled language");
+ break;
+ }
+
+ byte *curPtr = bufPtr;
+ int idxLines = 0;
+ bool loopCond = false;
+ do {
+ if (*curPtr == '%') {
+ if (curPtr[1] == '%') {
+ loopCond = true;
+ break;
+ }
+ _globals->_creditsItem[idxLines]._color = curPtr[1];
+ _globals->_creditsItem[idxLines]._actvFl = true;
+ _globals->_creditsItem[idxLines]._linePosY = _globals->_creditsPosY + idxLines * _globals->_creditsStep;
+
+ int idxBuf = 0;
+ for(; idxBuf < 49; idxBuf++) {
+ byte curChar = curPtr[idxBuf + 3];
+ if (curChar == '%' || curChar == 10)
+ break;
+ _globals->_creditsItem[idxLines]._line[idxBuf] = curChar;
+ }
+ _globals->_creditsItem[idxLines]._line[idxBuf] = 0;
+ _globals->_creditsItem[idxLines]._lineSize = idxBuf - 1;
+ curPtr = curPtr + idxBuf + 2;
+ ++idxLines;
+ } else {
+ curPtr++;
+ }
+ _globals->_creditsLineNumb = idxLines;
+ } while (!loopCond);
+
+ _globals->freeMemory(bufPtr);
+}
+
+void HopkinsEngine::displayCredits(int startPosY, byte *buffer, char color) {
+ byte *bufPtr = buffer;
+ int strWidth = 0;
+ byte curChar;
+ for (;;) {
+ curChar = *bufPtr++;
+ if (!curChar)
+ break;
+ if (curChar > 31)
+ strWidth += _objectsMan->getWidth(_fontMan->_font, curChar - 32);
+ }
+ int startPosX = 320 - strWidth / 2;
+ int endPosX = strWidth + startPosX;
+ int endPosY = startPosY + 12;
+ if ((_globals->_creditsStartX == -1) && (_globals->_creditsEndX == -1) && (_globals->_creditsStartY == -1) && (_globals->_creditsEndY == -1)) {
+ _globals->_creditsStartX = startPosX;
+ _globals->_creditsEndX = endPosX;
+ _globals->_creditsStartY = startPosY;
+ _globals->_creditsEndY = endPosY;
+ }
+
+ _globals->_creditsStartX = MIN(_globals->_creditsStartX, startPosX);
+ _globals->_creditsEndX = MAX(_globals->_creditsEndX, endPosX);
+ _globals->_creditsStartY = MIN(_globals->_creditsStartY, startPosY);
+ _globals->_creditsEndY = MAX(_globals->_creditsEndY, endPosY);
+
+ Common::String message = Common::String((char *)buffer);
+ _fontMan->displayText(startPosX, startPosY, message, color);
+}
+
+void HopkinsEngine::displayCredits() {
+ loadCredits();
+ _globals->_creditsPosY = 436;
+ _graphicsMan->loadImage("GENERIC");
+ _graphicsMan->fadeInLong();
+ _soundMan->playSound(28);
+ _events->_mouseFl = false;
+ _globals->_eventMode = EVENTMODE_CREDITS;
+ _globals->_creditsStartX = _globals->_creditsEndX = _globals->_creditsStartY = _globals->_creditsEndY = -1;
+ int soundId = 28;
+ do {
+ for (int i = 0; i < _globals->_creditsLineNumb; ++i) {
+ if (_globals->_creditsItem[i]._actvFl) {
+ int nextY = _globals->_creditsPosY + i * _globals->_creditsStep;
+ _globals->_creditsItem[i]._linePosY = nextY;
+
+ if ((nextY - 21 >= 0) && (nextY - 21 <= 418)) {
+ int col = 0;
+ switch (_globals->_creditsItem[i]._color) {
+ case '1':
+ col = 163;
+ break;
+ case '2':
+ col = 161;
+ break;
+ case '3':
+ col = 162;
+ break;
+ default:
+ warning("Unknown color, default to col #1");
+ col = 163;
+ break;
+ }
+ if (_globals->_creditsItem[i]._lineSize != -1)
+ displayCredits(nextY, _globals->_creditsItem[i]._line, col);
+ }
+ }
+ }
+ --_globals->_creditsPosY;
+ if (_globals->_creditsStartX != -1 || _globals->_creditsEndX != -1 || _globals->_creditsStartY != -1 || _globals->_creditsEndY != -1) {
+ _events->refreshScreenAndEvents();
+ _graphicsMan->copySurface(_graphicsMan->_backBuffer, 60, 50, 520, 380, _graphicsMan->_frontBuffer, 60, 50);
+ } else {
+ _events->refreshScreenAndEvents();
+ }
+ if (_globals->_creditsItem[_globals->_creditsLineNumb - 1]._linePosY <= 39) {
+ _globals->_creditsPosY = 440;
+ ++soundId;
+ if (soundId > 31)
+ soundId = 28;
+ _soundMan->playSound(soundId);
+ }
+ _globals->_creditsStartX = -1;
+ _globals->_creditsEndX = -1;
+ _globals->_creditsStartY = -1;
+ _globals->_creditsEndY = -1;
+ } while ((_events->getMouseButton() != 1) && (!shouldQuit()));
+ _graphicsMan->fadeOutLong();
+ _globals->_eventMode = EVENTMODE_IGNORE;
+ _events->_mouseFl = true;
+}
+
+void HopkinsEngine::handleOceanMouseEvents() {
+ _fontMan->hideText(9);
+ if (_events->_mouseCursorId != 16)
+ return;
+
+ _events->getMouseX();
+ if (_objectsMan->_zoneNum <= 0)
+ return;
+
+ int oldPosX = _events->getMouseX();
+ int oldPosY = _events->getMouseY();
+ bool displAnim = false;
+ int oldX;
+ switch (_objectsMan->_zoneNum) {
+ case 1:
+ switch (_globals->_oceanDirection) {
+ case DIR_UP:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "27,26,25,24,23,22,21,20,19,18,-1,", 6, false);
+ break;
+ case DIR_RIGHT:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,-1,", 6, false);
+ break;
+ case DIR_DOWN:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "9,10,11,12,13,14,15,16,17,18,-1,", 6, false);
+ break;
+ default:
+ break;
+ }
+
+ _globals->_oceanDirection = DIR_LEFT;
+ _globals->_exitId = 1;
+ oldX = _objectsMan->getSpriteX(0);
+ for (;;) {
+ if (_globals->_speed == 1)
+ oldX -= 2;
+ else if (_globals->_speed == 2)
+ oldX -= 4;
+ else if (_globals->_speed == 3)
+ oldX -= 6;
+ _objectsMan->setSpriteX(0, oldX);
+ setSubmarineSprites();
+ _events->refreshScreenAndEvents();
+ if (_events->getMouseButton() == 1 && oldPosX == _events->getMouseX() && _events->getMouseY() == oldPosY) {
+ displAnim = true;
+ break;
+ }
+
+ if (oldX <= -100)
+ break;
+ }
+ break;
+ case 2:
+ switch (_globals->_oceanDirection) {
+ case DIR_UP:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "27,28,29,30,31,32,33,34,35,36,-1,", 6, false);
+ break;
+ case DIR_DOWN:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "9,8,7,6,5,4,3,2,1,0,-1,", 6, false);
+ break;
+ case DIR_LEFT:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,-1,", 6, false);
+ break;
+ default:
+ break;
+ }
+ _globals->_oceanDirection = DIR_RIGHT;
+ _globals->_exitId = 2;
+ oldX = _objectsMan->getSpriteX(0);
+ for (;;) {
+ if (_globals->_speed == 1)
+ oldX += 2;
+ else if (_globals->_speed == 2)
+ oldX += 4;
+ else if (_globals->_speed == 3)
+ oldX += 6;
+ _objectsMan->setSpriteX(0, oldX);
+ setSubmarineSprites();
+ _events->refreshScreenAndEvents();
+ if (_events->getMouseButton() == 1 && oldPosX == _events->getMouseX() && _events->getMouseY() == oldPosY) {
+ displAnim = true;
+ break;
+ }
+ if (oldX > 499)
+ break;
+ }
+ break;
+ case 3:
+ switch (_globals->_oceanDirection) {
+ case DIR_RIGHT:
+ oldX = _objectsMan->getSpriteX(0);
+ do {
+ if (_globals->_speed == 1)
+ oldX += 2;
+ else if (_globals->_speed == 2)
+ oldX += 4;
+ else if (_globals->_speed == 3)
+ oldX += 6;
+ _objectsMan->setSpriteX(0, oldX);
+ setSubmarineSprites();
+ _events->refreshScreenAndEvents();
+ if (_events->getMouseButton() == 1 && oldPosX == _events->getMouseX() && _events->getMouseY() == oldPosY) {
+ displAnim = true;
+ break;
+ }
+ } while (oldX <= 235);
+ if (!displAnim)
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "36,35,34,33,32,31,30,29,28,27,-1,", 6, false);
+ break;
+ case DIR_DOWN:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,-1,", 6, false);
+ break;
+ case DIR_LEFT:
+ oldX = _objectsMan->getSpriteX(0);
+ do {
+ if (_globals->_speed == 1)
+ oldX -= 2;
+ else if (_globals->_speed == 2)
+ oldX -= 4;
+ else if (_globals->_speed == 3)
+ oldX -= 6;
+ _objectsMan->setSpriteX(0, oldX);
+ setSubmarineSprites();
+ _events->refreshScreenAndEvents();
+ if (_events->getMouseButton() == 1 && oldPosX == _events->getMouseX() && _events->getMouseY() == oldPosY) {
+ displAnim = true;
+ break;
+ }
+ } while (oldX > 236);
+ if (!displAnim)
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "18,19,20,21,22,23,24,25,26,27,-1,", 6, false);
+ break;
+ default:
+ break;
+ }
+ _globals->_oceanDirection = DIR_UP;
+ _globals->_exitId = 3;
+ break;
+ case 4:
+ switch (_globals->_oceanDirection) {
+ case DIR_UP:
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,-1,", 6, false);
+ break;
+ case DIR_RIGHT:
+ oldX = _objectsMan->getSpriteX(0);
+ do {
+ if (_globals->_speed == 1)
+ oldX += 2;
+ else if (_globals->_speed == 2)
+ oldX += 4;
+ else if (_globals->_speed == 3)
+ oldX += 6;
+ _objectsMan->setSpriteX(0, oldX);
+ setSubmarineSprites();
+ _events->refreshScreenAndEvents();
+ if (_events->getMouseButton() == 1 && oldPosX == _events->getMouseX() && _events->getMouseY() == oldPosY) {
+ displAnim = true;
+ break;
+ }
+ } while (oldX <= 235);
+ if (!displAnim)
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "0,1,2,3,4,5,6,7,8,9,-1,", 6, false);
+ break;
+ case DIR_LEFT:
+ oldX = _objectsMan->getSpriteX(0);
+ for (;;) {
+ if (_globals->_speed == 1)
+ oldX -= 2;
+ else if (_globals->_speed == 2)
+ oldX -= 4;
+ else if (_globals->_speed == 3)
+ oldX -= 6;
+ _objectsMan->setSpriteX(0, oldX);
+ setSubmarineSprites();
+ _events->refreshScreenAndEvents();
+ if (_events->getMouseButton() == 1 && oldPosX == _events->getMouseX() && _events->getMouseY() == oldPosY)
+ break;
+
+ if (oldX <= 236) {
+ if (!displAnim)
+ _objectsMan->showSpecialActionAnimationWithFlip(_globals->_characterSpriteBuf, "18,17,16,15,14,13,12,11,10,9,-1,", 6, false);
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ _globals->_oceanDirection = DIR_DOWN;
+ _globals->_exitId = 4;
+ break;
+ }
+}
+
+void HopkinsEngine::setSubmarineSprites() {
+ switch (_globals->_oceanDirection) {
+ case DIR_UP:
+ _objectsMan->setSpriteIndex(0, 27);
+ break;
+ case DIR_RIGHT:
+ _objectsMan->setSpriteIndex(0, 0);
+ break;
+ case DIR_DOWN:
+ _objectsMan->setSpriteIndex(0, 9);
+ break;
+ case DIR_LEFT:
+ _objectsMan->setSpriteIndex(0, 18);
+ break;
+ default:
+ break;
+ }
+}
+
+void HopkinsEngine::handleOceanMaze(int16 curExitId, Common::String backgroundFilename, Directions defaultDirection, int16 exit1, int16 exit2, int16 exit3, int16 exit4, int16 soundId) {
+ _globals->_cityMapEnabledFl = false;
+ _graphicsMan->_noFadingFl = false;
+ _globals->_freezeCharacterFl = false;
+ _globals->_exitId = 0;
+ _globals->_disableInventFl = true;
+ _soundMan->playSound(soundId);
+ _globals->_characterSpriteBuf = _fileIO->loadFile("VAISSEAU.SPR");
+ if (backgroundFilename.size())
+ _graphicsMan->loadImage(backgroundFilename);
+
+ if (curExitId == 77)
+ _objectsMan->loadLinkFile("IM77");
+ else if (curExitId == 84)
+ _objectsMan->loadLinkFile("IM84");
+ else if (curExitId == 91)
+ _objectsMan->loadLinkFile("IM91");
+ else
+ _objectsMan->loadLinkFile("ocean");
+
+ if (!exit1)
+ _linesMan->disableZone(1);
+ if (!exit2)
+ _linesMan->disableZone(2);
+ if (!exit3)
+ _linesMan->disableZone(3);
+ if (!exit4)
+ _linesMan->disableZone(4);
+
+ if (_globals->_oceanDirection == DIR_NONE)
+ _globals->_oceanDirection = defaultDirection;
+
+ switch (_globals->_oceanDirection) {
+ case DIR_UP:
+ _objectsMan->_characterPos.x = 236;
+ _objectsMan->_startSpriteIndex = 27;
+ break;
+ case DIR_RIGHT:
+ _objectsMan->_characterPos.x = -20;
+ _objectsMan->_startSpriteIndex = 0;
+ break;
+ case DIR_DOWN:
+ _objectsMan->_characterPos.x = 236;
+ _objectsMan->_startSpriteIndex = 9;
+ break;
+ case DIR_LEFT:
+ _objectsMan->_characterPos.x = 415;
+ _objectsMan->_startSpriteIndex = 18;
+ break;
+ default:
+ break;
+ }
+
+ _objectsMan->addStaticSprite(_globals->_characterSpriteBuf, Common::Point(_objectsMan->_characterPos.x, 110), 0, _objectsMan->_startSpriteIndex, 0, false, 0, 0);
+ _graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _graphicsMan->setColorPercentage(254, 0, 0, 0);
+ _objectsMan->animateSprite(0);
+ _linesMan->_route = NULL;
+ _events->mouseOn();
+ _events->changeMouseCursor(4);
+
+ for (int cpt = 0; cpt <= 4; cpt++)
+ _events->refreshScreenAndEvents();
+
+ if (!_graphicsMan->_noFadingFl)
+ _graphicsMan->fadeInLong();
+ _graphicsMan->_noFadingFl = false;
+ _globals->_eventMode = EVENTMODE_IGNORE;
+
+ for (;;) {
+ int mouseButton = _events->getMouseButton();
+ if (mouseButton && mouseButton == 1)
+ handleOceanMouseEvents();
+ _linesMan->checkZone();
+ setSubmarineSprites();
+
+ _events->refreshScreenAndEvents();
+ if (_globals->_exitId || shouldQuit())
+ break;
+ }
+
+ if (_globals->_exitId == 1)
+ _globals->_exitId = exit1;
+ else if (_globals->_exitId == 2)
+ _globals->_exitId = exit2;
+ else if (_globals->_exitId == 3)
+ _globals->_exitId = exit3;
+ else if (_globals->_exitId == 4)
+ _globals->_exitId = exit4;
+ _graphicsMan->fadeOutLong();
+ _objectsMan->removeSprite(0);
+ _objectsMan->clearScreen();
+ _globals->_characterSpriteBuf = _fileIO->loadFile("PERSO.SPR");
+ _globals->_characterType = 0;
+}
+
+void HopkinsEngine::syncSoundSettings() {
+ Engine::syncSoundSettings();
+
+ _soundMan->syncSoundSettings();
+}
+
+bool HopkinsEngine::displayAdultDisclaimer() {
+ int xp, yp;
+ int buttonIndex;
+
+ _graphicsMan->_minX = 0;
+ _graphicsMan->_minY = 0;
+ _graphicsMan->_maxX = SCREEN_WIDTH;
+ _graphicsMan->_maxY = SCREEN_HEIGHT - 1;
+ _events->_breakoutFl = false;
+ _objectsMan->_forestFl = false;
+ _globals->_disableInventFl = true;
+ _globals->_exitId = 0;
+
+ _graphicsMan->loadImage("ADULT");
+ _graphicsMan->fadeInLong();
+ _events->mouseOn();
+ _events->changeMouseCursor(0);
+ _events->_mouseCursorId = 0;
+ _events->_mouseSpriteId = 0;
+
+ do {
+ xp = _events->getMouseX();
+ yp = _events->getMouseY();
+
+ buttonIndex = 0;
+ if (xp >= 37 && xp <= 169 && yp >= 406 && yp <= 445)
+ buttonIndex = 2;
+ else if (xp >= 424 && xp <= 602 && yp >= 406 && yp <= 445)
+ buttonIndex = 1;
+
+ _events->refreshScreenAndEvents();
+ } while (!shouldQuit() && (buttonIndex == 0 || _events->getMouseButton() != 1));
+
+ _globals->_disableInventFl = false;
+ _graphicsMan->fadeOutLong();
+
+ if (buttonIndex != 2) {
+ // Quit game
+ return false;
+ } else {
+ // Continue
+ _graphicsMan->_minX = 0;
+ _graphicsMan->_maxY = 20;
+ _graphicsMan->_maxX = SCREEN_WIDTH;
+ _graphicsMan->_maxY = SCREEN_HEIGHT - 20;
+ return true;
+ }
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/hopkins.h b/engines/hopkins/hopkins.h
new file mode 100644
index 0000000000..499f0c466d
--- /dev/null
+++ b/engines/hopkins/hopkins.h
@@ -0,0 +1,197 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_HOPKINS_H
+#define HOPKINS_HOPKINS_H
+
+#include "hopkins/anim.h"
+#include "hopkins/computer.h"
+#include "hopkins/debugger.h"
+#include "hopkins/dialogs.h"
+#include "hopkins/events.h"
+#include "hopkins/files.h"
+#include "hopkins/font.h"
+#include "hopkins/globals.h"
+#include "hopkins/graphics.h"
+#include "hopkins/lines.h"
+#include "hopkins/menu.h"
+#include "hopkins/objects.h"
+#include "hopkins/saveload.h"
+#include "hopkins/script.h"
+#include "hopkins/sound.h"
+#include "hopkins/talk.h"
+
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/error.h"
+#include "common/random.h"
+#include "common/hash-str.h"
+#include "common/util.h"
+#include "engines/engine.h"
+#include "graphics/surface.h"
+
+/**
+ * This is the namespace of the Hopkins engine.
+ *
+ * Status of this engine: In Development
+ *
+ * Games using this engine:
+ * - Hopkins FBI
+ */
+namespace Hopkins {
+
+enum {
+ kHopkinsDebugAnimations = 1 << 0,
+ kHopkinsDebugActions = 1 << 1,
+ kHopkinsDebugSound = 1 << 2,
+ kHopkinsDebugMusic = 1 << 3,
+ kHopkinsDebugScripts = 1 << 4
+};
+
+#define DEBUG_BASIC 1
+#define DEBUG_INTERMEDIATE 2
+#define DEBUG_DETAILED 3
+
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 480
+
+#define MAX_LINES 400
+
+/**
+ * A wrapper macro used around three character constants, like 'END', to
+ * ensure portability. Typical usage: MKTAG24('E','N','D').
+ */
+#define MKTAG24(a0,a1,a2) ((uint32)((a2) | (a1) << 8 | ((a0) << 16)))
+
+#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x)
+
+struct HopkinsGameDescription;
+
+class HopkinsEngine : public Engine {
+private:
+ const HopkinsGameDescription *_gameDescription;
+ Common::RandomSource _randomSource;
+
+ void initializeSystem();
+
+ void displayNotAvailable();
+ void restoreSystem();
+ void endLinuxDemo();
+ void displayEndDemo();
+ void bombExplosion();
+ void handleConflagration();
+ void playSubmarineCutscene();
+ void playUnderwaterBaseCutscene();
+ void playPlaneCutscene();
+ void playEnding();
+
+ /**
+ * Displays the map screen in the underground base.
+ */
+ int handleBaseMap();
+
+ /**
+ * Loads the base map from the PBASE file
+ */
+ void loadBaseMap();
+
+ /**
+ * Draws a simple base map for the Windows version, which implemented a 'Wolfenstein 3D'
+ * style shooter for the base, rather than having a map
+ */
+ void drawBaseMap();
+
+ void handleOceanMouseEvents();
+ void setSubmarineSprites();
+ void handleOceanMaze(int16 curExitId, Common::String backgroundFilename, Directions defaultDirection, int16 exit1, int16 exit2, int16 exit3, int16 exit4, int16 soundId);
+ void loadCredits();
+ void displayCredits(int startPosY, byte *buffer, char color);
+ void displayCredits();
+ void handleNotAvailable(int nextScreen);
+
+ bool runWin95Demo();
+ bool runLinuxDemo();
+ bool runFull();
+
+ /**
+ * Show warning screen about the game being adults only.
+ */
+ bool displayAdultDisclaimer();
+protected:
+ // Engine APIs
+ virtual Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+
+public:
+ AnimationManager *_animMan;
+ ComputerManager *_computer;
+ DialogsManager *_dialog;
+ Debugger *_debug;
+ EventsManager *_events;
+ FileManager *_fileIO;
+ FontManager *_fontMan;
+ Globals *_globals;
+ GraphicsManager *_graphicsMan;
+ LinesManager *_linesMan;
+ MenuManager *_menuMan;
+ ObjectsManager *_objectsMan;
+ SaveLoadManager *_saveLoad;
+ ScriptManager *_script;
+ SoundManager *_soundMan;
+ TalkManager *_talkMan;
+
+public:
+ HopkinsEngine(OSystem *syst, const HopkinsGameDescription *gameDesc);
+ virtual ~HopkinsEngine();
+ void GUIError(const Common::String &msg);
+
+ uint32 getFeatures() const;
+ Common::Language getLanguage() const;
+ Common::Platform getPlatform() const;
+ uint16 getVersion() const;
+ bool getIsDemo() const;
+ bool shouldQuit() const;
+
+ int getRandomNumber(int maxNumber);
+ Common::String generateSaveName(int slotNumber);
+ virtual bool canLoadGameStateCurrently();
+ virtual bool canSaveGameStateCurrently();
+ virtual Common::Error loadGameState(int slot);
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ int _startGameSlot;
+ /**
+ * Run the introduction sequence
+ */
+ void playIntro();
+
+ /**
+ * Synchronizes the sound settings from ScummVM into the engine
+ */
+ virtual void syncSoundSettings();
+};
+
+// Global reference to the HopkinsEngine object
+extern HopkinsEngine *g_vm;
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_HOPKINS_H */
diff --git a/engines/hopkins/lines.cpp b/engines/hopkins/lines.cpp
new file mode 100644
index 0000000000..6603708449
--- /dev/null
+++ b/engines/hopkins/lines.cpp
@@ -0,0 +1,2914 @@
+/* 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/lines.h"
+
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+
+#include "common/system.h"
+#include "common/textconsole.h"
+
+namespace Hopkins {
+
+LinesManager::LinesManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ for (int i = 0; i < MAX_LINES; ++i) {
+ Common::fill((byte *)&_zoneLine[i], (byte *)&_zoneLine[i] + sizeof(LigneZoneItem), 0);
+ Common::fill((byte *)&_lineItem[i], (byte *)&_lineItem[i] + sizeof(LigneItem), 0);
+ }
+
+ for (int i = 0; i < 4000; ++i)
+ Common::fill((byte *)&_smoothRoute[i], (byte *)&_smoothRoute[i] + sizeof(SmoothItem), 0);
+
+ for (int i = 0; i < 8001; ++i)
+ _bestRoute[i].set(0, 0, DIR_NONE);
+
+ for (int i = 0; i < 101; ++i) {
+ Common::fill((byte *)&_segment[i], (byte *)&_segment[i] + sizeof(SegmentItem), 0);
+ Common::fill((byte *)&_squareZone[i], (byte *)&_squareZone[i] + sizeof(SquareZoneItem), 0);
+ }
+
+ for (int i = 0; i < 105; ++i) {
+ _bobZone[i] = 0;
+ _bobZoneFl[i] = false;
+ }
+
+ for (int i = 0; i < 106; ++i)
+ Common::fill((byte *)&_zone[i], (byte *)&_zone[i] + sizeof(ZoneItem), 0);
+
+ _linesNumb = 0;
+ _newLineIdx = 0;
+ _newLineDataIdx = 0;
+ _newRouteIdx = 0;
+ _newPosX = 0;
+ _newPosY = 0;
+ _smoothMoveDirection = DIR_NONE;
+ _lastLine = 0;
+ _maxLineIdx = 0;
+ _pathFindingMaxDepth = 0;
+ _testRoute0 = NULL;
+ _testRoute1 = NULL;
+ _testRoute2 = NULL;
+ _lineBuf = NULL;
+ _route = NULL;
+ _currentSegmentId = 0;
+ _largeBuf = NULL;
+ _zoneSkipCount = 0;
+ _hotspotTextColor = 0;
+ _forceHideText = false;
+ _oldMouseZoneId = 0;
+ _oldMouseX = 0;
+ _oldMouseY = 0;
+ _oldRouteFromX = 0;
+ _oldRouteFromY = 0;
+ _oldRouteDestX = 0;
+ _oldRouteDestY = 0;
+ _oldZoneNum = 0;
+}
+
+LinesManager::~LinesManager() {
+ _vm->_globals->freeMemory(_largeBuf);
+ if (_testRoute0)
+ delete[] _testRoute0;
+ if (_testRoute1)
+ delete[] _testRoute1;
+ if (_testRoute2)
+ delete[] _testRoute2;
+}
+
+int LigneItem::appendToRouteInc(int from, int to, RouteItem *route, int index) {
+ if (to == -1)
+ to = _lineDataEndIdx;
+
+ for (int i = from; i < to; ++i)
+ route[index++].set(_lineData[2*i], _lineData[2*i+1], _directionRouteInc);
+ return index;
+}
+int LigneItem::appendToRouteDec(int from, int to, RouteItem *route, int index) {
+ if (from == -1)
+ from = _lineDataEndIdx - 1;
+
+ for (int i = from; i > to; --i)
+ route[index++].set(_lineData[2*i], _lineData[2*i+1], _directionRouteDec);
+ return index;
+}
+
+/**
+ * Load lines
+ */
+void LinesManager::loadLines(const Common::String &file) {
+ resetLines();
+ _linesNumb = 0;
+ _lastLine = 0;
+ byte *ptr = _vm->_fileIO->loadFile(file);
+ for (int idx = 0; READ_LE_INT16((uint16 *)ptr + (idx * 5)) != -1; idx++) {
+ addLine(idx,
+ (Directions)READ_LE_INT16((uint16 *)ptr + (idx * 5)),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 1),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 2),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 3),
+ READ_LE_INT16((uint16 *)ptr + (idx * 5) + 4));
+ }
+ initRoute();
+ _vm->_globals->freeMemory(ptr);
+}
+
+/**
+ * Check Hotspots in Inventory screen
+ * Returns the ID of the hotspot under mouse
+ */
+int LinesManager::checkInventoryHotspots(int posX, int posY) {
+ int hotspotId = 0;
+ if (posY >= 120 && posY <= 153)
+ hotspotId = checkInventoryHotspotsRow(posX, 1, false);
+ if (posY >= 154 && posY <= 191)
+ hotspotId = checkInventoryHotspotsRow(posX, 7, false);
+ if (posY >= 192 && posY <= 229)
+ hotspotId = checkInventoryHotspotsRow(posX, 13, false);
+ if (posY >= 230 && posY <= 267)
+ hotspotId = checkInventoryHotspotsRow(posX, 19, false);
+ if (posY >= 268 && posY <= 306)
+ hotspotId = checkInventoryHotspotsRow(posX, 25, true);
+ if (posY >= 268 && posY <= 288 && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478)
+ hotspotId = 30;
+ if (posY >= 290 && posY <= 306 && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478)
+ hotspotId = 31;
+ if (posY < 114 || posY > 306 || posX < _vm->_graphicsMan->_scrollOffset + 152 || posX > _vm->_graphicsMan->_scrollOffset + 484)
+ hotspotId = 32;
+
+ return hotspotId;
+}
+
+/**
+ * Check the hotspots in an inventory line
+ * Returns the hotspot Id under the mouse, if any.
+ */
+int LinesManager::checkInventoryHotspotsRow(int posX, int minZoneNum, bool lastRow) {
+ int result = minZoneNum;
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 158 && posX < _vm->_graphicsMan->_scrollOffset + 208)
+ return result;
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 208 && posX < _vm->_graphicsMan->_scrollOffset + 266) {
+ result += 1;
+ return result;
+ }
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 266 && posX < _vm->_graphicsMan->_scrollOffset + 320) {
+ result += 2;
+ return result;
+ }
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 320 && posX < _vm->_graphicsMan->_scrollOffset + 370) {
+ result += 3;
+ return result;
+ }
+
+ if (posX >= _vm->_graphicsMan->_scrollOffset + 370 && posX < _vm->_graphicsMan->_scrollOffset + 424) {
+ result += 4;
+ return result;
+ }
+
+ if (!lastRow && posX >= _vm->_graphicsMan->_scrollOffset + 424 && posX <= _vm->_graphicsMan->_scrollOffset + 478) {
+ result += 5;
+ return result;
+ }
+
+ return 0;
+}
+
+/**
+ * Add Zone Line
+ */
+void LinesManager::addZoneLine(int idx, int fromX, int fromY, int destX, int destY, int bobZoneIdx) {
+ int16 *zoneData;
+
+ if (fromX == fromY && fromY == destX && fromY == destY) {
+ _bobZoneFl[bobZoneIdx] = true;
+ _bobZone[bobZoneIdx] = fromY;
+ } else {
+ assert (idx <= MAX_LINES);
+ _zoneLine[idx]._zoneData = (int16 *)_vm->_globals->freeMemory((byte *)_zoneLine[idx]._zoneData);
+
+ int distX = abs(fromX - destX);
+ int distY = abs(fromY - destY);
+ int maxDist = 1;
+ if (distX <= distY)
+ maxDist += distY;
+ else
+ maxDist += distX;
+
+ zoneData = (int16 *)_vm->_globals->allocMemory(2 * sizeof(int16) * maxDist + (4 * sizeof(int16)));
+ assert(zoneData);
+
+ _zoneLine[idx]._zoneData = zoneData;
+
+ int16 *dataP = zoneData;
+ int stepX = 1000 * distX / maxDist;
+ int stepY = 1000 * distY / maxDist;
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ for (int i = 0; i < maxDist; i++) {
+ *dataP++ = smoothPosX / 1000;
+ *dataP++ = smoothPosY / 1000;
+
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ }
+ *dataP++ = -1;
+ *dataP++ = -1;
+
+ _zoneLine[idx]._count = maxDist;
+ _zoneLine[idx]._bobZoneIdx = bobZoneIdx;
+ }
+}
+
+/**
+ * Add Line
+ */
+void LinesManager::addLine(int lineIdx, Directions direction, int fromX, int fromY, int destX, int destY) {
+ assert (lineIdx <= MAX_LINES);
+
+ if (_linesNumb < lineIdx)
+ _linesNumb = lineIdx;
+
+ _lineItem[lineIdx]._lineData = (int16 *)_vm->_globals->freeMemory((byte *)_lineItem[lineIdx]._lineData);
+ int distX = abs(fromX - destX) + 1;
+ int distY = abs(fromY - destY) + 1;
+ int maxDist = distY;
+ if (distX > maxDist)
+ maxDist = distX;
+
+ byte *zoneData = _vm->_globals->allocMemory(4 * maxDist + 8);
+ assert (zoneData);
+
+ Common::fill(zoneData, zoneData + 4 * maxDist + 8, 0);
+ _lineItem[lineIdx]._lineData = (int16 *)zoneData;
+
+ int16 *curLineData = _lineItem[lineIdx]._lineData;
+ int stepX = 1000 * distX / (maxDist - 1);
+ int stepY = 1000 * distY / (maxDist - 1);
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ int dirX = (int)stepX / 1000; // -1: Left, 0: None, 1: Right
+ int dirY = (int)stepY / 1000; // -1: Up, 0: None, 1: Right
+ if (!dirX) {
+ if (dirY == -1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN;
+ } else if (dirY == 1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP;
+ }
+ // If dirY == 0, no move
+ } else if (dirX == 1) {
+ if (dirY == -1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_LEFT;
+ } else if (!dirY) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_LEFT;
+ } else if (dirY == 1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_LEFT;
+ }
+ } else if (dirX == -1) {
+ if (dirY == 1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_RIGHT;
+ } else if (!dirY) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_RIGHT;
+ } else if (dirY == -1) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_RIGHT;
+ }
+ }
+
+ // Second pass to soften cases where dirY == 0
+ if (dirX == 1) {
+ if (stepY > 250 && stepY <= 999) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_LEFT;
+ } else if (stepY < -250 && stepY > -1000) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_RIGHT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_LEFT;
+ }
+ } else if (dirX == -1) {
+ if (stepY > 250 && stepY <= 999) {
+ _lineItem[lineIdx]._directionRouteInc = DIR_DOWN_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_UP_RIGHT;
+ } else if (stepY < -250 && stepY > -1000) {
+ // In the original code, the test was on positive values and
+ // was impossible to meet.
+ _lineItem[lineIdx]._directionRouteInc = DIR_UP_LEFT;
+ _lineItem[lineIdx]._directionRouteDec = DIR_DOWN_RIGHT;
+ }
+ }
+
+ stepX = 1000 * distX / maxDist;
+ stepY = 1000 * distY / maxDist;
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ for (int i = 0; i < maxDist - 1; i++) {
+ curLineData[0] = smoothPosX / 1000;
+ curLineData[1] = smoothPosY / 1000;
+ curLineData += 2;
+
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ }
+ curLineData[0] = destX;
+ curLineData[1] = destY;
+
+ curLineData += 2;
+ curLineData[0] = -1;
+ curLineData[1] = -1;
+
+ _lineItem[lineIdx]._lineDataEndIdx = maxDist;
+ _lineItem[lineIdx]._direction = direction;
+
+ ++_linesNumb;
+}
+
+/**
+ * Check collision line
+ */
+bool LinesManager::checkCollisionLine(int xp, int yp, int *foundDataIdx, int *foundLineIdx, int startLineIdx, int endLineIdx) {
+ int16 *lineData;
+
+ int left = xp + 4;
+ int right = xp - 4;
+ int top = yp + 4;
+ int bottom = yp - 4;
+
+ *foundDataIdx = -1;
+ *foundLineIdx = -1;
+
+ for (int curLineIdx = startLineIdx; curLineIdx <= endLineIdx; curLineIdx++) {
+ lineData = _lineItem[curLineIdx]._lineData;
+
+ if (lineData == NULL)
+ continue;
+
+ bool collisionFl = true;
+ int lineStartX = lineData[0];
+ int lineStartY = lineData[1];
+ int lineDataIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ int lineEndX = lineData[lineDataIdx - 2];
+ int lineEndY = lineData[lineDataIdx - 1];
+ if (lineStartX >= lineEndX) {
+ if (right > lineStartX || left < lineEndX)
+ collisionFl = false;
+ } else { // lineStartX < lineEndX
+ if (left < lineStartX || right > lineEndX)
+ collisionFl = false;
+ }
+ if (lineStartY >= lineEndY) {
+ if (bottom > lineStartY || top < lineEndY)
+ collisionFl = false;
+ } else { // lineStartY < lineEndY
+ if (top < lineStartY || bottom > lineEndY)
+ collisionFl = false;
+ }
+
+ if (!collisionFl)
+ continue;
+
+ for (int idx = 0; idx < _lineItem[curLineIdx]._lineDataEndIdx; idx++) {
+ int lineX = lineData[0];
+ int lineY = lineData[1];
+ lineData += 2;
+
+ if ((xp == lineX || xp + 1 == lineX) && (yp == lineY || yp + 1 == lineY)) {
+ *foundDataIdx = idx;
+ *foundLineIdx = curLineIdx;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Init route
+ */
+void LinesManager::initRoute() {
+ int lineX = _lineItem[0]._lineData[0];
+ int lineY = _lineItem[0]._lineData[1];
+
+ int lineIdx = 1;
+ for (;;) {
+ int curDataIdx = _lineItem[lineIdx]._lineDataEndIdx;
+ int16 *curLineData = _lineItem[lineIdx]._lineData;
+
+ int curLineX = curLineData[2 * curDataIdx - 2];
+ int curLineY = curLineData[2 * curDataIdx - 1];
+ if (_vm->_graphicsMan->_maxX == curLineX || _vm->_graphicsMan->_maxY == curLineY ||
+ _vm->_graphicsMan->_minX == curLineX || _vm->_graphicsMan->_minY == curLineY ||
+ (lineX == curLineX && lineY == curLineY))
+ break;
+ if (lineIdx == MAX_LINES)
+ error("ERROR - LAST LINE NOT FOUND");
+
+ int16 *nextLineData = _lineItem[lineIdx + 1]._lineData;
+ if (!nextLineData)
+ break;
+ if (nextLineData[0] != curLineX && nextLineData[1] != curLineY)
+ break;
+ ++lineIdx;
+ }
+
+ _lastLine = lineIdx;
+ for (int idx = 1; idx < MAX_LINES; idx++) {
+ if ((_lineItem[idx]._lineDataEndIdx < _maxLineIdx) && (idx != _lastLine + 1)) {
+ _lineItem[idx]._directionRouteInc = _lineItem[idx - 1]._directionRouteInc;
+ _lineItem[idx]._directionRouteDec = _lineItem[idx - 1]._directionRouteDec;
+ }
+ }
+}
+
+// Avoid obstacle
+int LinesManager::avoidObstacle(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route) {
+ int curLineIdx = lineIdx;
+ int curLineDataIdx = lineDataIdx;
+ int curRouteIdx = routeIdx;
+ if (lineIdx < destLineIdx) {
+ curRouteIdx = _lineItem[lineIdx].appendToRouteInc(lineDataIdx, -1, route, curRouteIdx);
+
+ for (int i = lineIdx + 1; i < destLineIdx; i++)
+ curRouteIdx = _lineItem[i].appendToRouteInc(0, -1, route, curRouteIdx);
+
+ curLineDataIdx = 0;
+ curLineIdx = destLineIdx;
+ }
+ if (curLineIdx > destLineIdx) {
+ curRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curLineDataIdx, 0, route, curRouteIdx);
+ for (int i = curLineIdx - 1; i > destLineIdx; i--)
+ curRouteIdx = _lineItem[i].appendToRouteDec(-1, 0, route, curRouteIdx);
+ curLineDataIdx = _lineItem[destLineIdx]._lineDataEndIdx - 1;
+ curLineIdx = destLineIdx;
+ }
+ if (curLineIdx == destLineIdx) {
+ if (destLineDataIdx >= curLineDataIdx) {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteInc(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ } else {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteDec(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ }
+ }
+ return curRouteIdx;
+}
+
+// Avoid Obstacle, taking into account start/End lind Idx
+int LinesManager::avoidObstacleOnSegment(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route, int startLineIdx, int endLineIdx) {
+ int curLineIdx = lineIdx;
+ int curLineDataIdx = lineDataIdx;
+ int curRouteIdx = routeIdx;
+ if (destLineIdx < lineIdx) {
+ curRouteIdx = _lineItem[lineIdx].appendToRouteInc(lineDataIdx, -1, route, curRouteIdx);
+ int wrkLineIdx = lineIdx + 1;
+ if (wrkLineIdx == endLineIdx + 1)
+ wrkLineIdx = startLineIdx;
+ while (destLineIdx != wrkLineIdx) {
+ curRouteIdx = _lineItem[wrkLineIdx].appendToRouteInc(0, -1, route, curRouteIdx);
+ ++wrkLineIdx;
+ if (endLineIdx + 1 == wrkLineIdx)
+ wrkLineIdx = startLineIdx;
+ }
+ curLineDataIdx = 0;
+ curLineIdx = destLineIdx;
+ }
+ if (destLineIdx > curLineIdx) {
+ curRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curLineDataIdx, 0, route, curRouteIdx);
+ int wrkLineIdx = curLineIdx - 1;
+ if (wrkLineIdx == startLineIdx - 1)
+ wrkLineIdx = endLineIdx;
+ while (destLineIdx != wrkLineIdx) {
+ curRouteIdx = _lineItem[wrkLineIdx].appendToRouteDec(-1, 0, route, curRouteIdx);
+ --wrkLineIdx;
+ if (startLineIdx - 1 == wrkLineIdx)
+ wrkLineIdx = endLineIdx;
+ }
+ curLineDataIdx = _lineItem[destLineIdx]._lineDataEndIdx - 1;
+ curLineIdx = destLineIdx;
+ }
+ if (destLineIdx == curLineIdx) {
+ if (destLineDataIdx >= curLineDataIdx) {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteInc(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ } else {
+ curRouteIdx = _lineItem[destLineIdx].appendToRouteDec(curLineDataIdx, destLineDataIdx, route, curRouteIdx);
+ }
+ }
+ return curRouteIdx;
+}
+
+bool LinesManager::MIRACLE(int fromX, int fromY, int lineIdx, int destLineIdx, int routeIdx) {
+ int newLinesDataIdx = 0;
+ int newLinesIdx = 0;
+ int lineIdxLeft = 0;
+ int lineDataIdxLeft = 0;
+ int lineIdxRight = 0;
+ int lineDataIdxRight = 0;
+ int linesIdxUp = 0;
+ int linesDataIdxUp = 0;
+ int lineIdxDown = 0;
+ int lineDataIdxDown = 0;
+
+ int curX = fromX;
+ int curY = fromY;
+ int curLineIdx = lineIdx;
+ int tmpRouteIdx = routeIdx;
+ int dummyDataIdx;
+ if (checkCollisionLine(fromX, fromY, &dummyDataIdx, &curLineIdx, 0, _linesNumb)) {
+ switch (_lineItem[curLineIdx]._direction) {
+ case DIR_UP:
+ curY -= 2;
+ break;
+ case DIR_UP_RIGHT:
+ curY -= 2;
+ curX += 2;
+ break;
+ case DIR_RIGHT:
+ curX += 2;
+ break;
+ case DIR_DOWN_RIGHT:
+ curY += 2;
+ curX += 2;
+ break;
+ case DIR_DOWN:
+ curY += 2;
+ break;
+ case DIR_DOWN_LEFT:
+ curY += 2;
+ curX -= 2;
+ break;
+ case DIR_LEFT:
+ curX -= 2;
+ break;
+ case DIR_UP_LEFT:
+ curY -= 2;
+ curX -= 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ int stepVertIncCount = 0;
+ for (int i = curY; curY + 200 > i; i++) {
+ if (checkCollisionLine(curX, i, &lineDataIdxDown, &lineIdxDown, 0, _lastLine) == 1 && lineIdxDown <= _lastLine)
+ break;
+ lineDataIdxDown = 0;
+ lineIdxDown = -1;
+ ++stepVertIncCount;
+ }
+
+ int stepVertDecCount = 0;
+ for (int i = curY; curY - 200 < i; i--) {
+ if (checkCollisionLine(curX, i, &linesDataIdxUp, &linesIdxUp, 0, _lastLine) == 1 && linesIdxUp <= _lastLine)
+ break;
+ linesDataIdxUp = 0;
+ linesIdxUp = -1;
+ ++stepVertDecCount;
+ }
+
+ int stepHoriIncCount = 0;
+ for (int i = curX; curX + 200 > i; i++) {
+ if (checkCollisionLine(i, curY, &lineDataIdxRight, &lineIdxRight, 0, _lastLine) == 1 && lineIdxRight <= _lastLine)
+ break;
+ lineDataIdxRight = 0;
+ lineIdxRight = -1;
+ ++stepHoriIncCount;
+ }
+
+ int stepHoriDecCount = 0;
+ for (int i = curX; curX - 200 < i; i--) {
+ if (checkCollisionLine(i, curY, &lineDataIdxLeft, &lineIdxLeft, 0, _lastLine) == 1 && lineIdxLeft <= _lastLine)
+ break;
+ lineDataIdxLeft = 0;
+ lineIdxLeft = -1;
+ ++stepHoriDecCount;
+ }
+
+ if (destLineIdx > curLineIdx) {
+ if (linesIdxUp != -1 && linesIdxUp <= curLineIdx)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && curLineIdx >= lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && curLineIdx >= lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && curLineIdx >= lineIdxLeft)
+ lineIdxLeft = -1;
+ if (linesIdxUp != -1 && destLineIdx < linesIdxUp)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && destLineIdx < lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && destLineIdx < lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && destLineIdx < lineIdxLeft)
+ lineIdxLeft = -1;
+ } else if (destLineIdx < curLineIdx) {
+ if (linesIdxUp != -1 && linesIdxUp >= curLineIdx)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && curLineIdx <= lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && curLineIdx <= lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && curLineIdx <= lineIdxLeft)
+ lineIdxLeft = -1;
+ if (linesIdxUp != -1 && destLineIdx > linesIdxUp)
+ linesIdxUp = -1;
+ if (lineIdxRight != -1 && destLineIdx > lineIdxRight)
+ lineIdxRight = -1;
+ if (lineIdxDown != -1 && destLineIdx > lineIdxDown)
+ lineIdxDown = -1;
+ if (lineIdxLeft != -1 && destLineIdx > lineIdxLeft)
+ lineIdxLeft = -1;
+ }
+ if (linesIdxUp != -1 || lineIdxRight != -1 || lineIdxDown != -1 || lineIdxLeft != -1) {
+ Directions newDir = DIR_NONE;
+ if (destLineIdx > curLineIdx) {
+ if (lineIdxDown <= linesIdxUp && lineIdxRight <= linesIdxUp && lineIdxLeft <= linesIdxUp && linesIdxUp > curLineIdx)
+ newDir = DIR_UP;
+ if (lineIdxDown <= lineIdxRight && linesIdxUp <= lineIdxRight && lineIdxLeft <= lineIdxRight && curLineIdx < lineIdxRight)
+ newDir = DIR_RIGHT;
+ if (linesIdxUp <= lineIdxDown && lineIdxRight <= lineIdxDown && lineIdxLeft <= lineIdxDown && curLineIdx < lineIdxDown)
+ newDir = DIR_DOWN;
+ if (lineIdxDown <= lineIdxLeft && lineIdxRight <= lineIdxLeft && linesIdxUp <= lineIdxLeft && curLineIdx < lineIdxLeft)
+ newDir = DIR_LEFT;
+ } else if (destLineIdx < curLineIdx) {
+ if (linesIdxUp == -1)
+ linesIdxUp = INVALID_LINE_VALUE;
+ if (lineIdxRight == -1)
+ lineIdxRight = INVALID_LINE_VALUE;
+ if (lineIdxDown == -1)
+ lineIdxDown = INVALID_LINE_VALUE;
+ if (lineIdxLeft == -1)
+ lineIdxLeft = INVALID_LINE_VALUE;
+ if (linesIdxUp != INVALID_LINE_VALUE && lineIdxDown >= linesIdxUp && lineIdxRight >= linesIdxUp && lineIdxLeft >= linesIdxUp && linesIdxUp < curLineIdx)
+ newDir = DIR_UP;
+ if (lineIdxRight != INVALID_LINE_VALUE && lineIdxDown >= lineIdxRight && linesIdxUp >= lineIdxRight && lineIdxLeft >= lineIdxRight && curLineIdx > lineIdxRight)
+ newDir = DIR_RIGHT;
+ if (lineIdxDown != INVALID_LINE_VALUE && linesIdxUp >= lineIdxDown && lineIdxRight >= lineIdxDown && lineIdxLeft >= lineIdxDown && curLineIdx > lineIdxDown)
+ newDir = DIR_DOWN;
+ if (lineIdxLeft != INVALID_LINE_VALUE && lineIdxDown >= lineIdxLeft && lineIdxRight >= lineIdxLeft && linesIdxUp >= lineIdxLeft && curLineIdx > lineIdxLeft)
+ newDir = DIR_LEFT;
+ }
+
+ switch(newDir) {
+ case DIR_UP:
+ newLinesIdx = linesIdxUp;
+ newLinesDataIdx = linesDataIdxUp;
+ for (int i = 0; i < stepVertDecCount; i++) {
+ if (checkCollisionLine(curX, curY - i, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxUp = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX, curY - i, curX, curY - stepVertDecCount, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxUp == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxUp;
+ if (_newPosY != -1)
+ i = _newPosY - curY;
+ }
+ _bestRoute[tmpRouteIdx].set(curX, curY - i, DIR_UP);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ case DIR_RIGHT:
+ newLinesIdx = lineIdxRight;
+ newLinesDataIdx = lineDataIdxRight;
+ for (int i = 0; i < stepHoriIncCount; i++) {
+ if (checkCollisionLine(i + curX, curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxRight = computeRouteIdx(linesIdxUp, linesDataIdxUp, i + curX, curY, stepHoriIncCount + curX, curY, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxRight == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxRight;
+ if (_newPosX != -1)
+ i = _newPosX - curX;
+ }
+ _bestRoute[tmpRouteIdx].set(i + curX, curY, DIR_RIGHT);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ case DIR_DOWN:
+ newLinesIdx = lineIdxDown;
+ newLinesDataIdx = lineDataIdxDown;
+ for (int i = 0; i < stepVertIncCount; i++) {
+ if (checkCollisionLine(curX, i + curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxDown = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX, i + curY, curX, stepVertIncCount + curY, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxDown == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxDown;
+ if (_newPosY != -1)
+ i = curY - _newPosY;
+ }
+ _bestRoute[tmpRouteIdx].set(curX, i + curY, DIR_DOWN);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ case DIR_LEFT:
+ newLinesIdx = lineIdxLeft;
+ newLinesDataIdx = lineDataIdxLeft;
+ for (int i = 0; i < stepHoriDecCount; i++) {
+ if (checkCollisionLine(curX - i, curY, &linesDataIdxUp, &linesIdxUp, _lastLine + 1, _linesNumb) && _lastLine < linesIdxUp) {
+ int tmpRouteIdxLeft = computeRouteIdx(linesIdxUp, linesDataIdxUp, curX - i, curY, curX - stepHoriDecCount, curY, tmpRouteIdx, &_bestRoute[0]);
+ if (tmpRouteIdxLeft == -1)
+ return false;
+ tmpRouteIdx = tmpRouteIdxLeft;
+ if (_newPosX != -1)
+ i = curX - _newPosX;
+ }
+ _bestRoute[tmpRouteIdx].set(curX - i, curY, DIR_LEFT);
+ tmpRouteIdx++;
+ }
+ _newLineIdx = newLinesIdx;
+ _newLineDataIdx = newLinesDataIdx;
+ _newRouteIdx = tmpRouteIdx;
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+int LinesManager::computeRouteIdx(int lineIdx, int dataIdx, int fromX, int fromY, int destX, int destY, int routerIdx, RouteItem *route) {
+ int result = routerIdx;
+ ++_pathFindingMaxDepth;
+ if (_pathFindingMaxDepth > 10) {
+ warning("PathFinding - Max depth reached");
+ route[routerIdx].invalidate();
+ return -1;
+ }
+ int lineX = _lineItem[lineIdx]._lineData[0];
+ int lineY = _lineItem[lineIdx]._lineData[1];
+ int startLineIdx = lineIdx;
+
+ int curLineDataEndIdx;
+ bool loopCond = false;
+ for (;;) {
+ int curLineIdx = startLineIdx - 1;
+ int endLineIdx = 2 * _lineItem[startLineIdx - 1]._lineDataEndIdx;
+
+ int16 *lineData = _lineItem[startLineIdx - 1]._lineData;
+ if (lineData == NULL)
+ break;
+ while (lineData[endLineIdx - 2] != lineX || lineY != lineData[endLineIdx - 1]) {
+ --curLineIdx;
+ if (_lastLine - 1 != curLineIdx) {
+ endLineIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ lineData = _lineItem[curLineIdx]._lineData;
+ if (lineData)
+ continue;
+ }
+ loopCond = true;
+ break;
+ }
+ if (loopCond)
+ break;
+
+ startLineIdx = curLineIdx;
+ lineX = lineData[0];
+ lineY = lineData[1];
+ }
+
+ int lastIdx = _lineItem[lineIdx]._lineDataEndIdx - 1;
+ int lastPosX = _lineItem[lineIdx]._lineData[(2 * lastIdx)];
+ int lastPosY = _lineItem[lineIdx]._lineData[(2 * lastIdx) + 1];
+ int endLineIdx = lineIdx;
+ int foundLineIdx, foundDataIdx;
+ loopCond = false;
+ for (;;) {
+ int curLineIdx = endLineIdx + 1;
+ int nextLineDataEndIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ int16 *lineData = _lineItem[curLineIdx]._lineData;
+ if (lineData == NULL)
+ break;
+ for (;;) {
+ curLineDataEndIdx = nextLineDataEndIdx;
+ if (lineData[0] == lastPosX && lastPosY == lineData[1])
+ break;
+
+ ++curLineIdx;
+ if (curLineIdx != _linesNumb + 1) {
+ nextLineDataEndIdx = 2 * _lineItem[curLineIdx]._lineDataEndIdx;
+ lineData = _lineItem[curLineIdx]._lineData;
+ if (lineData)
+ continue;
+ }
+ loopCond = true;
+ break;
+ }
+ if (loopCond)
+ break;
+
+ endLineIdx = curLineIdx;
+ lastPosX = lineData[curLineDataEndIdx - 2];
+ lastPosY = lineData[curLineDataEndIdx - 1];
+ }
+
+ int distX = abs(fromX - destX) + 1;
+ int distY = abs(fromY - destY) + 1;
+ int maxDist = distY;
+ if (distX > distY)
+ maxDist = distX;
+ int stepX = 1000 * distX / maxDist;
+ int stepY = 1000 * distY / maxDist;
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+ if (maxDist > 800)
+ maxDist = 800;
+
+ Common::fill(&_lineBuf[0], &_lineBuf[1000], 0);
+ int bugLigIdx = 0;
+ for (int i = 0; i < maxDist + 1; i++) {
+ _lineBuf[bugLigIdx] = smoothPosX / 1000;
+ _lineBuf[bugLigIdx + 1] = smoothPosY / 1000;
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ bugLigIdx += 2;
+ }
+ bugLigIdx -= 2;
+ int destDataIdx = 0;
+ int destLineIdx = -1;
+ int bufX = 0;
+ int bufY = 0;
+ for (int i = maxDist + 1; i > 0; i--) {
+ if (checkCollisionLine(_lineBuf[bugLigIdx], _lineBuf[bugLigIdx + 1], &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx) && _lastLine < foundLineIdx) {
+ destLineIdx = foundLineIdx;
+ destDataIdx = foundDataIdx;
+ bufX = _lineBuf[bugLigIdx];
+ bufY = _lineBuf[bugLigIdx + 1];
+ break;
+ }
+ bugLigIdx -= 2;
+ }
+ int maxLineX = 0;
+ int minLineX = 0;
+ int maxLineY = 0;
+ int minLineY = 0;
+ for (int i = startLineIdx; i <= endLineIdx; ++i) {
+ int16 *lineData = _lineItem[i]._lineData;
+ if (lineData == NULL)
+ error("error in genial routine");
+ if (i == startLineIdx) {
+ minLineY = MIN(lineData[1], lineData[2 * _lineItem[i]._lineDataEndIdx - 1]);
+ maxLineY = MAX(lineData[1], lineData[2 * _lineItem[i]._lineDataEndIdx - 1]);
+
+ minLineX = MIN(lineData[0], lineData[2 * _lineItem[i]._lineDataEndIdx - 2]);
+ maxLineX = MAX(lineData[0], lineData[2 * _lineItem[i]._lineDataEndIdx - 2]);
+ } else {
+ if (lineData[1] < lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] < minLineY)
+ minLineY = lineData[1];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < minLineY)
+ minLineY = lineData[2 * _lineItem[i]._lineDataEndIdx - 1];
+ if (lineData[1] > lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] > maxLineY)
+ maxLineY = lineData[1];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > maxLineY)
+ maxLineY = lineData[2 * _lineItem[i]._lineDataEndIdx - 1];
+ if (lineData[0] < lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && minLineX > lineData[0])
+ minLineX = lineData[0];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] < lineData[0] && minLineX > lineData[2 * _lineItem[i]._lineDataEndIdx - 2])
+ minLineX = lineData[2 * _lineItem[i]._lineDataEndIdx - 2];
+ if (lineData[0] > lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && maxLineX < lineData[0])
+ maxLineX = lineData[0];
+ if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] > lineData[0] && maxLineX < lineData[2 * _lineItem[i]._lineDataEndIdx - 2])
+ maxLineX = lineData[2 * _lineItem[i]._lineDataEndIdx - 2];
+ }
+ }
+
+ minLineX -= 2;
+ minLineY -= 2;
+ maxLineX += 2;
+ maxLineY += 2;
+ if (destX >= minLineX && destX <= maxLineX && destY >= minLineY && destY <= maxLineY) {
+ int curY = destY;
+ int linesIdxUp = -1;
+ for (;;) {
+ --curY;
+ if (!checkCollisionLine(destX, curY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+
+ linesIdxUp = foundLineIdx;
+ if (!curY || minLineY > curY)
+ break;
+ }
+ curY = destY;
+ int lineIdxDown = -1;
+ for (;;) {
+ ++curY;
+ if (!checkCollisionLine(destX, curY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+
+ lineIdxDown = foundLineIdx;
+ if (_vm->_globals->_characterMaxPosY <= curY || maxLineY <= curY)
+ break;
+ }
+ int curX = destX;
+ int lineIdxRight = -1;
+ for (;;) {
+ ++curX;
+ if (!checkCollisionLine(curX, destY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+
+ lineIdxRight = foundLineIdx;
+
+ if (_vm->_graphicsMan->_maxX <= curX || maxLineX <= curX)
+ break;
+ }
+ curX = destX;
+ int lineIdxLeft = -1;
+ for(;;) {
+ --curX;
+ if (!checkCollisionLine(curX, destY, &foundDataIdx, &foundLineIdx, startLineIdx, endLineIdx))
+ break;
+ lineIdxLeft = foundLineIdx;
+ if (curX <= 0 || minLineX >= curX)
+ break;
+ }
+ if (lineIdxRight != -1 && lineIdxLeft != -1 && linesIdxUp != -1 && lineIdxDown != -1) {
+ route[routerIdx].invalidate();
+ return -1;
+ }
+ }
+ if (bufX < fromX - 1 || bufX > fromX + 1 || bufY < fromY - 1 || bufY > fromY + 1) {
+ _newPosX = bufX;
+ _newPosY = bufY;
+ if (lineIdx < destLineIdx) {
+ int stepCount = 0;
+ int curLineIdx = lineIdx;
+ do {
+ if (curLineIdx == startLineIdx - 1)
+ curLineIdx = endLineIdx;
+ ++stepCount;
+ --curLineIdx;
+ if (curLineIdx == startLineIdx - 1)
+ curLineIdx = endLineIdx;
+ } while (destLineIdx != curLineIdx);
+ if (abs(destLineIdx - lineIdx) == stepCount) {
+ if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) {
+ result = avoidObstacle(lineIdx, dataIdx, routerIdx, destLineIdx, destDataIdx, route);
+ } else {
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, routerIdx, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ }
+ }
+ if (abs(destLineIdx - lineIdx) < stepCount)
+ result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
+ if (stepCount < abs(destLineIdx - lineIdx))
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ }
+ if (lineIdx > destLineIdx) {
+ int destStepCount = abs(lineIdx - destLineIdx);
+ int curLineIdx = lineIdx;
+ int curStepCount = 0;
+ do {
+ if (curLineIdx == endLineIdx + 1)
+ curLineIdx = startLineIdx;
+ ++curStepCount;
+ ++curLineIdx;
+ if (curLineIdx == endLineIdx + 1)
+ curLineIdx = startLineIdx;
+ } while (destLineIdx != curLineIdx);
+ if (destStepCount == curStepCount) {
+ if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) {
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ } else {
+ result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
+ }
+ }
+ if (destStepCount < curStepCount)
+ result = avoidObstacle(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route);
+ if (curStepCount < destStepCount)
+ result = avoidObstacleOnSegment(lineIdx, dataIdx, result, destLineIdx, destDataIdx, route, startLineIdx, endLineIdx);
+ }
+ if (lineIdx == destLineIdx)
+ result = avoidObstacle(lineIdx, dataIdx, result, lineIdx, destDataIdx, route);
+ for(;;) {
+ if (!checkCollisionLine(_newPosX, _newPosY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb))
+ break;
+
+ switch (_lineItem[foundLineIdx]._direction) {
+ case DIR_UP:
+ --_newPosY;
+ break;
+ case DIR_UP_RIGHT:
+ --_newPosY;
+ ++_newPosX;
+ break;
+ case DIR_RIGHT:
+ ++_newPosX;
+ break;
+ case DIR_DOWN_RIGHT:
+ ++_newPosY;
+ ++_newPosX;
+ break;
+ case DIR_DOWN:
+ ++_newPosY;
+ break;
+ case DIR_DOWN_LEFT:
+ ++_newPosY;
+ --_newPosX;
+ break;
+ case DIR_LEFT:
+ --_newPosX;
+ break;
+ case DIR_UP_LEFT:
+ --_newPosY;
+ --_newPosX;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ _newPosX = -1;
+ _newPosY = -1;
+ }
+ return result;
+}
+
+// Find Route from a point to the other
+RouteItem *LinesManager::findRoute(int fromX, int fromY, int destX, int destY) {
+ int foundLineIdx;
+ int foundDataIdx;
+ int curLineY = 0;
+ int curLineX = 0;
+ int stepArr[9];
+ int deltaArr[9];
+ int collLineDataIdxArr[9];
+ int collLineIdxArr[9];
+
+ int clipDestX = destX;
+ int clipDestY = destY;
+ int curLineIdx = 0;
+ int curLineDataIdx = 0;
+ int lineIdx = 0;
+ int lineDataIdx = 0;
+ Directions newDir = DIR_NONE;
+ if (destY <= 24)
+ clipDestY = 25;
+ if (!_vm->_globals->_checkDistanceFl) {
+ if (abs(fromX - _oldRouteFromX) <= 4 && abs(fromY - _oldRouteFromY) <= 4 &&
+ abs(_oldRouteDestX - destX) <= 4 && abs(_oldRouteDestY - clipDestY) <= 4)
+ return NULL;
+
+ if (abs(fromX - destX) <= 4 && abs(fromY - clipDestY) <= 4)
+ return NULL;
+
+ if (_oldZoneNum > 0 && _vm->_objectsMan->_zoneNum > 0 && _oldZoneNum == _vm->_objectsMan->_zoneNum)
+ return NULL;
+ }
+ _vm->_globals->_checkDistanceFl = false;
+ _oldZoneNum = _vm->_objectsMan->_zoneNum;
+ _oldRouteFromX = fromX;
+ _oldRouteDestX = destX;
+ _oldRouteFromY = fromY;
+ _oldRouteDestY = clipDestY;
+ _pathFindingMaxDepth = 0;
+ int routeIdx = 0;
+ if (destX <= 19)
+ clipDestX = 20;
+ if (clipDestY <= 19)
+ clipDestY = 20;
+ if (clipDestX > _vm->_graphicsMan->_maxX - 10)
+ clipDestX = _vm->_graphicsMan->_maxX - 10;
+ if (clipDestY > _vm->_globals->_characterMaxPosY)
+ clipDestY = _vm->_globals->_characterMaxPosY;
+
+ if (abs(fromX - clipDestX) <= 3 && abs(fromY - clipDestY) <= 3)
+ return NULL;
+
+ for (int i = 0; i <= 8; ++i) {
+ collLineIdxArr[i] = -1;
+ collLineDataIdxArr[i] = 0;
+ deltaArr[i] = INVALID_LINE_VALUE;
+ stepArr[i] = INVALID_LINE_VALUE;
+ }
+
+ if (characterRoute(fromX, fromY, clipDestX, clipDestY, -1, -1, 0) == 1)
+ return _bestRoute;
+
+ int tmpDelta = 0;
+ for (int tmpY = clipDestY; tmpY < _vm->_graphicsMan->_maxY; tmpY++, tmpDelta++) {
+ if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[DIR_DOWN], &collLineIdxArr[DIR_DOWN], 0, _lastLine) && collLineIdxArr[DIR_DOWN] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_DOWN] = 0;
+ collLineIdxArr[DIR_DOWN] = -1;
+ }
+ deltaArr[DIR_DOWN] = tmpDelta;
+
+ tmpDelta = 0;
+ for (int tmpY = clipDestY; tmpY > _vm->_graphicsMan->_minY; tmpY--, tmpDelta++) {
+ if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[DIR_UP], &collLineIdxArr[DIR_UP], 0, _lastLine) && collLineIdxArr[DIR_UP] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_UP] = 0;
+ collLineIdxArr[DIR_UP] = -1;
+ if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
+ break;
+ }
+ deltaArr[DIR_UP] = tmpDelta;
+
+ tmpDelta = 0;
+ for (int tmpX = clipDestX; tmpX < _vm->_graphicsMan->_maxX; tmpX++) {
+ if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[DIR_RIGHT], &collLineIdxArr[DIR_RIGHT], 0, _lastLine) && collLineIdxArr[DIR_RIGHT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_RIGHT] = 0;
+ collLineIdxArr[DIR_RIGHT] = -1;
+ ++tmpDelta;
+ if (deltaArr[DIR_UP] < tmpDelta && collLineIdxArr[DIR_UP] != -1)
+ break;
+ if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
+ break;
+ }
+ deltaArr[DIR_RIGHT] = tmpDelta;
+
+ tmpDelta = 0;
+ for (int tmpX = clipDestX; tmpX > _vm->_graphicsMan->_minX; tmpX--) {
+ if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[DIR_LEFT], &collLineIdxArr[DIR_LEFT], 0, _lastLine) && collLineIdxArr[DIR_LEFT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_LEFT] = 0;
+ collLineIdxArr[DIR_LEFT] = -1;
+ ++tmpDelta;
+ if (deltaArr[DIR_UP] < tmpDelta && collLineIdxArr[DIR_UP] != -1)
+ break;
+ if (deltaArr[DIR_DOWN] < tmpDelta && collLineIdxArr[DIR_DOWN] != -1)
+ break;
+ if (deltaArr[DIR_RIGHT] < tmpDelta && collLineIdxArr[DIR_RIGHT] != -1)
+ break;
+ }
+ deltaArr[DIR_LEFT] = tmpDelta;
+
+ if (collLineIdxArr[DIR_UP] < 0 || _lastLine < collLineIdxArr[DIR_UP])
+ collLineIdxArr[DIR_UP] = -1;
+ if (collLineIdxArr[DIR_RIGHT] < 0 || _lastLine < collLineIdxArr[DIR_RIGHT])
+ collLineIdxArr[DIR_RIGHT] = -1;
+ if (collLineIdxArr[DIR_DOWN] < 0 || _lastLine < collLineIdxArr[DIR_DOWN])
+ collLineIdxArr[DIR_DOWN] = -1;
+ if (collLineIdxArr[DIR_LEFT] < 0 || _lastLine < collLineIdxArr[DIR_LEFT])
+ collLineIdxArr[DIR_LEFT] = -1;
+ if (collLineIdxArr[DIR_UP] < 0)
+ deltaArr[DIR_UP] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_RIGHT] < 0)
+ deltaArr[DIR_RIGHT] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_DOWN] < 0)
+ deltaArr[DIR_DOWN] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_LEFT] < 0)
+ deltaArr[DIR_LEFT] = INVALID_LINE_VALUE;
+ if (collLineIdxArr[DIR_UP] == -1 && collLineIdxArr[DIR_RIGHT] == -1 && collLineIdxArr[DIR_DOWN] == -1 && collLineIdxArr[DIR_LEFT] == -1)
+ return NULL;
+
+ if (collLineIdxArr[DIR_DOWN] != -1 && deltaArr[DIR_UP] >= deltaArr[DIR_DOWN] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_DOWN] && deltaArr[DIR_LEFT] >= deltaArr[DIR_DOWN]) {
+ curLineIdx = collLineIdxArr[DIR_DOWN];
+ curLineDataIdx = collLineDataIdxArr[DIR_DOWN];
+ } else if (collLineIdxArr[DIR_UP] != -1 && deltaArr[DIR_DOWN] >= deltaArr[DIR_UP] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_UP] && deltaArr[DIR_LEFT] >= deltaArr[DIR_UP]) {
+ curLineIdx = collLineIdxArr[DIR_UP];
+ curLineDataIdx = collLineDataIdxArr[DIR_UP];
+ } else if (collLineIdxArr[DIR_RIGHT] != -1 && deltaArr[DIR_UP] >= deltaArr[DIR_RIGHT] && deltaArr[DIR_DOWN] >= deltaArr[DIR_RIGHT] && deltaArr[DIR_LEFT] >= deltaArr[DIR_RIGHT]) {
+ curLineIdx = collLineIdxArr[DIR_RIGHT];
+ curLineDataIdx = collLineDataIdxArr[DIR_RIGHT];
+ } else if (collLineIdxArr[DIR_LEFT] != -1 && deltaArr[DIR_DOWN] >= deltaArr[DIR_LEFT] && deltaArr[DIR_RIGHT] >= deltaArr[DIR_LEFT] && deltaArr[DIR_UP] >= deltaArr[DIR_LEFT]) {
+ curLineIdx = collLineIdxArr[DIR_LEFT];
+ curLineDataIdx = collLineDataIdxArr[DIR_LEFT];
+ }
+
+ for (int i = 0; i <= 8; ++i) {
+ collLineIdxArr[i] = -1;
+ collLineDataIdxArr[i] = 0;
+ deltaArr[i] = INVALID_LINE_VALUE;
+ stepArr[i] = INVALID_LINE_VALUE;
+ }
+
+ tmpDelta = 0;
+ for (int tmpY = fromY; tmpY < _vm->_graphicsMan->_maxY; tmpY++, tmpDelta++) {
+ if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[DIR_DOWN], &collLineIdxArr[DIR_DOWN], 0, _lastLine) && collLineIdxArr[DIR_DOWN] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_DOWN] = 0;
+ collLineIdxArr[DIR_DOWN] = -1;
+ }
+ deltaArr[DIR_DOWN] = tmpDelta + 1;
+
+ tmpDelta = 0;
+ for (int tmpY = fromY; tmpY > _vm->_graphicsMan->_minY; tmpY--) {
+ if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[DIR_UP], &collLineIdxArr[DIR_UP], 0, _lastLine) && collLineIdxArr[DIR_UP] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_UP] = 0;
+ collLineIdxArr[DIR_UP] = -1;
+ ++tmpDelta;
+ if (collLineIdxArr[DIR_DOWN] != -1 && tmpDelta > 80)
+ break;
+ }
+ deltaArr[DIR_UP] = tmpDelta + 1;
+
+ tmpDelta = 0;
+ for (int tmpX = fromX; tmpX < _vm->_graphicsMan->_maxX; tmpX++) {
+ if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[DIR_RIGHT], &collLineIdxArr[DIR_RIGHT], 0, _lastLine) && collLineIdxArr[DIR_RIGHT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_RIGHT] = 0;
+ collLineIdxArr[DIR_RIGHT] = -1;
+ ++tmpDelta;
+ if ((collLineIdxArr[DIR_DOWN] != -1 || collLineIdxArr[DIR_UP] != -1) && (tmpDelta > 100))
+ break;
+ }
+ deltaArr[DIR_RIGHT] = tmpDelta + 1;
+
+ tmpDelta = 0;
+ for (int tmpX = fromX; tmpX > _vm->_graphicsMan->_minX; tmpX--) {
+ if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[DIR_LEFT], &collLineIdxArr[DIR_LEFT], 0, _lastLine) && collLineIdxArr[DIR_LEFT] <= _lastLine)
+ break;
+ collLineDataIdxArr[DIR_LEFT] = 0;
+ collLineIdxArr[DIR_LEFT] = -1;
+ ++tmpDelta;
+ if ((collLineIdxArr[DIR_DOWN] != -1 || collLineIdxArr[DIR_UP] != -1 || collLineIdxArr[DIR_RIGHT] != -1) && (tmpDelta > 100))
+ break;
+ }
+ deltaArr[DIR_LEFT] = tmpDelta + 1;
+
+ if (collLineIdxArr[DIR_UP] != -1)
+ stepArr[DIR_UP] = abs(collLineIdxArr[DIR_UP] - curLineIdx);
+
+ if (collLineIdxArr[DIR_RIGHT] != -1)
+ stepArr[DIR_RIGHT] = abs(collLineIdxArr[DIR_RIGHT] - curLineIdx);
+
+ if (collLineIdxArr[DIR_DOWN] != -1)
+ stepArr[DIR_DOWN] = abs(collLineIdxArr[DIR_DOWN] - curLineIdx);
+
+ if (collLineIdxArr[DIR_LEFT] != -1)
+ stepArr[DIR_LEFT] = abs(collLineIdxArr[DIR_LEFT] - curLineIdx);
+
+ if (collLineIdxArr[DIR_UP] == -1 && collLineIdxArr[DIR_RIGHT] == -1 && collLineIdxArr[DIR_DOWN] == -1 && collLineIdxArr[DIR_LEFT] == -1)
+ error("Nearest point not found");
+
+ int delta = 0;
+ if (collLineIdxArr[DIR_UP] != -1 && stepArr[DIR_RIGHT] >= stepArr[DIR_UP] && stepArr[DIR_DOWN] >= stepArr[DIR_UP] && stepArr[DIR_LEFT] >= stepArr[DIR_UP]) {
+ lineIdx = collLineIdxArr[DIR_UP];
+ delta = deltaArr[DIR_UP];
+ newDir = DIR_UP;
+ lineDataIdx = collLineDataIdxArr[DIR_UP];
+ } else if (collLineIdxArr[DIR_DOWN] != -1 && stepArr[DIR_RIGHT] >= stepArr[DIR_DOWN] && stepArr[DIR_UP] >= stepArr[DIR_DOWN] && stepArr[DIR_LEFT] >= stepArr[DIR_DOWN]) {
+ lineIdx = collLineIdxArr[DIR_DOWN];
+ delta = deltaArr[DIR_DOWN];
+ newDir = DIR_DOWN;
+ lineDataIdx = collLineDataIdxArr[DIR_DOWN];
+ } else if (collLineIdxArr[DIR_RIGHT] != -1 && stepArr[DIR_UP] >= stepArr[DIR_RIGHT] && stepArr[DIR_DOWN] >= stepArr[DIR_RIGHT] && stepArr[DIR_LEFT] >= stepArr[DIR_RIGHT]) {
+ lineIdx = collLineIdxArr[DIR_RIGHT];
+ delta = deltaArr[DIR_RIGHT];
+ newDir = DIR_RIGHT;
+ lineDataIdx = collLineDataIdxArr[DIR_RIGHT];
+ } else if (collLineIdxArr[DIR_LEFT] != -1 && stepArr[DIR_UP] >= stepArr[DIR_LEFT] && stepArr[DIR_DOWN] >= stepArr[DIR_LEFT] && stepArr[DIR_RIGHT] >= stepArr[DIR_LEFT]) {
+ lineIdx = collLineIdxArr[DIR_LEFT];
+ delta = deltaArr[DIR_LEFT];
+ newDir = DIR_LEFT;
+ lineDataIdx = collLineDataIdxArr[DIR_LEFT];
+ }
+
+ int bestRouteNum = characterRoute(fromX, fromY, clipDestX, clipDestY, lineIdx, curLineIdx, 0);
+
+ if (bestRouteNum == 1)
+ return _bestRoute;
+
+ if (bestRouteNum == 2) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ } else {
+ switch (newDir) {
+ case DIR_UP:
+ for (int deltaY = 0; deltaY < delta; deltaY++) {
+ if (checkCollisionLine(fromX, fromY - deltaY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX, fromY - deltaY, fromX, fromY - delta, routeIdx, _bestRoute);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosY != -1)
+ deltaY = fromY - _newPosY;
+ }
+ _bestRoute[routeIdx].set(fromX, fromY - deltaY, DIR_UP);
+ routeIdx++;
+ }
+ break;
+ case DIR_DOWN:
+ for (int deltaY = 0; deltaY < delta; deltaY++) {
+ if (checkCollisionLine(fromX, deltaY + fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb)
+ && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX, deltaY + fromY, fromX, delta + fromY, routeIdx, &_bestRoute[0]);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosY != -1)
+ deltaY = _newPosY - fromY;
+ }
+ _bestRoute[routeIdx].set(fromX, fromY + deltaY, DIR_DOWN);
+ routeIdx++;
+ }
+ break;
+ case DIR_LEFT:
+ for (int deltaX = 0; deltaX < delta; deltaX++) {
+ if (checkCollisionLine(fromX - deltaX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, fromX - deltaX, fromY, fromX - delta, fromY, routeIdx, &_bestRoute[0]);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosX != -1)
+ deltaX = fromX - _newPosX;
+ }
+ _bestRoute[routeIdx].set(fromX - deltaX, fromY, DIR_LEFT);
+ routeIdx++;
+ }
+ break;
+ case DIR_RIGHT:
+ for (int deltaX = 0; deltaX < delta; deltaX++) {
+ if (checkCollisionLine(deltaX + fromX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) {
+ int tmpRouteIdx = computeRouteIdx(foundLineIdx, foundDataIdx, deltaX + fromX, fromY, delta + fromX, fromY, routeIdx, &_bestRoute[0]);
+ if (tmpRouteIdx == -1) {
+ _bestRoute[routeIdx].invalidate();
+ return &_bestRoute[0];
+ }
+ routeIdx = tmpRouteIdx;
+ if (_newPosX != -1)
+ deltaX = _newPosX - fromX;
+ }
+ _bestRoute[routeIdx].set(fromX + deltaX, fromY, DIR_RIGHT);
+ routeIdx++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool loopCond;
+ do {
+ loopCond = false;
+ if (lineIdx < curLineIdx) {
+ for (int i = lineDataIdx; _lineItem[lineIdx]._lineDataEndIdx > i; ++i) {
+ curLineX = _lineItem[lineIdx]._lineData[2 * i];
+ curLineY = _lineItem[lineIdx]._lineData[2 * i + 1];
+ _bestRoute[routeIdx].set(_lineItem[lineIdx]._lineData[2 * i], _lineItem[lineIdx]._lineData[2 * i + 1], _lineItem[lineIdx]._directionRouteInc);
+ routeIdx++;
+ }
+ for (int idx = lineIdx + 1; idx < curLineIdx; idx++) {
+ for (int dataIdx = 0; _lineItem[idx]._lineDataEndIdx > dataIdx; dataIdx++) {
+ curLineX = _lineItem[idx]._lineData[2 * dataIdx];
+ curLineY = _lineItem[idx]._lineData[2 * dataIdx + 1];
+ _bestRoute[routeIdx].set(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], _lineItem[idx]._directionRouteInc);
+ routeIdx++;
+ if (_lineItem[idx]._lineDataEndIdx > 30 && dataIdx == _lineItem[idx]._lineDataEndIdx / 2) {
+ bestRouteNum = characterRoute(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], clipDestX, clipDestY, idx, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+ }
+
+ if (loopCond)
+ break;
+
+ bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, idx, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+ if (loopCond)
+ continue;
+
+ lineDataIdx = 0;
+ lineIdx = curLineIdx;
+ }
+ if (lineIdx > curLineIdx) {
+ for (int dataIdx = lineDataIdx; dataIdx > 0; dataIdx--) {
+ curLineX = _lineItem[lineIdx]._lineData[2 * dataIdx];
+ curLineY = _lineItem[lineIdx]._lineData[2 * dataIdx + 1];
+
+ _bestRoute[routeIdx].set(_lineItem[lineIdx]._lineData[2 * dataIdx], _lineItem[lineIdx]._lineData[2 * dataIdx + 1], _lineItem[lineIdx]._directionRouteDec);
+ routeIdx++;
+ }
+ for (int i = lineIdx - 1; i > curLineIdx; i--) {
+ for (int dataIdx = _lineItem[i]._lineDataEndIdx - 1; dataIdx > -1; dataIdx--) {
+ curLineX = _lineItem[i]._lineData[2 * dataIdx];
+ curLineY = _lineItem[i]._lineData[2 * dataIdx + 1];
+ _bestRoute[routeIdx].set(_lineItem[i]._lineData[2 * dataIdx], _lineItem[i]._lineData[2 * dataIdx + 1], _lineItem[i]._directionRouteDec);
+ routeIdx++;
+ if (_lineItem[i]._lineDataEndIdx > 30 && dataIdx == _lineItem[i]._lineDataEndIdx / 2) {
+ bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, i, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, i, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+ }
+
+ if (loopCond)
+ break;
+
+ bestRouteNum = characterRoute(curLineX, curLineY, clipDestX, clipDestY, i, curLineIdx, routeIdx);
+ if (bestRouteNum == 1)
+ return &_bestRoute[0];
+ if (bestRouteNum == 2 || MIRACLE(curLineX, curLineY, i, curLineIdx, routeIdx)) {
+ lineIdx = _newLineIdx;
+ lineDataIdx = _newLineDataIdx;
+ routeIdx = _newRouteIdx;
+ loopCond = true;
+ break;
+ }
+ }
+
+ if (!loopCond) {
+ lineDataIdx = _lineItem[curLineIdx]._lineDataEndIdx - 1;
+ lineIdx = curLineIdx;
+ }
+ }
+ } while (loopCond);
+
+ if (lineIdx == curLineIdx) {
+ if (lineDataIdx <= curLineDataIdx)
+ routeIdx = _lineItem[curLineIdx].appendToRouteInc(lineDataIdx, curLineDataIdx, _bestRoute, routeIdx);
+ else
+ routeIdx = _lineItem[curLineIdx].appendToRouteDec(lineDataIdx, curLineDataIdx, _bestRoute, routeIdx);
+ }
+ if (characterRoute(_bestRoute[routeIdx - 1]._x, _bestRoute[routeIdx - 1]._y, clipDestX, clipDestY, -1, -1, routeIdx) != 1) {
+ _bestRoute[routeIdx].invalidate();
+ }
+
+ return &_bestRoute[0];
+}
+
+void LinesManager::useRoute0(int idx, int curRouteIdx) {
+ if (idx) {
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute0[i++];
+ } while (_testRoute0[i].isValid());
+ }
+ _bestRoute[curRouteIdx].invalidate();
+}
+
+void LinesManager::useRoute1(int idx, int curRouteIdx) {
+ if (idx) {
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute1[i++];
+ } while (_testRoute1[i].isValid());
+ }
+ _bestRoute[curRouteIdx].invalidate();
+}
+
+void LinesManager::useRoute2(int idx, int curRouteIdx) {
+ if (idx) {
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute2[i++];
+ } while (_testRoute2[i].isValid());
+ }
+ _bestRoute[curRouteIdx].invalidate();
+}
+
+int LinesManager::characterRoute(int fromX, int fromY, int destX, int destY, int startLineIdx, int endLineIdx, int routeIdx) {
+ int collDataIdxRoute2 = 0;
+ bool colResult = false;
+
+ int curX = fromX;
+ int curY = fromY;
+ int curRouteIdx = routeIdx;
+ bool dummyLineFl = false;
+ if (startLineIdx == -1 && endLineIdx == -1)
+ dummyLineFl = true;
+ int foundDataIdx;
+ int foundLineIdx = startLineIdx;
+ if (checkCollisionLine(fromX, fromY, &foundDataIdx, &foundLineIdx, 0, _linesNumb)) {
+ switch (_lineItem[foundLineIdx]._direction) {
+ case DIR_UP:
+ curY -= 2;
+ break;
+ case DIR_UP_RIGHT:
+ curY -= 2;
+ curX += 2;
+ break;
+ case DIR_RIGHT:
+ curX += 2;
+ break;
+ case DIR_DOWN_RIGHT:
+ curY += 2;
+ curX += 2;
+ case DIR_DOWN:
+ curY += 2;
+ break;
+ case DIR_DOWN_LEFT:
+ curY += 2;
+ curX -= 2;
+ break;
+ case DIR_LEFT:
+ curX -= 2;
+ break;
+ case DIR_UP_LEFT:
+ curY -= 2;
+ curX -= 2;
+ break;
+ default:
+ break;
+ }
+ }
+ int oldX = curX;
+ int oldY = curY;
+ int idxRoute0 = 0;
+ int collLineIdxRoute0 = -1;
+ int collLineIdxRoute1 = -1;
+ int collLineIdxRoute2 = -1;
+
+ int distX, distY;
+ int repeatFlag = 0;
+ int collDataIdxRoute0 = 0;
+ int collDataIdxRoute1 = 0;
+ for (;;) {
+ int newX = curX;
+ int newY = curY;
+ if (destX >= curX - 2 && destX <= curX + 2 && destY >= curY - 2 && destY <= curY + 2) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ distX = abs(curX - destX) + 1;
+ distY = abs(curY - destY) + 1;
+ int maxDist;
+ if (distX > distY)
+ maxDist = distX;
+ else
+ maxDist = distY;
+ maxDist--;
+ assert(maxDist != 0);
+ int stepX = 1000 * distX / maxDist;
+ int stepY = 1000 * distY / maxDist;
+ if (destX < curX)
+ stepX = -stepX;
+ if (destY < curY)
+ stepY = -stepY;
+ int vertDirection = (int16)stepX / 1000;
+ int horzDirection = (int16)stepY / 1000;
+ Directions newDirection = DIR_NONE;
+ if (horzDirection == -1 && (stepX >= 0 && stepX <= 150))
+ newDirection = DIR_UP;
+ if (vertDirection == 1 && (stepY >= -1 && stepY <= 150))
+ newDirection = DIR_RIGHT;
+ if (horzDirection == 1 && (stepX >= -150 && stepX <= 150))
+ newDirection = DIR_DOWN;
+ if (vertDirection == -1 && (stepY >= -150 && stepY <= 150))
+ newDirection = DIR_LEFT;
+ if (horzDirection == -1 && (stepX >= -150 && stepX <= 0))
+ newDirection = DIR_UP;
+
+ if (newDirection == DIR_NONE && !checkSmoothMove(curX, newY, destX, destY) && !makeSmoothMove(curX, newY, destX, destY)) {
+ newDirection = _smoothMoveDirection;
+ int smoothRouteIdx = 0;
+ for (smoothRouteIdx = 0; _smoothRoute[smoothRouteIdx]._posX != -1 && _smoothRoute[smoothRouteIdx]._posY != -1; ++smoothRouteIdx) {
+ if (checkCollisionLine(_smoothRoute[smoothRouteIdx]._posX, _smoothRoute[smoothRouteIdx]._posY, &collDataIdxRoute0, &collLineIdxRoute0, 0, _linesNumb)) {
+ if (collLineIdxRoute0 > _lastLine)
+ collLineIdxRoute0 = -1;
+ break;
+ }
+
+ _testRoute0[idxRoute0].set(_smoothRoute[smoothRouteIdx]._posX, _smoothRoute[smoothRouteIdx]._posY, newDirection);
+ idxRoute0++;
+
+ if (repeatFlag == 1) {
+ repeatFlag = 2;
+ break;
+ }
+ }
+
+ if (repeatFlag != 2 && _smoothRoute[smoothRouteIdx]._posX != -1 && _smoothRoute[smoothRouteIdx]._posY != -1)
+ break;
+
+ repeatFlag = 1;
+ newX = _smoothRoute[smoothRouteIdx - 1]._posX;
+ newY = _smoothRoute[smoothRouteIdx - 1]._posY;
+ }
+ int newDistX = abs(newX - destX) + 1;
+ int newDistY = abs(newY - destY) + 1;
+ int newMaxDist = newDistY;
+ if (newDistX > newDistY)
+ newMaxDist = newDistX;
+ if (newMaxDist <= 10) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ int newStepX = 1000 * newDistX / (newMaxDist - 1);
+ int newStepY = 1000 * newDistY / (newMaxDist - 1);
+ if (destX < newX)
+ newStepX = -newStepX;
+ if (destY < newY)
+ newStepY = -newStepY;
+ int newVertDirection = newStepX / 1000;
+ int newHorzDirection = newStepY / 1000;
+ int newSmoothX = 1000 * newX;
+ int newSmoothY = 1000 * newY;
+ int curPosX = newSmoothX / 1000;
+ int curPosY = newSmoothY / 1000;
+ if (!(newStepX / 1000) && newHorzDirection == -1)
+ newDirection = DIR_UP;
+ if (newVertDirection == 1) {
+ if (newHorzDirection == -1)
+ newDirection = DIR_UP_RIGHT;
+ if (!newHorzDirection)
+ newDirection = DIR_RIGHT;
+ if (newHorzDirection == 1)
+ newDirection = DIR_DOWN_RIGHT;
+ }
+ if (!newVertDirection && newHorzDirection == 1)
+ newDirection = DIR_DOWN;
+ if ((newVertDirection != -1) && (newHorzDirection == -1)) {
+ if (newStepX >= 0 && newStepX < 510)
+ newDirection = DIR_UP;
+ else if (newStepX >= 510 && newStepX <= 1000)
+ newDirection = DIR_UP_RIGHT;
+ } else {
+ if (newHorzDirection == 1)
+ newDirection = DIR_DOWN_LEFT;
+ else if (!newHorzDirection)
+ newDirection = DIR_LEFT;
+ else if (newHorzDirection == -1) {
+ if (newStepX >= 0 && newStepX < 510)
+ newDirection = DIR_UP;
+ else if (newStepX >= 510 && newStepX <= 1000)
+ newDirection = DIR_UP_RIGHT;
+ else
+ newDirection = DIR_UP_LEFT;
+ }
+ }
+ if (newVertDirection == 1) {
+ if (newStepY >= -1000 && newStepY <= -510)
+ newDirection = DIR_UP_RIGHT;
+ if (newStepY >= -510 && newStepY <= 510)
+ newDirection = DIR_RIGHT;
+ if (newStepY >= 510 && newStepY <= 1000)
+ newDirection = DIR_DOWN_RIGHT;
+ }
+ if (newHorzDirection == 1) {
+ if (newStepX >= 510 && newStepX <= 1000)
+ newDirection = DIR_DOWN_RIGHT;
+ if (newStepX >= -510 && newStepX <= 510)
+ newDirection = DIR_DOWN;
+ if (newStepX >= -1000 && newStepX <= -510)
+ newDirection = DIR_DOWN_LEFT;
+ }
+ if (newVertDirection == -1) {
+ if (newStepY >= 510 && newStepY <= 1000)
+ newDirection = DIR_DOWN_LEFT;
+ if (newStepY >= -510 && newStepY <= 510)
+ newDirection = DIR_LEFT;
+ if (newStepY >= -1000 && newStepY <= -510)
+ newDirection = DIR_UP_LEFT;
+ }
+ if (newHorzDirection == -1) {
+ if (newStepX >= -1000 && newStepX <= -510)
+ newDirection = DIR_UP_LEFT;
+ if (newStepX >= -510 && newStepX <= 0)
+ newDirection = DIR_UP;
+ }
+ if (newMaxDist + 1 <= 0) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ int curDist = 0;
+ while (!checkCollisionLine(curPosX, curPosY, &collDataIdxRoute0, &collLineIdxRoute0, 0, _linesNumb)) {
+ _testRoute0[idxRoute0].set(curPosX, curPosY, newDirection);
+ newSmoothX += newStepX;
+ newSmoothY += newStepY;
+ curPosX = newSmoothX / 1000;
+ curPosY = newSmoothY / 1000;
+ idxRoute0++;
+ ++curDist;
+ if (curDist >= newMaxDist + 1) {
+ _testRoute0[idxRoute0].invalidate();
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ }
+ if (_lastLine >= collLineIdxRoute0)
+ break;
+ int tmpRouteIdx = computeRouteIdx(collLineIdxRoute0, collDataIdxRoute0, curPosX, curPosY, destX, destY, idxRoute0, _testRoute0);
+ if (tmpRouteIdx == -1) {
+ useRoute0(idxRoute0, curRouteIdx);
+ return 1;
+ }
+ idxRoute0 = tmpRouteIdx;
+ if (_newPosX != -1 || _newPosY != -1) {
+ collLineIdxRoute0 = -1;
+ break;
+ }
+ curX = -1;
+ curY = -1;
+ }
+
+ _testRoute0[idxRoute0].invalidate();
+
+ int idxRoute1 = 0;
+ int posXRoute1 = oldX;
+ int posYRoute1 = oldY;
+
+ while (true) {
+
+ if (destX >= posXRoute1 - 2 && destX <= posXRoute1 + 2 && destY >= posYRoute1 - 2 && destY <= posYRoute1 + 2) {
+ _testRoute1[idxRoute1].invalidate();
+ useRoute1(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ while (posXRoute1 != destX) {
+ if (checkCollisionLine(posXRoute1, posYRoute1, &collDataIdxRoute1, &collLineIdxRoute1, 0, _linesNumb)) {
+ if (collLineIdxRoute1 > _lastLine)
+ collLineIdxRoute1 = -1;
+ break;
+ }
+
+ if (posXRoute1 < destX)
+ _testRoute1[idxRoute1++].set(posXRoute1++, posYRoute1, DIR_RIGHT);
+ else
+ _testRoute1[idxRoute1++].set(posXRoute1--, posYRoute1, DIR_LEFT);
+ }
+ if (posXRoute1 != destX)
+ break;
+
+ int curPosY = posYRoute1;
+ while (curPosY != destY) {
+ if (checkCollisionLine(destX, curPosY, &collDataIdxRoute1, &collLineIdxRoute1, 0, _linesNumb)) {
+ if (collLineIdxRoute1 <= _lastLine)
+ break;
+
+ int tmpRouteIdx = computeRouteIdx(collLineIdxRoute1, collDataIdxRoute1, destX, curPosY, destX, destY, idxRoute1, _testRoute1);
+ if (tmpRouteIdx == -1) {
+ useRoute1(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ idxRoute1 = tmpRouteIdx;
+ if (_newPosX != -1 && _newPosY != -1)
+ break;
+ }
+
+ if (curPosY < destY)
+ _testRoute1[idxRoute1++].set(destX, curPosY++, DIR_DOWN);
+ else
+ _testRoute1[idxRoute1++].set(destX, curPosY--, DIR_UP);
+ }
+ if (curPosY == destY) {
+ _testRoute1[idxRoute1].invalidate();
+ useRoute1(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ if (collLineIdxRoute1 <= _lastLine)
+ break;
+ posXRoute1 = _newPosX;
+ posYRoute1 = _newPosY;
+ bool colRes = checkCollisionLine(_newPosX, _newPosY, &collDataIdxRoute1, &collLineIdxRoute1, 0, _lastLine);
+ if (colRes && collLineIdxRoute1 <= _lastLine)
+ break;
+ }
+
+ _testRoute1[idxRoute1].invalidate();
+ idxRoute1 = 0;
+ int posXRoute2 = oldX;
+ int posYRoute2 = oldY;
+ while (true) {
+ int curPosX;
+ if (destX >= posXRoute2 - 2 && destX <= posXRoute2 + 2 && destY >= posYRoute2 - 2 && destY <= posYRoute2 + 2) {
+ _testRoute2[idxRoute1].invalidate();
+ useRoute2(idxRoute1, curRouteIdx);
+ return 1;
+ }
+
+ int curPosYRoute2 = posYRoute2;
+ while (curPosYRoute2 != destY) {
+ if (checkCollisionLine(posXRoute2, curPosYRoute2, &collDataIdxRoute2, &collLineIdxRoute2, 0, _linesNumb)) {
+ if (collLineIdxRoute2 > _lastLine)
+ collLineIdxRoute2 = -1;
+ break;
+ }
+
+ if (curPosYRoute2 < destY)
+ _testRoute2[idxRoute1++].set(posXRoute2, curPosYRoute2++, DIR_DOWN);
+ else
+ _testRoute2[idxRoute1++].set(posXRoute2, curPosYRoute2--, DIR_UP);
+ }
+ if (curPosYRoute2 != destY)
+ break;
+
+ curPosX = posXRoute2;
+ while (curPosX != destX) {
+ if (checkCollisionLine(curPosX, destY, &collDataIdxRoute2, &collLineIdxRoute2, 0, _linesNumb)) {
+ if (collLineIdxRoute2 <= _lastLine)
+ break;
+
+ int tmpRouteIdx = computeRouteIdx(collLineIdxRoute2, collDataIdxRoute2, curPosX, destY, destX, destY, idxRoute1, _testRoute2);
+ if (tmpRouteIdx == -1) {
+ useRoute2(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ idxRoute1 = tmpRouteIdx;
+ if (_newPosX != -1 && _newPosY != -1)
+ break;
+ }
+
+ if (curPosX < destX)
+ _testRoute2[idxRoute1++].set(curPosX++, destY, DIR_RIGHT);
+ else
+ _testRoute2[idxRoute1++].set(curPosX--, destY, DIR_LEFT);
+ }
+ if (curPosX == destX) {
+ collLineIdxRoute2 = -1;
+ _testRoute2[idxRoute1].invalidate();
+ useRoute2(idxRoute1, curRouteIdx);
+ return 1;
+ }
+ if (collLineIdxRoute2 <= _lastLine)
+ break;
+
+ posXRoute2 = _newPosX;
+ posYRoute2 = _newPosY;
+ colResult = checkCollisionLine(_newPosX, _newPosY, &collDataIdxRoute2, &collLineIdxRoute2, 0, _lastLine);
+ if (colResult && collLineIdxRoute2 <= _lastLine)
+ break;
+ }
+
+ _testRoute2[idxRoute1].invalidate();
+
+ if (!dummyLineFl) {
+ if (endLineIdx > foundLineIdx) {
+ if (_testRoute0[0]._x != -1 && collLineIdxRoute0 > foundLineIdx && collLineIdxRoute1 <= collLineIdxRoute0 && collLineIdxRoute2 <= collLineIdxRoute0 && endLineIdx >= collLineIdxRoute0) {
+ _newLineIdx = collLineIdxRoute0;
+ _newLineDataIdx = collDataIdxRoute0;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute0[i++];
+ } while (_testRoute0[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ if (_testRoute1[0]._x != -1 && foundLineIdx < collLineIdxRoute1 && collLineIdxRoute2 <= collLineIdxRoute1 && collLineIdxRoute0 <= collLineIdxRoute1 && endLineIdx >= collLineIdxRoute1) {
+ _newLineIdx = collLineIdxRoute1;
+ _newLineDataIdx = collDataIdxRoute1;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute1[i++];
+ } while (_testRoute1[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ if (_testRoute2[0]._x != -1 && foundLineIdx < collLineIdxRoute2 && collLineIdxRoute1 < collLineIdxRoute2 && collLineIdxRoute0 < collLineIdxRoute2 && endLineIdx >= collLineIdxRoute2) {
+ _newLineIdx = collLineIdxRoute2;
+ _newLineDataIdx = collDataIdxRoute2;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute2[i++];
+ } while (_testRoute2[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ }
+ if (endLineIdx < foundLineIdx) {
+ if (collLineIdxRoute0 == -1)
+ collLineIdxRoute0 = INVALID_LINE_VALUE;
+ if (collLineIdxRoute1 == -1)
+ collLineIdxRoute0 = INVALID_LINE_VALUE;
+ if (collLineIdxRoute2 == -1)
+ collLineIdxRoute0 = INVALID_LINE_VALUE;
+ if (_testRoute1[0]._x != -1 && collLineIdxRoute1 < foundLineIdx && collLineIdxRoute2 >= collLineIdxRoute1 && collLineIdxRoute0 >= collLineIdxRoute1 && endLineIdx <= collLineIdxRoute1) {
+ _newLineIdx = collLineIdxRoute1;
+ _newLineDataIdx = collDataIdxRoute1;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute1[i++];
+ } while (_testRoute1[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ if (_testRoute2[0]._x != -1 && foundLineIdx > collLineIdxRoute2 && collLineIdxRoute1 >= collLineIdxRoute2 && collLineIdxRoute0 >= collLineIdxRoute2 && endLineIdx <= collLineIdxRoute2) {
+ _newLineIdx = collLineIdxRoute2;
+ _newLineDataIdx = collDataIdxRoute2;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute2[i++];
+ } while (_testRoute2[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ // CHECKME: Checking essai0[0]._x might make more sense here?
+ if (_testRoute1[0]._x != -1 && foundLineIdx > collLineIdxRoute0 && collLineIdxRoute1 >= collLineIdxRoute0 && collLineIdxRoute2 >= collLineIdxRoute0 && endLineIdx <= collLineIdxRoute0) {
+ _newLineIdx = collLineIdxRoute0;
+ _newLineDataIdx = collDataIdxRoute0;
+ int i = 0;
+ do {
+ assert(curRouteIdx <= 8000);
+ _bestRoute[curRouteIdx++] = _testRoute0[i++];
+ } while (_testRoute0[i].isValid());
+ _newRouteIdx = curRouteIdx;
+ return 2;
+ }
+ }
+ }
+ return 0;
+}
+
+RouteItem *LinesManager::cityMapCarRoute(int x1, int y1, int x2, int y2) {
+ RouteItem *result;
+ int arrDelta[10];
+ int arrDataIdx[10];
+ int arrLineIdx[10];
+
+ int clipX2 = x2;
+ int clipY2 = y2;
+ if (x2 <= 14)
+ clipX2 = 15;
+ if (y2 <= 14)
+ clipY2 = 15;
+ if (clipX2 > _vm->_graphicsMan->_maxX - 10)
+ clipX2 = _vm->_graphicsMan->_maxX - 10;
+ if (clipY2 > 445)
+ clipY2 = 440;
+
+ int delta = 0;
+ for (delta = 0; clipY2 + delta < _vm->_graphicsMan->_maxY; delta++) {
+ if (checkCollisionLine(clipX2, clipY2 + delta, &arrDataIdx[DIR_DOWN], &arrLineIdx[DIR_DOWN], 0, _lastLine) && arrLineIdx[DIR_DOWN] <= _lastLine)
+ break;
+ arrDataIdx[DIR_DOWN] = 0;
+ arrLineIdx[DIR_DOWN] = -1;
+ }
+ arrDelta[DIR_DOWN] = delta;
+
+ for (delta = 0; clipY2 - delta > _vm->_graphicsMan->_minY; delta++) {
+ if (checkCollisionLine(clipX2, clipY2 - delta , &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine) && arrLineIdx[DIR_UP] <= _lastLine)
+ break;
+ arrDataIdx[DIR_UP] = 0;
+ arrLineIdx[DIR_UP] = -1;
+ if (arrDelta[DIR_DOWN] < delta && arrLineIdx[DIR_DOWN] != -1)
+ break;
+ }
+ arrDelta[DIR_UP] = delta;
+
+ for (delta = 0; clipX2 + delta < _vm->_graphicsMan->_maxX; delta++) {
+ if (checkCollisionLine(clipX2 + delta, clipY2, &arrDataIdx[DIR_RIGHT], &arrLineIdx[DIR_RIGHT], 0, _lastLine) && arrLineIdx[DIR_RIGHT] <= _lastLine)
+ break;
+ arrDataIdx[DIR_RIGHT] = 0;
+ arrLineIdx[DIR_RIGHT] = -1;
+ if ((arrDelta[DIR_UP] <= delta && arrLineIdx[DIR_UP] != -1) || (arrDelta[DIR_DOWN] <= delta && arrLineIdx[DIR_DOWN] != -1))
+ break;
+ }
+ arrDelta[DIR_RIGHT] = delta;
+
+ for (delta = 0; clipX2 - delta > _vm->_graphicsMan->_minX; delta++) {
+ if (checkCollisionLine(clipX2 - delta, clipY2, &arrDataIdx[DIR_LEFT], &arrLineIdx[DIR_LEFT], 0, _lastLine) && arrLineIdx[DIR_LEFT] <= _lastLine)
+ break;
+ arrDataIdx[DIR_LEFT] = 0;
+ arrLineIdx[DIR_LEFT] = -1;
+ if ((arrDelta[DIR_UP] <= delta && arrLineIdx[DIR_UP] != -1) || (arrDelta[DIR_RIGHT] <= delta && arrLineIdx[DIR_RIGHT] != -1) || (arrDelta[DIR_DOWN] <= delta && arrLineIdx[DIR_DOWN] != -1))
+ break;
+ }
+ arrDelta[DIR_LEFT] = delta;
+
+ if (arrLineIdx[DIR_UP] == -1)
+ arrDelta[DIR_UP] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_RIGHT] == -1)
+ arrDelta[DIR_RIGHT] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_DOWN] == -1)
+ arrDelta[DIR_DOWN] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_LEFT] == -1)
+ arrDelta[DIR_LEFT] = INVALID_LINE_VALUE;
+ if (arrLineIdx[DIR_UP] != -1 || arrLineIdx[DIR_RIGHT] != -1 || arrLineIdx[DIR_DOWN] != -1 || arrLineIdx[DIR_LEFT] != -1) {
+ int curLineDataIdx = 0;
+ int curLineIdx = 0;
+ if (arrLineIdx[DIR_DOWN] != -1 && arrDelta[DIR_UP] >= arrDelta[DIR_DOWN] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_DOWN] && arrDelta[DIR_LEFT] >= arrDelta[DIR_DOWN]) {
+ curLineIdx = arrLineIdx[DIR_DOWN];
+ curLineDataIdx = arrDataIdx[DIR_DOWN];
+ } else if (arrLineIdx[DIR_UP] != -1 && arrDelta[DIR_DOWN] >= arrDelta[DIR_UP] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_UP] && arrDelta[DIR_LEFT] >= arrDelta[DIR_UP]) {
+ curLineIdx = arrLineIdx[DIR_UP];
+ curLineDataIdx = arrDataIdx[DIR_UP];
+ } else if (arrLineIdx[DIR_RIGHT] != -1 && arrDelta[DIR_UP] >= arrDelta[DIR_RIGHT] && arrDelta[DIR_DOWN] >= arrDelta[DIR_RIGHT] && arrDelta[DIR_LEFT] >= arrDelta[DIR_RIGHT]) {
+ curLineIdx = arrLineIdx[DIR_RIGHT];
+ curLineDataIdx = arrDataIdx[DIR_RIGHT];
+ } else if (arrLineIdx[DIR_LEFT] != -1 && arrDelta[DIR_DOWN] >= arrDelta[DIR_LEFT] && arrDelta[DIR_RIGHT] >= arrDelta[DIR_LEFT] && arrDelta[DIR_UP] >= arrDelta[DIR_LEFT]) {
+ curLineIdx = arrLineIdx[DIR_LEFT];
+ curLineDataIdx = arrDataIdx[DIR_LEFT];
+ }
+
+ for (int i = 0; i <= 8; i++) {
+ arrLineIdx[i] = -1;
+ arrDataIdx[i] = 0;
+ arrDelta[i] = INVALID_LINE_VALUE;
+ }
+
+ int superRouteIdx = 0;
+ int curRouteDataIdx = 0;
+ int curRouteLineIdx = 0;
+ if (checkCollisionLine(x1, y1, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine)) {
+ curRouteLineIdx = arrLineIdx[DIR_UP];
+ curRouteDataIdx = arrDataIdx[DIR_UP];
+ } else if (checkCollisionLine(x1, y1, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _linesNumb)) {
+ int curRouteIdx = 0;
+ int curRouteX;
+ for (;;) {
+ curRouteX = _testRoute2[curRouteIdx]._x;
+ int curRouteY = _testRoute2[curRouteIdx]._y;
+ Directions curRouteDir = _testRoute2[curRouteIdx]._dir;
+ curRouteIdx++;
+
+ if (checkCollisionLine(curRouteX, curRouteY, &arrDataIdx[DIR_UP], &arrLineIdx[DIR_UP], 0, _lastLine))
+ break;
+
+ _bestRoute[superRouteIdx].set(curRouteX, curRouteY, curRouteDir);
+
+ _testRoute0[superRouteIdx].set(curRouteX, curRouteY, curRouteDir);
+ superRouteIdx++;
+ if (curRouteX == -1)
+ break;;
+ }
+ if (curRouteX != -1) {
+ curRouteLineIdx = arrLineIdx[DIR_UP];
+ curRouteDataIdx = arrDataIdx[DIR_UP];
+ }
+ } else {
+ curRouteLineIdx = 1;
+ curRouteDataIdx = 1;
+ superRouteIdx = 0;
+ }
+ bool loopFl = true;
+ while (loopFl) {
+ loopFl = false;
+ if (curRouteLineIdx < curLineIdx) {
+ superRouteIdx = _lineItem[curRouteLineIdx].appendToRouteInc(curRouteDataIdx, _lineItem[curRouteLineIdx]._lineDataEndIdx - 2, _bestRoute, superRouteIdx);
+ for (int j = curRouteLineIdx + 1; j < curLineIdx; ++j) {
+ if (PLAN_TEST(_lineItem[j]._lineData[0], _lineItem[j]._lineData[1], superRouteIdx, j, curLineIdx)) {
+ curRouteLineIdx = _newLineIdx;
+ curRouteDataIdx = _newLineDataIdx;
+ superRouteIdx = _newRouteIdx;
+ loopFl = true;
+ break;
+ }
+ if (_lineItem[j]._lineDataEndIdx - 2 > 0) {
+ superRouteIdx = _lineItem[j].appendToRouteInc(0, _lineItem[j]._lineDataEndIdx - 2, _bestRoute, superRouteIdx);
+ }
+ }
+ if (loopFl)
+ continue;
+ curRouteDataIdx = 0;
+ curRouteLineIdx = curLineIdx;
+ }
+ if (curRouteLineIdx > curLineIdx) {
+ superRouteIdx = _lineItem[curRouteLineIdx].appendToRouteDec(curRouteDataIdx, 0, _bestRoute, superRouteIdx);
+ for (int l = curRouteLineIdx - 1; l > curLineIdx; --l) {
+ if (PLAN_TEST(_lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 2], _lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 1], superRouteIdx, l, curLineIdx)) {
+ curRouteLineIdx = _newLineIdx;
+ curRouteDataIdx = _newLineDataIdx;
+ superRouteIdx = _newRouteIdx;
+ loopFl = true;
+ break;
+ }
+
+ superRouteIdx = _lineItem[l].appendToRouteDec(_lineItem[l]._lineDataEndIdx - 2, 0, _bestRoute, superRouteIdx);
+ }
+ if (loopFl)
+ continue;
+
+ curRouteDataIdx = _lineItem[curLineIdx]._lineDataEndIdx - 1;
+ curRouteLineIdx = curLineIdx;
+ }
+ if (curRouteLineIdx == curLineIdx) {
+ if (curRouteDataIdx <= curLineDataIdx) {
+ superRouteIdx = _lineItem[curLineIdx].appendToRouteInc(curRouteDataIdx, curLineDataIdx, _bestRoute, superRouteIdx);
+ } else {
+ superRouteIdx = _lineItem[curLineIdx].appendToRouteDec(curRouteDataIdx, curLineDataIdx, _bestRoute, superRouteIdx);
+ }
+ }
+ }
+ _bestRoute[superRouteIdx].invalidate();
+ result = &_bestRoute[0];
+ } else {
+ result = NULL;
+ }
+ return result;
+}
+
+bool LinesManager::checkSmoothMove(int fromX, int fromY, int destX, int destY) {
+ int distX = abs(fromX - destX) + 1;
+ int distY = abs(fromY - destY) + 1;
+ if (distX > distY)
+ distY = distX;
+ if (distY <= 10)
+ return true;
+
+ int stepX = 1000 * distX / (distY - 1);
+ int stepY = 1000 * distY / (distY - 1);
+ if (destX < fromX)
+ stepX = -stepX;
+ if (destY < fromY)
+ stepY = -stepY;
+
+ int smoothPosX = 1000 * fromX;
+ int smoothPosY = 1000 * fromY;
+ int newPosX = fromX;
+ int newPosY = fromY;
+
+ if (distY + 1 > 0) {
+ int stepCount = 0;
+ int foundLineIdx;
+ int foundDataIdx;
+ while (!checkCollisionLine(newPosX, newPosY, &foundDataIdx, &foundLineIdx, 0, _linesNumb) || foundLineIdx > _lastLine) {
+ smoothPosX += stepX;
+ smoothPosY += stepY;
+ newPosX = smoothPosX / 1000;
+ newPosY = smoothPosY / 1000;
+ ++stepCount;
+ if (stepCount >= distY + 1)
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool LinesManager::makeSmoothMove(int fromX, int fromY, int destX, int destY) {
+ int curX = fromX;
+ int curY = fromY;
+ if (fromX > destX && destY > fromY) {
+ int hopkinsIdx = 36;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX > destX && destY > curY) {
+ int realSpeedX = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedX;
+ int realSpeedY = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedY;
+ int spriteSize = _vm->_globals->_spriteSize[curY];
+ if (spriteSize < 0) {
+ realSpeedX = _vm->_graphicsMan->zoomOut(realSpeedX, -spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomOut(realSpeedY, -spriteSize);
+ } else if (spriteSize > 0) {
+ realSpeedX = _vm->_graphicsMan->zoomIn(realSpeedX, spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomIn(realSpeedY, spriteSize);
+ }
+ for (int i = 0; i < realSpeedX; i++) {
+ --curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if (curY != curY + realSpeedY)
+ curY++;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 48)
+ hopkinsIdx = 36;
+ ++stepCount;
+ }
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_DOWN_LEFT;
+ return false;
+ }
+ } else if (fromX < destX && destY > fromY) {
+ int hopkinsIdx = 36;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX < destX && destY > curY) {
+ int realSpeedX = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedX;
+ int realSpeedY = _vm->_globals->_hopkinsItem[hopkinsIdx]._speedY;
+ int spriteSize = _vm->_globals->_spriteSize[curY];
+ if (spriteSize < 0) {
+ realSpeedX = _vm->_graphicsMan->zoomOut(realSpeedX, -spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomOut(realSpeedY, -spriteSize);
+ } else if (spriteSize > 0) {
+ realSpeedX = _vm->_graphicsMan->zoomIn(realSpeedX, spriteSize);
+ realSpeedY = _vm->_graphicsMan->zoomIn(realSpeedY, spriteSize);
+ }
+ for (int i = 0; i < realSpeedX; i++) {
+ ++curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if (curY != curY + realSpeedY)
+ curY++;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 48)
+ hopkinsIdx = 36;
+ ++stepCount;
+ }
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_DOWN_RIGHT;
+ return false;
+ }
+ } else if (fromX > destX && destY < fromY) {
+ int hopkinsIdx = 12;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX > destX && destY < curY) {
+ int realSpeedX = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedX, 25);
+ int realSpeedY = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedY, 25);
+ int oldY = curY;
+ for (int i = 0; i < realSpeedX; i++) {
+ --curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if ((uint16)curY != (uint16)oldY + realSpeedY)
+ curY--;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 24)
+ hopkinsIdx = 12;
+ ++stepCount;
+ }
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_UP_LEFT;
+ return false;
+ }
+ } else if (fromX < destX && destY < fromY) {
+ int hopkinsIdx = 12;
+ int smoothIdx = 0;
+ int stepCount = 0;
+ while (curX < destX && destY < curY) {
+ int oldY = curY;
+ int realSpeedX = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedX, 25);
+ int realSpeedY = _vm->_graphicsMan->zoomOut(_vm->_globals->_hopkinsItem[hopkinsIdx]._speedY, 25);
+ for (int i = 0; i < realSpeedX; i++) {
+ ++curX;
+ _smoothRoute[smoothIdx]._posX = curX;
+ if ((uint16)curY != (uint16)oldY + realSpeedY)
+ curY--;
+ _smoothRoute[smoothIdx]._posY = curY;
+ smoothIdx++;
+ }
+ ++hopkinsIdx;
+ if (hopkinsIdx == 24)
+ hopkinsIdx = 12;
+ ++stepCount;
+ }
+
+ if (stepCount > 5) {
+ _smoothRoute[smoothIdx]._posX = -1;
+ _smoothRoute[smoothIdx]._posY = -1;
+ _smoothMoveDirection = DIR_UP_RIGHT;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LinesManager::PLAN_TEST(int paramX, int paramY, int superRouteIdx, int paramStartLineIdx, int paramEndLineIdx) {
+ int sideTestUp;
+ int sideTestDown;
+ int sideTestLeft;
+ int sideTestRight;
+ int lineIdxTestUp;
+ int lineIdxTestDown;
+ int lineIdxTestLeft;
+ int lineIdxTestRight;
+ int dataIdxTestUp;
+ int dataIdxTestDown;
+ int dataIdxTestLeft;
+ int dataIdxTestRight;
+
+ int idxTestUp = testLine(paramX, paramY - 2, &sideTestUp, &lineIdxTestUp, &dataIdxTestUp);
+ int idxTestDown = testLine(paramX, paramY + 2, &sideTestDown, &lineIdxTestDown, &dataIdxTestDown);
+ int idxTestLeft = testLine(paramX - 2, paramY, &sideTestLeft, &lineIdxTestLeft, &dataIdxTestLeft);
+ int idxTestRight = testLine(paramX + 2, paramY, &sideTestRight, &lineIdxTestRight, &dataIdxTestRight);
+ if (idxTestUp == -1 && idxTestDown == -1 && idxTestLeft == -1 && idxTestRight == -1)
+ return false;
+
+ // Direction: 1 = Up, 2 = Down, 3 = Left, 4 = Right
+ int direction;
+ if (paramStartLineIdx == -1 || paramEndLineIdx == -1) {
+ if (idxTestUp != -1)
+ direction = 1;
+ else if (idxTestDown != -1)
+ direction = 2;
+ else if (idxTestLeft != -1)
+ direction = 3;
+ else if (idxTestRight != -1)
+ direction = 4;
+ else
+ return false;
+ } else {
+ int stepCountUp = 100;
+ int stepCountDown = 100;
+ int stepCountLeft = 100;
+ int stepCountRight = 100;
+ int paramStepCount = abs(paramStartLineIdx - paramEndLineIdx);
+ if (idxTestUp != -1) {
+ stepCountUp = abs(lineIdxTestUp - paramEndLineIdx);
+ }
+ if (idxTestDown != -1) {
+ stepCountDown = abs(lineIdxTestDown - paramEndLineIdx);
+ }
+ if (idxTestLeft != -1) {
+ stepCountLeft = abs(lineIdxTestLeft - paramEndLineIdx);
+ }
+ if (idxTestRight != -1) {
+ stepCountRight = abs(lineIdxTestRight - paramEndLineIdx);
+ }
+
+ if (stepCountUp < paramStepCount && stepCountUp <= stepCountDown && stepCountUp <= stepCountLeft && stepCountUp <= stepCountRight)
+ direction = 1;
+ else if (paramStepCount > stepCountDown && stepCountUp >= stepCountDown && stepCountLeft >= stepCountDown && stepCountRight >= stepCountDown)
+ direction = 2;
+ else if (stepCountLeft < paramStepCount && stepCountLeft <= stepCountUp && stepCountLeft <= stepCountDown && stepCountLeft <= stepCountRight)
+ direction = 3;
+ else if (stepCountRight < paramStepCount && stepCountRight <= stepCountUp && stepCountRight <= stepCountDown && stepCountRight <= stepCountLeft)
+ direction = 4;
+ else
+ return false;
+ }
+
+ int sideTest = 0;
+ int idxTest = 0;
+ if (direction == 1) {
+ idxTest = idxTestUp;
+ sideTest = sideTestUp;
+ _newLineIdx = lineIdxTestUp;
+ _newLineDataIdx = dataIdxTestUp;
+ } else if (direction == 2) {
+ idxTest = idxTestDown;
+ sideTest = sideTestDown;
+ _newLineIdx = lineIdxTestDown;
+ _newLineDataIdx = dataIdxTestDown;
+ } else if (direction == 3) {
+ idxTest = idxTestLeft;
+ sideTest = sideTestLeft;
+ _newLineIdx = lineIdxTestLeft;
+ _newLineDataIdx = dataIdxTestLeft;
+ } else if (direction == 4) {
+ idxTest = idxTestRight;
+ sideTest = sideTestRight;
+ _newLineIdx = lineIdxTestRight;
+ _newLineDataIdx = dataIdxTestRight;
+ }
+
+ int routeIdx = superRouteIdx;
+ if (sideTest == 1) {
+ routeIdx = _lineItem[idxTest].appendToRouteInc(0, -1, _bestRoute, routeIdx);
+ } else if (sideTest == 2) {
+ routeIdx = _lineItem[idxTest].appendToRouteDec(-1, -1, _bestRoute, routeIdx);
+ }
+ _newRouteIdx = routeIdx;
+ return true;
+}
+
+// Test line
+int LinesManager::testLine(int paramX, int paramY, int *testValue, int *foundLineIdx, int *foundDataIdx) {
+ int16 *lineData;
+ int lineDataEndIdx;
+ int collLineIdx;
+ int collDataIdx;
+
+ for (int idx = _lastLine + 1; idx < _linesNumb + 1; idx++) {
+ lineData = _lineItem[idx]._lineData;
+ lineDataEndIdx = _lineItem[idx]._lineDataEndIdx;
+ if (lineData) {
+ if (lineData[0] == paramX && lineData[1] == paramY) {
+ *testValue = 1;
+ int posX = lineData[2 * (lineDataEndIdx - 1)];
+ int posY = lineData[2 * (lineDataEndIdx - 1) + 1];
+ if (_lineItem[idx]._directionRouteInc == DIR_DOWN || _lineItem[idx]._directionRouteInc == DIR_UP)
+ posY += 2;
+ if (_lineItem[idx]._directionRouteInc == DIR_RIGHT || _lineItem[idx]._directionRouteDec == DIR_LEFT)
+ posX += 2;
+ if (!checkCollisionLine(posX, posY, &collDataIdx, &collLineIdx, 0, _lastLine))
+ error("Error in test line");
+ *foundLineIdx = collLineIdx;
+ *foundDataIdx = collDataIdx;
+ return idx;
+ }
+ }
+
+ if (lineDataEndIdx > 0) {
+ if (lineData[2 * (lineDataEndIdx - 1)] == paramX && lineData[2 * (lineDataEndIdx - 1) + 1] == paramY) {
+ *testValue = 2;
+ int posX = lineData[0];
+ int posY = lineData[1];
+ if (_lineItem[idx]._directionRouteInc == DIR_DOWN || _lineItem[idx]._directionRouteInc == DIR_UP)
+ posY -= 2;
+ if (_lineItem[idx]._directionRouteInc == DIR_RIGHT || _lineItem[idx]._directionRouteDec == DIR_LEFT)
+ posX -= 2;
+ if (!checkCollisionLine(posX, posY, &collDataIdx, &collLineIdx, 0, _lastLine))
+ error("Error in test line");
+ *foundLineIdx = collLineIdx;
+ *foundDataIdx = collDataIdx;
+ return idx;
+ }
+ }
+ }
+ return -1;
+}
+
+int LinesManager::computeYSteps(int idx) {
+ int zoomPct = _vm->_globals->_spriteSize[idx];
+ if (_vm->_globals->_characterType == 1) {
+ if (zoomPct < 0)
+ zoomPct = -zoomPct;
+ zoomPct = 20 * (5 * zoomPct - 100) / -80;
+ } else if (_vm->_globals->_characterType == 2) {
+ if (zoomPct < 0)
+ zoomPct = -zoomPct;
+ zoomPct = 20 * (5 * zoomPct - 165) / -67;
+ }
+
+ int retVal = 25;
+ if (zoomPct < 0)
+ retVal = _vm->_graphicsMan->zoomOut(25, -zoomPct);
+ else if (zoomPct > 0)
+ retVal = _vm->_graphicsMan->zoomIn(25, zoomPct);
+
+ return retVal;
+}
+
+void LinesManager::optimizeRoute(RouteItem *route) {
+ if (route[0]._x == -1 && route[0]._y == -1)
+ return;
+
+ int routeIdx = 0;
+ Directions oldDir = DIR_NONE;
+ int route0Y = route[0]._y;
+ Directions curDir = route[0]._dir;
+
+ for (;;) {
+ if (oldDir != DIR_NONE && curDir != oldDir) {
+ int oldRouteIdx = routeIdx;
+ int routeCount = 0;
+ int yStep = computeYSteps(route0Y);
+ int curRouteX = route[routeIdx]._x;
+ int curRouteY = route[routeIdx]._y;
+ while (curRouteX != -1 || curRouteY != -1) {
+ int idx = routeIdx;
+ ++routeIdx;
+ ++routeCount;
+ if (route[idx]._dir != curDir)
+ break;
+ curRouteX = route[routeIdx]._x;
+ curRouteY = route[routeIdx]._y;
+ }
+ if (routeCount < yStep) {
+ int idx = oldRouteIdx;
+ for (int i = 0; i < routeCount; i++) {
+ route[idx]._dir = oldDir;
+ idx++;
+ }
+ curDir = oldDir;
+ }
+ routeIdx = oldRouteIdx;
+ if (curRouteX == -1 && curRouteY == -1)
+ break;
+ }
+ routeIdx++;
+ oldDir = curDir;
+ route0Y = route[routeIdx]._y;
+ curDir = route[routeIdx]._dir;
+ if (route[routeIdx]._x == -1 && route0Y == -1)
+ break;
+ }
+}
+
+int LinesManager::getMouseZone() {
+ int result;
+
+ int xp = _vm->_events->_mousePos.x + _vm->_events->_mouseOffset.x;
+ int yp = _vm->_events->_mousePos.y + _vm->_events->_mouseOffset.y;
+ if ((_vm->_events->_mousePos.y + _vm->_events->_mouseOffset.y) > 19) {
+ for (int bobZoneId = 0; bobZoneId <= 48; bobZoneId++) {
+ int bobId = _bobZone[bobZoneId];
+ if (bobId && _bobZoneFl[bobZoneId] && _vm->_objectsMan->_bob[bobId]._bobMode && _vm->_objectsMan->_bob[bobId]._frameIndex != 250 &&
+ !_vm->_objectsMan->_bob[bobId]._disabledAnimationFl && xp > _vm->_objectsMan->_bob[bobId]._oldX &&
+ xp < _vm->_objectsMan->_bob[bobId]._oldWidth + _vm->_objectsMan->_bob[bobId]._oldX && yp > _vm->_objectsMan->_bob[bobId]._oldY) {
+ if (yp < _vm->_objectsMan->_bob[bobId]._oldHeight + _vm->_objectsMan->_bob[bobId]._oldY) {
+ if (_zone[bobZoneId]._spriteIndex == -1) {
+ _zone[bobZoneId]._destX = 0;
+ _zone[bobZoneId]._destY = 0;
+ }
+ if (!_zone[bobZoneId]._destX && !_zone[bobZoneId]._destY) {
+ _zone[bobZoneId]._destX = _vm->_objectsMan->_bob[bobId]._oldWidth + _vm->_objectsMan->_bob[bobId]._oldX;
+ _zone[bobZoneId]._destY = _vm->_objectsMan->_bob[bobId]._oldHeight + _vm->_objectsMan->_bob[bobId]._oldY + 6;
+ _zone[bobZoneId]._spriteIndex = -1;
+ }
+ return bobZoneId;
+ }
+ }
+ }
+ _currentSegmentId = 0;
+ for (int squareZoneId = 0; squareZoneId <= 99; squareZoneId++) {
+ if (_zone[squareZoneId]._enabledFl && _squareZone[squareZoneId]._enabledFl
+ && _squareZone[squareZoneId]._left <= xp && _squareZone[squareZoneId]._right >= xp
+ && _squareZone[squareZoneId]._top <= yp && _squareZone[squareZoneId]._bottom >= yp) {
+ if (_squareZone[squareZoneId]._squareZoneFl)
+ return _zoneLine[_squareZone[squareZoneId]._minZoneLineIdx]._bobZoneIdx;
+
+ _segment[_currentSegmentId]._minZoneLineIdx = _squareZone[squareZoneId]._minZoneLineIdx;
+ _segment[_currentSegmentId]._maxZoneLineIdx = _squareZone[squareZoneId]._maxZoneLineIdx;
+ ++_currentSegmentId;
+ }
+ }
+ if (!_currentSegmentId)
+ return -1;
+
+
+ int colRes1 = 0;
+ for (int yCurrent = yp; yCurrent >= 0; --yCurrent) {
+ colRes1 = checkCollision(xp, yCurrent);
+ if (colRes1 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+
+ if (colRes1 == -1)
+ return -1;
+
+ int colRes2 = 0;
+ for (int j = yp; j < _vm->_graphicsMan->_maxY; ++j) {
+ colRes2 = checkCollision(xp, j);
+ if (colRes2 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+
+ if (colRes2 == -1)
+ return -1;
+
+ int colRes3 = 0;
+ for (int k = xp; k >= 0; --k) {
+ colRes3 = checkCollision(k, yp);
+ if (colRes3 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+ if (colRes3 == -1)
+ return -1;
+
+ int colRes4 = 0;
+ for (int xCurrent = xp; _vm->_graphicsMan->_maxX > xCurrent; ++xCurrent) {
+ colRes4 = checkCollision(xCurrent, yp);
+ if (colRes4 != -1 && _zone[colRes1]._enabledFl)
+ break;
+ }
+ if (colRes1 == colRes2 && colRes1 == colRes3 && colRes1 == colRes4)
+ result = colRes1;
+ else
+ result = -1;
+
+ } else {
+ result = 0;
+ }
+ return result;
+}
+
+int LinesManager::checkCollision(int xp, int yp) {
+ if (_currentSegmentId <= 0)
+ return -1;
+
+ int xMax = xp + 4;
+ int xMin = xp - 4;
+
+ for (int idx = 0; idx <= _currentSegmentId; ++idx) {
+ int curZoneLineIdx = _segment[idx]._minZoneLineIdx;
+ if (_segment[idx]._maxZoneLineIdx < curZoneLineIdx)
+ continue;
+
+ int yMax = yp + 4;
+ int yMin = yp - 4;
+
+ do {
+ LigneZoneItem *curZoneLine = &_zoneLine[curZoneLineIdx];
+ int16 *dataP = curZoneLine->_zoneData;
+ if (dataP) {
+ int count = curZoneLine->_count;
+ int startX = dataP[0];
+ int startY = dataP[1];
+ int destX = dataP[count * 2 - 2];
+ int destY = dataP[count * 2 - 1];
+
+ bool flag = true;
+ if ((startX < destX && (xMax < startX || xMin > destX)) ||
+ (startX >= destX && (xMin > startX || xMax < destX)) ||
+ (startY < destY && (yMax < startY || yMin > destY)) ||
+ (startY >= destY && (yMin > startY || yMax < destY)))
+ flag = false;
+
+ if (flag && curZoneLine->_count > 0) {
+ for (int i = 0; i < count; ++i) {
+ int xCheck = *dataP++;
+ int yCheck = *dataP++;
+
+ if ((xp == xCheck || (xp + 1) == xCheck) && (yp == yCheck))
+ return curZoneLine->_bobZoneIdx;
+ }
+ }
+ }
+ } while (++curZoneLineIdx <= _segment[idx]._maxZoneLineIdx);
+ }
+
+ return -1;
+}
+
+// Square Zone
+void LinesManager::initSquareZones() {
+ for (int idx = 0; idx < 100; ++idx) {
+ SquareZoneItem *curZone = &_squareZone[idx];
+ curZone->_enabledFl = false;
+ curZone->_squareZoneFl = false;
+ curZone->_left = 1280;
+ curZone->_right = 0;
+ curZone->_top = 460;
+ curZone->_bottom = 0;
+ curZone->_minZoneLineIdx = 401;
+ curZone->_maxZoneLineIdx = 0;
+ }
+
+ for (int idx = 0; idx < MAX_LINES; ++idx) {
+ int16 *dataP = _zoneLine[idx]._zoneData;
+ if (dataP == NULL)
+ continue;
+
+ SquareZoneItem *curZone = &_squareZone[_zoneLine[idx]._bobZoneIdx];
+ curZone->_enabledFl = true;
+ curZone->_maxZoneLineIdx = MAX(curZone->_maxZoneLineIdx, idx);
+ curZone->_minZoneLineIdx = MIN(curZone->_minZoneLineIdx, idx);
+
+ for (int i = 0; i < _zoneLine[idx]._count; i++) {
+ int zoneX = *dataP++;
+ int zoneY = *dataP++;
+
+ curZone->_left = MIN(curZone->_left, zoneX);
+ curZone->_right = MAX(curZone->_right, zoneX);
+ curZone->_top = MIN(curZone->_top, zoneY);
+ curZone->_bottom = MAX(curZone->_bottom, zoneY);
+ }
+ }
+
+ for (int idx = 0; idx < 100; idx++) {
+ int zoneWidth = abs(_squareZone[idx]._left - _squareZone[idx]._right);
+ int zoneHeight = abs(_squareZone[idx]._top - _squareZone[idx]._bottom);
+ if (zoneWidth == zoneHeight)
+ _squareZone[idx]._squareZoneFl = true;
+ }
+}
+
+void LinesManager::clearAll() {
+ for (int idx = 0; idx < 105; ++idx) {
+ _zone[idx]._destX = 0;
+ _zone[idx]._destY = 0;
+ _zone[idx]._spriteIndex = 0;
+ }
+
+ _testRoute0 = NULL;
+ _testRoute1 = NULL;
+ _testRoute2 = NULL;
+ _lineBuf = NULL;
+ _route = NULL;
+
+ for (int idx = 0; idx < MAX_LINES; ++idx) {
+ _lineItem[idx]._lineDataEndIdx = 0;
+ _lineItem[idx]._direction = DIR_NONE;
+ _lineItem[idx]._directionRouteInc = DIR_NONE;
+ _lineItem[idx]._directionRouteDec = DIR_NONE;
+ _lineItem[idx]._lineData = NULL;
+
+ _zoneLine[idx]._count = 0;
+ _zoneLine[idx]._bobZoneIdx = 0;
+ _zoneLine[idx]._zoneData = NULL;
+ }
+
+ for (int idx = 0; idx < 100; ++idx)
+ _squareZone[idx]._enabledFl = false;
+
+ _testRoute0 = new RouteItem[8334];
+ _testRoute1 = new RouteItem[8334];
+ _testRoute2 = new RouteItem[8334];
+ if (!_testRoute0)
+ _testRoute0 = NULL;
+ if (!_testRoute1)
+ _testRoute1 = NULL;
+ if (!_testRoute2)
+ _testRoute2 = NULL;
+
+ _largeBuf = _vm->_globals->allocMemory(10000);
+ _lineBuf = (int16 *)(_largeBuf);
+}
+
+/**
+ * Clear all zones and reset nextLine
+ */
+void LinesManager::clearAllZones() {
+ for (int idx = 0; idx < MAX_LINES; ++idx)
+ removeZoneLine(idx);
+}
+
+/**
+ * Remove Zone Line
+ */
+void LinesManager::removeZoneLine(int idx) {
+ assert (idx <= MAX_LINES);
+ _zoneLine[idx]._zoneData = (int16 *)_vm->_globals->freeMemory((byte *)_zoneLine[idx]._zoneData);
+}
+
+void LinesManager::resetLines() {
+ for (int idx = 0; idx < MAX_LINES; ++idx) {
+ removeLine(idx);
+ _lineItem[idx]._lineDataEndIdx = 0;
+ _lineItem[idx]._lineData = NULL;
+ }
+}
+
+// Remove Line
+void LinesManager::removeLine(int idx) {
+ if (idx > MAX_LINES)
+ error("Attempting to add a line obstacle > MAX_LIGNE.");
+ _lineItem[idx]._lineData = (int16 *)_vm->_globals->freeMemory((byte *)_lineItem[idx]._lineData);
+}
+
+void LinesManager::setMaxLineIdx(int idx) {
+ _maxLineIdx = idx;
+}
+
+void LinesManager::resetLastLine() {
+ _lastLine = 0;
+}
+
+void LinesManager::resetLinesNumb() {
+ _linesNumb = 0;
+}
+
+void LinesManager::enableZone(int idx) {
+ if (_bobZone[idx]) {
+ _bobZoneFl[idx] = true;
+ } else {
+ _zone[idx]._enabledFl = true;
+ }
+}
+
+void LinesManager::disableZone(int idx) {
+ if (_bobZone[idx]) {
+ _bobZoneFl[idx] = false;
+ } else {
+ _zone[idx]._enabledFl = false;
+ }
+}
+
+void LinesManager::checkZone() {
+ int mouseX = _vm->_events->getMouseX();
+ int mouseY = _vm->_events->getMouseY();
+ int oldMouseY = mouseY;
+ if (_vm->_globals->_cityMapEnabledFl
+ || _vm->_events->_startPos.x >= mouseX
+ || (mouseY = _vm->_graphicsMan->_scrollOffset + 54, mouseX >= mouseY)
+ || (mouseY = oldMouseY - 1, mouseY < 0 || mouseY > 59)) {
+ if (_vm->_objectsMan->_visibleFl)
+ _vm->_objectsMan->_eraseVisibleCounter = 4;
+ _vm->_objectsMan->_visibleFl = false;
+ } else {
+ _vm->_objectsMan->_visibleFl = true;
+ }
+ if (_vm->_objectsMan->_forceZoneFl) {
+ _zoneSkipCount = 100;
+ _oldMouseZoneId = -1;
+ _oldMouseX = -200;
+ _oldMouseY = -220;
+ _vm->_objectsMan->_forceZoneFl = false;
+ }
+
+ _zoneSkipCount++;
+ if (_zoneSkipCount <= 1)
+ return;
+
+ if (_vm->_globals->_freezeCharacterFl || (_route == NULL) || _zoneSkipCount > 4) {
+ _zoneSkipCount = 0;
+ int zoneId;
+ if (_oldMouseX != mouseX || _oldMouseY != oldMouseY) {
+ zoneId = getMouseZone();
+ } else {
+ zoneId = _oldMouseZoneId;
+ }
+ if (_oldMouseZoneId != zoneId) {
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(4);
+ if (_forceHideText) {
+ _vm->_fontMan->hideText(5);
+ _forceHideText = false;
+ return;
+ }
+ }
+ if (zoneId != -1) {
+ if (_zone[zoneId]._verbFl1 || _zone[zoneId]._verbFl2 ||
+ _zone[zoneId]._verbFl3 || _zone[zoneId]._verbFl4 ||
+ _zone[zoneId]._verbFl5 || _zone[zoneId]._verbFl6 ||
+ _zone[zoneId]._verbFl7 || _zone[zoneId]._verbFl8 ||
+ _zone[zoneId]._verbFl9 || _zone[zoneId]._verbFl10) {
+ if (_oldMouseZoneId != zoneId) {
+ _vm->_fontMan->initTextBuffers(5, _zone[zoneId]._messageId, _vm->_globals->_zoneFilename, 0, 430, 0, 0, 252);
+ _vm->_fontMan->showText(5);
+ _forceHideText = true;
+ }
+ _hotspotTextColor += 25;
+ if (_hotspotTextColor > 100)
+ _hotspotTextColor = 0;
+ _vm->_graphicsMan->setColorPercentage2(251, _hotspotTextColor, _hotspotTextColor, _hotspotTextColor);
+ if (_vm->_events->_mouseCursorId == 4) {
+ if (_zone[zoneId]._verbFl1 == 2) {
+ _vm->_events->changeMouseCursor(16);
+ _vm->_events->_mouseCursorId = 16;
+ _vm->_objectsMan->setVerb(16);
+ }
+ }
+ } else {
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(4);
+ }
+ }
+ _vm->_objectsMan->_zoneNum = zoneId;
+ _oldMouseX = mouseX;
+ _oldMouseY = oldMouseY;
+ _oldMouseZoneId = zoneId;
+ if (_vm->_globals->_freezeCharacterFl && (_vm->_events->_mouseCursorId == 4)) {
+ if (zoneId != -1 && zoneId != 0)
+ _vm->_objectsMan->handleRightButton();
+ }
+ if ((_vm->_globals->_cityMapEnabledFl && zoneId == -1) || !zoneId) {
+ _vm->_objectsMan->setVerb(0);
+ _vm->_events->_mouseCursorId = 0;
+ _vm->_events->changeMouseCursor(0);
+ }
+ }
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/lines.h b/engines/hopkins/lines.h
new file mode 100644
index 0000000000..9e397cca3d
--- /dev/null
+++ b/engines/hopkins/lines.h
@@ -0,0 +1,196 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_LINES_H
+#define HOPKINS_LINES_H
+
+#include "hopkins/globals.h"
+
+#include "common/scummsys.h"
+#include "common/str.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+struct LigneZoneItem {
+ int _count;
+ int _bobZoneIdx;
+ int16 *_zoneData;
+};
+
+#define INVALID_LINE_VALUE 1300
+
+struct RouteItem;
+
+struct LigneItem {
+ int _lineDataEndIdx;
+ Directions _direction;
+ Directions _directionRouteInc;
+ Directions _directionRouteDec;
+ int16 *_lineData;
+
+ int appendToRouteInc(int from, int to, RouteItem *route, int index);
+ int appendToRouteDec(int from, int to, RouteItem *route, int index);
+};
+
+struct SmoothItem {
+ int _posX;
+ int _posY;
+};
+
+struct SegmentItem {
+ int _minZoneLineIdx;
+ int _maxZoneLineIdx;
+};
+
+struct SquareZoneItem {
+ bool _enabledFl;
+ int _left;
+ int _right;
+ int _top;
+ int _bottom;
+ int _minZoneLineIdx;
+ int _maxZoneLineIdx;
+ bool _squareZoneFl;
+};
+
+struct ZoneItem {
+ int _destX;
+ int _destY;
+ int _spriteIndex;
+ int _verbFl1;
+ int _verbFl2;
+ int _verbFl3;
+ int _verbFl4;
+ int _verbFl5;
+ int _verbFl6;
+ int _verbFl7;
+ int _verbFl8;
+ int _verbFl9;
+ int _verbFl10;
+ bool _enabledFl;
+ int _messageId;
+};
+
+struct RouteItem {
+ int16 _x;
+ int16 _y;
+ Directions _dir;
+ bool isValid() const { return _x != -1 || _y != -1; }
+ void invalidate() { _x = _y = -1; _dir = DIR_NONE; }
+ void set(int16 X, int16 Y, Directions dir) { _x = X; _y = Y; _dir = dir; }
+};
+
+
+class LinesManager {
+private:
+ HopkinsEngine *_vm;
+
+ bool _forceHideText;
+ int _hotspotTextColor;
+ int _pathFindingMaxDepth;
+ SmoothItem _smoothRoute[4000];
+ Directions _smoothMoveDirection;
+ LigneZoneItem _zoneLine[401];
+ SegmentItem _segment[101];
+ SquareZoneItem _squareZone[101];
+ int _currentSegmentId;
+ int _maxLineIdx;
+ int _lastLine;
+ int _linesNumb;
+ int _newLineIdx;
+ int _newLineDataIdx;
+ int _newRouteIdx;
+ int _newPosX;
+ int _newPosY;
+ int _oldMouseX, _oldMouseY;
+ int _oldRouteFromX;
+ int _oldRouteFromY;
+ int _oldRouteDestX;
+ int _oldRouteDestY;
+ int _oldZoneNum;
+
+ byte *_largeBuf;
+ RouteItem *_testRoute0;
+ RouteItem *_testRoute1;
+ int16 *_lineBuf;
+ LigneItem _lineItem[400];
+ RouteItem _bestRoute[8001];
+ int _zoneSkipCount;
+ int _oldMouseZoneId;
+
+ int avoidObstacle(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route);
+ int avoidObstacleOnSegment(int lineIdx, int lineDataIdx, int routeIdx, int destLineIdx, int destLineDataIdx, RouteItem *route, int startLineIdx, int endLineIdx);
+ int checkInventoryHotspotsRow(int posX, int minZoneNum, bool lastRow);
+ void removeZoneLine(int idx);
+ void removeLine(int idx);
+ int checkCollision(int xp, int yp);
+ bool checkCollisionLine(int xp, int yp, int *foundDataIdx, int *foundLineIdx, int startLineIdx, int endLineIdx);
+ bool checkSmoothMove(int fromX, int fromY, int destX, int destY);
+ bool makeSmoothMove(int fromX, int fromY, int destX, int destY);
+ int characterRoute(int fromX, int fromY, int destX, int destY, int startLineIdx, int endLineIdx, int routeIdx);
+ int testLine(int paramX, int paramY, int *testValue, int *foundLineIdx, int *foundDataIdx);
+ void useRoute0(int idx, int curRouteIdx);
+ void useRoute1(int idx, int curRouteIdx);
+ void useRoute2(int idx, int curRouteIdx);
+ int computeYSteps(int idx);
+ int computeRouteIdx(int lineIdx, int dataIdx, int fromX, int fromY, int destX, int destY, int routerIdx, RouteItem *route);
+
+ bool MIRACLE(int fromX, int fromY, int lineIdx, int destLineIdx, int routeIdx);
+ bool PLAN_TEST(int paramX, int paramY, int superRouteIdx, int paramStartLineIdx, int paramEndLineIdx);
+
+public:
+ RouteItem *_route;
+ RouteItem *_testRoute2;
+
+ int _bobZone[105];
+ bool _bobZoneFl[105];
+ ZoneItem _zone[106];
+
+ LinesManager(HopkinsEngine *vm);
+ ~LinesManager();
+ void clearAll();
+
+ void setMaxLineIdx(int idx);
+ int checkInventoryHotspots(int posX, int posY);
+ void addZoneLine(int idx, int fromX, int fromY, int destX, int destY, int bobZoneIdx);
+ void loadLines(const Common::String &file);
+ void addLine(int lineIdx, Directions direction, int fromX, int fromY, int destX, int destY);
+ void initRoute();
+ RouteItem *findRoute(int fromX, int fromY, int destX, int destY);
+ RouteItem *cityMapCarRoute(int x1, int y1, int x2, int y2);
+ void clearAllZones();
+ void initSquareZones();
+ void resetLines();
+ void resetLinesNumb();
+ void resetLastLine();
+ void enableZone(int idx);
+ void disableZone(int idx);
+ void checkZone();
+ int getMouseZone();
+ void optimizeRoute(RouteItem *route);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_FONT_H */
diff --git a/engines/hopkins/menu.cpp b/engines/hopkins/menu.cpp
new file mode 100644
index 0000000000..01aa84e4ed
--- /dev/null
+++ b/engines/hopkins/menu.cpp
@@ -0,0 +1,168 @@
+/* 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/menu.h"
+
+#include "hopkins/dialogs.h"
+#include "hopkins/files.h"
+#include "hopkins/hopkins.h"
+#include "hopkins/globals.h"
+#include "hopkins/events.h"
+#include "hopkins/graphics.h"
+#include "hopkins/sound.h"
+
+#include "common/scummsys.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/util.h"
+
+namespace Hopkins {
+
+enum MenuSelection { MENU_NONE = 0, PLAY_GAME = 1, LOAD_GAME = 2, OPTIONS = 3, INTRODUCTION = 4, QUIT = 5 };
+
+MenuManager::MenuManager(HopkinsEngine *vm) {
+ _vm = vm;
+}
+
+int MenuManager::menu() {
+ byte *spriteData = NULL;
+ MenuSelection menuIndex;
+ Common::Point mousePos;
+ signed int result;
+ int frameIndex[] = { 0, 0, 0, 0, 0 };
+
+ if (g_system->getEventManager()->shouldQuit())
+ return -1;
+
+ result = 0;
+ while (!g_system->getEventManager()->shouldQuit()) {
+ _vm->_objectsMan->_forestFl = false;
+ _vm->_events->_breakoutFl = false;
+ _vm->_globals->_disableInventFl = true;
+ _vm->_globals->_exitId = 0;
+
+ for (int idx = 0; idx < 31; ++idx)
+ _vm->_globals->_inventory[idx] = 0;
+
+ memset(_vm->_globals->_saveData, 0, 2000);
+ _vm->_objectsMan->addObject(14);
+ memset(frameIndex, 0, sizeof(int) * ARRAYSIZE(frameIndex));
+
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ _vm->_graphicsMan->loadImage("MENU");
+ else if (_vm->_globals->_language == LANG_EN)
+ _vm->_graphicsMan->loadImage("MENUAN");
+ else if (_vm->_globals->_language == LANG_FR)
+ _vm->_graphicsMan->loadImage("MENUFR");
+ else if (_vm->_globals->_language == LANG_SP)
+ _vm->_graphicsMan->loadImage("MENUES");
+
+ _vm->_graphicsMan->fadeInLong();
+
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ spriteData = _vm->_objectsMan->loadSprite("MENU.SPR");
+ else if (_vm->_globals->_language == LANG_EN)
+ spriteData = _vm->_objectsMan->loadSprite("MENUAN.SPR");
+ else if (_vm->_globals->_language == LANG_FR)
+ spriteData = _vm->_objectsMan->loadSprite("MENUFR.SPR");
+ else if (_vm->_globals->_language == LANG_SP)
+ spriteData = _vm->_objectsMan->loadSprite("MENUES.SPR");
+
+ _vm->_events->mouseOn();
+ _vm->_events->changeMouseCursor(0);
+ _vm->_events->_mouseCursorId = 0;
+ _vm->_events->_mouseSpriteId = 0;
+
+ _vm->_soundMan->playSound(28);
+
+ // Loop to make menu selection
+ bool selectionMade = false;
+ do {
+ if (g_system->getEventManager()->shouldQuit())
+ return -1;
+
+ menuIndex = MENU_NONE;
+ mousePos = Common::Point(_vm->_events->getMouseX(), _vm->_events->getMouseY());
+
+ if (mousePos.x >= 232 && mousePos.x <= 408) {
+ if (mousePos.y >= 261 && mousePos.y <= 284)
+ menuIndex = PLAY_GAME;
+ else if (mousePos.y >= 293 && mousePos.y <= 316)
+ menuIndex = LOAD_GAME;
+ else if (mousePos.y >= 325 && mousePos.y <= 347)
+ menuIndex = OPTIONS;
+ else if (mousePos.y >= 356 && mousePos.y <= 379)
+ menuIndex = INTRODUCTION;
+ else if (mousePos.y >= 388 && mousePos.y <= 411)
+ menuIndex = QUIT;
+ }
+
+ memset(frameIndex, 0, sizeof(int) * ARRAYSIZE(frameIndex));
+ if (menuIndex > MENU_NONE)
+ frameIndex[menuIndex - 1] = 1;
+
+ _vm->_graphicsMan->fastDisplay(spriteData, 230, 259, frameIndex[0]);
+ _vm->_graphicsMan->fastDisplay(spriteData, 230, 291, frameIndex[1] + 2);
+ _vm->_graphicsMan->fastDisplay(spriteData, 230, 322, frameIndex[2] + 4);
+ _vm->_graphicsMan->fastDisplay(spriteData, 230, 354, frameIndex[3] + 6);
+ _vm->_graphicsMan->fastDisplay(spriteData, 230, 386, frameIndex[4] + 8);
+ _vm->_events->refreshScreenAndEvents();
+
+ if (_vm->_events->getMouseButton() == 1 && menuIndex != MENU_NONE)
+ selectionMade = true;
+ } while (!selectionMade);
+
+ if (menuIndex > MENU_NONE) {
+ _vm->_graphicsMan->fastDisplay(spriteData, 230, 259 + 32 * (menuIndex - 1), 10 + (menuIndex - 1));
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->delay(200);
+ }
+
+ if (menuIndex == PLAY_GAME) {
+ result = 1;
+ break;
+ } else if (menuIndex == LOAD_GAME) {
+ _vm->_globals->_exitId = -1;
+ _vm->_dialog->showLoadGame();
+
+ if (_vm->_globals->_exitId != -1) {
+ result = _vm->_globals->_exitId;
+ break;
+ }
+ _vm->_globals->_exitId = 0;
+ } else if (menuIndex == OPTIONS) {
+ _vm->_dialog->showOptionsDialog();
+ } else if (menuIndex == INTRODUCTION) {
+ _vm->playIntro();
+ } else if (menuIndex == QUIT) {
+ result = -1;
+ break;
+ }
+ }
+
+ _vm->_globals->freeMemory(spriteData);
+ _vm->_globals->_disableInventFl = false;
+ _vm->_graphicsMan->fadeOutLong();
+ return result;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/menu.h b/engines/hopkins/menu.h
new file mode 100644
index 0000000000..e926c29dbd
--- /dev/null
+++ b/engines/hopkins/menu.h
@@ -0,0 +1,46 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_MENU_H
+#define HOPKINS_MENU_H
+
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/error.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+class MenuManager {
+private:
+ HopkinsEngine *_vm;
+
+public:
+ MenuManager(HopkinsEngine *vm);
+
+ int menu();
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_MENU_H */
diff --git a/engines/hopkins/module.mk b/engines/hopkins/module.mk
new file mode 100644
index 0000000000..5c1a7dd478
--- /dev/null
+++ b/engines/hopkins/module.mk
@@ -0,0 +1,29 @@
+MODULE := engines/hopkins
+
+MODULE_OBJS := \
+ anim.o \
+ computer.o \
+ debugger.o \
+ detection.o \
+ dialogs.o \
+ events.o \
+ files.o \
+ font.o \
+ graphics.o \
+ globals.o \
+ hopkins.o \
+ lines.o \
+ menu.o \
+ objects.o \
+ saveload.o \
+ script.o \
+ sound.o \
+ talk.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_HOPKINS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/hopkins/objects.cpp b/engines/hopkins/objects.cpp
new file mode 100644
index 0000000000..f139ee55ab
--- /dev/null
+++ b/engines/hopkins/objects.cpp
@@ -0,0 +1,4058 @@
+/* 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/objects.h"
+
+#include "hopkins/dialogs.h"
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/hopkins.h"
+
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "common/file.h"
+#include "common/rect.h"
+#include "engines/util.h"
+
+namespace Hopkins {
+
+ObjectsManager::ObjectsManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ for (int i = 0; i < 6; ++i)
+ Common::fill((byte *)&_sprite[i], (byte *)&_sprite[i] + sizeof(SpriteItem), 0);
+
+ for (int i = 0; i < 36; ++i)
+ Common::fill((byte *)&_bob[i], (byte *)&_bob[i] + sizeof(BobItem), 0);
+
+ for (int i = 0; i < 30; ++i) {
+ Common::fill((byte *)&_vBob[i], (byte *)&_vBob[i] + sizeof(VBobItem), 0);
+ Common::fill((byte *)&_lockedAnims[i], (byte *)&_lockedAnims[i] + sizeof(LockAnimItem), 0);
+ }
+
+ for (int i = 0; i < 300; ++i)
+ Common::fill((byte *)&_objectAuthIcons[i], (byte *)&_objectAuthIcons[i] + sizeof(ObjectAuthIcon), 0);
+
+ _sortedDisplayCount = 0;
+ for (int i = 0; i < 51; ++i)
+ Common::fill((byte *)&_sortedDisplay[i], (byte *)&_sortedDisplay[i] + sizeof(SortItem), 0);
+
+ for (int i = 0; i < 25; ++i)
+ Common::fill((byte *)&_hidingItem[i], (byte *)&_hidingItem[i] + sizeof(HidingItem), 0);
+
+ for (int i = 0; i < 6; ++i)
+ _hidingItemData[i] = NULL;
+
+ for (int i = 0; i < 6; ++i)
+ Common::fill((byte *)&_liste[i], (byte *)&_liste[i] + sizeof(ListeItem), 0);
+
+ for (int i = 0; i < 35; ++i)
+ Common::fill((byte *)&_liste2[i], (byte *)&_liste2[i] + sizeof(ListeItem), 0);
+
+ _helicopterFl = false;
+ _priorityFl = false;
+ _oldBorderPos = Common::Point(0, 0);
+ _oldBorderSpriteIndex = 0;
+ _borderPos = Common::Point(0, 0);
+ _borderSpriteIndex = 0;
+ _saveLoadX = _saveLoadY = 0;
+ _oldCharacterPosX = _oldCharacterPosY = 0;
+ _eraseVisibleCounter = 0;
+ _saveLoadSprite = NULL;
+ _saveLoadSprite2 = NULL;
+ _spritePtr = NULL;
+ _oldSpriteData = NULL;
+ _saveLoadFl = false;
+ _visibleFl = false;
+ _zoneNum = 0;
+ _forceZoneFl = false;
+ _changeVerbFl = false;
+ _verb = 0;
+ _changeHeadFl = false;
+ _disableFl = false;
+ _twoCharactersFl = false;
+ _characterPos = Common::Point(0, 0);
+ _startSpriteIndex = 0;
+ _jumpVerb = 0;
+ _jumpZone = 0;
+ _oldSpriteIndex = 0;
+ _oldFrameIndex = 0;
+ _oldFlipFl = false;
+ _curObjectIndex = 0;
+ _forestFl = false;
+ _mapCarPosX = _mapCarPosY = 0;
+ _forestSprite = NULL;
+ _gestureBuf = NULL;
+ _curGestureFile = 0;
+ _headSprites = NULL;
+ _homeRateCounter = 0;
+ _lastDirection = DIR_NONE;
+ _oldDirection = DIR_NONE;
+ _oldDirectionSpriteIdx = 59;
+ _objectWidth = _objectHeight = 0;
+ _hidingActiveFl = false;
+ _curObjectFileNum = 0;
+ _objectDataBuf = NULL;
+ _charactersEnabledFl = false;
+ _refreshBobMode10Fl = false;
+}
+
+ObjectsManager::~ObjectsManager() {
+ _vm->_globals->freeMemory(_forestSprite);
+ _vm->_globals->freeMemory(_gestureBuf);
+ _vm->_globals->freeMemory(_headSprites);
+ _vm->_globals->freeMemory(_objectDataBuf);
+ clearVBob();
+
+ for (int idx = 0; idx < 6; ++idx)
+ _hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]);
+}
+
+void ObjectsManager::clearAll() {
+ _forestFl = false;
+ _forestSprite = _vm->_globals->freeMemory(_forestSprite);
+ _curGestureFile = 0;
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curObjectFileNum = 0;
+
+ for (int idx = 0; idx < 6; ++idx)
+ _hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]);
+
+ _objectDataBuf = _vm->_globals->freeMemory(_objectDataBuf);
+ initVBob();
+}
+
+// Load Object
+void ObjectsManager::loadObjects() {
+ byte *data = _vm->_fileIO->loadFile("OBJET.DAT");
+ byte *srcP = data;
+
+ for (int idx = 0; idx < 300; ++idx) {
+ ObjectAuthIcon *objectAuthIcon = &_objectAuthIcons[idx];
+ objectAuthIcon->_objectFileNum = *srcP++;
+ objectAuthIcon->_idx = *srcP++;
+ objectAuthIcon->_flag1 = *srcP++;
+ objectAuthIcon->_flag2 = *srcP++;
+ objectAuthIcon->_flag3 = *srcP++;
+ objectAuthIcon->_flag4 = *srcP++;
+ objectAuthIcon->_flag5 = *srcP++;
+ objectAuthIcon->_flag6 = *srcP++;
+ }
+
+ _vm->_globals->freeMemory(data);
+}
+
+// Reset Hiding Items
+void ObjectsManager::resetHidingItems() {
+ for (int idx = 1; idx <= 5; ++idx) {
+ _hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]);
+ }
+
+ for (int idx = 0; idx <= 20; ++idx) {
+ HidingItem *hid = &_hidingItem[idx];
+ hid->_spriteData = NULL;
+ hid->_x = 0;
+ hid->_y = 0;
+ hid->_spriteIndex = 0;
+ hid->_useCount = 0;
+ hid->_width = 0;
+ hid->_height = 0;
+ hid->_resetUseCount = false;
+ hid->_yOffset = 0;
+ }
+
+ _hidingActiveFl = false;
+}
+
+/**
+ * Change Object
+ */
+void ObjectsManager::changeObject(int objIndex) {
+ _vm->_events->_objectBuf = loadObjectFromFile(objIndex, true);
+ _curObjectIndex = objIndex;
+}
+
+byte *ObjectsManager::loadObjectFromFile(int objIndex, bool mode) {
+ byte *dataP = NULL;
+ int objectFileNum = _objectAuthIcons[objIndex]._objectFileNum;
+ int idx = _objectAuthIcons[objIndex]._idx;
+
+ if (mode)
+ ++idx;
+
+ if (objectFileNum != _curObjectFileNum) {
+ if (_objectDataBuf)
+ removeObjectDataBuf();
+ if (objectFileNum == 1) {
+ _objectDataBuf = loadSprite("OBJET1.SPR");
+ }
+ _curObjectFileNum = objectFileNum;
+ }
+
+ int width = getWidth(_objectDataBuf, idx);
+ int height = getHeight(_objectDataBuf, idx);
+ _objectWidth = width;
+ _objectHeight = height;
+
+ if (mode) {
+ sprite_alone(_objectDataBuf, _vm->_events->_objectBuf, idx);
+ dataP = _vm->_events->_objectBuf;
+ } else {
+ dataP = _vm->_globals->allocMemory(height * width);
+ if (dataP == NULL)
+ error("CAPTURE_OBJET");
+
+ capture_mem_sprite(_objectDataBuf, dataP, idx);
+ }
+
+ return dataP;
+}
+
+/**
+ * Remove an Object from the inventory
+ */
+void ObjectsManager::removeObject(int objIndex) {
+ int idx;
+ for (idx = 1; idx <= 32; ++idx) {
+ if (_vm->_globals->_inventory[idx] == objIndex)
+ break;
+ }
+
+ if (idx <= 32) {
+ if (idx == 32) {
+ _vm->_globals->_inventory[32] = 0;
+ } else {
+ for (int i = idx; i < 32; ++i)
+ _vm->_globals->_inventory[i] = _vm->_globals->_inventory[i + 1];
+ }
+ }
+ changeObject(14);
+
+}
+
+/**
+ * Set Offset XY
+ */
+void ObjectsManager::setOffsetXY(byte *data, int idx, int xp, int yp, bool isSize) {
+ byte *startP = data + 3;
+ for (int i = idx; i; --i)
+ startP += READ_LE_UINT32(startP) + 16;
+
+ byte *rectP = startP + 8;
+ if (isSize) {
+ // Set size
+ byte *pointP = rectP + 4;
+ WRITE_LE_UINT16(pointP, xp);
+ WRITE_LE_UINT16(pointP + 2, yp);
+ } else {
+ // Set position
+ WRITE_LE_UINT16(rectP, xp);
+ WRITE_LE_UINT16(rectP + 2, yp);
+ }
+}
+
+int ObjectsManager::getOffsetX(const byte *spriteData, int spriteIndex, bool isSize) {
+ const byte *data = spriteData + 3;
+ for (int i = spriteIndex; i; --i)
+ data += READ_LE_UINT32(data) + 16;
+
+ int result;
+ if (isSize)
+ result = READ_LE_INT16(data + 12);
+ else
+ result = READ_LE_INT16(data + 8);
+
+ return result;
+}
+
+int ObjectsManager::getOffsetY(const byte *spriteData, int spriteIndex, bool isSize) {
+ const byte *data = spriteData + 3;
+ for (int i = spriteIndex; i; --i)
+ data += READ_LE_UINT32(data) + 16;
+
+ int result;
+ if (isSize)
+ result = READ_LE_INT16(data + 14);
+ else
+ result = READ_LE_INT16(data + 10);
+
+ return result;
+}
+
+/**
+ * Get Width
+ */
+int ObjectsManager::getWidth(const byte *objectData, int idx) {
+ const byte *rectP = objectData + 3;
+ for (int i = idx; i; --i)
+ rectP += READ_LE_UINT32(rectP) + 16;
+
+ return READ_LE_INT16(rectP + 4);
+}
+
+/**
+ * Get height
+ */
+int ObjectsManager::getHeight(const byte *objectData, int idx) {
+ const byte *rectP = objectData + 3;
+ for (int i = idx; i; --i)
+ rectP += READ_LE_UINT32(rectP) + 16;
+
+ return READ_LE_INT16(rectP + 6);
+}
+
+void ObjectsManager::sprite_alone(const byte *objectData, byte *sprite, int objIndex) {
+ const byte *objP = objectData + 3;
+ for (int i = objIndex; i; --i) {
+ objP += READ_LE_UINT32(objP) + 16;
+ }
+
+ objP += 4;
+ int result = READ_LE_INT16(objP) * READ_LE_INT16(objP + 2);
+
+ memcpy(sprite + 3, objP - 4, result + 16);
+}
+
+void ObjectsManager::capture_mem_sprite(const byte *objectData, byte *sprite, int objIndex) {
+ const byte *objP = objectData + 3;
+ for (int i = objIndex; i; --i) {
+ objP += READ_LE_UINT32(objP) + 16;
+ }
+
+ objP += 4;
+ int result = READ_LE_INT16(objP) * READ_LE_INT16(objP + 2);
+ memcpy(sprite, objP + 12, result);
+}
+
+void ObjectsManager::removeObjectDataBuf() {
+ _curObjectFileNum = 0;
+ _objectDataBuf = _vm->_globals->freeMemory(_objectDataBuf);
+}
+
+/**
+ * Load Sprite from file
+ */
+byte *ObjectsManager::loadSprite(const Common::String &file) {
+ return _vm->_fileIO->loadFile(file);
+}
+
+/**
+ * Add Object
+ */
+void ObjectsManager::addObject(int objIndex) {
+ int arrIndex = 0;
+ for (;;) {
+ ++arrIndex;
+ if ((!_vm->_globals->_inventory[arrIndex]) || (arrIndex == 32))
+ break;
+ }
+
+ _vm->_globals->_inventory[arrIndex] = objIndex;
+}
+
+/**
+ * Display Sprite
+ */
+void ObjectsManager::displaySprite() {
+ int clipX;
+ int clipY;
+ bool loopCondFl;
+ uint16 arr[50];
+
+ // Handle copying any background areas that text are going to be drawn on
+ _sortedDisplayCount = 0;
+ for (int idx = 0; idx <= 10; ++idx) {
+ TxtItemList *curTxtList = &_vm->_fontMan->_textList[idx];
+ if (curTxtList->_enabledFl && _vm->_fontMan->_text[idx]._textType != 2) {
+ clipX = curTxtList->_pos.x - 2;
+
+ if (clipX < _vm->_graphicsMan->_minX)
+ clipX = _vm->_graphicsMan->_minX;
+
+ clipY = curTxtList->_pos.y - 2;
+ if (clipY < _vm->_graphicsMan->_minY)
+ clipY = _vm->_graphicsMan->_minY;
+
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, clipX, clipY,
+ curTxtList->_width + 4, curTxtList->_height + 4, _vm->_graphicsMan->_frontBuffer, clipX, clipY);
+ curTxtList->_enabledFl = false;
+ }
+ }
+
+ if (!_charactersEnabledFl) {
+ for (int idx = 0; idx < MAX_SPRITE; ++idx) {
+ ListeItem *curList = &_liste[idx];
+ if (curList->_visibleFl) {
+ clipX = curList->_posX - 2;
+ if (clipX < _vm->_graphicsMan->_minX)
+ clipX = _vm->_graphicsMan->_minX;
+
+ clipY = curList->_posY - 2;
+ if (clipY < _vm->_graphicsMan->_minY)
+ clipY = _vm->_graphicsMan->_minY;
+
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, clipX, clipY,
+ curList->_width + 4, curList->_height + 4, _vm->_graphicsMan->_frontBuffer, clipX, clipY);
+ curList->_visibleFl = false;
+ }
+ }
+ }
+
+ displayBobAnim();
+ displayVBob();
+
+ if (!_charactersEnabledFl) {
+ // Handle drawing characters on the screen
+ for (int idx = 0; idx < MAX_SPRITE; ++idx) {
+ _liste[idx]._visibleFl = false;
+ SpriteItem *curSpr = &_sprite[idx];
+ if (curSpr->_animationType == 1) {
+ computeSprite(idx);
+ if (curSpr->_activeFl)
+ beforeSort(SORT_SPRITE, idx, curSpr->_height + curSpr->_destY);
+ }
+ }
+
+ if (_hidingActiveFl)
+ checkHidingItem();
+ }
+
+ if (_priorityFl && _sortedDisplayCount) {
+ for (int i = 1; i <= 48; i++)
+ arr[i] = i;
+
+ do {
+ loopCondFl = false;
+ for (int sortIdx = 1; sortIdx < _sortedDisplayCount; sortIdx++) {
+ if (_sortedDisplay[arr[sortIdx]]._priority > _sortedDisplay[arr[sortIdx + 1]]._priority) {
+ SWAP(arr[sortIdx], arr[sortIdx + 1]);
+ loopCondFl = true;
+ }
+ }
+ } while (loopCondFl);
+
+ for (int sortIdx = 1; sortIdx < _sortedDisplayCount + 1; sortIdx++) {
+ int idx = arr[sortIdx];
+ switch (_sortedDisplay[idx]._sortMode) {
+ case SORT_BOB:
+ setBobInfo(_sortedDisplay[idx]._index);
+ break;
+ case SORT_SPRITE:
+ showSprite(_sortedDisplay[idx]._index);
+ break;
+ case SORT_HIDING:
+ displayHiding(_sortedDisplay[idx]._index);
+ break;
+ default:
+ break;
+ }
+ _sortedDisplay[idx]._sortMode = SORT_NONE;
+ }
+ } else {
+ for (int idx = 1; idx < _sortedDisplayCount + 1; ++idx) {
+ switch (_sortedDisplay[idx]._sortMode) {
+ case SORT_BOB:
+ setBobInfo(_sortedDisplay[idx]._index);
+ break;
+ case SORT_SPRITE:
+ showSprite(_sortedDisplay[idx]._index);
+ break;
+ case SORT_HIDING:
+ displayHiding(_sortedDisplay[idx]._index);
+ break;
+ default:
+ break;
+ }
+ _sortedDisplay[idx]._sortMode = SORT_NONE;
+ }
+ }
+
+ // Reset the Sort array
+ for (int idx = 0; idx < 50; ++idx) {
+ SortItem *disp = &_sortedDisplay[idx];
+ disp->_sortMode = SORT_NONE;
+ disp->_index = 0;
+ disp->_priority = 0;
+ }
+
+ _sortedDisplayCount = 0;
+
+ _vm->_dialog->drawInvent(_oldBorderPos, _oldBorderSpriteIndex, _borderPos, _borderSpriteIndex);
+
+ if (_saveLoadFl) {
+ int16 posX = _vm->_events->_startPos.x;
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, _saveLoadSprite, posX + 183, 60, 274, 353);
+ if (_saveLoadX && _saveLoadY)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _saveLoadSprite2, _saveLoadX + posX + 300, _saveLoadY + 300, 0);
+
+ _vm->_graphicsMan->addDirtyRect(posX + 183, 60, posX + 457, 413);
+ }
+
+ // If the Options dialog is activated, draw the elements
+ if (_vm->_globals->_optionDialogFl) {
+ int16 posX = _vm->_events->_startPos.x;
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 464, 407, 0);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 657, 556, _vm->_globals->_menuSpeed);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 731, 495, _vm->_globals->_menuTextOff);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 731, 468, _vm->_globals->_menuVoiceOff);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 731, 441, _vm->_globals->_menuSoundOff);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 731, 414, _vm->_globals->_menuMusicOff);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 600, 522, _vm->_globals->_menuDisplayType);
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
+ posX + 611, 502, _vm->_globals->_menuScrollSpeed);
+ _vm->_graphicsMan->addDirtyRect(posX + 164, 107, posX + 498, 320);
+ }
+
+ // Loop to draw any on-screen text
+ for (int idx = 0; idx <= 10; ++idx) {
+ TxtItem *curTxt = &_vm->_fontMan->_text[idx];
+ if (curTxt->_textOnFl) {
+ TxtItemList *curTxtList = &_vm->_fontMan->_textList[idx];
+ if ((curTxt->_textType < 2) || (curTxt->_textType > 3))
+ _vm->_fontMan->box(idx, curTxt->_messageId, curTxt->_filename, _vm->_events->_startPos.x + curTxt->_pos.x, curTxt->_pos.y);
+ else
+ _vm->_fontMan->box(idx, curTxt->_messageId, curTxt->_filename, curTxt->_pos.x, curTxt->_pos.y);
+ curTxtList->_enabledFl = true;
+
+ if ((curTxt->_textType < 2) || (curTxt->_textType > 3))
+ curTxtList->_pos.x = _vm->_events->_startPos.x + curTxt->_pos.x;
+ else
+ curTxtList->_pos.x = curTxt->_pos.x;
+
+ curTxtList->_pos.y = curTxt->_pos.y;
+ curTxtList->_width = curTxt->_width;
+ curTxtList->_height = curTxt->_height;
+
+ if (curTxtList->_pos.x < _vm->_graphicsMan->_minX)
+ curTxtList->_pos.x = _vm->_graphicsMan->_minX - 1;
+ if (curTxtList->_pos.y < _vm->_graphicsMan->_minY)
+ curTxtList->_pos.y = _vm->_graphicsMan->_minY - 1;
+
+ int posX = curTxtList->_pos.x;
+ if (curTxtList->_width + posX > _vm->_graphicsMan->_maxX)
+ curTxtList->_width = _vm->_graphicsMan->_maxX - posX;
+ int posY = curTxtList->_pos.y;
+ if (curTxtList->_height + posY > _vm->_graphicsMan->_maxY)
+ curTxtList->_height = _vm->_graphicsMan->_maxY - posY;
+ if (curTxtList->_width <= 0 || curTxtList->_height <= 0)
+ curTxtList->_enabledFl = false;
+ }
+ }
+
+ _vm->_dialog->inventAnim();
+}
+
+void ObjectsManager::resetBob(int idx) {
+ BobItem &bob = _bob[idx];
+ ListeItem &item = _liste2[idx];
+
+ bob._bobMode = 0;
+ bob._spriteData = NULL;
+ bob._xp = 0;
+ bob._yp = 0;
+ bob._frameIndex = 0;
+ bob._animDataIdx = 0;
+ bob._moveChange1 = 0;
+ bob._moveChange2 = 0;
+ bob._disabledAnimationFl = false;
+ bob._animData = NULL;
+ bob._bobMode10 = false;
+ bob._bobModeChange = 0;
+ bob._modeChangeCtr = 0;
+ bob._modeChangeUnused = 0;
+ bob._disableFl = false;
+ bob._zoomFactor = 0;
+ bob._flipFl = false;
+ bob._oldX2 = 0;
+
+ item._visibleFl = false;
+ item._posX = 0;
+ item._posY = 0;
+ item._width = 0;
+ item._height = 0;
+}
+
+void ObjectsManager::setBobInfo(int idx) {
+ BobItem *curBob = &_bob[idx];
+
+ if (!curBob->_activeFl)
+ return;
+
+ int xp = curBob->_oldX;
+ int yp = curBob->_oldY;
+
+ if (curBob->_isSpriteFl)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, curBob->_spriteData,
+ xp + 300, yp + 300, curBob->_frameIndex);
+ else
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer,
+ curBob->_spriteData, xp + 300, yp + 300, curBob->_frameIndex,
+ curBob->_zoomOutFactor, curBob->_zooInmFactor, curBob->_flipFl);
+
+ ListeItem *curLst = &_liste2[idx];
+ curLst->_visibleFl = true;
+ curLst->_posX = xp;
+ curLst->_posY = yp;
+
+ curLst->_width = curBob->_oldWidth;
+ curLst->_height = curBob->_oldHeight;
+
+ if (curLst->_posX < _vm->_graphicsMan->_minX) {
+ curLst->_width -= _vm->_graphicsMan->_minX - curLst->_posX;
+ curLst->_posX = _vm->_graphicsMan->_minX;
+ }
+
+ if (curLst->_posY < _vm->_graphicsMan->_minY) {
+ curLst->_height -= _vm->_graphicsMan->_minY - curLst->_posY;
+ curLst->_posY = _vm->_graphicsMan->_minY;
+ }
+
+ if (curLst->_width + curLst->_posX > _vm->_graphicsMan->_maxX)
+ curLst->_width = _vm->_graphicsMan->_maxX - curLst->_posX;
+
+ if (curLst->_height + curLst->_posY > _vm->_graphicsMan->_maxY)
+ curLst->_height = _vm->_graphicsMan->_maxY - curLst->_posY;
+
+ if (curLst->_width <= 0 || curLst->_height <= 0)
+ curLst->_visibleFl = false;
+
+ if (curLst->_visibleFl)
+ _vm->_graphicsMan->addDirtyRect(curLst->_posX, curLst->_posY, curLst->_posX + curLst->_width, curLst->_posY + curLst->_height);
+}
+
+void ObjectsManager::displayBob(int idx) {
+ BobItem *curBob = &_bob[idx];
+
+ _priorityFl = true;
+
+ if (curBob->_bobMode)
+ return;
+
+ resetBob(idx);
+
+ const byte *data = _vm->_animMan->_animBqe[idx]._data;
+ int bankIdx = READ_LE_INT16(data);
+ if (!bankIdx)
+ return;
+ if ((!_vm->_animMan->Bank[bankIdx]._loadedFl) || (!READ_LE_UINT16(data + 24)))
+ return;
+
+
+ int16 bobModeChange = READ_LE_INT16(data + 2);
+ int16 modeChangeUnused = READ_LE_INT16(data + 4);
+ // data[6] isn't used, read skipped
+ int16 newModeChangeCtr = READ_LE_INT16(data + 8);
+
+ if (!bobModeChange)
+ bobModeChange = 1;
+ if (!newModeChangeCtr)
+ newModeChangeCtr = -1;
+
+ curBob->_isSpriteFl = false;
+
+ if (_vm->_animMan->Bank[bankIdx]._fileHeader == 1) {
+ curBob->_isSpriteFl = true;
+ curBob->_zoomFactor = 0;
+ curBob->_flipFl = false;
+ }
+
+ curBob->_animData = _vm->_animMan->_animBqe[idx]._data;
+ curBob->_bobMode = 10;
+ curBob->_spriteData = _vm->_animMan->Bank[bankIdx]._data;
+
+ curBob->_bobModeChange = bobModeChange;
+ curBob->_modeChangeCtr = newModeChangeCtr;
+ curBob->_modeChangeUnused = modeChangeUnused;
+}
+
+void ObjectsManager::hideBob(int idx) {
+ BobItem *curBob = &_bob[idx];
+ if ((curBob->_bobMode == 3) || (curBob->_bobMode == 10))
+ curBob->_bobMode++;
+}
+
+void ObjectsManager::setBobOffset(int idx, int offset) {
+ _bob[idx]._oldX2 = offset;
+}
+
+void ObjectsManager::computeHideCounter(int idx) {
+ HidingItem *hid = &_hidingItem[idx];
+ if (hid->_useCount == 0)
+ return;
+
+ for (int i = 0; i <= 20; i++) {
+ BobItem *curBob = &_bob[i];
+ if ((curBob->_bobMode) && (!curBob->_disabledAnimationFl) && (!curBob->_disableFl) && (curBob->_frameIndex != 250)) {
+ int oldRight = curBob->_oldX + curBob->_oldWidth;
+ int oldBottom = curBob->_oldY + curBob->_oldHeight;
+ int hiddenRight = hid->_x + hid->_width;
+
+ if ((oldBottom > hid->_y) && (oldBottom < hid->_yOffset + hid->_height + hid->_y)) {
+ if ((oldRight >= hid->_x && oldRight <= hiddenRight)
+ // CHECKME: The original was doing the test two times. This looks like an
+ // original bug
+ // || (cachedRight >= curBob->_oldWidth && curBob->_oldWidth >= hid->_x)
+ || (hiddenRight >= curBob->_oldWidth && curBob->_oldWidth >= hid->_x)
+ || (curBob->_oldWidth >= hid->_x && oldRight <= hiddenRight)
+ || (curBob->_oldWidth <= hid->_x && oldRight >= hiddenRight))
+ ++hid->_useCount;
+ }
+ }
+ }
+}
+
+void ObjectsManager::initBobVariables(int idx) {
+ BobItem *bob = &_bob[idx];
+
+ bob->_activeFl = false;
+ if (bob->_isSpriteFl) {
+ bob->_flipFl = false;
+ bob->_zoomFactor = 0;
+ }
+
+ int spriteIdx = bob->_frameIndex;
+ if (spriteIdx == 250)
+ return;
+
+ int deltaY, deltaX;
+ if (bob->_flipFl) {
+ deltaX = getOffsetX(bob->_spriteData, spriteIdx, true);
+ deltaY = getOffsetY(bob->_spriteData, bob->_frameIndex, true);
+ } else {
+ deltaX = getOffsetX(bob->_spriteData, spriteIdx, false);
+ deltaY = getOffsetY(bob->_spriteData, bob->_frameIndex, false);
+ }
+
+ int negZoom = 0;
+ int posZoom = 0;
+ if (bob->_zoomFactor < 0)
+ negZoom = CLIP(-bob->_zoomFactor, 0, 95);
+ else
+ posZoom = bob->_zoomFactor;
+
+ if (posZoom) {
+ if (deltaX >= 0)
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, posZoom);
+ else
+ deltaX = -_vm->_graphicsMan->zoomIn(-deltaX, posZoom);
+
+ if (deltaY >= 0)
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, posZoom);
+ else
+ deltaY = -_vm->_graphicsMan->zoomIn(abs(deltaX), posZoom);
+ }
+
+ if (negZoom) {
+ if (deltaX >= 0)
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, negZoom);
+ else
+ deltaX = -_vm->_graphicsMan->zoomOut(-deltaX, negZoom);
+
+ if (deltaY >= 0)
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, negZoom);
+ else
+ deltaY = -_vm->_graphicsMan->zoomOut(abs(deltaX), negZoom);
+ }
+
+ int newX = bob->_xp - deltaX;
+ int newY = bob->_yp - deltaY;
+ bob->_activeFl = true;
+ bob->_oldX = newX;
+ bob->_oldY = newY;
+ bob->_zooInmFactor = posZoom;
+ bob->_zoomOutFactor = negZoom;
+
+ ListeItem *curList = &_liste2[idx];
+ curList->_visibleFl = true;
+ curList->_posX = newX;
+ curList->_posY = newY;
+
+ int width = getWidth(bob->_spriteData, bob->_frameIndex);
+ int height = getHeight(bob->_spriteData, bob->_frameIndex);
+
+ if (posZoom) {
+ width = _vm->_graphicsMan->zoomIn(width, posZoom);
+ height = _vm->_graphicsMan->zoomIn(height, posZoom);
+ } else if (negZoom) {
+ width = _vm->_graphicsMan->zoomOut(width, negZoom);
+ height = _vm->_graphicsMan->zoomOut(height, negZoom);
+ }
+
+ curList->_width = width;
+ curList->_height = height;
+ bob->_oldWidth = width;
+ bob->_oldHeight = height;
+}
+
+void ObjectsManager::checkHidingItem() {
+ for (int hidingItemIdx = 0; hidingItemIdx <= 19; hidingItemIdx++) {
+ HidingItem *hid = &_hidingItem[hidingItemIdx];
+ if (hid->_useCount == 0)
+ continue;
+
+ int _oldUseCount = hid->_useCount;
+ for (int spriteIdx = 0; spriteIdx <= 4; spriteIdx++) {
+ const SpriteItem *spr = &_sprite[spriteIdx];
+ if (spr->_animationType == 1 && spr->_spriteIndex != 250) {
+ int right = spr->_width + spr->_destX;
+ int bottom = spr->_height + spr->_destY;
+ int hidingRight = hid->_width + hid->_x;
+
+ if (bottom > hid->_y && bottom < (hid->_yOffset + hid->_height + hid->_y)) {
+ if ((right >= hid->_x && right <= hidingRight)
+ // CHECKME: The original was doing the test two times. This looks like an
+ // original bug
+ // || (hidingRight >= spr->_destX && hid->_x <= spr->_destX)
+ || (hidingRight >= spr->_destX && hid->_x <= spr->_destX)
+ || (hid->_x <= spr->_destX && right <= hidingRight)
+ || (hid->_x >= spr->_destX && right >= hidingRight))
+ ++hid->_useCount;
+ }
+ }
+ }
+
+ computeHideCounter(hidingItemIdx);
+ if (hid->_useCount != _oldUseCount) {
+ int priority = hid->_yOffset + hid->_height + hid->_y;
+ if (priority > 440)
+ priority = 500;
+
+ beforeSort(SORT_HIDING, hidingItemIdx, priority);
+ hid->_useCount = 1;
+ hid->_resetUseCount = true;
+ } else if (hid->_resetUseCount) {
+ hid->_resetUseCount = false;
+ hid->_useCount = 1;
+ }
+
+ }
+}
+
+void ObjectsManager::showSprite(int idx) {
+ SpriteItem *spr = &_sprite[idx];
+ if (!spr->_activeFl)
+ return;
+
+ if (spr->_rleFl)
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, spr->_spriteData,
+ spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex);
+ else
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, spr->_spriteData,
+ spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex, spr->_reducePct, spr->_zoomPct, spr->_flipFl);
+
+ ListeItem *list = &_liste[idx];
+ list->_width = spr->_width;
+ list->_height = spr->_height;
+
+ if (list->_posX < _vm->_graphicsMan->_minX) {
+ list->_width -= _vm->_graphicsMan->_minX - list->_posX;
+ list->_posX = _vm->_graphicsMan->_minX;
+ }
+
+ if (list->_posY < _vm->_graphicsMan->_minY) {
+ list->_height -= _vm->_graphicsMan->_minY - list->_posY;
+ list->_posY = _vm->_graphicsMan->_minY;
+ }
+
+ list->_width = MIN(list->_width, _vm->_graphicsMan->_maxX - list->_posX);
+ list->_height = MIN(list->_height, _vm->_graphicsMan->_maxY - list->_posY);
+
+ if (list->_width <= 0 || list->_height <= 0)
+ list->_visibleFl = false;
+
+ if (list->_visibleFl)
+ _vm->_graphicsMan->addDirtyRect( list->_posX, list->_posY, list->_posX + list->_width, list->_posY + list->_height);
+}
+
+void ObjectsManager::displayHiding(int idx) {
+ HidingItem *hid = &_hidingItem[idx];
+
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _hidingItemData[1],
+ hid->_x + 300, hid->_y + 300, hid->_spriteIndex);
+ _vm->_graphicsMan->addDirtyRect(hid->_x, hid->_y, hid->_x + hid->_width, hid->_y + hid->_height);
+}
+
+// Compute Sprite
+void ObjectsManager::computeSprite(int idx) {
+ SpriteItem *spr = &_sprite[idx];
+
+ spr->_activeFl = false;
+ int spriteIndex = spr->_spriteIndex;
+ if (spriteIndex == 250)
+ return;
+
+ int offX;
+ int offY;
+ if (spr->_flipFl) {
+ offX = getOffsetX(spr->_spriteData, spriteIndex, true);
+ offY = getOffsetY(spr->_spriteData, spr->_spriteIndex, true);
+ } else {
+ offX = getOffsetX(spr->_spriteData, spriteIndex, false);
+ offY = getOffsetY(spr->_spriteData, spr->_spriteIndex, false);
+ }
+
+ int tmpX = spr->_deltaX + offX;
+ int deltaX = tmpX;
+ int tmpY = spr->_deltaY + offY;
+ int deltaY = tmpY;
+ int zoomPercent = 0;
+ int reducePercent = 0;
+
+ if (spr->_zoomFactor < 0) {
+ reducePercent = -spr->_zoomFactor;
+ if (reducePercent > 95)
+ reducePercent = 95;
+ } else
+ zoomPercent = spr->_zoomFactor;
+
+ if (zoomPercent) {
+ if (tmpX >= 0)
+ deltaX = _vm->_graphicsMan->zoomIn(tmpX, zoomPercent);
+ else
+ deltaX = -_vm->_graphicsMan->zoomIn(-tmpX, zoomPercent);
+
+ if (tmpY >= 0) {
+ deltaY = _vm->_graphicsMan->zoomIn(tmpY, zoomPercent);
+ } else {
+ tmpY = abs(tmpX);
+ deltaY = -_vm->_graphicsMan->zoomIn(tmpY, zoomPercent);
+ }
+ } else if (reducePercent) {
+ if (tmpX >= 0)
+ deltaX = _vm->_graphicsMan->zoomOut(tmpX, reducePercent);
+ else
+ deltaX = -_vm->_graphicsMan->zoomOut(-tmpX, reducePercent);
+
+ if (tmpY >= 0) {
+ deltaY = _vm->_graphicsMan->zoomOut(tmpY, reducePercent);
+ } else {
+ tmpY = abs(tmpX);
+ deltaY = -_vm->_graphicsMan->zoomOut(tmpY, reducePercent);
+ }
+ }
+
+ int newPosX = spr->_spritePos.x - deltaX;
+ int newPosY = spr->_spritePos.y - deltaY;
+ spr->_destX = newPosX;
+ spr->_destY = newPosY;
+ spr->_activeFl = true;
+ spr->_zoomPct = zoomPercent;
+ spr->_reducePct = reducePercent;
+
+ _liste[idx]._visibleFl = true;
+ _liste[idx]._posX = newPosX;
+ _liste[idx]._posY = newPosY;
+
+ int width = getWidth(spr->_spriteData, spr->_spriteIndex);
+ int height = getHeight(spr->_spriteData, spr->_spriteIndex);
+
+ if (zoomPercent) {
+ width = _vm->_graphicsMan->zoomIn(width, zoomPercent);
+ height = _vm->_graphicsMan->zoomIn(height, zoomPercent);
+ } else if (reducePercent) {
+ height = _vm->_graphicsMan->zoomOut(height, reducePercent);
+ width = _vm->_graphicsMan->zoomOut(width, reducePercent);
+ }
+
+ spr->_width = width;
+ spr->_height = height;
+}
+
+// Before Sort
+void ObjectsManager::beforeSort(SortMode sortMode, int index, int priority) {
+ ++_sortedDisplayCount;
+ assert (_sortedDisplayCount <= 48);
+
+ _sortedDisplay[_sortedDisplayCount]._sortMode = sortMode;
+ _sortedDisplay[_sortedDisplayCount]._index = index;
+ _sortedDisplay[_sortedDisplayCount]._priority = priority;
+}
+
+// Display BOB Anim
+void ObjectsManager::displayBobAnim() {
+ for (int idx = 1; idx <= 35; idx++) {
+ BobItem *bob = &_bob[idx];
+ if (idx <= 20 && _charactersEnabledFl) {
+ bob->_bobMode10 = false;
+ continue;
+ }
+
+ if (bob->_bobMode != 10)
+ continue;
+
+ bob->_bobMode10 = false;
+ if (bob->_animData == NULL || bob->_disabledAnimationFl || bob->_modeChangeCtr == 0 || bob->_modeChangeCtr < -1) {
+ if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
+ bob->_bobMode10 = true;
+ continue;
+ }
+
+ if (bob->_moveChange1 == bob->_moveChange2) {
+ bob->_bobMode10 = true;
+ } else {
+ bob->_moveChange2++;
+ bob->_bobMode10 = false;
+ }
+
+ if (!bob->_bobMode10) {
+ if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
+ bob->_bobMode10 = true;
+ continue;
+ }
+
+ byte *dataPtr = bob->_animData + 20;
+ int dataIdx = bob->_animDataIdx;
+ bob->_xp = READ_LE_INT16(dataPtr + 2 * dataIdx);
+ if (_lockedAnims[idx]._enableFl)
+ bob->_xp = _lockedAnims[idx]._posX;
+ if ( _charactersEnabledFl && idx > 20)
+ bob->_xp += _vm->_events->_startPos.x;
+
+ bob->_yp = READ_LE_INT16(dataPtr + 2 * dataIdx + 2);
+ bob->_moveChange1 = READ_LE_INT16(dataPtr + 2 * dataIdx + 4);
+ bob->_zoomFactor = READ_LE_INT16(dataPtr + 2 * dataIdx + 6);
+ bob->_frameIndex = dataPtr[2 * dataIdx + 8];
+ bob->_flipFl = (dataPtr[2 * dataIdx + 9] != 0);
+ bob->_animDataIdx += 5;
+
+ if (bob->_moveChange1 > 0) {
+ bob->_moveChange1 /= _vm->_globals->_speed;
+ if (bob->_moveChange1 > 0) {
+ bob->_moveChange2 = 1;
+ if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
+ bob->_bobMode10 = true;
+ continue;
+ }
+
+ bob->_moveChange1 = 1;
+ }
+ if (!bob->_moveChange1) {
+ if (bob->_modeChangeCtr > 0)
+ bob->_modeChangeCtr--;
+ if (bob->_modeChangeCtr != -1 && bob->_modeChangeCtr <= 0) {
+ bob->_bobMode = 11;
+ } else {
+ bob->_animDataIdx = 0;
+ byte *bobData = bob->_animData + 20;
+ bob->_xp = READ_LE_INT16(bobData);
+
+ if (_lockedAnims[idx]._enableFl)
+ bob->_xp = _lockedAnims[idx]._posX;
+ if (_charactersEnabledFl && idx > 20)
+ bob->_xp += _vm->_events->_startPos.x;
+
+ bob->_yp = READ_LE_INT16(bobData + 2);
+ bob->_moveChange1 = READ_LE_INT16(bobData + 4);
+ bob->_zoomFactor = READ_LE_INT16(bobData + 6);
+ bob->_frameIndex = bobData[8];
+ bob->_flipFl = (bobData[9] != 0);
+ bob->_animDataIdx += 5;
+
+ if (bob->_moveChange1 > 0) {
+ bob->_moveChange1 /= _vm->_globals->_speed;
+ // Original code. It can't be negative, so the check is on == 0
+ if (bob->_moveChange1 <= 0)
+ bob->_moveChange1 = 1;
+ }
+ }
+ }
+
+ bob->_moveChange2 = 1;
+ if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
+ bob->_bobMode10 = true;
+ }
+
+ if (!_charactersEnabledFl && _refreshBobMode10Fl) {
+ for (int i = 0; i < 35; i++) {
+ BobItem *curBob = &_bob[i];
+ if (curBob->_bobMode == 10 && !curBob->_disabledAnimationFl)
+ curBob->_bobMode10 = true;
+ }
+ }
+
+ _refreshBobMode10Fl = false;
+
+ for (int i = 1; i <= 35; i++) {
+ BobItem *curBob = &_bob[i];
+ ListeItem *curList = &_liste2[i];
+ if (i > 20 || !_charactersEnabledFl) {
+ if ((curBob->_bobMode == 10) && (curBob->_bobMode10)) {
+ if ((curBob->_bobModeChange != 2) && (curBob->_bobModeChange != 4)) {
+ if (curList->_visibleFl) {
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, curList->_posX, curList->_posY,
+ curList->_width, curList->_height, _vm->_graphicsMan->_frontBuffer, curList->_posX, curList->_posY);
+ curList->_visibleFl = false;
+ }
+ }
+ }
+
+ if (curBob->_bobMode == 11) {
+ if (curList->_visibleFl) {
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, curList->_posX, curList->_posY,
+ curList->_width, curList->_height, _vm->_graphicsMan->_frontBuffer, curList->_posX, curList->_posY);
+ curList->_visibleFl = false;
+ }
+
+ curBob->_bobMode = 0;
+ }
+ }
+ }
+
+ for (int i = 1; i <= 35; i++) {
+ BobItem *curBob = &_bob[i];
+ curBob->_oldY = 0;
+ if (curBob->_bobMode == 10 && !curBob->_disabledAnimationFl && curBob->_bobMode10) {
+ initBobVariables(i);
+ int priority = curBob->_oldX2 + curBob->_oldHeight + curBob->_oldY;
+
+ if (priority > 450)
+ priority = 600;
+
+ if (curBob->_activeFl)
+ beforeSort(SORT_BOB, i, priority);
+ }
+ }
+}
+
+// Display VBOB
+void ObjectsManager::displayVBob() {
+ int width, height;
+
+ for (int idx = 0; idx <= 29; idx++) {
+ VBobItem *vbob = &_vBob[idx];
+ if (vbob->_displayMode == 4) {
+ width = getWidth(vbob->_spriteData, vbob->_frameIndex);
+ height = getHeight(vbob->_spriteData, vbob->_frameIndex);
+
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_backBuffer, vbob->_surface,
+ vbob->_xp, vbob->_yp, width, height);
+
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, vbob->_surface,
+ vbob->_xp, vbob->_yp, width, height);
+
+ _vm->_graphicsMan->addDirtyRect(vbob->_xp, vbob->_yp, vbob->_xp + width, height + vbob->_yp);
+ vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
+
+ vbob->_displayMode = 0;
+ vbob->_spriteData = NULL;
+ vbob->_xp = 0;
+ vbob->_yp = 0;
+ vbob->_oldX = 0;
+ vbob->_oldY = 0;
+ vbob->_frameIndex = 0;
+ vbob->_oldFrameIndex = 0;
+ vbob->_oldSpriteData = NULL;
+ }
+
+ if (vbob->_displayMode == 3) {
+ width = getWidth(vbob->_oldSpriteData, vbob->_oldFrameIndex);
+ height = getHeight(vbob->_oldSpriteData, vbob->_oldFrameIndex);
+
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_backBuffer, vbob->_surface,
+ vbob->_oldX, vbob->_oldY, width, height);
+
+ _vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, vbob->_surface,
+ vbob->_oldX, vbob->_oldY, width, height);
+
+ _vm->_graphicsMan->addDirtyRect(vbob->_oldX, vbob->_oldY, vbob->_oldX + width, vbob->_oldY + height);
+
+ vbob->_displayMode = 1;
+ vbob->_oldSpriteData = vbob->_spriteData;
+
+ vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
+
+ vbob->_oldX = vbob->_xp;
+ vbob->_oldY = vbob->_yp;
+ vbob->_oldFrameIndex = vbob->_frameIndex;
+ }
+
+ if (vbob->_displayMode == 1) {
+ width = getWidth(vbob->_spriteData, vbob->_frameIndex);
+ height = getHeight(vbob->_spriteData, vbob->_frameIndex);
+
+ vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
+
+ byte *surface = _vm->_globals->allocMemory(height * width);
+ vbob->_surface = surface;
+
+ _vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_backBuffer, surface,
+ vbob->_xp, vbob->_yp, width, height);
+
+ if (*vbob->_spriteData == 78) {
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_backBuffer, vbob->_spriteData,
+ vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false);
+
+ _vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, vbob->_spriteData,
+ vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false);
+ } else {
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, vbob->_spriteData,
+ vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex);
+
+ _vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_backBuffer, vbob->_spriteData,
+ vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex);
+ }
+
+ _vm->_graphicsMan->addDirtyRect(vbob->_xp, vbob->_yp , vbob->_xp + width, vbob->_yp + height);
+ vbob->_displayMode = 2;
+ }
+ }
+}
+
+/**
+ * Get Sprite X coordinate
+ */
+int ObjectsManager::getSpriteX(int idx) {
+ assert (idx <= MAX_SPRITE);
+ return _sprite[idx]._spritePos.x;
+}
+
+/**
+ * Get Sprite Y coordinate
+ */
+int ObjectsManager::getSpriteY(int idx) {
+ assert (idx <= MAX_SPRITE);
+ return _sprite[idx]._spritePos.y;
+}
+
+/**
+ * Clear sprite structure
+ */
+void ObjectsManager::clearSprite() {
+ for (int idx = 0; idx < MAX_SPRITE; idx++) {
+ _sprite[idx]._spriteData = NULL;
+ _sprite[idx]._animationType = 0;
+ }
+
+ for (int idx = 0; idx < MAX_SPRITE; idx++) {
+ ListeItem *list = &_liste[idx];
+ list->_visibleFl = false;
+ list->_posX = 0;
+ list->_posY = 0;
+ list->_width = 0;
+ list->_height = 0;
+ }
+}
+
+void ObjectsManager::animateSprite(int idx) {
+ assert (idx <= MAX_SPRITE);
+ _sprite[idx]._animationType = 1;
+}
+
+void ObjectsManager::addStaticSprite(const byte *spriteData, Common::Point pos, int idx, int spriteIndex, int zoomFactor, bool flipFl, int deltaX, int deltaY) {
+ assert (idx <= MAX_SPRITE);
+
+ SpriteItem *spr = &_sprite[idx];
+ spr->_spriteData = spriteData;
+ spr->_spritePos = pos;
+ spr->_spriteIndex = spriteIndex;
+ spr->_zoomFactor = zoomFactor;
+ spr->_flipFl = flipFl;
+ spr->_deltaX = deltaX;
+ spr->_deltaY = deltaY;
+ spr->_animationType = 0;
+
+ if (READ_BE_UINT24(spriteData) == MKTAG24('R', 'L', 'E')) {
+ spr->_rleFl = true;
+ spr->_zoomFactor = 0;
+ spr->_flipFl = false;
+ } else
+ spr->_rleFl = false;
+
+}
+
+/**
+ * Freeze sprite animation and free its memory
+ */
+void ObjectsManager::removeSprite(int idx) {
+ // Type 3 was also used by freeSprite(), which has been removed as it wasn't used
+ _sprite[idx]._animationType = 3;
+}
+
+/**
+ * Set Sprite X coordinate
+ */
+void ObjectsManager::setSpriteX(int idx, int xp) {
+ assert (idx <= MAX_SPRITE);
+ _sprite[idx]._spritePos.x = xp;
+}
+
+/**
+ * Set Sprite Y coordinate
+ */
+void ObjectsManager::setSpriteY(int idx, int yp) {
+ assert (idx <= MAX_SPRITE);
+ _sprite[idx]._spritePos.y = yp;
+}
+
+/**
+ * Set Sprite Index
+ */
+void ObjectsManager::setSpriteIndex(int idx, int spriteIndex) {
+ assert (idx <= MAX_SPRITE);
+ _sprite[idx]._spriteIndex = spriteIndex;
+}
+
+// Set Sprite Size
+void ObjectsManager::setSpriteZoom(int idx, int zoomFactor) {
+ assert (idx <= MAX_SPRITE);
+ if (!_sprite[idx]._rleFl)
+ _sprite[idx]._zoomFactor = zoomFactor;
+}
+
+void ObjectsManager::setFlipSprite(int idx, bool flipFl) {
+ assert (idx <= MAX_SPRITE);
+ if (!_sprite[idx]._rleFl)
+ _sprite[idx]._flipFl = flipFl;
+}
+
+void ObjectsManager::goHome() {
+ if (_vm->_linesMan->_route == NULL)
+ return;
+
+ if (_homeRateCounter > 1) {
+ --_homeRateCounter;
+ return;
+ }
+
+ int newPosX;
+ int newPosY;
+ Directions newDirection;
+
+ int oldPosX = 0;
+ int oldPosY = 0;
+ int oldFrameIdx = 0;
+ _homeRateCounter = 0;
+ if (_oldDirection == DIR_NONE) {
+ computeAndSetSpriteSize();
+ newPosX = _vm->_linesMan->_route->_x;
+ newPosY = _vm->_linesMan->_route->_y;
+ newDirection = _vm->_linesMan->_route->_dir;
+ _vm->_linesMan->_route++;
+
+ if (newPosX != -1 || newPosY != -1) {
+ _oldDirection = newDirection;
+ _oldDirectionSpriteIdx = newDirection + 59;
+ _oldFrameIndex = 0;
+ _oldCharacterPosX = newPosX;
+ _oldCharacterPosY = newPosY;
+ } else {
+ setSpriteIndex(0, _oldDirection + 59);
+ _vm->_globals->_actionDirection = DIR_NONE;
+ int zoneId;
+ if (_vm->_globals->_actionMoveTo)
+ zoneId = _vm->_globals->_saveData->_data[svLastZoneNum];
+ else
+ zoneId = _zoneNum;
+ _vm->_linesMan->_route = NULL;
+ computeAndSetSpriteSize();
+ setFlipSprite(0, false);
+ _homeRateCounter = 0;
+ _vm->_linesMan->_route = NULL;
+ _oldDirection = DIR_NONE;
+ if (zoneId > 0) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[zoneId];
+ if (curZone->_destX && curZone->_destY && curZone->_destY != 31) {
+ if (curZone->_spriteIndex == -1) {
+ curZone->_destX = 0;
+ curZone->_destY = 0;
+ curZone->_spriteIndex = 0;
+ } else {
+ setSpriteIndex(0, curZone->_spriteIndex);
+ _vm->_globals->_actionDirection = curZone->_spriteIndex - 59;
+ }
+ }
+ }
+ }
+ _homeRateCounter = 0;
+ return;
+ }
+ if (_oldDirection == DIR_RIGHT) {
+ if (_oldFrameIndex < 24 || _oldFrameIndex > 35) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 24;
+ } else {
+ int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
+ int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
+
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ } else if (_sprite[0]._zoomFactor > 0) {
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = _oldCharacterPosX + deltaX;
+ oldPosY = _oldCharacterPosY + deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 35)
+ oldFrameIdx = 24;
+ }
+ _homeRateCounter = 5 / _vm->_globals->_speed;
+ }
+ if (_oldDirection == DIR_LEFT) {
+ if (_oldFrameIndex < 24 || _oldFrameIndex > 35) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 24;
+ } else {
+ int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
+ int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ } else if (_sprite[0]._zoomFactor > 0) {
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = _oldCharacterPosX - deltaX;
+ oldPosY = _oldCharacterPosY - deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 35)
+ oldFrameIdx = 24;
+ }
+ _homeRateCounter = 5 / _vm->_globals->_speed;
+ }
+ if (_oldDirection == DIR_UP) {
+ if (_oldFrameIndex > 11) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 0;
+ } else {
+ int deltaY = abs(_vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY);
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ } else if (_sprite[0]._zoomFactor > 0) {
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY - deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 11)
+ oldFrameIdx = 0;
+ }
+ _homeRateCounter = 4 / _vm->_globals->_speed;
+ }
+
+ if (_oldDirection == DIR_DOWN) {
+ if (_oldFrameIndex < 48 || _oldFrameIndex > 59) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 48;
+ } else {
+ int deltaY = abs(_vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY);
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ } else if (_sprite[0]._zoomFactor > 0) {
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = _oldCharacterPosX;
+ oldPosY = deltaY + _oldCharacterPosY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 59)
+ oldFrameIdx = 48;
+ }
+ _homeRateCounter = 4 / _vm->_globals->_speed;
+ }
+ if (_oldDirection == DIR_UP_RIGHT) {
+ if (_oldFrameIndex < 12 || _oldFrameIndex > 23) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 12;
+ } else {
+ int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
+ int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ }
+ if (_sprite[0]._zoomFactor > 0) {
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = deltaX + _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY + deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 23)
+ oldFrameIdx = 12;
+ }
+ _homeRateCounter = 5 / _vm->_globals->_speed;
+ }
+ if (_oldDirection == DIR_UP_LEFT) {
+ if (_oldFrameIndex < 12 || _oldFrameIndex > 23) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 12;
+ } else {
+ int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
+ int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ } else if (_sprite[0]._zoomFactor > 0) {
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = _oldCharacterPosX - deltaX;
+ oldPosY = _oldCharacterPosY + deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 23)
+ oldFrameIdx = 12;
+ }
+ _homeRateCounter = 5 / _vm->_globals->_speed;
+ }
+ if (_oldDirection == DIR_DOWN_RIGHT) {
+ if (_oldFrameIndex < 36 || _oldFrameIndex > 47) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 36;
+ } else {
+ int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
+ int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ }
+ if (_sprite[0]._zoomFactor > 0) {
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = deltaX + _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY + deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 47)
+ oldFrameIdx = 36;
+ }
+ _homeRateCounter = 5 / _vm->_globals->_speed;
+ }
+ if (_oldDirection == DIR_DOWN_LEFT) {
+ if (_oldFrameIndex < 36 || _oldFrameIndex > 47) {
+ oldPosX = _oldCharacterPosX;
+ oldPosY = _oldCharacterPosY;
+ oldFrameIdx = 36;
+ } else {
+ int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
+ int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
+ if (_sprite[0]._zoomFactor < 0) {
+ deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
+ }
+ if (_sprite[0]._zoomFactor > 0) {
+ deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
+ deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
+ }
+ oldPosX = _oldCharacterPosX - deltaX;
+ oldPosY = _oldCharacterPosY + deltaY;
+ oldFrameIdx = _oldFrameIndex + 1;
+ if (oldFrameIdx > 47)
+ oldFrameIdx = 36;
+ }
+ _homeRateCounter = 5 / _vm->_globals->_speed;
+ }
+ bool loopCond = false;
+ do {
+ newPosX = _vm->_linesMan->_route->_x;
+ newPosY = _vm->_linesMan->_route->_y;
+ newDirection = (Directions)_vm->_linesMan->_route->_dir;
+ _vm->_linesMan->_route++;
+
+ if (newPosX == -1 && newPosY == -1) {
+ int zoneId;
+ if (_vm->_globals->_actionMoveTo)
+ zoneId = _vm->_globals->_saveData->_data[svLastZoneNum];
+ else
+ zoneId = _zoneNum;
+ setSpriteIndex(0, _oldDirection + 59);
+ _vm->_globals->_actionDirection = DIR_NONE;
+ _vm->_linesMan->_route = NULL;
+ computeAndSetSpriteSize();
+ setFlipSprite(0, false);
+ _homeRateCounter = 0;
+ _oldDirection = DIR_NONE;
+ _oldCharacterPosX = getSpriteX(0);
+ _oldCharacterPosY = getSpriteY(0);
+
+ if (zoneId > 0) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[zoneId];
+ if (curZone->_destX && curZone->_destY && curZone->_destY != 31) {
+ if ( curZone->_spriteIndex == -1) {
+ curZone->_destX = 0;
+ curZone->_destY = 0;
+ curZone->_spriteIndex = 0;
+ } else {
+ setSpriteIndex(0, curZone->_spriteIndex);
+ _vm->_globals->_actionDirection = curZone->_spriteIndex - 59;
+ }
+ }
+ }
+ _homeRateCounter = 0;
+ return;
+ }
+ if (_oldDirection != newDirection)
+ break;
+ if ((newDirection == DIR_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_LEFT && newPosX <= oldPosX) ||
+ (_oldDirection == DIR_UP && newPosY <= oldPosY) || (_oldDirection == DIR_DOWN && newPosY >= oldPosY) ||
+ (_oldDirection == DIR_UP_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_UP_LEFT && newPosX <= oldPosX) ||
+ (_oldDirection == DIR_DOWN_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_DOWN_LEFT && newPosX <= oldPosX))
+ loopCond = true;
+ } while (!loopCond);
+ if (loopCond) {
+ computeAndSetSpriteSize();
+ if ((_oldDirection == DIR_DOWN_LEFT) || (_oldDirection == DIR_LEFT) || (_oldDirection == DIR_UP_LEFT))
+ setFlipSprite(0, true);
+
+ if ((_oldDirection == DIR_UP) || (_oldDirection == DIR_UP_RIGHT) || (_oldDirection == DIR_RIGHT) ||
+ (_oldDirection == DIR_DOWN_RIGHT) || (_oldDirection == DIR_DOWN))
+ setFlipSprite(0, false);
+
+ setSpriteX(0, newPosX);
+ setSpriteY(0, newPosY);
+ setSpriteIndex(0, oldFrameIdx);
+ } else {
+ if ((_oldDirection == DIR_DOWN_LEFT) || (_oldDirection == DIR_LEFT) || (_oldDirection == DIR_UP_LEFT))
+ setFlipSprite(0, true);
+
+ if ((_oldDirection == DIR_UP) || (_oldDirection == DIR_UP_RIGHT) || (_oldDirection == DIR_RIGHT) ||
+ (_oldDirection == DIR_DOWN_RIGHT) || (_oldDirection == DIR_DOWN))
+ setFlipSprite(0, false);
+ _homeRateCounter = 0;
+ }
+ _oldDirection = newDirection;
+ _oldDirectionSpriteIdx = newDirection + 59;
+ _oldFrameIndex = oldFrameIdx;
+ _oldCharacterPosX = newPosX;
+ _oldCharacterPosY = newPosY;
+}
+
+void ObjectsManager::goHome2() {
+ if (_vm->_linesMan->_route == NULL)
+ return;
+
+ int realSpeed = 2;
+ if (_vm->_globals->_speed == 2)
+ realSpeed = 4;
+ else if (_vm->_globals->_speed == 3)
+ realSpeed = 6;
+
+ int countColisionPixel = 0;
+
+ for (;;) {
+ int nexPosX = _vm->_linesMan->_route->_x;
+ int newPosY = _vm->_linesMan->_route->_y;
+ Directions newDirection = (Directions)_vm->_linesMan->_route->_dir;
+ _vm->_linesMan->_route++;
+
+ if ((nexPosX == -1) && (newPosY == -1))
+ break;
+
+ ++countColisionPixel;
+ if (countColisionPixel >= realSpeed) {
+ _lastDirection = newDirection;
+ setSpriteX(0, nexPosX);
+ setSpriteY(0, newPosY);
+ switch (_lastDirection) {
+ case DIR_UP:
+ setSpriteIndex(0, 4);
+ break;
+ case DIR_RIGHT:
+ setSpriteIndex(0, 5);
+ break;
+ case DIR_DOWN:
+ setSpriteIndex(0, 6);
+ break;
+ case DIR_LEFT:
+ setSpriteIndex(0, 7);
+ break;
+ default:
+ break;
+ }
+
+ return;
+ }
+ }
+
+ switch (_lastDirection) {
+ case DIR_UP:
+ setSpriteIndex(0, 0);
+ break;
+ case DIR_RIGHT:
+ setSpriteIndex(0, 1);
+ break;
+ case DIR_DOWN:
+ setSpriteIndex(0, 2);
+ break;
+ case DIR_LEFT:
+ setSpriteIndex(0, 3);
+ break;
+ default:
+ break;
+ }
+
+ _vm->_linesMan->_route = NULL;
+}
+
+/**
+ * Load Zone
+ */
+void ObjectsManager::loadZone(const Common::String &file) {
+ for (int i = 1; i <= 100; i++) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[i];
+ curZone->_destX = 0;
+ curZone->_destY = 0;
+ curZone->_spriteIndex = 0;
+ curZone->_verbFl1 = 0;
+ curZone->_verbFl2 = 0;
+ curZone->_verbFl3 = 0;
+ curZone->_verbFl4 = 0;
+ curZone->_verbFl5 = 0;
+ curZone->_verbFl6 = 0;
+ curZone->_verbFl7 = 0;
+ curZone->_verbFl8 = 0;
+ curZone->_verbFl9 = 0;
+ curZone->_verbFl10 = 0;
+ curZone->_messageId = 0;
+ curZone->_enabledFl = false;
+ }
+
+ Common::File f;
+ if (!f.exists(file))
+ error("File not found : %s", file.c_str());
+
+ byte *ptr = _vm->_fileIO->loadFile(file);
+ int bufId = 0;
+ int zoneLineIdx = 0;
+ int bobZoneIdx;
+ do {
+ bobZoneIdx = READ_LE_INT16((uint16 *)ptr + bufId);
+ if (bobZoneIdx != -1) {
+ _vm->_linesMan->addZoneLine(
+ zoneLineIdx,
+ READ_LE_UINT16((uint16 *)ptr + bufId + 1),
+ READ_LE_UINT16((uint16 *)ptr + bufId + 2),
+ READ_LE_UINT16((uint16 *)ptr + bufId + 3),
+ READ_LE_UINT16((uint16 *)ptr + bufId + 4),
+ bobZoneIdx);
+ _vm->_linesMan->_zone[bobZoneIdx]._enabledFl = true;
+ }
+ bufId += 5;
+ ++zoneLineIdx;
+ } while (bobZoneIdx != -1);
+
+ for (int i = 1; i <= 100; i++) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[i];
+ curZone->_destX = READ_LE_INT16((uint16 *)ptr + bufId);
+ curZone->_destY = READ_LE_INT16((uint16 *)ptr + bufId + 1);
+ curZone->_spriteIndex = READ_LE_INT16((uint16 *)ptr + bufId + 2);
+ bufId += 3;
+ }
+
+ byte *verbData = (ptr + 10 * zoneLineIdx + 606);
+ bufId = 0;
+ for (int i = 1; i <= 100; i++) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[i];
+ curZone->_verbFl1 = verbData[bufId];
+ curZone->_verbFl2 = verbData[bufId + 1];
+ curZone->_verbFl3 = verbData[bufId + 2];
+ curZone->_verbFl4 = verbData[bufId + 3];
+ curZone->_verbFl5 = verbData[bufId + 4];
+ curZone->_verbFl6 = verbData[bufId + 5];
+ curZone->_verbFl7 = verbData[bufId + 6];
+ curZone->_verbFl8 = verbData[bufId + 7];
+ curZone->_verbFl9 = verbData[bufId + 8];
+ curZone->_verbFl10 = verbData[bufId + 9];
+
+ bufId += 10;
+ }
+ verbData += 1010;
+ for (int i = 0; i < 100; i++)
+ _vm->_linesMan->_zone[i + 1]._messageId = READ_LE_UINT16(verbData + 2 * i);
+
+ _vm->_globals->freeMemory(ptr);
+ _vm->_linesMan->initSquareZones();
+}
+
+void ObjectsManager::handleCityMap() {
+ _vm->_dialog->_inventFl = false;
+ _vm->_events->_gameKey = KEY_NONE;
+ _vm->_linesMan->setMaxLineIdx(1);
+ _vm->_globals->_characterMaxPosY = 440;
+ _vm->_globals->_cityMapEnabledFl = true;
+ _vm->_graphicsMan->_noFadingFl = false;
+ _vm->_globals->_freezeCharacterFl = false;
+ _spritePtr = NULL;
+ _vm->_globals->_exitId = 0;
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_soundMan->playSound(31);
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ _vm->_graphicsMan->loadImage("PLAN");
+ _vm->_linesMan->loadLines("PLAN.OB2");
+ loadHidingItems("PLAN.CA2");
+ loadZone("PLAN.ZO2");
+ _spritePtr = _vm->_fileIO->loadFile("VOITURE.SPR");
+ _vm->_animMan->loadAnim("PLAN");
+ _vm->_graphicsMan->displayAllBob();
+ _vm->_graphicsMan->initScreen("PLAN", 2, false);
+ for (int i = 0; i <= 15; i++)
+ disableHidingItem(i);
+ disableHidingItem(19);
+ disableHidingItem(20);
+ enableHidingBehavior();
+
+ if (!_mapCarPosX && !_mapCarPosY) {
+ _mapCarPosX = 900;
+ _mapCarPosY = 319;
+ }
+ addStaticSprite(_spritePtr, Common::Point(_mapCarPosX, _mapCarPosY), 0, 1, 0, false, 5, 5);
+ _vm->_events->setMouseXY(_mapCarPosX, _mapCarPosY);
+ _vm->_events->mouseOn();
+ _vm->_graphicsMan->scrollScreen(getSpriteX(0) - 320);
+ _vm->_graphicsMan->_scrollOffset = getSpriteX(0) - 320;
+ animateSprite(0);
+ _vm->_linesMan->_route = NULL;
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ _vm->_graphicsMan->fadeInLong();
+ _vm->_events->changeMouseCursor(4);
+ _vm->_graphicsMan->_noFadingFl = false;
+
+ bool loopCond = false;
+ do {
+ int mouseButton = _vm->_events->getMouseButton();
+ if (mouseButton) {
+ // First cop call : Go to the bank and free the hostages
+ if (_vm->_globals->_saveData->_data[svBankAttackAnimPlayedFl] == 1 && !_vm->_globals->_saveData->_data[svCopCall1PlayedFl]) {
+ _vm->_globals->_saveData->_data[svCopCall1PlayedFl] = 1;
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("APPEL1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ mouseButton = 0;
+ }
+ // Second cop call: Helico has been found in the empty lot
+ if (_vm->_globals->_saveData->_data[svFreedHostageFl] == 1 && !_vm->_globals->_saveData->_data[svCopCall2PlayedFl]) {
+ _vm->_globals->_saveData->_data[svCopCall2PlayedFl] = 1;
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("APPEL2.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ mouseButton = 0;
+ _vm->_events->_curMouseButton = 0;
+ }
+ if (mouseButton == 1)
+ handleLeftButton();
+ }
+
+ _vm->_linesMan->checkZone();
+ goHome2();
+
+ if (_vm->_linesMan->_route == NULL && _vm->_globals->_actionMoveTo)
+ paradise();
+ _vm->_events->refreshScreenAndEvents();
+
+ if (_vm->_globals->_exitId)
+ loopCond = true;
+ } while (!_vm->shouldQuit() && !loopCond);
+
+ if (!_vm->_graphicsMan->_noFadingFl)
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_globals->_eventMode = EVENTMODE_DEFAULT;
+ _vm->_graphicsMan->_noFadingFl = false;
+ _mapCarPosX = getSpriteX(0);
+ _mapCarPosY = getSpriteY(0);
+ removeSprite(0);
+ _spritePtr = _vm->_globals->freeMemory(_spritePtr);
+ clearScreen();
+ _vm->_globals->_cityMapEnabledFl = false;
+}
+
+/**
+ * Handle Left button
+ */
+void ObjectsManager::handleLeftButton() {
+ _vm->_fontMan->hideText(9);
+ int destX = _vm->_events->getMouseX();
+ int destY = _vm->_events->getMouseY();
+
+ if (!_vm->_dialog->_inventFl && !_vm->_globals->_cityMapEnabledFl &&
+ destX > _vm->_graphicsMan->_scrollOffset - 30 && destX < _vm->_graphicsMan->_scrollOffset + 50 &&
+ destY > -30 && destY < 50) {
+ int oldMouseCursor = _vm->_events->_mouseCursorId;
+ _vm->_dialog->_inventFl = true;
+ _vm->_dialog->showInventory();
+ _vm->_dialog->_inventFl = false;
+ _vm->_events->_gameKey = KEY_NONE;
+ if (!_vm->_globals->_exitId) {
+ _vm->_dialog->_inventFl = false;
+ _vm->_events->_mouseCursorId = oldMouseCursor;
+ }
+ return;
+ }
+ if (_vm->_globals->_saveData->_data[svField354] == 1 && !_vm->_globals->_cityMapEnabledFl
+ && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 59) {
+ changeCharacterHead(CHARACTER_HOPKINS_CLONE, CHARACTER_HOPKINS);
+ return;
+ }
+ if (_vm->_globals->_saveData->_data[svField356] == 1 && !_vm->_globals->_cityMapEnabledFl
+ && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 48) {
+ changeCharacterHead(CHARACTER_SAMANTHA, CHARACTER_HOPKINS);
+ return;
+ }
+ if (_vm->_globals->_saveData->_data[svField357] == 1) {
+ if (_vm->_globals->_saveData->_data[svField353] == 1 && !_vm->_globals->_cityMapEnabledFl
+ && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 59) {
+ changeCharacterHead(CHARACTER_HOPKINS, CHARACTER_HOPKINS_CLONE);
+ return;
+ }
+ if (_vm->_globals->_saveData->_data[svField355] == 1 && !_vm->_globals->_cityMapEnabledFl
+ && destX >= 567 && destX <= 593 && destY >= 26 && destY <= 59) {
+ changeCharacterHead(CHARACTER_HOPKINS, CHARACTER_SAMANTHA);
+ return;
+ }
+ }
+ if (_vm->_globals->_cityMapEnabledFl && _vm->_globals->_actionMoveTo) {
+ _vm->_linesMan->checkZone();
+ if (_zoneNum <= 0)
+ return;
+ int routeIdx = 0;
+ do {
+ _vm->_linesMan->_testRoute2[routeIdx] = _vm->_linesMan->_route[routeIdx];
+ ++routeIdx;
+ } while (_vm->_linesMan->_route[routeIdx]._x != -1);
+
+ _vm->_linesMan->_testRoute2[routeIdx].invalidate();
+ }
+
+ if (_vm->_globals->_actionMoveTo) {
+ _vm->_linesMan->checkZone();
+ _vm->_globals->_actionMoveTo = false;
+ _vm->_globals->_saveData->_data[svLastMouseCursor] = 0;
+ _vm->_globals->_saveData->_data[svLastZoneNum] = 0;
+ }
+
+ if (_vm->_globals->_cityMapEnabledFl && (_vm->_events->_mouseCursorId != 4 || _zoneNum <= 0))
+ return;
+ if (_zoneNum != -1 && _zoneNum != 0) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[_zoneNum];
+ if (curZone->_destX && curZone->_destY && curZone->_destY != 31) {
+ destX = curZone->_destX;
+ destY = curZone->_destY;
+ }
+ }
+ _vm->_globals->_actionMoveTo = false;
+ RouteItem *oldRoute = _vm->_linesMan->_route;
+ _vm->_linesMan->_route = NULL;
+ if (_forestFl && _zoneNum >= 20 && _zoneNum <= 23) {
+ if (getSpriteY(0) > 374 && getSpriteY(0) <= 410) {
+ _vm->_linesMan->_route = NULL;
+ setSpriteIndex(0, _oldDirectionSpriteIdx);
+ _vm->_globals->_actionDirection = DIR_NONE;
+ _vm->_linesMan->_route = NULL;
+ computeAndSetSpriteSize();
+ setFlipSprite(0, false);
+ _homeRateCounter = 0;
+ _oldDirection = DIR_NONE;
+ } else {
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), getSpriteX(0), 390);
+ if (_vm->_linesMan->_route)
+ _vm->_linesMan->optimizeRoute(_vm->_linesMan->_route);
+ _oldCharacterPosX = getSpriteX(0);
+ _oldCharacterPosY = getSpriteY(0);
+ _homeRateCounter = 0;
+ if (_vm->_linesMan->_route || oldRoute == _vm->_linesMan->_route) {
+ _oldDirection = DIR_NONE;
+ } else {
+ _vm->_linesMan->_route = oldRoute;
+ }
+ }
+ } else {
+ if (!_vm->_globals->_freezeCharacterFl && !_vm->_globals->_cityMapEnabledFl) {
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), destX, destY);
+ if (_vm->_linesMan->_route)
+ _vm->_linesMan->optimizeRoute(_vm->_linesMan->_route);
+ _oldCharacterPosX = getSpriteX(0);
+ _oldCharacterPosY = getSpriteY(0);
+ _homeRateCounter = 0;
+ if (_vm->_linesMan->_route || oldRoute == _vm->_linesMan->_route)
+ _oldDirection = DIR_NONE;
+ else
+ _vm->_linesMan->_route = oldRoute;
+ }
+ }
+
+ if (!_vm->_globals->_freezeCharacterFl && _vm->_globals->_cityMapEnabledFl)
+ _vm->_linesMan->_route = _vm->_linesMan->cityMapCarRoute(getSpriteX(0), getSpriteY(0), destX, destY);
+
+ if (_zoneNum != -1 && _zoneNum != 0) {
+ if (_vm->_events->_mouseCursorId == 23)
+ _vm->_globals->_saveData->_data[svLastMouseCursor] = 5;
+ else
+ _vm->_globals->_saveData->_data[svLastMouseCursor] = _vm->_events->_mouseCursorId;
+
+ if (_vm->_globals->_cityMapEnabledFl)
+ _vm->_globals->_saveData->_data[svLastMouseCursor] = 6;
+ _vm->_globals->_saveData->_data[svLastZoneNum] = _zoneNum;
+ _vm->_globals->_saveData->_data[svLastObjectIndex] = _curObjectIndex;
+ _vm->_globals->_actionMoveTo = true;
+ }
+ _vm->_fontMan->hideText(5);
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ if (_vm->_globals->_screenId == 20 && _vm->_globals->_saveData->_data[svField132] == 1
+ && _curObjectIndex == 20 && _zoneNum == 12
+ && _vm->_events->_mouseCursorId == 23) {
+ // Special case for throwing darts at the switch in Purgatory - the player shouldn't move
+ _vm->_linesMan->_route = NULL;
+ getSpriteX(0);
+ getSpriteY(0);
+ }
+}
+
+void ObjectsManager::paradise() {
+ char result = _vm->_globals->_saveData->_data[svLastMouseCursor];
+ if (result && _vm->_globals->_saveData->_data[svLastZoneNum] && result != 4 && result > 3) {
+ _vm->_fontMan->hideText(5);
+ if (!_forestFl || _zoneNum < 20 || _zoneNum > 23) {
+ if (_vm->_graphicsMan->_largeScreenFl) {
+ _vm->_graphicsMan->_scrollStatus = 2;
+ if (_vm->_events->_startPos.x + 320 - getSpriteX(0) > 160) {
+ bool loopCond = false;
+ do {
+ _vm->_graphicsMan->_scrollPosX -= _vm->_graphicsMan->_scrollSpeed;
+ if (_vm->_graphicsMan->_scrollPosX < 0) {
+ _vm->_graphicsMan->_scrollPosX = 0;
+ loopCond = true;
+ }
+ if (_vm->_graphicsMan->_scrollPosX > SCREEN_WIDTH) {
+ _vm->_graphicsMan->_scrollPosX = SCREEN_WIDTH;
+ loopCond = true;
+ }
+ if (_vm->_events->getMouseX() > _vm->_graphicsMan->_scrollPosX + 620)
+ _vm->_events->setMouseXY(_vm->_events->_mousePos.x - 4, _vm->_events->getMouseY());
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (!loopCond && _vm->_events->_startPos.x > getSpriteX(0) - 320);
+ } else if (_vm->_events->_startPos.x + 320 - getSpriteX(0) < -160) {
+ bool loopCond = false;
+ do {
+ _vm->_graphicsMan->_scrollPosX += _vm->_graphicsMan->_scrollSpeed;
+ if (_vm->_graphicsMan->_scrollPosX < 0) {
+ _vm->_graphicsMan->_scrollPosX = 0;
+ loopCond = true;
+ }
+ if (_vm->_graphicsMan->_scrollPosX > SCREEN_WIDTH) {
+ _vm->_graphicsMan->_scrollPosX = SCREEN_WIDTH;
+ loopCond = true;
+ }
+ if (_vm->_events->getMouseX() < _vm->_graphicsMan->_scrollPosX + 10)
+ _vm->_events->setMouseXY(_vm->_events->_mousePos.x + 4, _vm->_events->getMouseY());
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (!loopCond && _vm->_events->_startPos.x < getSpriteX(0) - 320);
+ }
+ if (_vm->_events->getMouseX() > _vm->_graphicsMan->_scrollPosX + 620)
+ _vm->_events->setMouseXY(_vm->_graphicsMan->_scrollPosX + 610, 0);
+ if (_vm->_events->getMouseX() < _vm->_graphicsMan->_scrollPosX + 10)
+ _vm->_events->setMouseXY(_vm->_graphicsMan->_scrollPosX + 10, 0);
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->_scrollStatus = 0;
+ }
+ _vm->_talkMan->handleAnswer(_vm->_globals->_saveData->_data[svLastZoneNum], _vm->_globals->_saveData->_data[svLastMouseCursor]);
+ } else {
+ _vm->_talkMan->handleForestAnswser(_vm->_globals->_saveData->_data[svLastZoneNum], _vm->_globals->_saveData->_data[svLastMouseCursor]);
+ }
+ _vm->_events->changeMouseCursor(4);
+ if (_zoneNum != -1 && _zoneNum != 0 && !_vm->_linesMan->_zone[_zoneNum]._enabledFl) {
+ _zoneNum = -1;
+ _forceZoneFl = true;
+ }
+ if (_zoneNum != _vm->_globals->_saveData->_data[svLastZoneNum] || _zoneNum == -1 || _zoneNum == 0) {
+ _vm->_events->_mouseCursorId = 4;
+ _changeVerbFl = false;
+ } else {
+ _vm->_events->_mouseCursorId = _vm->_globals->_saveData->_data[svLastMouseCursor];
+ if (_changeVerbFl) {
+ nextVerbIcon();
+ _changeVerbFl = false;
+ }
+ if (_vm->_events->_mouseCursorId == 5)
+ _vm->_events->_mouseCursorId = 4;
+ }
+ if (_vm->_events->_mouseCursorId != 23)
+ _vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId);
+ _zoneNum = 0;
+ _vm->_globals->_saveData->_data[svLastMouseCursor] = 0;
+ _vm->_globals->_saveData->_data[svLastZoneNum] = 0;
+ }
+ if (_vm->_globals->_cityMapEnabledFl) {
+ _vm->_events->_mouseCursorId = 0;
+ _vm->_events->changeMouseCursor(0);
+ }
+ if (_vm->_globals->_freezeCharacterFl && _vm->_events->_mouseCursorId == 4) {
+ if (_zoneNum != -1 && _zoneNum != 0)
+ handleRightButton();
+ }
+ _vm->_globals->_actionMoveTo = false;
+}
+
+/**
+ * Clear Screen
+ */
+void ObjectsManager::clearScreen() {
+ clearSprite();
+ _vm->_graphicsMan->endDisplayBob();
+ _vm->_fontMan->hideText(5);
+ _vm->_fontMan->hideText(9);
+ clearVBob();
+ _vm->_animMan->clearAnim();
+ _vm->_linesMan->clearAllZones();
+ _vm->_linesMan->resetLines();
+ resetHidingItems();
+
+ for (int i = 0; i <= 48; i++) {
+ _vm->_linesMan->_bobZone[i] = 0;
+ _vm->_linesMan->_bobZoneFl[i] = false;
+ }
+ _vm->_events->_mouseCursorId = 4;
+ _verb = 4;
+ _zoneNum = 0;
+ _forceZoneFl = true;
+ _vm->_linesMan->resetLinesNumb();
+ _vm->_linesMan->resetLastLine();
+ _vm->_linesMan->_route = NULL;
+ _vm->_globals->_answerBuffer = _vm->_globals->freeMemory(_vm->_globals->_answerBuffer);
+ _vm->_globals->_levelSpriteBuf = _vm->_globals->freeMemory(_vm->_globals->_levelSpriteBuf);
+ _vm->_events->_startPos.x = 0;
+ _vm->_events->_mouseSpriteId = 0;
+ _vm->_globals->_saveData->_data[svLastMouseCursor] = 0;
+ _vm->_globals->_saveData->_data[svLastZoneNum] = 0;
+ _vm->_globals->_actionMoveTo = false;
+ _forceZoneFl = true;
+ _changeVerbFl = false;
+ _vm->_linesMan->_route = NULL;
+ _oldDirection = DIR_NONE;
+ _vm->_graphicsMan->resetDirtyRects();
+}
+
+/**
+ * Change the currently active player face / Head
+ * @param oldCharacter Previously played character
+ * @param newCharacter New character to play
+ */
+void ObjectsManager::changeCharacterHead(PlayerCharacter oldCharacter, PlayerCharacter newCharacter) {
+ CharacterLocation *loc;
+
+ _changeHeadFl = true;
+ _vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, 532, 25, 65, 40, _vm->_graphicsMan->_frontBuffer, 532, 25);
+ _vm->_graphicsMan->addDirtyRect(532, 25, 597, 65);
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = NULL;
+
+ if (oldCharacter == CHARACTER_SAMANTHA && newCharacter == CHARACTER_HOPKINS
+ && _vm->_globals->_saveData->_realHopkins._location == _vm->_globals->_screenId) {
+ _changeHeadFl = false;
+ loc = &_vm->_globals->_saveData->_samantha;
+ loc->_pos.x = getSpriteX(0);
+ loc->_pos.y = getSpriteY(0);
+ loc->_startSpriteIndex = 64;
+ loc->_location = _vm->_globals->_screenId;
+ loc->_zoomFactor = _sprite[0]._animationType;
+
+ removeSprite(1);
+ addStaticSprite(_headSprites, loc->_pos, 1, 3, loc->_zoomFactor, false, 20, 127);
+ animateSprite(1);
+ removeSprite(0);
+
+ _vm->_globals->_saveData->_data[svField354] = 0;
+ _vm->_globals->_saveData->_data[svField356] = 0;
+ _vm->_globals->_saveData->_data[svField357] = 1;
+
+ loc = &_vm->_globals->_saveData->_realHopkins;
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR");
+ _vm->_globals->_characterType = 0;
+ addStaticSprite(_vm->_globals->_characterSpriteBuf, loc->_pos, 0, 64, loc->_zoomFactor, false, 34, 190);
+ animateSprite(0);
+ _vm->_globals->loadCharacterData();
+ } else if (oldCharacter == CHARACTER_HOPKINS && newCharacter == CHARACTER_SAMANTHA
+ && _vm->_globals->_saveData->_samantha._location == _vm->_globals->_screenId) {
+ _changeHeadFl = false;
+ loc = &_vm->_globals->_saveData->_realHopkins;
+ loc->_pos.x = getSpriteX(0);
+ loc->_pos.y = getSpriteY(0);
+ loc->_startSpriteIndex = 64;
+ loc->_location = _vm->_globals->_screenId;
+ loc->_zoomFactor = _sprite[0]._zoomFactor;
+
+ removeSprite(1);
+ addStaticSprite(_headSprites, loc->_pos, 1, 2, loc->_zoomFactor, false, 34, 190);
+ animateSprite(1);
+ removeSprite(0);
+
+ _vm->_globals->_saveData->_data[svField354] = 0;
+ _vm->_globals->_saveData->_data[svField356] = 1;
+ _vm->_globals->_saveData->_data[svField357] = 0;
+
+ loc = &_vm->_globals->_saveData->_samantha;
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PSAMAN.SPR");
+ _vm->_globals->_characterType = 2;
+ addStaticSprite(_vm->_globals->_characterSpriteBuf, loc->_pos, 0, 64, loc->_zoomFactor, false, 20, 127);
+ animateSprite(0);
+ _vm->_globals->loadCharacterData();
+ } else {
+ switch (oldCharacter) {
+ case CHARACTER_HOPKINS:
+ loc = &_vm->_globals->_saveData->_realHopkins;
+ loc->_pos.x = getSpriteX(0);
+ loc->_pos.y = getSpriteY(0);
+ loc->_startSpriteIndex = 64;
+ loc->_location = _vm->_globals->_screenId;
+ loc->_zoomFactor = _sprite[0]._zoomFactor;
+ break;
+ case CHARACTER_HOPKINS_CLONE:
+ loc = &_vm->_globals->_saveData->_cloneHopkins;
+ loc->_pos.x = getSpriteX(0);
+ loc->_pos.y = getSpriteY(0);
+ loc->_startSpriteIndex = 64;
+ loc->_location = _vm->_globals->_screenId;
+ loc->_zoomFactor = _sprite[0]._zoomFactor;
+ break;
+ case CHARACTER_SAMANTHA:
+ loc = &_vm->_globals->_saveData->_samantha;
+ loc->_pos.x = getSpriteX(0);
+ loc->_pos.y = getSpriteY(0);
+ loc->_startSpriteIndex = 64;
+ loc->_location = _vm->_globals->_screenId;
+ loc->_zoomFactor = _sprite[0]._zoomFactor;
+ break;
+ default:
+ break;
+ }
+
+ switch (newCharacter) {
+ case CHARACTER_HOPKINS:
+ _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 0;
+ _vm->_globals->_saveData->_data[svField354] = 0;
+ _vm->_globals->_saveData->_data[svField356] = 0;
+ _vm->_globals->_saveData->_data[svField357] = 1;
+ _vm->_globals->_exitId = _vm->_globals->_saveData->_realHopkins._location;
+ break;
+ case CHARACTER_HOPKINS_CLONE:
+ _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 1;
+ _vm->_globals->_saveData->_data[svField354] = 1;
+ _vm->_globals->_saveData->_data[svField356] = 0;
+ _vm->_globals->_saveData->_data[svField357] = 0;
+ _vm->_globals->_exitId = _vm->_globals->_saveData->_cloneHopkins._location;
+ break;
+ case CHARACTER_SAMANTHA:
+ _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 0;
+ _vm->_globals->_saveData->_data[svField354] = 0;
+ _vm->_globals->_saveData->_data[svField356] = 1;
+ _vm->_globals->_saveData->_data[svField357] = 0;
+ _vm->_globals->_exitId = _vm->_globals->_saveData->_samantha._location;
+ break;
+ }
+ }
+}
+
+// Check Size
+void ObjectsManager::computeAndSetSpriteSize() {
+ int size = _vm->_globals->_spriteSize[getSpriteY(0)];
+ if (_vm->_globals->_characterType == 1) {
+ size = 20 * (5 * abs(size) - 100) / -80;
+ } else if (_vm->_globals->_characterType == 2) {
+ size = 20 * (5 * abs(size) - 165) / -67;
+ }
+ setSpriteZoom(0, size);
+}
+
+/**
+ * Get next verb icon (or text)
+ */
+void ObjectsManager::nextVerbIcon() {
+ _vm->_events->_mouseCursorId++;
+
+ for(;;) {
+ if (_vm->_events->_mouseCursorId == 4) {
+ if (!_vm->_globals->_freezeCharacterFl || _zoneNum == -1 || _zoneNum == 0)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 5 || _vm->_events->_mouseCursorId == 6) {
+ _vm->_events->_mouseCursorId = 6;
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl1 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 7) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl2 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 8) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl3 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 9) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 10) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl5 == 1)
+ return;
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 11) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl6 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 12) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl7 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 13) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl8 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 14) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl9 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 15) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl10 == 1)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 16) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl1 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 17) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 18) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl5 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 19) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl6 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 20) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl7 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 21) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl10 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 22) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl8 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 23) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl3 == 2)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 24) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 3)
+ return;
+
+ ++_vm->_events->_mouseCursorId;
+ }
+
+ if (_vm->_events->_mouseCursorId == 25) {
+ if (_vm->_linesMan->_zone[_zoneNum]._verbFl9 == 2)
+ return;
+ }
+ _vm->_events->_mouseCursorId = 4;
+ }
+}
+
+/**
+ * Handle Right button
+ */
+void ObjectsManager::handleRightButton() {
+ if (_zoneNum != -1 && _zoneNum != 0) {
+ nextVerbIcon();
+ if (_vm->_events->_mouseCursorId != 23)
+ _vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId);
+ _verb = _vm->_events->_mouseCursorId;
+ }
+}
+
+/**
+ * Prepare border used to highlight the place below mouse cursor, in the inventory.
+ * Also set the mouse cursor
+ */
+void ObjectsManager::initBorder(int zoneIdx) {
+ _oldBorderPos = _borderPos;
+ _oldBorderSpriteIndex = _borderSpriteIndex;
+ if (zoneIdx >= 1 && zoneIdx <= 6)
+ _borderPos.y = 120;
+ else if (zoneIdx >= 7 && zoneIdx <= 12)
+ _borderPos.y = 158;
+ else if (zoneIdx >= 13 && zoneIdx <= 18)
+ _borderPos.y = 196;
+ else if (zoneIdx >= 19 && zoneIdx <= 24)
+ _borderPos.y = 234;
+ else if (zoneIdx >= 25 && zoneIdx <= 29)
+ _borderPos.y = 272;
+ else if (zoneIdx == 30)
+ _borderPos.y = 272;
+ else if (zoneIdx == 31)
+ _borderPos.y = 290;
+
+ if (zoneIdx == 1 || zoneIdx == 7 || zoneIdx == 13 || zoneIdx == 19 || zoneIdx == 25)
+ _borderPos.x = _vm->_graphicsMan->_scrollOffset + 158;
+ else if (zoneIdx == 2 || zoneIdx == 8 || zoneIdx == 14 || zoneIdx == 20 || zoneIdx == 26)
+ _borderPos.x = _vm->_graphicsMan->_scrollOffset + 212;
+ else if (zoneIdx == 3 || zoneIdx == 9 || zoneIdx == 15 || zoneIdx == 21 || zoneIdx == 27)
+ _borderPos.x = _vm->_graphicsMan->_scrollOffset + 266;
+ else if (zoneIdx == 4 || zoneIdx == 10 || zoneIdx == 16 || zoneIdx == 22 || zoneIdx == 28)
+ _borderPos.x = _vm->_graphicsMan->_scrollOffset + 320;
+ else if (zoneIdx == 5 || zoneIdx == 11 || zoneIdx == 17 || zoneIdx == 23 || zoneIdx == 29)
+ _borderPos.x = _vm->_graphicsMan->_scrollOffset + 374;
+ else if (zoneIdx == 6 || zoneIdx == 12 || zoneIdx == 18 || zoneIdx == 24 || zoneIdx == 30 || zoneIdx == 31)
+ _borderPos.x = _vm->_graphicsMan->_scrollOffset + 428;
+
+ if (zoneIdx >= 1 && zoneIdx <= 29)
+ _borderSpriteIndex = 0;
+ else if (zoneIdx == 30 || zoneIdx == 31)
+ _borderSpriteIndex = 2;
+ else if (!zoneIdx || zoneIdx == 32) {
+ _borderPos = Common::Point(0, 0);
+ _borderSpriteIndex = 0;
+ }
+
+ if (!zoneIdx)
+ _vm->_events->_mouseCursorId = 0;
+ else if (zoneIdx >= 1 && zoneIdx <= 28)
+ _vm->_events->_mouseCursorId = 8;
+ else if (zoneIdx == 29)
+ _vm->_events->_mouseCursorId = 1;
+ else if (zoneIdx == 30)
+ _vm->_events->_mouseCursorId = 2;
+ else if (zoneIdx == 31)
+ _vm->_events->_mouseCursorId = 3;
+ else if (zoneIdx == 32)
+ _vm->_events->_mouseCursorId = 16;
+
+ if (zoneIdx >= 1 && zoneIdx <= 28 && !_vm->_globals->_inventory[zoneIdx]) {
+ _vm->_events->_mouseCursorId = 0;
+ _borderPos = Common::Point(0, 0);
+ _borderSpriteIndex = 0;
+ }
+
+ if (_vm->_events->_mouseCursorId != 23)
+ _vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId);
+ _vm->_events->getMouseX();
+ _vm->_events->getMouseY();
+}
+
+/**
+ * Get next icon for an object in the inventory
+ */
+void ObjectsManager::nextObjectIcon(int idx) {
+ int cursorId = _vm->_events->_mouseCursorId;
+ ObjectAuthIcon *curAuthIco = &_objectAuthIcons[_vm->_globals->_inventory[idx]];
+
+ if (cursorId == 0 || cursorId == 2 || cursorId == 3 || cursorId == 16)
+ return;
+
+ int nextCursorId = cursorId + 1;
+ if (nextCursorId > 25)
+ nextCursorId = 6;
+
+ do {
+ if (nextCursorId == 2 || nextCursorId == 5 || nextCursorId == 6) {
+ _vm->_events->_mouseCursorId = 6;
+ if (curAuthIco->_flag1 == 1)
+ return;
+ nextCursorId++;
+ }
+ if (nextCursorId == 7) {
+ _vm->_events->_mouseCursorId = 7;
+ if (curAuthIco->_flag2 == 1)
+ return;
+ nextCursorId++;
+ }
+ if (nextCursorId == 8) {
+ _vm->_events->_mouseCursorId = 8;
+ return;
+ }
+ if (nextCursorId == 9 || nextCursorId == 10) {
+ _vm->_events->_mouseCursorId = 10;
+ if (curAuthIco->_flag6 == 1)
+ return;
+ nextCursorId = 11;
+ }
+
+ if (nextCursorId == 11) {
+ _vm->_events->_mouseCursorId = 11;
+ if (curAuthIco->_flag3 == 1)
+ return;
+ nextCursorId++;
+ }
+
+ if (nextCursorId == 12 || nextCursorId == 13) {
+ _vm->_events->_mouseCursorId = 13;
+ if (curAuthIco->_flag4 == 1)
+ return;
+ nextCursorId = 14;
+ }
+
+ if (nextCursorId == 14 || nextCursorId == 15) {
+ _vm->_events->_mouseCursorId = 15;
+ if (curAuthIco->_flag5 == 1)
+ return;
+ nextCursorId = 23;
+ }
+
+ if (nextCursorId >= 16 && nextCursorId <= 23) {
+ _vm->_events->_mouseCursorId = 23;
+ if (curAuthIco->_flag5 == 2)
+ return;
+ nextCursorId = 24;
+ }
+
+ if (nextCursorId == 24 || nextCursorId == 25) {
+ _vm->_events->_mouseCursorId = 25;
+ }
+
+ nextCursorId = 6;
+ } while (curAuthIco->_flag6 != 2);
+}
+
+void ObjectsManager::takeInventoryObject(int idx) {
+ if (_vm->_events->_mouseCursorId == 8)
+ changeObject(idx);
+}
+
+void ObjectsManager::loadObjectIniFile() {
+ byte *data;
+ Common::String file;
+ int lastOpcodeResult = 1;
+
+ file = "OBJET1.ini";
+ bool fileFoundFl = false;
+ data = _vm->_fileIO->searchCat(file, RES_INI, fileFoundFl);
+ if (!fileFoundFl) {
+ data = _vm->_fileIO->loadFile(file);
+ if (data == NULL)
+ error("INI file %s not found", file.c_str());
+ }
+
+ if (READ_BE_UINT24(data) != MKTAG24('I', 'N', 'I'))
+ error("File %s is not an INI file", file.c_str());
+
+ for (;;) {
+ int opcodeType = _vm->_script->handleOpcode(data + 20 * lastOpcodeResult);
+ if (_vm->shouldQuit())
+ return;
+
+ if (opcodeType == 2)
+ lastOpcodeResult = _vm->_script->handleGoto(data + 20 * lastOpcodeResult);
+ else if (opcodeType == 3)
+ lastOpcodeResult = _vm->_script->handleIf(data, lastOpcodeResult);
+
+ if (lastOpcodeResult == -1)
+ error("defective IFF function");
+
+ if (opcodeType == 1 || opcodeType == 4)
+ ++lastOpcodeResult;
+ else if (!opcodeType || opcodeType == 5)
+ break;
+ }
+
+ _vm->_globals->freeMemory(data);
+}
+
+void ObjectsManager::handleSpecialGames() {
+ byte *oldPalette;
+
+ switch (_vm->_globals->_screenId) {
+ case 5:
+ if ((getSpriteY(0) > 399) || _vm->_globals->_saveData->_data[svField173])
+ break;
+
+ _vm->_globals->_saveData->_data[svField173] = 1;
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("flicspe1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+
+ if (_vm->_globals->_censorshipFl)
+ break;
+
+ oldPalette = _vm->_globals->allocMemory(1000);
+ memcpy(oldPalette, _vm->_graphicsMan->_palette, 769);
+
+ _vm->_graphicsMan->backupScreen();
+
+ if (!_vm->_graphicsMan->_lineNbr)
+ _vm->_graphicsMan->_scrollOffset = 0;
+ _vm->_graphicsMan->displayScreen(true);
+ _vm->_soundMan->_specialSoundNum = 198;
+ _charactersEnabledFl = true;
+ _vm->_animMan->unsetClearAnimFlag();
+ _vm->_animMan->playAnim("otage.ANM", 1, 24, 500, true);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->displayScreen(false);
+
+ _vm->_graphicsMan->restoreScreen();
+
+ _charactersEnabledFl = false;
+ memcpy(_vm->_graphicsMan->_palette, oldPalette, 769);
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ _vm->_globals->freeMemory(oldPalette);
+ _vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399);
+
+ _vm->_graphicsMan->_scrollStatus = 0;
+ _vm->_graphicsMan->updateScreen();
+ break;
+ case 20:
+ _vm->_globals->_saveData->_data[svField132] = (getSpriteX(0) > 65 && getSpriteX(0) <= 124 && getSpriteY(0) > 372 && getSpriteY(0) <= 398) ? 1 : 0;
+ break;
+ case 35:
+ if (_vm->_globals->_prevScreenId == 16)
+ handleForest(35, 500, 555, 100, 440, 1);
+ else if (_vm->_globals->_prevScreenId == 36)
+ handleForest(35, 6, 84, 100, 440, 4);
+ break;
+ case 36:
+ if (_vm->_globals->_prevScreenId == 35)
+ handleForest(36, 551, 633, 100, 440, 2);
+ else if (_vm->_globals->_prevScreenId == 37)
+ handleForest(36, 6, 84, 100, 440, 4);
+ break;
+ case 37:
+ if (_vm->_globals->_prevScreenId == 36)
+ handleForest(37, 551, 633, 100, 440, 1);
+ else if (_vm->_globals->_prevScreenId == 38)
+ handleForest(37, 392, 529, 100, 440, 2);
+ break;
+ case 38:
+ if (_vm->_globals->_prevScreenId == 37)
+ handleForest(38, 133, 252, 100, 440, 4);
+ else if (_vm->_globals->_prevScreenId == 39)
+ handleForest(38, 6, 84, 100, 440, 3);
+ break;
+ case 39:
+ if (_vm->_globals->_prevScreenId == 38)
+ handleForest(39, 551, 633, 100, 440, 2);
+ else if (_vm->_globals->_prevScreenId == 40)
+ handleForest(39, 6, 84, 100, 440, 3);
+ break;
+ case 40:
+ if (_vm->_globals->_prevScreenId == 39)
+ handleForest(40, 133, 252, 100, 440, 4);
+ else if (_vm->_globals->_prevScreenId == 41)
+ handleForest(40, 392, 529, 100, 440, 2);
+ break;
+ case 41:
+ if (_vm->_globals->_prevScreenId == 40)
+ handleForest(41, 551, 633, 100, 440, 1);
+ else if (_vm->_globals->_prevScreenId == 17)
+ handleForest(41, 6, 84, 100, 440, 3);
+ break;
+ case 57:
+ _vm->_globals->_disableInventFl = true;
+ if (_vm->_globals->_saveData->_data[svField261] == 1 && getBobAnimDataIdx(5) == 37) {
+ stopBobAnimation(5);
+ setBobAnimDataIdx(5, 0);
+ setBobAnimation(6);
+ _vm->_globals->_saveData->_data[svField261] = 2;
+ _vm->_linesMan->disableZone(15);
+ _vm->_soundMan->playSoundFile("SOUND75.WAV");
+ }
+ if (_vm->_globals->_saveData->_data[svField261] == 2 && getBobAnimDataIdx(6) == 6) {
+ stopBobAnimation(6);
+ setBobAnimDataIdx(6, 0);
+ setBobAnimation(7);
+ _vm->_linesMan->enableZone(14);
+ _vm->_globals->_saveData->_data[svField261] = 3;
+ }
+ _vm->_globals->_disableInventFl = false;
+ break;
+ case 93:
+ if (_vm->_globals->_saveData->_data[svField333])
+ break;
+
+ _vm->_globals->_disableInventFl = true;
+ do
+ _vm->_events->refreshScreenAndEvents();
+ while (getBobAnimDataIdx(8) != 3);
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("GM3.PE2");
+ stopBobAnimation(8);
+ _vm->_globals->_saveData->_data[svField333] = 1;
+ _vm->_globals->_disableInventFl = false;
+ break;
+ }
+}
+
+void ObjectsManager::quickDisplayBobSprite(int idx) {
+ int startPos = 10 * idx;
+ if (!READ_LE_UINT16(_vm->_talkMan->_characterAnim + startPos + 4))
+ return;
+
+ int xp = READ_LE_INT16(_vm->_talkMan->_characterAnim + startPos);
+ int yp = READ_LE_INT16(_vm->_talkMan->_characterAnim + startPos + 2);
+ int spriteIndex = _vm->_talkMan->_characterAnim[startPos + 8];
+
+ _vm->_graphicsMan->fastDisplay(_vm->_talkMan->_characterSprite, xp, yp, spriteIndex);
+}
+
+void ObjectsManager::initVbob(const byte *src, int idx, int xp, int yp, int frameIndex) {
+ if (idx > 29)
+ error("MAX_VBOB exceeded");
+
+ VBobItem *vbob = &_vBob[idx];
+ if (vbob->_displayMode <= 1) {
+ vbob->_displayMode = 1;
+ vbob->_xp = xp;
+ vbob->_yp = yp;
+ vbob->_frameIndex = frameIndex;
+ vbob->_oldX = xp;
+ vbob->_oldY = yp;
+ vbob->_oldFrameIndex = frameIndex;
+ vbob->_spriteData = src;
+ vbob->_oldSpriteData = src;
+ vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
+ } else if (vbob->_displayMode == 2 || vbob->_displayMode == 4) {
+ vbob->_displayMode = 3;
+ vbob->_oldX = vbob->_xp;
+ vbob->_oldY = vbob->_yp;
+ vbob->_oldSpriteData = vbob->_spriteData;
+ vbob->_oldFrameIndex = vbob->_frameIndex;
+ vbob->_xp = xp;
+ vbob->_yp = yp;
+ vbob->_frameIndex = frameIndex;
+ vbob->_spriteData = src;
+ }
+}
+
+void ObjectsManager::disableVbob(int idx) {
+ if (idx > 29)
+ error("MAX_VBOB exceeded");
+
+ VBobItem *vbob = &_vBob[idx];
+ if (vbob->_displayMode <= 1)
+ vbob->_displayMode = 0;
+ else
+ vbob->_displayMode = 4;
+}
+
+void ObjectsManager::doActionBack(int idx) {
+ if (_curGestureFile != 1) {
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curGestureFile = 1;
+ _gestureBuf = _vm->_fileIO->loadFile("DOS.SPR");
+ }
+
+ switch (idx) {
+ case 1:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, false);
+ break;
+ case 2:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,13,-1,", 8, false);
+ break;
+ case 3:
+ showSpecialActionAnimation(_gestureBuf, "12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8);
+ break;
+ case 4:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,9,10,11,12,13,12,11,12,13,12,11,12,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, false);
+ break;
+ case 5:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, false);
+ break;
+ case 6:
+ showSpecialActionAnimation(_gestureBuf, "20,19,18,17,16,15,-1,", 8);
+ break;
+ case 7:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 8, false);
+ break;
+ case 8:
+ showSpecialActionAnimation(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 8);
+ break;
+ case 9:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 8, false);
+ break;
+ case 10:
+ showSpecialActionAnimation(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 8);
+ break;
+ }
+}
+
+void ObjectsManager::doActionRight(int idx) {
+ if (_curGestureFile != 3) {
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curGestureFile = 3;
+ _gestureBuf = _vm->_fileIO->loadFile("PROFIL.SPR");
+ }
+
+ switch (idx) {
+ case 1:
+ showActionAnimation(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 8, false);
+ break;
+ case 2:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 8, false);
+ break;
+ case 3:
+ showSpecialActionAnimation(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 8);
+ break;
+ case 4:
+ showActionAnimation(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 8, false);
+ break;
+ case 5:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,-1,", 8, false);
+ break;
+ case 6:
+ showSpecialActionAnimation(_gestureBuf, "24,,23,-1,", 8);
+ break;
+ case 7:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,-1,", 8, false);
+ break;
+ case 8:
+ showSpecialActionAnimation(_gestureBuf, "26,25,24,23,-1,", 8);
+ break;
+ case 9:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,28,29,-1,", 8, false);
+ break;
+ case 10:
+ showSpecialActionAnimation(_gestureBuf, "28,27,26,25,24,23,-1,", 8);
+ break;
+ }
+}
+
+void ObjectsManager::doActionDiagRight(int idx) {
+ if (_curGestureFile != 4) {
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curGestureFile = 4;
+ _gestureBuf = _vm->_fileIO->loadFile("3Q.SPR");
+ }
+
+ switch (idx) {
+ case 1:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, false);
+ break;
+ case 2:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 8, false);
+ break;
+ case 3:
+ showSpecialActionAnimation(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8);
+ break;
+ case 4:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,11,12,11,12,11,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, false);
+ break;
+ case 5:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,-1,", 8, false);
+ break;
+ case 6:
+ showSpecialActionAnimation(_gestureBuf, "17,16,15,-1,", 8);
+ break;
+ case 7:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20-1,", 8, false);
+ break;
+ case 8:
+ showSpecialActionAnimation(_gestureBuf, "19,18,17,16,15,-1,", 8);
+ break;
+ case 9:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, false);
+ break;
+ case 10:
+ showSpecialActionAnimation(_gestureBuf, "20,19,18,17,15,-1,", 8);
+ break;
+ }
+}
+
+void ObjectsManager::doActionFront(int idx) {
+ if (_curGestureFile != 2) {
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curGestureFile = 2;
+ _gestureBuf = _vm->_fileIO->loadFile("FACE.SPR");
+ }
+
+ switch (idx) {
+ case 1:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,9,9,9,9,9,9,7,6,5,4,3,2,1,0,-1,", 8, false);
+ break;
+ case 2:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,15,-1,", 8, false);
+ break;
+ case 3:
+ showSpecialActionAnimation(_gestureBuf, "14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 8);
+ break;
+ case 4:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 8, false);
+ break;
+ }
+}
+
+void ObjectsManager::doActionDiagLeft(int idx) {
+ if (_curGestureFile != 4) {
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curGestureFile = 4;
+ _gestureBuf = _vm->_fileIO->loadFile("3Q.SPR");
+ }
+
+ switch (idx) {
+ case 1:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, true);
+ break;
+ case 2:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 8, true);
+ break;
+ case 3:
+ showSpecialActionAnimation(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8);
+ break;
+ case 4:
+ showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,11,12,11,12,11,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, true);
+ break;
+ case 5:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,-1,", 8, true);
+ break;
+ case 6:
+ showSpecialActionAnimation(_gestureBuf, "17,16,15,-1,", 8);
+ break;
+ case 7:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,-1,", 8, true);
+ break;
+ case 8:
+ showSpecialActionAnimation(_gestureBuf, "19,18,17,16,15,-1,", 8);
+ break;
+ case 9:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, true);
+ break;
+ case 10:
+ showSpecialActionAnimation(_gestureBuf, "20,19,18,17,15,-1,", 8);
+ break;
+ }
+}
+
+void ObjectsManager::doActionLeft(int idx) {
+ if (_curGestureFile != 3) {
+ _gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
+ _curGestureFile = 3;
+ _gestureBuf = _vm->_fileIO->loadFile("PROFIL.SPR");
+ }
+
+ switch (idx) {
+ case 1:
+ showActionAnimation(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 8, true);
+ break;
+ case 2:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 8, true);
+ break;
+ case 3:
+ showSpecialActionAnimation(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 8);
+ break;
+ case 4:
+ showActionAnimation(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 8, true);
+ break;
+ case 5:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,-1,", 8, true);
+ break;
+ case 6:
+ showSpecialActionAnimation(_gestureBuf, "24,,23,-1,", 8);
+ break;
+ case 7:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,-1,", 8, true);
+ break;
+ case 8:
+ showSpecialActionAnimation(_gestureBuf, "26,25,24,23,-1,", 8);
+ break;
+ case 9:
+ showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,28,29,-1,", 8, true);
+ break;
+ case 10:
+ showSpecialActionAnimation(_gestureBuf, "28,27,26,25,24,23,-1,", 8);
+ break;
+ }
+}
+
+void ObjectsManager::setAndPlayAnim(int idx, int animIdx, int destPosi, bool animAction) {
+ // Set Hopkins animation and position
+ setBobAnimation(idx);
+ setBobAnimDataIdx(idx, animIdx);
+
+ // Make Hopkins walk to the expected place
+ do {
+ _vm->_events->refreshScreenAndEvents();
+ } while (destPosi != getBobAnimDataIdx(idx));
+
+ if (!animAction)
+ stopBobAnimation(idx);
+ else {
+ BobItem *bob = &_bob[idx];
+ _vm->_graphicsMan->fastDisplay(bob->_spriteData, bob->_oldX, bob->_oldY, bob->_frameIndex);
+ stopBobAnimation(idx);
+ _vm->_events->refreshScreenAndEvents();
+ }
+}
+
+int ObjectsManager::getBobAnimDataIdx(int idx) {
+ return _bob[idx]._animDataIdx / 5;
+}
+
+void ObjectsManager::setBobAnimDataIdx(int idx, int animIdx) {
+ BobItem *bob = &_bob[idx];
+ bob->_animDataIdx = 5 * animIdx;
+ bob->_moveChange1 = 0;
+ bob->_moveChange2 = 0;
+}
+
+/**
+ * Set Hopkins animation
+ */
+void ObjectsManager::setBobAnimation(int idx) {
+ BobItem *bob = &_bob[idx];
+ if (!bob->_disabledAnimationFl)
+ return;
+
+ bob->_disabledAnimationFl = false;
+ bob->_animDataIdx = 5;
+ bob->_frameIndex = 250;
+ bob->_moveChange1 = 0;
+ bob->_moveChange2 = 0;
+}
+
+/**
+ * Stop Hopkins animation
+ */
+void ObjectsManager::stopBobAnimation(int idx) {
+ _bob[idx]._disabledAnimationFl = true;
+}
+
+/**
+ * Get X position
+ */
+int ObjectsManager::getBobPosX(int idx) {
+ return _bob[idx]._xp;
+}
+
+void ObjectsManager::loadLinkFile(const Common::String &file, bool skipDetails) {
+ Common::File f;
+ Common::String filename = file + ".LNK";
+ bool fileFoundFl = false;
+ byte *ptr = _vm->_fileIO->searchCat(filename, RES_LIN, fileFoundFl);
+ size_t nbytes = _vm->_fileIO->_catalogSize;
+ if (!fileFoundFl) {
+ if (!f.open(filename))
+ error("Error opening file - %s", filename.c_str());
+
+ nbytes = f.size();
+ ptr = _vm->_globals->allocMemory(nbytes);
+ if (ptr == NULL)
+ error("INILINK");
+ _vm->_fileIO->readStream(f, ptr, nbytes);
+ f.close();
+ }
+ if (!skipDetails) {
+ for (int idx = 0; idx < 500; ++idx)
+ _vm->_globals->_spriteSize[idx] = READ_LE_INT16((uint16 *)ptr + idx);
+
+ resetHidingItems();
+
+ Common::String filename2 = Common::String((const char *)ptr + 1000);
+ if (!filename2.empty()) {
+ fileFoundFl = false;
+ _hidingItemData[1] = _vm->_fileIO->searchCat(filename2, RES_SLI, fileFoundFl);
+
+ if (!fileFoundFl) {
+ _hidingItemData[1] = _vm->_fileIO->loadFile(filename2);
+ } else {
+ _hidingItemData[1] = _vm->_fileIO->loadFile("RES_SLI.RES");
+ }
+
+ int curDataCacheId = 60;
+ byte *curDataPtr = ptr + 1000;
+ for (int hidingIdx = 0; hidingIdx <= 21; hidingIdx++) {
+ HidingItem *hid = &_hidingItem[hidingIdx];
+ int curSpriteId = READ_LE_INT16(curDataPtr + 2 * curDataCacheId);
+ hid->_spriteIndex = curSpriteId;
+ hid->_x = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 2);
+ hid->_y = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 4);
+ hid->_yOffset = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 8);
+
+ if (!_hidingItemData[1]) {
+ hid->_useCount = 0;
+ } else {
+ hid->_spriteData = _hidingItemData[1];
+ hid->_width = getWidth(_hidingItemData[1], curSpriteId);
+ hid->_height = getHeight(_hidingItemData[1], curSpriteId);
+ hid->_useCount = 1;
+ }
+ if (!hid->_x && !hid->_y && !hid->_spriteIndex)
+ hid->_useCount = 0;
+
+ curDataCacheId += 5;
+ }
+ enableHidingBehavior();
+ }
+ }
+
+ _vm->_linesMan->resetLines();
+ for (size_t idx = 0; idx < nbytes - 3; idx++) {
+ if (READ_BE_UINT24(&ptr[idx]) == MKTAG24('O', 'B', '2')) {
+ byte *curDataPtr = &ptr[idx + 4];
+ int lineDataIdx = 0;
+ int curLineIdx = 0;
+ _vm->_linesMan->resetLinesNumb();
+ Directions curDirection;
+ do {
+ curDirection = (Directions)READ_LE_INT16(curDataPtr + 2 * lineDataIdx);
+ if (curDirection != DIR_NONE) {
+ _vm->_linesMan->addLine(
+ curLineIdx,
+ curDirection,
+ READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 2),
+ READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 4),
+ READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 6),
+ READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 8));
+ }
+ lineDataIdx += 5;
+ ++curLineIdx;
+ } while (curDirection != DIR_NONE);
+ _vm->_linesMan->initRoute();
+ }
+ }
+
+ if (!skipDetails) {
+ for (size_t idx = 0; idx < nbytes - 3; idx++) {
+ if (READ_BE_UINT24(&ptr[idx]) == MKTAG24('Z', 'O', '2')) {
+ byte *curDataPtr = &ptr[idx + 4];
+ int curDataIdx = 0;
+ for (int i = 1; i <= 100; i++) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[i];
+ curZone->_destX = 0;
+ curZone->_destY = 0;
+ curZone->_spriteIndex = 0;
+ curZone->_verbFl1 = 0;
+ curZone->_verbFl2 = 0;
+ curZone->_verbFl3 = 0;
+ curZone->_verbFl4 = 0;
+ curZone->_verbFl5 = 0;
+ curZone->_verbFl6 = 0;
+ curZone->_verbFl7 = 0;
+ curZone->_verbFl8 = 0;
+ curZone->_verbFl9 = 0;
+ curZone->_verbFl10 = 0;
+ curZone->_messageId = 0;
+ }
+
+ int curLineIdx = 0;
+ for (;;) {
+ int bobZoneId = READ_LE_INT16(curDataPtr + 2 * curDataIdx);
+ if (bobZoneId != -1) {
+ _vm->_linesMan->addZoneLine(
+ curLineIdx,
+ READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2),
+ READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4),
+ READ_LE_INT16(curDataPtr + 2 * curDataIdx + 6),
+ READ_LE_INT16(curDataPtr + 2 * curDataIdx + 8),
+ bobZoneId);
+ _vm->_linesMan->_zone[bobZoneId]._enabledFl = true;
+ }
+ curDataIdx += 5;
+ ++curLineIdx;
+ if (bobZoneId == -1)
+ break;
+ }
+ for (int i = 1; i <= 100; i++) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[i];
+ curZone->_destX = READ_LE_INT16(curDataPtr + 2 * curDataIdx);
+ curZone->_destY = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2);
+ curZone->_spriteIndex = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4);
+ curDataIdx += 3;
+ }
+
+ byte *verbData = ptr + idx + (10 * curLineIdx + 606) + 4;
+ for (int i = 1; i <= 100; i++) {
+ int j = (i - 1) * 10;
+ ZoneItem *curZone = &_vm->_linesMan->_zone[i];
+ curZone->_verbFl1 = verbData[j];
+ curZone->_verbFl2 = verbData[j + 1];
+ curZone->_verbFl3 = verbData[j + 2];
+ curZone->_verbFl4 = verbData[j + 3];
+ curZone->_verbFl5 = verbData[j + 4];
+ curZone->_verbFl6 = verbData[j + 5];
+ curZone->_verbFl7 = verbData[j + 6];
+ curZone->_verbFl8 = verbData[j + 7];
+ curZone->_verbFl9 = verbData[j + 8];
+ curZone->_verbFl10 = verbData[j + 9];
+ }
+ int dep = 1010;
+ for (int i = 1; i <= 100; i++) {
+ _vm->_linesMan->_zone[i]._messageId = READ_LE_INT16(verbData + dep);
+ dep += 2;
+ }
+ _vm->_linesMan->initSquareZones();
+ }
+ }
+ }
+ _vm->_globals->freeMemory(ptr);
+}
+
+void ObjectsManager::sceneSpecialIni() {
+ switch (_vm->_globals->_screenId) {
+ case 17:
+ if (_vm->_globals->_prevScreenId == 20) {
+ _vm->_globals->_disableInventFl = true;
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->fadeInLong();
+ animateSprite(0);
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+ initVbob(_vm->_globals->_levelSpriteBuf, 5, 15, 28, 1);
+ _vm->_fontMan->hideText(9);
+ bool displayedTxtFl = false;
+ if (!_vm->_soundMan->_textOffFl) {
+ _vm->_fontMan->initTextBuffers(9, 383, _vm->_globals->_textFilename, 220, 72, 6, 36, 253);
+ _vm->_fontMan->showText(9);
+ displayedTxtFl = true;
+ }
+ if (!_vm->_soundMan->_voiceOffFl)
+ _vm->_soundMan->mixVoice(383, 4, displayedTxtFl);
+ _vm->_globals->_saveData->_data[svField270] = 1;
+ _vm->_globals->_saveData->_data[svField300] = 1;
+ _vm->_globals->_saveData->_data[svField320] = 1;
+ if (_vm->_soundMan->_voiceOffFl) {
+ for (int i = 0; i <= 199; i++)
+ _vm->_events->refreshScreenAndEvents();
+ }
+ _vm->_fontMan->hideText(9);
+ disableVbob(5);
+ for (int i = 0; i <= 3; i++)
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_globals->_disableInventFl = false;
+ }
+ break;
+
+ case 18:
+ if (_vm->_globals->_prevScreenId == 17) {
+ _vm->_events->_mouseSpriteId = 4;
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->fadeInLong();
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ _vm->_globals->_disableInventFl = false;
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("MAGE1.pe2");
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_globals->_disableInventFl = false;
+ }
+ break;
+
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ _vm->_linesMan->_bobZone[20] = 1;
+ _vm->_linesMan->_bobZone[21] = 2;
+ _vm->_linesMan->_bobZone[22] = 3;
+ _vm->_linesMan->_bobZone[23] = 4;
+ _vm->_linesMan->_bobZoneFl[20] = true;
+ _vm->_linesMan->_bobZoneFl[21] = true;
+ _vm->_linesMan->_bobZoneFl[22] = true;
+ _vm->_linesMan->_bobZoneFl[23] = true;
+ enableVerb(20, 5);
+ enableVerb(21, 5);
+ enableVerb(22, 5);
+ enableVerb(23, 5);
+ _vm->_linesMan->_zone[20]._messageId = 30;
+ _vm->_linesMan->_zone[21]._messageId = 30;
+ _vm->_linesMan->_zone[22]._messageId = 30;
+ _vm->_linesMan->_zone[23]._messageId = 30;
+ for (int i = svField200; i <= svField214; i++) {
+ if (_vm->_globals->_saveData->_data[i] != 2)
+ _vm->_globals->_saveData->_data[i] = 0;
+ }
+ break;
+
+ case 73:
+ if (!_vm->_globals->_saveData->_data[svSecondElevatorAvailableFl]) {
+ resetHidingUseCount(0);
+ resetHidingUseCount(1);
+ }
+ break;
+
+ case 93:
+ if (!_vm->_globals->_saveData->_data[svField333])
+ setBobAnimation(8);
+ break;
+ }
+}
+
+void ObjectsManager::setMultiBobAnim(int idx1, int idx2, int anim1Idx, int anim2Idx) {
+ if (idx1 != -1)
+ setBobAnimation(idx1);
+ if (idx2 != -1)
+ setBobAnimation(idx2);
+ if (idx1 != -1)
+ setBobAnimDataIdx(idx1, anim1Idx);
+ if (idx2 != -1)
+ setBobAnimDataIdx(idx2, anim2Idx);
+}
+
+void ObjectsManager::checkEventBobAnim(int idx, int animIdx, int animDataIdx, int a4) {
+ _vm->_events->_curMouseButton = 0;
+ _vm->_events->_mouseButton = 0;
+
+ if (a4 != 3) {
+ setBobAnimation(idx);
+ setBobAnimDataIdx(idx, animIdx);
+ }
+
+ do {
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_events->_curMouseButton)
+ break;
+ } while (animDataIdx != getBobAnimDataIdx(idx));
+ if (!a4)
+ stopBobAnimation(idx);
+}
+
+void ObjectsManager::disableVerb(int idx, int a2) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[idx];
+ switch (a2) {
+ case 6:
+ case 16:
+ curZone->_verbFl1 = 0;
+ break;
+ case 7:
+ curZone->_verbFl2 = 0;
+ break;
+ case 5:
+ case 8:
+ curZone->_verbFl3 = 0;
+ break;
+ case 9:
+ case 17:
+ case 24:
+ curZone->_verbFl4 = 0;
+ break;
+ case 10:
+ case 18:
+ curZone->_verbFl5 = 0;
+ break;
+ case 11:
+ case 19:
+ curZone->_verbFl6 = 0;
+ break;
+ case 12:
+ case 20:
+ curZone->_verbFl7 = 0;
+ break;
+ case 13:
+ case 22:
+ curZone->_verbFl8 = 0;
+ case 14:
+ case 21:
+ case 25:
+ curZone->_verbFl9 = 0;
+ break;
+ case 15:
+ curZone->_verbFl10 = 0;
+ break;
+ }
+ _changeVerbFl = true;
+}
+
+void ObjectsManager::enableVerb(int idx, int a2) {
+ ZoneItem *curZone = &_vm->_linesMan->_zone[idx];
+
+ switch (a2) {
+ case 5:
+ curZone->_verbFl3 = 2;
+ break;
+ case 6:
+ curZone->_verbFl1 = 1;
+ break;
+ case 7:
+ curZone->_verbFl2 = 1;
+ break;
+ case 8:
+ curZone->_verbFl3 = 1;
+ break;
+ case 9:
+ curZone->_verbFl4 = 1;
+ break;
+ case 10:
+ curZone->_verbFl5 = 1;
+ break;
+ case 11:
+ curZone->_verbFl6 = 1;
+ break;
+ case 12:
+ curZone->_verbFl7 = 1;
+ break;
+ case 13:
+ curZone->_verbFl8 = 1;
+ break;
+ case 14:
+ curZone->_verbFl8 = 1;
+ break;
+ case 15:
+ curZone->_verbFl9 = 1;
+ break;
+ case 16:
+ curZone->_verbFl1 = 2;
+ break;
+ case 17:
+ curZone->_verbFl4 = 2;
+ break;
+ case 18:
+ curZone->_verbFl5 = 2;
+ break;
+ case 19:
+ curZone->_verbFl6 = 2;
+ break;
+ case 20:
+ curZone->_verbFl7 = 2;
+ break;
+ case 21:
+ curZone->_verbFl9 = 2;
+ break;
+ case 22:
+ curZone->_verbFl8 = 2;
+ break;
+ case 24:
+ curZone->_verbFl4 = 3;
+ break;
+ case 25:
+ curZone->_verbFl9 = 2;
+ break;
+ }
+}
+
+void ObjectsManager::showActionAnimation(const byte *spriteData, const Common::String &actionStr, int speed, bool flipFl) {
+ Common::String tmpStr = "";
+ int realSpeed = speed;
+ if (_vm->_globals->_speed == 2)
+ realSpeed = speed / 2;
+ else if (_vm->_globals->_speed == 3)
+ realSpeed = speed / 3;
+ const byte *oldSpriteData = _sprite[0]._spriteData;
+ int spriteIndex = _sprite[0]._spriteIndex;
+ bool oldFlipFl = _sprite[0]._flipFl;
+ _sprite[0]._flipFl = flipFl;
+
+ int idx = 0;
+ for (int strPos = 0; ; strPos++) {
+ bool tokenCompleteFl = false;
+ char curChar = actionStr[strPos];
+ if (curChar == ',') {
+ idx = atoi(tmpStr.c_str());
+ tmpStr = "";
+ tokenCompleteFl = true;
+ } else {
+ tmpStr += curChar;
+ }
+
+ if (tokenCompleteFl) {
+ if (idx == -1) {
+ _sprite[0]._spriteData = oldSpriteData;
+ _sprite[0]._spriteIndex = spriteIndex;
+ _sprite[0]._flipFl = oldFlipFl;
+ } else {
+ _sprite[0]._spriteData = spriteData;
+ _sprite[0]._spriteIndex = idx;
+ }
+ for (int i = 0; i < realSpeed; i++)
+ _vm->_events->refreshScreenAndEvents();
+ if (idx == -1)
+ break;
+ }
+ }
+}
+
+void ObjectsManager::showSpecialActionAnimationWithFlip(const byte *spriteData, const Common::String &animationSeq, int speed, bool flipFl) {
+ Common::String tmpStr = "";
+
+ int realSpeed = speed;
+ if (_vm->_globals->_speed == 2)
+ realSpeed = speed / 2;
+ else if (_vm->_globals->_speed == 3)
+ realSpeed = speed / 3;
+
+ _oldSpriteData = _sprite[0]._spriteData;
+ _oldSpriteIndex = _sprite[0]._spriteIndex;
+ _oldFlipFl = _sprite[0]._flipFl;
+ _sprite[0]._flipFl = flipFl;
+
+ uint strPos = 0;
+ int spriteIndex = 0;
+ do {
+ bool completeTokenFl = false;
+ do {
+ char nextChar = animationSeq[strPos];
+ if ((animationSeq[strPos] == ',') || (strPos == animationSeq.size() - 1)) {
+ // Safeguard: if the sequence doesn't end with a coma, simulate it's present.
+ if (animationSeq[strPos] != ',')
+ tmpStr += nextChar;
+ spriteIndex = atoi(tmpStr.c_str());
+ tmpStr = "";
+ completeTokenFl = true;
+ } else {
+ tmpStr += nextChar;
+ }
+ ++strPos;
+ } while (!completeTokenFl);
+
+ if (spriteIndex != -1) {
+ _sprite[0]._spriteData = spriteData;
+ _sprite[0]._spriteIndex = spriteIndex;
+ }
+ for (int i = 0; i < realSpeed; i++)
+ _vm->_events->refreshScreenAndEvents();
+ } while (spriteIndex != -1);
+}
+
+void ObjectsManager::showSpecialActionAnimation(const byte *spriteData, const Common::String &animString, int speed) {
+ Common::String tmpStr = "";
+ int realSpeed = speed;
+ if (_vm->_globals->_speed == 2)
+ realSpeed = speed / 2;
+ else if (_vm->_globals->_speed == 3)
+ realSpeed = speed / 3;
+
+ int spriteIndex = 0;
+ bool completeTokenFl;
+ char nextChar;
+
+ for (int idx = 0; ; idx++) {
+ completeTokenFl = false;
+ nextChar = animString[idx];
+ if (nextChar == ',') {
+ spriteIndex = atoi(tmpStr.c_str());
+ tmpStr = "";
+ completeTokenFl = true;
+ } else {
+ tmpStr += nextChar;
+ }
+
+ if (completeTokenFl) {
+ if (spriteIndex == -1) {
+ _sprite[0]._spriteData = _oldSpriteData;
+ _sprite[0]._spriteIndex = _oldSpriteIndex;
+ _sprite[0]._flipFl = _oldFlipFl;
+ } else {
+ _sprite[0]._spriteData = spriteData;
+ _sprite[0]._spriteIndex = spriteIndex;
+ }
+
+ for (int i = 0; i < realSpeed; i++)
+ _vm->_events->refreshScreenAndEvents();
+
+ if (spriteIndex == -1)
+ break;
+ }
+ }
+}
+
+void ObjectsManager::handleForest(int screenId, int minX, int maxX, int minY, int maxY, int idx) {
+ int savegameIdx = screenId;
+ if (_vm->_globals->_screenId != screenId)
+ return;
+
+ switch (_vm->_globals->_screenId) {
+ case 35:
+ if (idx > 2)
+ savegameIdx = 201;
+ else
+ savegameIdx = 200;
+ break;
+ case 36:
+ if (idx > 2)
+ savegameIdx = 203;
+ else
+ savegameIdx = 202;
+ break;
+ case 37:
+ if (idx > 2)
+ savegameIdx = 205;
+ else
+ savegameIdx = 204;
+ break;
+ case 38:
+ if (idx > 2)
+ savegameIdx = 207;
+ else
+ savegameIdx = 206;
+ break;
+ case 39:
+ if (idx > 2)
+ savegameIdx = 209;
+ else
+ savegameIdx = 208;
+ break;
+ case 40:
+ if (idx > 2)
+ savegameIdx = 211;
+ else
+ savegameIdx = 210;
+ break;
+ case 41:
+ if (idx > 2)
+ savegameIdx = 213;
+ else
+ savegameIdx = 212;
+ break;
+ }
+
+ if (_vm->_globals->_saveData->_data[savegameIdx] == 2)
+ return;
+
+ if (_vm->_globals->_saveData->_data[savegameIdx]) {
+ if (_vm->_globals->_saveData->_data[savegameIdx] == 1) {
+ if (((idx == 1 || idx == 2) && getBobAnimDataIdx(idx) == 26) || ((idx == 3 || idx == 4) && getBobAnimDataIdx(idx) == 27)) {
+ _vm->_dialog->disableInvent();
+ _vm->_soundMan->playSample(1);
+ _vm->_globals->_saveData->_data[savegameIdx] = 4;
+ }
+ }
+ if (_vm->_globals->_saveData->_data[savegameIdx] == 4) {
+ if (idx >= 1 && idx <= 4 && getBobAnimDataIdx(idx) > 30)
+ _vm->_globals->_saveData->_data[savegameIdx] = 3;
+ }
+ if (_vm->_globals->_saveData->_data[savegameIdx] == 3) {
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playAnim("CREVE2.ANM", 100, 24, 500);
+ _vm->_globals->_exitId = 150;
+ _vm->_graphicsMan->_noFadingFl = true;
+ hideBob(1);
+ hideBob(2);
+ hideBob(3);
+ hideBob(4);
+ }
+ } else if (minX < getSpriteX(0)
+ && maxX > getSpriteX(0)
+ && minY < getSpriteY(0)
+ && maxY > getSpriteY(0)) {
+ if (idx >= 1 && idx <= 4)
+ setBobAnimation(idx);
+ _vm->_globals->_saveData->_data[savegameIdx] = 1;
+ }
+}
+
+void ObjectsManager::lockAnimX(int idx, int x) {
+ _lockedAnims[idx]._enableFl = true;
+ _lockedAnims[idx]._posX = x;
+}
+
+/**
+ * Game scene control method
+ */
+void ObjectsManager::sceneControl(const Common::String &backgroundFile, const Common::String &linkFile,
+ const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) {
+ _vm->_dialog->_inventFl = false;
+ _vm->_events->_gameKey = KEY_NONE;
+ _vm->_dialog->enableInvent();
+ _vm->_graphicsMan->_scrollOffset = 0;
+ _vm->_globals->_cityMapEnabledFl = false;
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ _vm->_soundMan->playSound(soundNum);
+ _vm->_linesMan->_route = NULL;
+ _vm->_globals->_freezeCharacterFl = true;
+ _vm->_globals->_exitId = 0;
+ if (!backgroundFile.empty())
+ _vm->_graphicsMan->loadImage(backgroundFile);
+ if (!linkFile.empty())
+ loadLinkFile(linkFile);
+ if (!animFile.empty())
+ _vm->_animMan->loadAnim(animFile);
+ _vm->_graphicsMan->displayAllBob();
+ if (!s4.empty()) {
+ if (initializeScreen)
+ _vm->_graphicsMan->initScreen(s4, 0, initializeScreen);
+ else
+ _vm->_graphicsMan->initScreen(s4, 2, initializeScreen);
+ }
+ _vm->_events->mouseOn();
+ if (_vm->_globals->_screenId == 61) {
+ addStaticSprite(_vm->_globals->_characterSpriteBuf, Common::Point(330, 418), 0, 60, 0, false, 34, 190);
+ animateSprite(0);
+ _vm->_linesMan->_route = NULL;
+ computeAndSetSpriteSize();
+ }
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+ _vm->_events->changeMouseCursor(4);
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->fadeInLong();
+ if (_vm->_globals->_screenId == 61) {
+ _vm->_animMan->playSequence("OUVRE.SEQ", 10, 4, 10, false, false);
+ stopBobAnimation(3);
+ _vm->_globals->_checkDistanceFl = true;
+ _oldCharacterPosX = getSpriteX(0);
+ _oldDirection = DIR_NONE;
+ _homeRateCounter = 0;
+ _vm->_linesMan->_route = NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), 330, 345);
+ _vm->_globals->_checkDistanceFl = true;
+ do {
+ goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route);
+ setSpriteIndex(0, 64);
+ }
+ do {
+ int mouseButton = _vm->_events->getMouseButton();
+ if (mouseButton == 1) {
+ handleLeftButton();
+ mouseButton = 1;
+ } else if (mouseButton == 2)
+ handleRightButton();
+ _vm->_dialog->testDialogOpening();
+ _vm->_linesMan->checkZone();
+ if (_vm->_globals->_actionMoveTo)
+ paradise();
+ if (!_vm->_globals->_exitId)
+ _vm->_events->refreshScreenAndEvents();
+
+ if (_vm->_globals->_exitId)
+ break;
+ } while (!_vm->shouldQuit());
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_graphicsMan->fadeOutLong();
+ if (!animFile.empty())
+ _vm->_graphicsMan->endDisplayBob();
+ if (_vm->_globals->_screenId == 61)
+ removeSprite(0);
+ clearScreen();
+ _vm->_globals->_eventMode = EVENTMODE_DEFAULT;
+}
+
+/**
+ * Game scene control method
+ */
+void ObjectsManager::sceneControl2(const Common::String &backgroundFile, const Common::String &linkFile,
+ const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) {
+ _vm->_dialog->_inventFl = false;
+ _vm->_events->_gameKey = KEY_NONE;
+ _verb = 4;
+ _vm->_graphicsMan->_scrollOffset = 0;
+ _vm->_dialog->enableInvent();
+ _vm->_globals->_cityMapEnabledFl = false;
+ _vm->_graphicsMan->_noFadingFl = false;
+ _vm->_globals->_freezeCharacterFl = false;
+ _vm->_globals->_exitId = 0;
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_soundMan->playSound(soundNum);
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ if (!backgroundFile.empty())
+ _vm->_graphicsMan->loadImage(backgroundFile);
+ if (!linkFile.empty())
+ loadLinkFile(linkFile);
+ if (!animFile.empty()) {
+ _vm->_animMan->loadAnim(animFile);
+ _vm->_graphicsMan->displayAllBob();
+ }
+ if (!s4.empty()) {
+ if (initializeScreen)
+ _vm->_graphicsMan->initScreen(s4, 0, initializeScreen);
+ else
+ _vm->_graphicsMan->initScreen(s4, 2, initializeScreen);
+ }
+ _vm->_events->mouseOn();
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+ if (_vm->_globals->_characterType) {
+ if (!_vm->_globals->_saveData->_data[svAlternateSpriteFl] && !_vm->_globals->_saveData->_data[svField356]) {
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR");
+ _vm->_globals->_characterType = 0;
+ }
+ }
+ if (!_vm->_globals->_characterType && _vm->_globals->_saveData->_data[svAlternateSpriteFl] == 1) {
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("HOPFEM.SPR");
+ _vm->_globals->_characterType = 1;
+ }
+
+ if (_vm->_globals->_characterType != 2 && _vm->_globals->_saveData->_data[svField356] == 1) {
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PSAMAN.SPR");
+ _vm->_globals->_characterType = 2;
+ }
+ _vm->_globals->loadCharacterData();
+ switch (_vm->_globals->_characterType) {
+ case 0:
+ addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 34, 190);
+ break;
+ case 1:
+ addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 28, 155);
+ break;
+ case 2:
+ addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 20, 127);
+ break;
+ }
+ _vm->_events->setMouseXY(_characterPos);
+ if (_vm->_graphicsMan->_largeScreenFl)
+ _vm->_graphicsMan->_scrollPosX = (int16)getSpriteX(0) - 320;
+ computeAndSetSpriteSize();
+ animateSprite(0);
+ enableHidingBehavior();
+ _vm->_linesMan->_route = NULL;
+ computeAndSetSpriteSize();
+ sceneSpecialIni();
+ _vm->_events->_mouseSpriteId = 4;
+ _oldCharacterPosX = _characterPos.x;
+ _oldCharacterPosY = _characterPos.y;
+ _oldDirection = DIR_NONE;
+ _homeRateCounter = 0;
+
+ for (int idx = 0; idx < 5; ++idx)
+ _vm->_events->refreshScreenAndEvents();
+
+ _vm->_globals->_eventMode = EVENTMODE_IGNORE;
+ if (!_vm->_graphicsMan->_noFadingFl)
+ _vm->_graphicsMan->fadeInLong();
+ _vm->_graphicsMan->_noFadingFl = false;
+ _vm->_events->changeMouseCursor(4);
+
+ int xCheck = 0;
+ int yCheck = 0;
+
+ bool breakFlag = false;
+ while (!_vm->shouldQuit() && !breakFlag) {
+ int mouseButtons = _vm->_events->getMouseButton();
+ if (mouseButtons) {
+ if (mouseButtons == 1) {
+ if (_verb == 16 && _vm->_events->_mouseCursorId == 16) {
+ int xp = _vm->_events->getMouseX();
+ int yp = _vm->_events->getMouseY();
+
+ if ((xCheck == xp) && (yCheck == yp)) {
+ _vm->_linesMan->_route = NULL;
+ paradise();
+ if (_vm->_globals->_exitId)
+ breakFlag = true;
+ }
+ xCheck = xp;
+ yCheck = yp;
+ }
+ handleLeftButton();
+ } else if (mouseButtons == 2) {
+ handleRightButton();
+ }
+ }
+ if (!_vm->_globals->_exitId) {
+ _vm->_dialog->testDialogOpening();
+ _vm->_linesMan->checkZone();
+ if (_vm->_linesMan->_route == NULL
+ || (goHome(), _vm->_linesMan->_route == NULL)) {
+ if (_vm->_globals->_actionMoveTo)
+ paradise();
+ }
+ handleSpecialGames();
+ _vm->_events->refreshScreenAndEvents();
+ if (!_vm->_globals->_exitId)
+ continue;
+ }
+ breakFlag = true;
+ }
+
+ if (_vm->_globals->_exitId != 8 || _vm->_globals->_screenId != 5 || !_helicopterFl) {
+ if (!_vm->_graphicsMan->_noFadingFl)
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_graphicsMan->_noFadingFl = false;
+ removeSprite(0);
+ if (_twoCharactersFl) {
+ removeSprite(1);
+ _twoCharactersFl = false;
+ }
+ if (!animFile.empty())
+ _vm->_graphicsMan->endDisplayBob();
+ clearScreen();
+ } else {
+ _helicopterFl = false;
+ }
+ _vm->_globals->_eventMode = EVENTMODE_DEFAULT;
+}
+
+void ObjectsManager::setVerb(int id) {
+ _verb = id;
+}
+
+void ObjectsManager::resetHidingUseCount(int idx) {
+ _hidingItem[idx]._useCount = 0;
+}
+
+void ObjectsManager::setHidingUseCount(int idx) {
+ _hidingItem[idx]._useCount = 1;
+}
+
+// Load Hiding Items
+void ObjectsManager::loadHidingItems(const Common::String &file) {
+ resetHidingItems();
+ byte *ptr = _vm->_fileIO->loadFile(file);
+ Common::String filename = Common::String((const char *)ptr);
+
+ Common::File f;
+ if (!f.exists(filename))
+ return;
+
+ byte *spriteData = _vm->_fileIO->loadFile(filename);
+ _hidingItemData[1] = spriteData;
+ int curBufIdx = 60;
+ for (int i = 0; i <= 21; i++) {
+ HidingItem *hid = &_hidingItem[i];
+ hid->_spriteIndex = READ_LE_INT16((uint16 *)ptr + curBufIdx);
+ hid->_x = READ_LE_INT16((uint16 *)ptr + curBufIdx + 1);
+ hid->_y = READ_LE_INT16((uint16 *)ptr + curBufIdx + 2);
+ hid->_yOffset = READ_LE_INT16((uint16 *)ptr + curBufIdx + 4);
+ if (spriteData == NULL) {
+ hid->_useCount = 0;
+ } else {
+ hid->_spriteData = spriteData;
+ hid->_width = getWidth(spriteData, hid->_spriteIndex);
+ hid->_height = getHeight(spriteData, hid->_spriteIndex);
+ hid->_useCount = 1;
+ }
+
+ if ( !hid->_x && !hid->_y && !hid->_spriteIndex)
+ hid->_useCount = 0;
+ curBufIdx += 5;
+ }
+ enableHidingBehavior();
+ _vm->_globals->freeMemory(ptr);
+}
+
+void ObjectsManager::initVBob() {
+ for (int idx = 0; idx < 30; ++idx) {
+ VBobItem *vbob = &_vBob[idx];
+ vbob->_displayMode = 0;
+ vbob->_xp = 0;
+ vbob->_yp = 0;
+ vbob->_frameIndex = 0;
+ vbob->_surface = NULL;
+ vbob->_spriteData = NULL;
+ vbob->_oldSpriteData = NULL;
+ }
+}
+
+void ObjectsManager::clearVBob() {
+ for (int idx = 0; idx < 30; ++idx) {
+ VBobItem *vbob = &_vBob[idx];
+ vbob->_displayMode = 0;
+ vbob->_xp = 0;
+ vbob->_yp = 0;
+ vbob->_frameIndex = 0;
+ vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
+ vbob->_spriteData = NULL;
+ vbob->_oldSpriteData = NULL;
+ }
+}
+
+void ObjectsManager::disableHidingItem(int idx) {
+ assert(idx < 36);
+ _bob[idx]._disableFl = true;
+}
+
+void ObjectsManager::enableHidingBehavior() {
+ _hidingActiveFl = true;
+}
+
+void ObjectsManager::disableHidingBehavior() {
+ _hidingActiveFl = false;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/objects.h b/engines/hopkins/objects.h
new file mode 100644
index 0000000000..a5e309344b
--- /dev/null
+++ b/engines/hopkins/objects.h
@@ -0,0 +1,338 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_OBJECTS_H
+#define HOPKINS_OBJECTS_H
+
+#include "hopkins/globals.h"
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/str.h"
+
+#define MAX_SPRITE 5
+namespace Hopkins {
+
+struct ObjectAuthIcon {
+ byte _objectFileNum;
+ byte _idx;
+ byte _flag1;
+ byte _flag2;
+ byte _flag3;
+ byte _flag4;
+ byte _flag5;
+ byte _flag6;
+};
+
+struct SpriteItem {
+ int _animationType;
+ const byte *_spriteData;
+ Common::Point _spritePos;
+ int _zoomFactor;
+ bool _flipFl;
+ int _spriteIndex;
+ int _deltaX;
+ int _deltaY;
+ bool _rleFl;
+ bool _activeFl;
+ int _destX;
+ int _destY;
+ int _width;
+ int _height;
+ int _zoomPct;
+ int _reducePct;
+};
+
+struct BobItem {
+ int _bobMode;
+ byte *_spriteData;
+ int _xp;
+ int _yp;
+ int _frameIndex;
+ int _animDataIdx;
+ int _moveChange1;
+ int _moveChange2;
+ bool _disabledAnimationFl;
+ byte *_animData;
+ bool _bobMode10;
+ int _bobModeChange;
+ int _modeChangeCtr;
+ int _modeChangeUnused;
+ bool _disableFl; // Set to true in B_CACHE_OFF()
+ int _zoomFactor;
+ bool _flipFl;
+ bool _isSpriteFl;
+ bool _activeFl;
+ int _oldX;
+ int _oldY;
+ int _oldWidth;
+ int _oldHeight;
+ int _oldX2;
+ int _zooInmFactor;
+ int _zoomOutFactor;
+};
+
+struct HidingItem {
+ int _x;
+ int _y;
+ int _spriteIndex;
+ int _width;
+ int _height;
+ int _useCount;
+ byte *_spriteData;
+ bool _resetUseCount;
+ int _yOffset;
+};
+
+struct LockAnimItem {
+ bool _enableFl;
+ int _posX;
+};
+
+struct VBobItem {
+ const byte *_spriteData;
+ int _displayMode;
+ int _xp;
+ int _yp;
+ int _frameIndex;
+ byte *_surface;
+ int _oldX;
+ int _oldY;
+ int _oldFrameIndex;
+ const byte *_oldSpriteData;
+};
+
+struct ListeItem {
+ bool _visibleFl;
+ int _posX;
+ int _posY;
+ int _width;
+ int _height;
+};
+
+/**
+ * Mode for SortItem records
+ */
+enum SortMode { SORT_NONE = 0, SORT_BOB = 1, SORT_SPRITE = 2, SORT_HIDING = 3 };
+
+/**
+ * Structure to represent a pending display of either a Bob, Sprite, or Cache Item.
+ */
+struct SortItem {
+ SortMode _sortMode;
+ int _index;
+ int _priority;
+};
+
+class HopkinsEngine;
+
+class ObjectsManager {
+private:
+ HopkinsEngine *_vm;
+
+ int _objectWidth, _objectHeight;
+ int _oldBorderSpriteIndex;
+ int _borderSpriteIndex;
+ byte *_spritePtr;
+ const byte *_oldSpriteData;
+ int _verb;
+ int _oldSpriteIndex;
+ int _oldFrameIndex;
+ int _oldDirectionSpriteIdx;
+ Directions _oldDirection;
+ Directions _lastDirection;
+ bool _oldFlipFl;
+ int _curGestureFile;
+ byte *_gestureBuf;
+ int _homeRateCounter;
+ int _sortedDisplayCount;
+ SortItem _sortedDisplay[51];
+ byte *_hidingItemData[6];
+ HidingItem _hidingItem[25];
+ bool _hidingActiveFl;
+ ObjectAuthIcon _objectAuthIcons[300];
+ int _curObjectFileNum;
+ byte *_objectDataBuf;
+
+ VBobItem _vBob[30];
+ ListeItem _liste[6];
+ ListeItem _liste2[35];
+
+ void initVBob();
+ void clearVBob();
+
+ void sprite_alone(const byte *objectData, byte *sprite, int objIndex);
+ void removeObjectDataBuf();
+
+ int getOffsetX(const byte *spriteData, int spriteIndex, bool isSize);
+ int getOffsetY(const byte *spriteData, int spriteIndex, bool isSize);
+
+ void capture_mem_sprite(const byte *objectData, byte *sprite, int objIndex);
+ void setBobInfo(int idx);
+ void computeHideCounter(int idx);
+ void initBobVariables(int idx);
+
+ void checkHidingItem();
+ void displayHiding(int idx);
+ void computeSprite(int idx);
+ void beforeSort(SortMode sortMode, int index, int priority);
+ void displayBobAnim();
+ void displayVBob();
+ void showSprite(int idx);
+ void clearSprite();
+ void setSpriteZoom(int idx, int zoomFactor);
+
+ void loadZone(const Common::String &file);
+ void changeCharacterHead(PlayerCharacter oldCharacter, PlayerCharacter newCharacter);
+ void goHome2();
+
+ void nextVerbIcon();
+ void handleForest(int screenId, int minX, int maxX, int minY, int maxY, int idx);
+
+ void sceneSpecialIni();
+ void showActionAnimation(const byte *spriteData, const Common::String &actionStr, int speed, bool flipFl);
+public:
+ bool _disableFl;
+ bool _forestFl;
+ bool _visibleFl;
+ bool _saveLoadFl;
+ bool _forceZoneFl;
+ bool _changeVerbFl;
+ bool _helicopterFl;
+ bool _twoCharactersFl;
+ bool _changeHeadFl;
+ bool _priorityFl;
+ int _jumpVerb;
+ int _jumpZone;
+ int _zoneNum;
+ int _eraseVisibleCounter;
+ int _curObjectIndex;
+ int _startSpriteIndex;
+ int _saveLoadX, _saveLoadY;
+ int _mapCarPosX, _mapCarPosY;
+ int _oldCharacterPosX, _oldCharacterPosY;
+ Common::Point _borderPos;
+ Common::Point _oldBorderPos;
+ Common::Point _characterPos;
+ byte *_forestSprite;
+ byte *_saveLoadSprite;
+ byte *_saveLoadSprite2;
+ byte *_headSprites;
+ SpriteItem _sprite[6];
+ BobItem _bob[36];
+ LockAnimItem _lockedAnims[30];
+ bool _charactersEnabledFl;
+ bool _refreshBobMode10Fl;
+
+ ObjectsManager(HopkinsEngine *vm);
+ ~ObjectsManager();
+
+ void clearAll();
+
+ int getWidth(const byte *objectData, int idx);
+ int getHeight(const byte *objectData, int idx);
+ byte *loadSprite(const Common::String &file);
+ void loadLinkFile(const Common::String &file, bool OBSSEUL = false);
+ void addStaticSprite(const byte *spriteData, Common::Point pos, int idx, int spriteIndex, int zoomFactor, bool flipFl, int deltaX, int deltaY);
+ void animateSprite(int idx);
+ void removeSprite(int idx);
+ void setSpriteX(int idx, int xp);
+ void setSpriteY(int idx, int yp);
+ int getSpriteX(int idx);
+ int getSpriteY(int idx);
+ void setSpriteIndex(int idx, int spriteIndex);
+ void displaySprite();
+ void computeAndSetSpriteSize();
+ void setFlipSprite(int idx, bool flip);
+
+ int getBobAnimDataIdx(int idx);
+ void initBorder(int zoneIdx);
+ void nextObjectIcon(int idx);
+ void takeInventoryObject(int idx);
+ void handleSpecialGames();
+
+ void addObject(int objIndex);
+ void changeObject(int objIndex);
+ void removeObject(int objIndex);
+
+ void resetBob(int idx);
+ void hideBob(int idx);
+ void displayBob(int idx);
+ void setBobOffset(int idx, int offset);
+ void setBobAnimDataIdx(int idx, int animIdx);
+ void setBobAnimation(int idx);
+ void stopBobAnimation(int idx);
+ int getBobPosX(int idx);
+
+ void handleCityMap();
+ void clearScreen();
+ void disableVerb(int idx, int a2);
+ void enableVerb(int idx, int a2);
+ void lockAnimX(int idx, int x);
+ void handleLeftButton();
+ void handleRightButton();
+ void setOffsetXY(byte *data, int idx, int xp, int yp, bool isSize);
+ void setVerb(int id);
+
+ void doActionBack(int idx);
+ void doActionRight(int idx);
+ void doActionFront(int idx);
+ void doActionLeft(int idx);
+ void doActionDiagRight(int idx);
+ void doActionDiagLeft(int idx);
+ void loadObjects();
+ byte *loadObjectFromFile(int objIndex, bool mode);
+ void resetHidingItems();
+ void resetHidingUseCount(int idx);
+ void setHidingUseCount(int idx);
+ void loadHidingItems(const Common::String &file);
+ void enableHidingBehavior();
+ void disableHidingBehavior();
+ void disableHidingItem(int idx);
+
+ void resetHomeRateCounter() { _homeRateCounter = 0; }
+ void resetOldFrameIndex() { _oldFrameIndex = -1; }
+ void resetOldDirection() { _oldDirection = DIR_NONE; }
+ int getObjectWidth() { return _objectWidth; }
+ int getObjectHeight() { return _objectHeight; }
+
+ void showSpecialActionAnimationWithFlip(const byte *spriteData, const Common::String &animationSeq, int speed, bool flipFl);
+ void showSpecialActionAnimation(const byte *spriteData, const Common::String &animString, int speed);
+ void checkEventBobAnim(int idx, int animIdx, int animDataIdx, int a4);
+ void setMultiBobAnim(int idx1, int idx2, int anim1Idx, int anim2Idx);
+ void loadObjectIniFile();
+ void quickDisplayBobSprite(int idx);
+ void initVbob(const byte *src, int idx, int xp, int yp, int frameIndex);
+ void disableVbob(int idx);
+ void setAndPlayAnim(int idx, int animIdx, int destPosi, bool animAction);
+
+ void sceneControl(const Common::String &backgroundFile, const Common::String &linkFile,
+ const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen);
+ void sceneControl2(const Common::String &backgroundFile, const Common::String &linkFile,
+ const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen);
+ void goHome();
+ void paradise();
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_OBJECTS_H */
diff --git a/engines/hopkins/saveload.cpp b/engines/hopkins/saveload.cpp
new file mode 100644
index 0000000000..af0b043641
--- /dev/null
+++ b/engines/hopkins/saveload.cpp
@@ -0,0 +1,333 @@
+/* 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/saveload.h"
+
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/hopkins.h"
+
+
+#include "common/system.h"
+#include "common/savefile.h"
+#include "graphics/surface.h"
+#include "graphics/scaler.h"
+#include "graphics/thumbnail.h"
+
+namespace Hopkins {
+
+const char *SAVEGAME_STR = "HOPKINS";
+#define SAVEGAME_STR_SIZE 13
+
+SaveLoadManager::SaveLoadManager(HopkinsEngine *vm) {
+ _vm = vm;
+}
+
+bool SaveLoadManager::save(const Common::String &file, const void *buf, size_t n) {
+ Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(file);
+
+ if (f) {
+ size_t bytesWritten = f->write(buf, n);
+ f->finalize();
+ delete f;
+
+ return bytesWritten == n;
+ } else
+ return false;
+}
+
+// Save File
+bool SaveLoadManager::saveFile(const Common::String &file, const void *buf, size_t n) {
+ return save(file, buf, n);
+}
+
+void SaveLoadManager::initSaves() {
+ Common::String dataFilename = "HISCORE.DAT";
+ byte data[100];
+ Common::fill(&data[0], &data[100], 0);
+
+ saveFile(dataFilename, data, 100);
+}
+
+void SaveLoadManager::load(const Common::String &file, byte *buf) {
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(file);
+ if (f == NULL)
+ error("Error openinig file - %s", file.c_str());
+
+ int32 filesize = f->size();
+ f->read(buf, filesize);
+ delete f;
+}
+
+bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header) {
+ char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
+ header._thumbnail = NULL;
+
+ // Validate the header Id
+ in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
+ if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
+ return false;
+
+ header._version = in->readByte();
+ if (header._version > HOPKINS_SAVEGAME_VERSION)
+ return false;
+
+ // Read in the string
+ header._saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0') header._saveName += ch;
+
+ // Get the thumbnail
+ header._thumbnail = Graphics::loadThumbnail(*in);
+ if (!header._thumbnail)
+ return false;
+
+ // Read in save date/time
+ header._year = in->readSint16LE();
+ header._month = in->readSint16LE();
+ header._day = in->readSint16LE();
+ header._hour = in->readSint16LE();
+ header._minute = in->readSint16LE();
+ header._totalFrames = in->readUint32LE();
+
+ return true;
+}
+
+void SaveLoadManager::writeSavegameHeader(Common::OutSaveFile *out, hopkinsSavegameHeader &header) {
+ // Write out a savegame header
+ out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
+
+ out->writeByte(HOPKINS_SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->write(header._saveName.c_str(), header._saveName.size() + 1);
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ createThumbnail(thumb);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+ out->writeUint32LE(_vm->_events->_gameCounter);
+}
+
+Common::Error SaveLoadManager::saveGame(int slot, const Common::String &saveName) {
+ /* Pack any necessary data into the savegame data structure */
+ // Set the selected slot number
+ _vm->_globals->_saveData->_data[svLastSavegameSlot] = slot;
+
+ // Set up the inventory
+ for (int i = 0; i < 35; ++i)
+ _vm->_globals->_saveData->_inventory[i] = _vm->_globals->_inventory[i];
+
+ _vm->_globals->_saveData->_mapCarPosX = _vm->_objectsMan->_mapCarPosX;
+ _vm->_globals->_saveData->_mapCarPosY = _vm->_objectsMan->_mapCarPosY;
+
+ /* Create the savegame */
+ Common::OutSaveFile *savefile = g_system->getSavefileManager()->openForSaving(_vm->generateSaveName(slot));
+ if (!savefile)
+ return Common::kCreatingFileFailed;
+
+ // Set up the serializer
+ Common::Serializer serializer(NULL, savefile);
+
+ // Write out the savegame header
+ hopkinsSavegameHeader header;
+ header._saveName = saveName;
+ header._version = HOPKINS_SAVEGAME_VERSION;
+ writeSavegameHeader(savefile, header);
+
+ // Write out the savegame data
+ syncSavegameData(serializer, header._version);
+
+ // Save file complete
+ savefile->finalize();
+ delete savefile;
+
+ return Common::kNoError;
+}
+
+Common::Error SaveLoadManager::loadGame(int slot) {
+ // Try and open the save file for reading
+ Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(
+ _vm->generateSaveName(slot));
+ if (!savefile)
+ return Common::kReadingFailed;
+
+ // Set up the serializer
+ Common::Serializer serializer(savefile, NULL);
+
+ // Read in the savegame header
+ hopkinsSavegameHeader header;
+ readSavegameHeader(savefile, header);
+ if (header._thumbnail)
+ header._thumbnail->free();
+ delete header._thumbnail;
+
+ // Read in the savegame data
+ syncSavegameData(serializer, header._version);
+
+ // Loading save file complete
+ delete savefile;
+
+ // Unpack the inventory
+ for (int i = 0; i < 35; ++i)
+ _vm->_globals->_inventory[i] = _vm->_globals->_saveData->_inventory[i];
+
+ // Set variables from loaded data as necessary
+ _vm->_globals->_saveData->_data[svLastSavegameSlot] = slot;
+ _vm->_globals->_exitId = _vm->_globals->_saveData->_data[svLastScreenId];
+ _vm->_globals->_saveData->_data[svLastPrevScreenId] = 0;
+ _vm->_globals->_screenId = 0;
+ _vm->_objectsMan->_mapCarPosX = _vm->_globals->_saveData->_mapCarPosX;
+ _vm->_objectsMan->_mapCarPosY = _vm->_globals->_saveData->_mapCarPosY;
+
+ return Common::kNoError;
+}
+
+bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header) {
+ // Try and open the save file for reading
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
+ g_vm->generateSaveName(slot));
+ if (!saveFile)
+ return false;
+
+ bool result = readSavegameHeader(saveFile, header);
+ delete saveFile;
+ return result;
+}
+
+#define REDUCE_AMOUNT 80
+
+void SaveLoadManager::createThumbnail(Graphics::Surface *s) {
+ int w = _vm->_graphicsMan->zoomOut(SCREEN_WIDTH, REDUCE_AMOUNT);
+ int h = _vm->_graphicsMan->zoomOut(SCREEN_HEIGHT - 40, REDUCE_AMOUNT);
+
+ Graphics::Surface thumb8;
+ thumb8.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+
+ _vm->_graphicsMan->reduceScreenPart(_vm->_graphicsMan->_frontBuffer, (byte *)thumb8.pixels,
+ _vm->_events->_startPos.x, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 40, 80);
+
+ // Convert the 8-bit pixel to 16 bit surface
+ s->create(w, h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+
+ const byte *srcP = (const byte *)thumb8.pixels;
+ uint16 *destP = (uint16 *)s->pixels;
+
+ for (int yp = 0; yp < h; ++yp) {
+ // Copy over the line, using the source pixels as lookups into the pixels palette
+ const byte *lineSrcP = srcP;
+ uint16 *lineDestP = destP;
+
+ for (int xp = 0; xp < w; ++xp)
+ *lineDestP++ = *(uint16 *)&_vm->_graphicsMan->_palettePixels[*lineSrcP++ * 2];
+
+ // Move to the start of the next line
+ srcP += w;
+ destP += w;
+ }
+ thumb8.free();
+}
+
+void SaveLoadManager::syncSavegameData(Common::Serializer &s, int version) {
+ s.syncBytes(&_vm->_globals->_saveData->_data[0], 2050);
+ syncCharacterLocation(s, _vm->_globals->_saveData->_cloneHopkins);
+ syncCharacterLocation(s, _vm->_globals->_saveData->_realHopkins);
+ syncCharacterLocation(s, _vm->_globals->_saveData->_samantha);
+
+ for (int i = 0; i < 35; ++i)
+ s.syncAsSint16LE(_vm->_globals->_saveData->_inventory[i]);
+
+ if (version > 1) {
+ s.syncAsSint16LE(_vm->_globals->_saveData->_mapCarPosX);
+ s.syncAsSint16LE(_vm->_globals->_saveData->_mapCarPosY);
+ } else {
+ _vm->_globals->_saveData->_mapCarPosX = _vm->_globals->_saveData->_mapCarPosY = 0;
+ }
+
+}
+
+void SaveLoadManager::syncCharacterLocation(Common::Serializer &s, CharacterLocation &item) {
+ s.syncAsSint16LE(item._pos.x);
+ s.syncAsSint16LE(item._pos.y);
+ s.syncAsSint16LE(item._startSpriteIndex);
+ s.syncAsSint16LE(item._location);
+ s.syncAsSint16LE(item._zoomFactor);
+}
+
+void SaveLoadManager::convertThumb16To8(Graphics::Surface *thumb16, Graphics::Surface *thumb8) {
+ thumb8->create(thumb16->w, thumb16->h, Graphics::PixelFormat::createFormatCLUT8());
+ Graphics::PixelFormat pixelFormat16(2, 5, 6, 5, 0, 11, 5, 0, 0);
+
+ byte paletteR[PALETTE_SIZE];
+ byte paletteG[PALETTE_SIZE];
+ byte paletteB[PALETTE_SIZE];
+ for (int palIndex = 0; palIndex < PALETTE_SIZE; ++palIndex) {
+ uint16 p = READ_UINT16(&_vm->_graphicsMan->_palettePixels[palIndex * 2]);
+ pixelFormat16.colorToRGB(p, paletteR[palIndex], paletteG[palIndex], paletteB[palIndex]);
+ }
+
+ const uint16 *srcP = (const uint16 *)thumb16->pixels;
+ byte *destP = (byte *)thumb8->pixels;
+
+ for (int yp = 0; yp < thumb16->h; ++yp) {
+ const uint16 *lineSrcP = srcP;
+ byte *lineDestP = destP;
+
+ for (int xp = 0; xp < thumb16->w; ++xp) {
+ byte r, g, b;
+ pixelFormat16.colorToRGB(*lineSrcP++, r, g, b);
+
+ // Scan the palette for the closest match
+ int difference = 99999, foundIndex = 0;
+ for (int palIndex = 0; palIndex < PALETTE_SIZE; ++palIndex) {
+ byte rCurrent = paletteR[palIndex];
+ byte gCurrent = paletteG[palIndex];
+ byte bCurrent = paletteB[palIndex];
+
+ int diff = ABS((int)r - (int)rCurrent) + ABS((int)g - (int)gCurrent) + ABS((int)b - (int)bCurrent);
+ if (diff < difference) {
+ difference = diff;
+ foundIndex = palIndex;
+ }
+ }
+
+ *lineDestP++ = foundIndex;
+ }
+
+ // Move to the start of the next line
+ srcP += thumb16->w;
+ destP += thumb16->w;
+ }
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/saveload.h b/engines/hopkins/saveload.h
new file mode 100644
index 0000000000..221a445fd2
--- /dev/null
+++ b/engines/hopkins/saveload.h
@@ -0,0 +1,78 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_SAVELOAD_H
+#define HOPKINS_SAVELOAD_H
+
+#include "hopkins/globals.h"
+#include "hopkins/graphics.h"
+
+#include "common/scummsys.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/str.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+#define HOPKINS_SAVEGAME_VERSION 2
+
+struct hopkinsSavegameHeader {
+ uint8 _version;
+ Common::String _saveName;
+ Graphics::Surface *_thumbnail;
+ int _year, _month, _day;
+ int _hour, _minute;
+ int _totalFrames;
+};
+
+class SaveLoadManager {
+private:
+ HopkinsEngine *_vm;
+
+ void createThumbnail(Graphics::Surface *s);
+ void syncSavegameData(Common::Serializer &s, int version);
+ void syncCharacterLocation(Common::Serializer &s, CharacterLocation &item);
+public:
+ SaveLoadManager(HopkinsEngine *vm);
+
+ void initSaves();
+ bool save(const Common::String &file, const void *buf, size_t n);
+ bool saveFile(const Common::String &file, const void *buf, size_t n);
+ void load(const Common::String &file, byte *buf);
+
+ static bool readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header);
+ void writeSavegameHeader(Common::OutSaveFile *out, hopkinsSavegameHeader &header);
+ static bool readSavegameHeader(int slot, hopkinsSavegameHeader &header);
+ Common::Error saveGame(int slot, const Common::String &saveName);
+ Common::Error loadGame(int slot);
+
+ /**
+ * Converts a 16-bit thumbnail to 8 bit paletted using the currently active palette.
+ */
+ void convertThumb16To8(Graphics::Surface *thumb16, Graphics::Surface *thumb8);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_SAVELOAD_H */
diff --git a/engines/hopkins/script.cpp b/engines/hopkins/script.cpp
new file mode 100644
index 0000000000..6167ac4c23
--- /dev/null
+++ b/engines/hopkins/script.cpp
@@ -0,0 +1,2624 @@
+/* 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/objects.h"
+#include "hopkins/dialogs.h"
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/sound.h"
+#include "hopkins/hopkins.h"
+
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "common/file.h"
+#include "common/rect.h"
+#include "engines/util.h"
+
+namespace Hopkins {
+
+ScriptManager::ScriptManager(HopkinsEngine *vm) {
+ _vm = vm;
+ _tempObjectFl = false;
+}
+
+int ScriptManager::handleOpcode(const byte *dataP) {
+ if (READ_BE_UINT16(dataP) != MKTAG16('F', 'C'))
+ return 0;
+
+ int opcodeType = 0;
+ int vbobFrameIndex = 0;
+
+ uint32 signature24 = READ_BE_UINT24(&dataP[2]);
+ switch (signature24) {
+ case MKTAG24('T', 'X', 'T'): {
+ vbobFrameIndex = dataP[6];
+ int mesgId = READ_LE_INT16(dataP + 13);
+ opcodeType = 1;
+ if (!_tempObjectFl) {
+ if (_vm->_globals->_saveData->_data[svField356] == 1) {
+ if (mesgId == 53)
+ mesgId = 644;
+ if (mesgId == 624)
+ mesgId = 639;
+ if (mesgId == 627)
+ mesgId = 630;
+ if (mesgId == 625)
+ mesgId = 639;
+ if (mesgId == 8)
+ mesgId = 637;
+ if (mesgId == 53)
+ mesgId = 644;
+ if (mesgId == 557)
+ mesgId = 636;
+ if (mesgId == 51)
+ mesgId = 644;
+ if (mesgId == 287)
+ mesgId = 636;
+ if (mesgId == 619)
+ mesgId = 633;
+ if (mesgId == 620)
+ mesgId = 634;
+ if (mesgId == 622)
+ mesgId = 644;
+ if (mesgId == 297)
+ mesgId = 636;
+ if (mesgId == 612 || mesgId == 613 || mesgId == 614 || mesgId == 134)
+ mesgId = 636;
+ if (mesgId == 615)
+ mesgId = 635;
+ if (mesgId == 618)
+ mesgId = 632;
+ if (mesgId == 611)
+ mesgId = 642;
+ if (mesgId == 610)
+ mesgId = 641;
+ if (mesgId == 18)
+ mesgId = 643;
+ if (mesgId == 602)
+ mesgId = 645;
+ if (mesgId == 603)
+ mesgId = 646;
+ if (mesgId == 604)
+ mesgId = 647;
+ if (mesgId == 51)
+ mesgId = 644;
+ if (mesgId == 607)
+ mesgId = 650;
+ if (mesgId == 605)
+ mesgId = 648;
+ if (mesgId == 606)
+ mesgId = 649;
+ if (mesgId == 601)
+ mesgId = 652;
+ if (mesgId == 37)
+ mesgId = 636;
+ if (mesgId == 595)
+ mesgId = 633;
+ if (mesgId == 596)
+ mesgId = 634;
+ if (mesgId == 532)
+ mesgId = 636;
+ if (mesgId == 599)
+ mesgId = 636;
+ if (mesgId == 363)
+ mesgId = 636;
+ }
+ if (!_vm->_soundMan->_soundOffFl && _vm->_soundMan->_soundFl) {
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_soundMan->_soundFl);
+ }
+ bool displayedTxtFl = false;
+ if (!_vm->_soundMan->_textOffFl) {
+ int textPosX = READ_LE_INT16(dataP + 9);
+ int textPosY = READ_LE_INT16(dataP + 11);
+ _vm->_fontMan->initTextBuffers(9, mesgId, _vm->_globals->_textFilename, 2 * textPosX, 2 * textPosY + 40, 6, dataP[7], 253);
+ _vm->_fontMan->showText(9);
+ displayedTxtFl = true;
+ }
+ if (!_vm->_soundMan->_voiceOffFl)
+ _vm->_soundMan->mixVoice(mesgId, 4, displayedTxtFl);
+ } else { // if (_tempObjectFl)
+ if (_vm->_globals->_saveData->_data[svField356]) {
+ _vm->_fontMan->initTextBuffers(9, 635, _vm->_globals->_textFilename, 55, 20, dataP[8], 35, 253);
+ bool displayedTxtFl = false;
+ if (!_vm->_soundMan->_textOffFl) {
+ _vm->_fontMan->showText(9);
+ displayedTxtFl = true;
+ }
+
+ if (!_vm->_soundMan->_voiceOffFl)
+ _vm->_soundMan->mixVoice(635, 4, displayedTxtFl);
+ } else {
+ int textPosX = READ_LE_INT16(dataP + 9);
+ if (_vm->_globals->_language == LANG_FR && !_vm->_soundMan->_textOffFl)
+ _vm->_fontMan->initTextBuffers(9, mesgId, "OBJET1.TXT", 2 * textPosX, 60, 6, dataP[7], 253);
+ else if (_vm->_globals->_language == LANG_EN && !_vm->_soundMan->_textOffFl)
+ _vm->_fontMan->initTextBuffers(9, mesgId, "OBJETAN.TXT", 2 * textPosX, 60, 6, dataP[7], 253);
+ else if (_vm->_globals->_language == LANG_SP && !_vm->_soundMan->_textOffFl) {
+ _vm->_fontMan->initTextBuffers(9, mesgId, "OBJETES.TXT", 2 * textPosX, 60, 6, dataP[7], 253);
+ }
+
+ bool displayedTxtFl = false;
+ if (!_vm->_soundMan->_textOffFl) {
+ _vm->_fontMan->showText(9);
+ displayedTxtFl = true;
+ }
+
+ if (!_vm->_soundMan->_voiceOffFl)
+ _vm->_soundMan->mixVoice(mesgId, 5, displayedTxtFl);
+ }
+ }
+ break;
+ }
+ case MKTAG24('B', 'O', 'B'):
+ if (!_vm->_objectsMan->_disableFl) {
+ int vbobIdx = dataP[5];
+ vbobFrameIndex = dataP[6];
+ int moveChange = dataP[7];
+ int vbobPosX = READ_LE_INT16(dataP + 8);
+ int vbobPosY = READ_LE_INT16(dataP + 10);
+ if (vbobIdx == 52) {
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, vbobPosX, READ_LE_INT16(dataP + 10), vbobFrameIndex);
+ } else if (vbobIdx == 51) {
+ _vm->_objectsMan->quickDisplayBobSprite(vbobFrameIndex);
+ } else if (vbobIdx != 50) {
+ _vm->_objectsMan->initVbob(_vm->_globals->_levelSpriteBuf, vbobIdx, vbobPosX, vbobPosY, vbobFrameIndex);
+ if (moveChange)
+ moveChange /= _vm->_globals->_speed;
+ if (moveChange > 1) {
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ --moveChange;
+ _vm->_events->refreshScreenAndEvents();
+ } while (moveChange);
+ }
+ }
+ }
+ opcodeType = 1;
+ break;
+ case MKTAG24('S', 'T', 'P'):
+ if (!_vm->_objectsMan->_disableFl) {
+ _vm->_objectsMan->_twoCharactersFl = false;
+ _vm->_objectsMan->_characterPos.x = READ_LE_INT16(dataP + 6);
+ _vm->_objectsMan->_characterPos.y = READ_LE_INT16(dataP + 8);
+ _vm->_objectsMan->_startSpriteIndex = dataP[5];
+ if (_vm->_objectsMan->_changeHeadFl) {
+ if (_vm->_globals->_saveData->_data[svField354] == 1
+ && _vm->_globals->_saveData->_cloneHopkins._pos.x && _vm->_globals->_saveData->_cloneHopkins._pos.y
+ && _vm->_globals->_saveData->_cloneHopkins._startSpriteIndex && _vm->_globals->_saveData->_cloneHopkins._location) {
+
+ _vm->_objectsMan->_characterPos = _vm->_globals->_saveData->_cloneHopkins._pos;
+ _vm->_objectsMan->_startSpriteIndex = _vm->_globals->_saveData->_cloneHopkins._startSpriteIndex;
+ }
+ if (_vm->_globals->_saveData->_data[svField356] == 1
+ && _vm->_globals->_saveData->_samantha._pos.x && _vm->_globals->_saveData->_samantha._pos.y
+ && _vm->_globals->_saveData->_samantha._startSpriteIndex && _vm->_globals->_saveData->_samantha._location) {
+ _vm->_objectsMan->_characterPos = _vm->_globals->_saveData->_samantha._pos;
+ _vm->_objectsMan->_startSpriteIndex = _vm->_globals->_saveData->_samantha._startSpriteIndex;
+ }
+ if (_vm->_globals->_saveData->_data[svField357] == 1
+ && _vm->_globals->_saveData->_realHopkins._pos.x && _vm->_globals->_saveData->_realHopkins._pos.y
+ && _vm->_globals->_saveData->_realHopkins._startSpriteIndex && _vm->_globals->_saveData->_realHopkins._location) {
+ _vm->_objectsMan->_characterPos = _vm->_globals->_saveData->_realHopkins._pos;
+ _vm->_objectsMan->_startSpriteIndex = _vm->_globals->_saveData->_realHopkins._startSpriteIndex;
+ }
+ }
+ if (_vm->_globals->_saveData->_data[svField356] == 1
+ && _vm->_globals->_saveData->_realHopkins._location == _vm->_globals->_screenId) {
+ _vm->_objectsMan->addStaticSprite(
+ _vm->_objectsMan->_headSprites,
+ _vm->_globals->_saveData->_realHopkins._pos,
+ 1,
+ 2,
+ _vm->_globals->_saveData->_realHopkins._zoomFactor,
+ false,
+ 34,
+ 190);
+ _vm->_objectsMan->animateSprite(1);
+ _vm->_objectsMan->_twoCharactersFl = true;
+ }
+ if (_vm->_globals->_saveData->_data[svField357] == 1
+ && _vm->_globals->_saveData->_data[svField355] == 1
+ && _vm->_globals->_saveData->_samantha._location == _vm->_globals->_screenId) {
+ _vm->_objectsMan->addStaticSprite(
+ _vm->_objectsMan->_headSprites,
+ _vm->_globals->_saveData->_samantha._pos,
+ 1,
+ 3,
+ _vm->_globals->_saveData->_samantha._zoomFactor,
+ false,
+ 20,
+ 127);
+ _vm->_objectsMan->animateSprite(1);
+ _vm->_objectsMan->_twoCharactersFl = true;
+ }
+ }
+ opcodeType = 1;
+ _vm->_objectsMan->_changeHeadFl = false;
+ break;
+ case MKTAG24('S', 'T', 'E'):
+ if (!_vm->_objectsMan->_disableFl) {
+ _vm->_globals->_prevScreenId = _vm->_globals->_screenId;
+ _vm->_globals->_saveData->_data[svLastPrevScreenId] = _vm->_globals->_screenId;
+ _vm->_globals->_screenId = _vm->_globals->_saveData->_data[svLastScreenId] = dataP[5];
+ vbobFrameIndex = dataP[6];
+ }
+ opcodeType = 1;
+ break;
+ case MKTAG24('B', 'O', 'F'):
+ if (!_vm->_objectsMan->_disableFl)
+ _vm->_objectsMan->disableVbob(READ_LE_INT16(dataP + 5));
+ opcodeType = 1;
+ break;
+ case MKTAG24('P', 'E', 'R'): {
+ int specialOpcode = READ_LE_INT16(dataP + 5);
+ if (!_vm->_globals->_saveData->_data[svAlternateSpriteFl] && !_vm->_globals->_saveData->_data[svField356]) {
+ vbobFrameIndex = 0;
+
+ switch (specialOpcode) {
+ case 1:
+ case 14:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(4);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(4);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(4);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(4);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(4);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(4);
+ break;
+ case 2:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(7);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(7);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(7);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(7);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(7);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(7);
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(8);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(8);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(8);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(8);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(8);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(8);
+ break;
+ case 19:
+ case 4:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(1);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(1);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(1);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(1);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(1);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(1);
+ break;
+ case 5:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(5);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(5);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(5);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(5);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(5);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(5);
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(6);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(6);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(6);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(6);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(6);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(6);
+ break;
+ case 17:
+ case 7:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(2);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(2);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(2);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(2);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(2);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(2);
+ break;
+ case 18:
+ case 8:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(3);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(3);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(3);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(3);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(3);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(3);
+ break;
+ case 9:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(5);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(5);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(5);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(5);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(5);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(5);
+ break;
+ case 10:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(6);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(6);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(6);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(6);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(6);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(6);
+ break;
+ case 15:
+ case 11:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(7);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(7);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(7);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(7);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(7);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(7);
+ break;
+ case 16:
+ case 12:
+ if (_vm->_globals->_actionDirection == DIR_UP)
+ _vm->_objectsMan->doActionBack(8);
+ if (_vm->_globals->_actionDirection == DIR_RIGHT)
+ _vm->_objectsMan->doActionRight(8);
+ if (_vm->_globals->_actionDirection == DIR_UP_RIGHT)
+ _vm->_objectsMan->doActionDiagRight(8);
+ if (_vm->_globals->_actionDirection == DIR_DOWN)
+ _vm->_objectsMan->doActionFront(8);
+ if (_vm->_globals->_actionDirection == DIR_UP_LEFT)
+ _vm->_objectsMan->doActionDiagLeft(8);
+ if (_vm->_globals->_actionDirection == DIR_LEFT)
+ _vm->_objectsMan->doActionLeft(8);
+ break;
+ }
+ }
+ opcodeType = 1;
+ break;
+ }
+ case MKTAG24('M', 'U', 'S'):
+ opcodeType = 1;
+ break;
+ case MKTAG24('W', 'A', 'I'): {
+ uint frameNumb = READ_LE_UINT16(dataP + 5) / _vm->_globals->_speed;
+ if (!frameNumb)
+ frameNumb = 1;
+ for (uint i = 0; i < frameNumb + 1; i++) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ }
+ opcodeType = 1;
+ break;
+ }
+ case MKTAG24('O', 'B', 'P'):
+ opcodeType = 1;
+ _vm->_objectsMan->addObject(READ_LE_INT16(dataP + 5));
+ break;
+ case MKTAG24('O', 'B', 'M'):
+ opcodeType = 1;
+ _vm->_objectsMan->removeObject(READ_LE_INT16(dataP + 5));
+ break;
+ case MKTAG24('G', 'O', 'T'):
+ opcodeType = 2;
+ break;
+ case MKTAG24('Z', 'O', 'N'):
+ _vm->_linesMan->enableZone(READ_LE_INT16(dataP + 5));
+ opcodeType = 1;
+ break;
+ case MKTAG24('Z', 'O', 'F'):
+ _vm->_linesMan->disableZone(READ_LE_INT16(dataP + 5));
+ opcodeType = 1;
+ break;
+ case MKTAG24('E', 'X', 'I'):
+ opcodeType = 5;
+ break;
+ case MKTAG24('S', 'O', 'R'):
+ _vm->_globals->_exitId = READ_LE_INT16(dataP + 5);
+ opcodeType = 5;
+ break;
+ case MKTAG24('B', 'C', 'A'):
+ _vm->_objectsMan->disableHidingItem(READ_LE_INT16(dataP + 5));
+ opcodeType = 1;
+ break;
+ case MKTAG24('A', 'N', 'I'): {
+ int animId = READ_LE_INT16(dataP + 5);
+ if (animId <= 100)
+ _vm->_objectsMan->setBobAnimation(animId);
+ else
+ _vm->_objectsMan->stopBobAnimation(animId - 100);
+ opcodeType = 1;
+ break;
+ }
+ case MKTAG24('S', 'P', 'E'):
+ switch (READ_LE_INT16(dataP + 5)) {
+ case 6:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setAndPlayAnim(20, 0, 14, true);
+ break;
+
+ case 7:
+ _vm->_talkMan->startAnimatedCharacterDialogue("rueh1.pe2");
+ break;
+
+ case 8:
+ _vm->_talkMan->startAnimatedCharacterDialogue("ruef1.pe2");
+ break;
+
+ case 10:
+ _vm->_talkMan->startAnimatedCharacterDialogue("bqeflic1.pe2");
+ break;
+
+ case 11:
+ _vm->_talkMan->startAnimatedCharacterDialogue("bqeflic2.pe2");
+ break;
+
+ case 12:
+ _vm->_fontMan->hideText(9);
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_talkMan->startAnimatedCharacterDialogue("bqetueur.pe2");
+ break;
+
+ case 13:
+ _vm->_events->_mouseButton = _vm->_events->_curMouseButton;
+ _vm->_globals->_disableInventFl = true;
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_objectsMan->disableHidingBehavior();
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_fontMan->hideText(5);
+ _vm->_fontMan->hideText(9);
+ _vm->_graphicsMan->endDisplayBob();
+ _vm->_objectsMan->clearScreen();
+
+ if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo()) {
+ _vm->_graphicsMan->fadeOutLong();
+ } else {
+ _vm->_soundMan->playSoundFile("SOUND17.WAV");
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playSequence2("HELICO.SEQ", 10, 4, 10);
+ }
+
+ _vm->_animMan->loadAnim("otage");
+ _vm->_graphicsMan->loadImage("IM05");
+ _vm->_graphicsMan->displayAllBob();
+
+ for (int i = 0; i <= 4; i++) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ }
+
+ _vm->_events->mouseOff();
+ _vm->_graphicsMan->fadeInDefaultLength(_vm->_graphicsMan->_frontBuffer);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(3) != 100);
+ _vm->_graphicsMan->fadeOutDefaultLength(_vm->_graphicsMan->_frontBuffer);
+ _vm->_graphicsMan->endDisplayBob();
+
+ // If uncensored, rip the throat of the hostage
+ if (!_vm->_globals->_censorshipFl) {
+ _vm->_soundMan->_specialSoundNum = 16;
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playAnim("EGORGE.ANM", 50, 28, 500);
+ _vm->_soundMan->_specialSoundNum = 0;
+ }
+ _vm->_animMan->loadAnim("ASCEN");
+ _vm->_events->mouseOff();
+ _vm->_graphicsMan->loadImage("ASCEN");
+ _vm->_graphicsMan->displayAllBob();
+
+ for (int i = 0; i <= 4; i++) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ }
+
+ _vm->_events->mouseOff();
+ _vm->_graphicsMan->fadeInDefaultLength(_vm->_graphicsMan->_frontBuffer);
+ _vm->_objectsMan->checkEventBobAnim(1, 0, 17, 3);
+ _vm->_graphicsMan->fadeOutDefaultLength(_vm->_graphicsMan->_frontBuffer);
+ _vm->_graphicsMan->endDisplayBob();
+
+ if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo())
+ _vm->_soundMan->playSoundFile("SOUND17.WAV");
+
+ _vm->_soundMan->_specialSoundNum = 14;
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playSequence2("ASSOM.SEQ", 10, 4, 500);
+ _vm->_soundMan->_specialSoundNum = 0;
+
+ if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo())
+ _vm->_graphicsMan->fadeOutLong();
+
+ _vm->_globals->_disableInventFl = false;
+ _vm->_objectsMan->_helicopterFl = true;
+ break;
+
+ case 16:
+ _vm->_talkMan->startAnimatedCharacterDialogue("ftoubib.pe2");
+ break;
+
+ case 17:
+ _vm->_talkMan->startAnimatedCharacterDialogue("flic2b.pe2");
+ break;
+
+ case 18:
+ _vm->_talkMan->startAnimatedCharacterDialogue("fjour.pe2");
+ break;
+
+ case 20:
+ _vm->_talkMan->startAnimatedCharacterDialogue("PUNK.pe2");
+ break;
+
+ case 21:
+ _vm->_talkMan->startAnimatedCharacterDialogue("MEDLEG.pe2");
+ break;
+
+ case 22:
+ _vm->_talkMan->animateObject("CADAVRE1.pe2");
+ break;
+
+ case 23:
+ _vm->_talkMan->startStaticCharacterDialogue("CHERCHE1.pe2");
+ break;
+
+ case 25:
+ _vm->_talkMan->startAnimatedCharacterDialogue("AGENT1.pe2");
+ break;
+
+ case 26:
+ _vm->_talkMan->startAnimatedCharacterDialogue("AGENT2.pe2");
+ break;
+
+ case 27:
+ if (_vm->_globals->_saveData->_data[svField94] != 1 || _vm->_globals->_saveData->_data[svField95] != 1)
+ _vm->_talkMan->startAnimatedCharacterDialogue("STANDAR.pe2");
+ else
+ _vm->_talkMan->startAnimatedCharacterDialogue("STANDAR1.pe2");
+ break;
+
+ case 29:
+ _vm->_globals->_disableInventFl = true;
+ _vm->_talkMan->animateObject("TELEP.pe2");
+ _vm->_globals->_disableInventFl = false;
+ break;
+
+ case 32:
+ _vm->_talkMan->startAnimatedCharacterDialogue("SAMAN.pe2");
+ break;
+
+ case 35:
+ if (!_vm->_soundMan->_soundOffFl) {
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_soundMan->_soundFl);
+ }
+ _vm->_talkMan->startAnimatedCharacterDialogue("PTLAB.pe2");
+ break;
+
+ case 36:
+ if (_vm->_globals->_saveData->_data[svField270] == 2 && _vm->_globals->_saveData->_data[svField94] == 1 && _vm->_globals->_saveData->_data[svField95] == 1)
+ _vm->_globals->_saveData->_data[svField270] = 3;
+
+ switch (_vm->_globals->_saveData->_data[svField270]) {
+ case 0:
+ _vm->_talkMan->startStaticCharacterDialogue("PATRON0.pe2");
+ break;
+ case 1:
+ _vm->_talkMan->startStaticCharacterDialogue("PATRON1.pe2");
+ break;
+ case 2:
+ _vm->_talkMan->startStaticCharacterDialogue("PATRON2.pe2");
+ break;
+ case 3:
+ _vm->_talkMan->startStaticCharacterDialogue("PATRON3.pe2");
+ break;
+ default:
+ if (_vm->_globals->_saveData->_data[svField270] > 3) {
+ _vm->_talkMan->startStaticCharacterDialogue("PATRON4.pe2");
+ _vm->_globals->_saveData->_data[svField270] = 5;
+ }
+ break;
+ }
+ break;
+
+ case 37:
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playSequence2("corde.SEQ", 32, 32, 100);
+ _vm->_graphicsMan->_noFadingFl = true;
+ break;
+
+ case 38:
+ _vm->_soundMan->loadSample(1, "SOUND44.WAV");
+ _vm->_soundMan->loadSample(2, "SOUND42.WAV");
+ _vm->_soundMan->loadSample(3, "SOUND41.WAV");
+ _vm->_soundMan->_specialSoundNum = 17;
+ _vm->_animMan->playSequence("grenade.SEQ", 1, 32, 100, false, false);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playAnim("CREVE17.ANM", 24, 24, 200);
+ _vm->_soundMan->removeSample(1);
+ _vm->_soundMan->removeSample(2);
+ _vm->_soundMan->removeSample(3);
+ _vm->_graphicsMan->_noFadingFl = true;
+ break;
+
+ case 40:
+ _vm->_talkMan->startAnimatedCharacterDialogue("MAGE.pe2");
+ break;
+
+ case 41:
+ _vm->_talkMan->startAnimatedCharacterDialogue("MORT3.pe2");
+ break;
+
+ case 42:
+ _vm->_talkMan->startAnimatedCharacterDialogue("MORT2.pe2");
+ break;
+
+ case 43:
+ _vm->_talkMan->startAnimatedCharacterDialogue("MORT1.pe2");
+ break;
+
+ case 44:
+ _vm->_talkMan->startAnimatedCharacterDialogue("MORT3A.pe2");
+ break;
+
+ case 45:
+ _vm->_talkMan->startAnimatedCharacterDialogue("FEM3.pe2");
+ break;
+
+ case 46: {
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 564, 420);
+ _vm->_objectsMan->_zoneNum = -1;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_soundMan->loadSample(1, "SOUND44.WAV");
+ _vm->_soundMan->loadSample(2, "SOUND45.WAV");
+ _vm->_objectsMan->setMultiBobAnim(9, 10, 0, 0);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(9)) {
+ case 4:
+ case 16:
+ case 28:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 5:
+ case 17:
+ case 29:
+ playFl = false;
+ break;
+ }
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(10)) {
+ case 10:
+ case 22:
+ case 33:
+ if (!playFl) {
+ _vm->_soundMan->playSample(2);
+ playFl = true;
+ }
+ break;
+ case 11:
+ playFl = false;
+ break;
+ case 12:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 249, 1);
+ break;
+ case 23:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 249, 2);
+ playFl = false;
+ break;
+ case 34:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 249, 3);
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(9) == 36)
+ break;
+ }
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->stopBobAnimation(9);
+ _vm->_objectsMan->stopBobAnimation(10);
+ _vm->_soundMan->removeSample(1);
+ _vm->_soundMan->removeSample(2);
+ break;
+ }
+
+ case 47:
+ _vm->_talkMan->startAnimatedCharacterDialogue("BARMAN.pe2");
+ break;
+
+ case 48:
+ _vm->_talkMan->startAnimatedCharacterDialogue("SAMAN2.pe2");
+ break;
+
+ case 49: {
+ _vm->_objectsMan->disableHidingBehavior();
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setMultiBobAnim(9, 10, 0, 0);
+
+ int endIdx;
+ if (_vm->_globals->_saveData->_data[svField133] == 1)
+ endIdx = 41;
+ else
+ endIdx = 12;
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(9)) {
+ case 4:
+ case 18:
+ if (!playFl) {
+ _vm->_soundMan->directPlayWav("SOUND44.WAV");
+ playFl = true;
+ }
+ break;
+ case 5:
+ case 9:
+ playFl = false;
+ break;
+ }
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(10)) {
+ case 11:
+ if (!playFl) {
+ _vm->_soundMan->directPlayWav("SOUND45.WAV");
+ playFl = true;
+ }
+ break;
+ case 12:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(9) == endIdx)
+ break;
+ }
+
+ if (endIdx == 12) {
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->stopBobAnimation(9);
+ }
+ _vm->_objectsMan->enableHidingBehavior();
+ break;
+ }
+
+ case 50:
+ _vm->_soundMan->playSoundFile("SOUND46.WAv");
+ _vm->_objectsMan->setAndPlayAnim(11, 0, 23, false);
+ break;
+
+ case 51: {
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_objectsMan->disableHidingBehavior();
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_fontMan->hideText(5);
+ _vm->_fontMan->hideText(9);
+ _vm->_graphicsMan->endDisplayBob();
+ _vm->_graphicsMan->loadImage("IM20f");
+ _vm->_animMan->loadAnim("ANIM20f");
+ _vm->_graphicsMan->displayAllBob();
+ _vm->_events->mouseOff();
+ _vm->_graphicsMan->fadeInLong();
+ _vm->_soundMan->loadWav("SOUND46.WAV", 1);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ if (_vm->_objectsMan->getBobAnimDataIdx(12) == 5 && !playFl) {
+ _vm->_soundMan->playWav(1);
+ playFl = true;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(12) == 34)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(2);
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_globals->_exitId = 20;
+ break;
+ }
+
+ case 52:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("GARDE.PE2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 53:
+ _vm->_talkMan->startAnimatedCharacterDialogue("GARDE1.pe2");
+ break;
+
+ case 54:
+ _vm->_talkMan->startAnimatedCharacterDialogue("GARDE2.pe2");
+ break;
+
+ case 55:
+ _vm->_objectsMan->stopBobAnimation(1);
+ _vm->_objectsMan->setAndPlayAnim(15, 0, 12, false);
+ _vm->_objectsMan->stopBobAnimation(15);
+ _vm->_objectsMan->loadLinkFile("IM19a", true);
+ break;
+
+ case 56:
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("HOPFEM.SPR");
+ _vm->_globals->_characterType = 1;
+ _vm->_globals->_saveData->_data[svAlternateSpriteFl] = 1;
+ _vm->_globals->loadCharacterData();
+ _vm->_objectsMan->_sprite[0]._deltaX = 28;
+ _vm->_objectsMan->_sprite[0]._deltaY = 155;
+ _vm->_objectsMan->computeAndSetSpriteSize();
+ break;
+
+ case 57:
+ _vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR");
+ _vm->_globals->_characterType = 0;
+ _vm->_globals->_saveData->_data[svAlternateSpriteFl] = 0;
+ _vm->_globals->loadCharacterData();
+ _vm->_objectsMan->_sprite[0]._deltaX = 34;
+ _vm->_objectsMan->_sprite[0]._deltaY = 190;
+ _vm->_objectsMan->computeAndSetSpriteSize();
+ break;
+
+ case 58:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("Gm1.PE2");
+ _vm->_globals->_saveData->_data[svField176] = 1;
+ _vm->_globals->_saveData->_data[svField270] = 2;
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 59: {
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_oldCharacterPosX = _vm->_objectsMan->getSpriteX(0);
+ _vm->_objectsMan->resetOldDirection();
+ _vm->_objectsMan->resetHomeRateCounter();
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 445, 332);
+ _vm->_globals->_checkDistanceFl = true;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(7);
+ _vm->_objectsMan->setBobAnimDataIdx(7, 0);
+ bool playFl = false;
+ _vm->_soundMan->loadSample(1, "SOUND40.WAV");
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(7)) {
+ case 10:
+ case 18:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 11:
+ playFl = false;
+ break;
+ case 19:
+ _vm->_objectsMan->setBobAnimation(3);
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(3) == 48)
+ break;
+ }
+ _vm->_soundMan->removeSample(1);
+ _vm->_objectsMan->setSpriteIndex(0, 62);
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->setBobAnimation(6);
+ _vm->_objectsMan->stopBobAnimation(7);
+ _vm->_objectsMan->stopBobAnimation(3);
+ break;
+ }
+
+ case 62:
+ _vm->_talkMan->animateObject("SBCADA.pe2");
+ break;
+
+ case 65:
+ _vm->_talkMan->animateObject("ScCADA.pe2");
+ break;
+
+ case 80: {
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(12);
+ _vm->_objectsMan->setBobAnimation(13);
+ _vm->_objectsMan->setBobAnimDataIdx(12, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(13, 0);
+ _vm->_soundMan->loadWav("SOUND44.WAV", 1);
+ _vm->_soundMan->loadWav("SOUND71.WAV", 2);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(12)) {
+ case 4:
+ if (!playFl) {
+ _vm->_soundMan->playWav(1);
+ playFl = true;
+ }
+ break;
+ case 5:
+ playFl = false;
+ break;
+ }
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(4)) {
+ case 5:
+ if (!playFl) {
+ _vm->_soundMan->playWav(2);
+ playFl = true;
+ }
+ case 6:
+ playFl = false;
+ break;
+ }
+
+ if (_vm->_objectsMan->getBobAnimDataIdx(13) == 8) {
+ _vm->_objectsMan->stopBobAnimation(13);
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_objectsMan->setBobAnimation(4);
+ _vm->_objectsMan->setBobAnimDataIdx(4, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(13, 0);
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(4) == 16)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(12);
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->loadLinkFile("IM27a", true);
+ break;
+ }
+
+ case 81: {
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_oldCharacterPosX = _vm->_objectsMan->getSpriteX(0);
+ _vm->_objectsMan->resetOldDirection();
+ _vm->_objectsMan->resetHomeRateCounter();
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 119, 268);
+ _vm->_globals->_checkDistanceFl = true;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(11);
+ _vm->_objectsMan->setBobAnimation(8);
+ _vm->_objectsMan->setBobAnimDataIdx(11, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(8, 0);
+ _vm->_soundMan->loadWav("SOUND44.WAV", 1);
+ _vm->_soundMan->loadWav("SOUND48.WAV", 2);
+ _vm->_soundMan->loadWav("SOUND49.WAV", 3);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(11)) {
+ case 4:
+ if (!playFl) {
+ _vm->_soundMan->playWav(1);
+ playFl = true;
+ }
+ break;
+ case 5:
+ playFl = false;
+ break;
+ }
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(8)) {
+ case 11:
+ if (!playFl) {
+ _vm->_soundMan->playWav(2);
+ playFl = true;
+ }
+ break;
+ case 12:
+ playFl = false;
+ break;
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(8) == 32)
+ break;
+ }
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 201, 14, 1);
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->stopBobAnimation(11);
+ _vm->_objectsMan->stopBobAnimation(8);
+ _vm->_objectsMan->setBobAnimation(5);
+ _vm->_objectsMan->setBobAnimation(6);
+ _vm->_objectsMan->setBobAnimDataIdx(5, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(6, 0);
+ _vm->_soundMan->playWav(3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) != 74);
+ _vm->_objectsMan->stopBobAnimation(5);
+ _vm->_objectsMan->stopBobAnimation(6);
+ _vm->_objectsMan->setBobAnimation(9);
+ _vm->_objectsMan->setBobAnimation(7);
+ break;
+ }
+
+ case 83:
+ _vm->_talkMan->startAnimatedCharacterDialogue("CVIGIL.pe2");
+ break;
+
+ case 84:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("CVIGIL1.PE2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 85:
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_objectsMan->setBobAnimation(5);
+ _vm->_objectsMan->setBobAnimDataIdx(5, 0);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) != 6);
+ _vm->_objectsMan->stopBobAnimation(5);
+ _vm->_objectsMan->setBobAnimation(6);
+ _vm->_objectsMan->loadLinkFile("IM24a", true);
+ break;
+
+ case 86:
+ if (_vm->_globals->_saveData->_data[svField231] == 1) {
+ _vm->_talkMan->startAnimatedCharacterDialogue("chotess1.pe2");
+ } else {
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("chotesse.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ }
+ break;
+
+ case 87:
+ if (_vm->_globals->_saveData->_data[svField188])
+ _vm->_talkMan->startAnimatedCharacterDialogue("stand2.pe2");
+ else
+ _vm->_talkMan->startAnimatedCharacterDialogue("stand1.pe2");
+ break;
+
+ case 88:
+ if (_vm->_globals->_saveData->_data[svField183] == 1) {
+ _vm->_objectsMan->setBobAnimDataIdx(1, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(2, 0);
+ _vm->_objectsMan->setBobAnimation(1);
+ _vm->_objectsMan->setBobAnimation(2);
+ _vm->_soundMan->loadSample(1, "SOUND40.WAV");
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(1)) {
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(1) == 9)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(1);
+ _vm->_objectsMan->stopBobAnimation(2);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 283, 160, 6);
+ _vm->_soundMan->removeSample(1);
+ }
+ if (_vm->_globals->_saveData->_data[svField183] == 2) {
+ _vm->_objectsMan->setBobAnimDataIdx(1, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(3, 0);
+ _vm->_objectsMan->setBobAnimation(1);
+ _vm->_objectsMan->setBobAnimation(3);
+ _vm->_soundMan->loadSample(1, "SOUND40.WAV");
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(1)) {
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(1) == 9)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(1);
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 283, 161, 8);
+ _vm->_soundMan->removeSample(1);
+ }
+ break;
+
+ case 90:
+ _vm->_soundMan->playSoundFile("SOUND52.WAV");
+ if (!_vm->_globals->_saveData->_data[svField186]) {
+ _vm->_animMan->playSequence("CIB5A.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 0);
+ } else if (_vm->_globals->_saveData->_data[svField186] == 1) {
+ _vm->_animMan->playSequence("CIB5C.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 0);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 329, 87, 2);
+ }
+ break;
+
+ case 91:
+ _vm->_soundMan->playSoundFile("SOUND52.WAV");
+ if (!_vm->_globals->_saveData->_data[svField186]) {
+ _vm->_animMan->playSequence("CIB5B.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 5);
+ } else if (_vm->_globals->_saveData->_data[svField186] == 1) {
+ _vm->_animMan->playSequence("CIB5D.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 5);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 283, 160, 6);
+ }
+ break;
+
+ case 92:
+ _vm->_soundMan->playSoundFile("SOUND52.WAV");
+ if (!_vm->_globals->_saveData->_data[svField184]) {
+ _vm->_animMan->playSequence("CIB6A.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 0);
+ } else if (_vm->_globals->_saveData->_data[svField184] == 1) {
+ _vm->_animMan->playSequence("CIB6C.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 0);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 293, 139, 3);
+ }
+ break;
+
+ case 93:
+ _vm->_soundMan->playSoundFile("SOUND52.WAV");
+ if (!_vm->_globals->_saveData->_data[svField184]) {
+ _vm->_animMan->playSequence("CIB6B.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 5);
+ } else if (_vm->_globals->_saveData->_data[svField184] == 1) {
+ _vm->_animMan->playSequence("CIB6D.SEQ", 1, 12, 1, false, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 155, 29, 5);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 283, 161, 8);
+ }
+ break;
+
+ case 94:
+ if (!_vm->_globals->_saveData->_data[svField228])
+ _vm->_talkMan->startAnimatedCharacterDialogue("flicn.pe2");
+ else if (_vm->_globals->_saveData->_data[svField228] == 1)
+ _vm->_talkMan->startAnimatedCharacterDialogue("flicn1.pe2");
+ break;
+
+ case 95:
+ _vm->_objectsMan->setBobAnimation(9);
+ _vm->_objectsMan->setBobAnimation(10);
+ _vm->_objectsMan->setBobAnimation(12);
+ _vm->_objectsMan->setBobAnimDataIdx(9, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(10, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(12, 0);
+ _vm->_objectsMan->removeSprite(0);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(9) != 15);
+ _vm->_objectsMan->stopBobAnimation(9);
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_soundMan->playSoundFile("SOUND50.WAV");
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(12) != 117);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 830, 122, 0);
+ _vm->_objectsMan->stopBobAnimation(12);
+ _vm->_objectsMan->stopBobAnimation(10);
+ _vm->_objectsMan->setBobAnimation(11);
+ break;
+
+ case 98:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("CVIGIL2.PE2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 100:
+ _vm->_talkMan->startAnimatedCharacterDialogue("tourist.pe2");
+ break;
+
+ case 101:
+ _vm->_talkMan->startAnimatedCharacterDialogue("tahi1.pe2");
+ break;
+
+ case 103:
+ // Dice game
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("tourist1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ _vm->_animMan->playAnim2("T421.ANM", 100, 14, 500);
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("tourist2.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 104:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("tourist3.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 105:
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_oldCharacterPosX = _vm->_objectsMan->getSpriteX(0);
+ _vm->_objectsMan->resetOldDirection();
+ _vm->_objectsMan->resetHomeRateCounter();
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ switch (_vm->_globals->_saveData->_data[svField253]) {
+ case 1:
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 201, 294);
+ break;
+ case 2:
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 158, 338);
+ break;
+ default:
+ if (_vm->_globals->_saveData->_data[svField253] > 2)
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 211, 393);
+ break;
+ }
+ _vm->_globals->_checkDistanceFl = true;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setSpriteIndex(0, 60);
+ _vm->_soundMan->loadSample(1, "SOUND63.WAV");
+ if (_vm->_globals->_saveData->_data[svField253] > 2) {
+ _vm->_objectsMan->setBobAnimation(4);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(4)) {
+ case 9:
+ case 32:
+ case 55:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 10:
+ case 33:
+ case 56:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(4) == 72)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(4);
+ }
+ if (_vm->_globals->_saveData->_data[svField253] == 1) {
+ _vm->_objectsMan->setBobAnimation(6);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(6)) {
+ case 9:
+ case 32:
+ case 55:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 10:
+ case 33:
+ case 56:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(6) == 72)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(6);
+ }
+ if (_vm->_globals->_saveData->_data[svField253] == 2) {
+ _vm->_objectsMan->setBobAnimation(5);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(5)) {
+ case 9:
+ case 32:
+ case 55:
+ if (!playFl) {
+ _vm->_soundMan->playSample(1);
+ playFl = true;
+ }
+ break;
+ case 10:
+ case 33:
+ case 56:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(5) == 72)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(5);
+ }
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->doActionBack(1);
+ _vm->_soundMan->removeSample(1);
+ break;
+
+ case 106:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(4);
+ _vm->_objectsMan->setBobAnimDataIdx(4, 0);
+ _vm->_soundMan->loadWav("SOUND61.WAV", 1);
+ _vm->_soundMan->loadWav("SOUND62.WAV", 2);
+ _vm->_soundMan->loadWav("SOUND61.WAV", 3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(4) != 10);
+ _vm->_soundMan->playWav(1);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(4) != 18);
+ _vm->_soundMan->playWav(2);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(4) != 62);
+ _vm->_soundMan->playWav(3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(4) != 77);
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->animateSprite(0);
+ break;
+
+ case 107:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(5);
+ _vm->_objectsMan->setBobAnimDataIdx(5, 0);
+ _vm->_soundMan->loadWav("SOUND61.WAV", 1);
+ _vm->_soundMan->loadWav("SOUND62.WAV", 2);
+ _vm->_soundMan->loadWav("SOUND61.WAV", 3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) != 10);
+ _vm->_soundMan->playWav(1);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) != 18);
+ _vm->_soundMan->playWav(2);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) != 38);
+ _vm->_soundMan->playWav(3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) != 53);
+ _vm->_objectsMan->stopBobAnimation(5);
+ _vm->_objectsMan->animateSprite(0);
+ break;
+
+ case 108:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("peche1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 109:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("peche2.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 110:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("peche3.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 111:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("peche4.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 112:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("teint1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 113:
+ _vm->_talkMan->startAnimatedCharacterDialogue("teint.pe2");
+ break;
+
+ case 114:
+ _vm->_talkMan->startAnimatedCharacterDialogue("tahibar.pe2");
+ break;
+
+ case 115:
+ _vm->_talkMan->startAnimatedCharacterDialogue("ilebar.pe2");
+ break;
+
+ case 116:
+ _vm->_talkMan->startAnimatedCharacterDialogue("Profred.pe2");
+ break;
+
+ case 170:
+ _vm->_talkMan->startAnimatedCharacterDialogue("GRED.pe2");
+ break;
+
+ case 171: {
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("gred1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_oldCharacterPosX = _vm->_objectsMan->getSpriteX(0);
+ _vm->_objectsMan->resetOldDirection();
+ _vm->_objectsMan->resetHomeRateCounter();
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 361, 325);
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_zoneNum = -1;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_globals->_exitId = 59;
+ break;
+ }
+
+ case 172:
+ _vm->_talkMan->startAnimatedCharacterDialogue("GBLEU.pe2");
+ break;
+
+ case 173: {
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("gbleu1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_oldCharacterPosX = _vm->_objectsMan->getSpriteX(0);
+ _vm->_objectsMan->resetOldDirection();
+ _vm->_objectsMan->resetHomeRateCounter();
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 361, 325);
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_zoneNum = -1;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_globals->_exitId = 59;
+ break;
+ }
+
+ case 174:
+ _vm->_talkMan->startAnimatedCharacterDialogue("Profbl.pe2");
+ break;
+
+ case 175:
+ _vm->_objectsMan->setSpriteIndex(0, 55);
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(9);
+ _vm->_objectsMan->setBobAnimation(10);
+ _vm->_objectsMan->setBobOffset(10, 300);
+ _vm->_soundMan->playSoundFile("SOUND44.WAV");
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(10) != 7);
+ _vm->_objectsMan->setBobAnimation(6);
+ _vm->_objectsMan->stopBobAnimation(3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(6) != 10);
+ _vm->_soundMan->playSoundFile("SOUND71.WAV");
+ _vm->_objectsMan->setBobAnimation(7);
+ _vm->_objectsMan->stopBobAnimation(4);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(7) != 15);
+ _vm->_objectsMan->stopBobAnimation(5);
+ _vm->_objectsMan->setBobAnimation(8);
+ _vm->_soundMan->playSoundFile("SOUND70.WAV");
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(8) != 76);
+ _vm->_objectsMan->stopBobAnimation(6);
+ _vm->_objectsMan->stopBobAnimation(7);
+ _vm->_objectsMan->stopBobAnimation(8);
+ _vm->_objectsMan->stopBobAnimation(9);
+ _vm->_objectsMan->stopBobAnimation(10);
+ _vm->_objectsMan->animateSprite(0);
+ break;
+
+ case 176:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("gred2.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 177:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("gbleu2.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 200:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("Gm2.PE2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 201:
+ _vm->_objectsMan->setBobAnimation(3);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(3) != 18);
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_objectsMan->setBobAnimation(4);
+ break;
+
+ case 202:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("SVGARD2.PE2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 203:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(4);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(4) == 18)
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 18, 334, 0, false);
+ } while (_vm->_objectsMan->getBobAnimDataIdx(4) != 26);
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->animateSprite(0);
+ break;
+
+ case 204: {
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(3);
+ _vm->_soundMan->loadWav("SOUND67.WAV", 1);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(3)) {
+ case 10:
+ if (!playFl) {
+ _vm->_soundMan->playWav(1);
+ playFl = true;
+ }
+ break;
+ case 11:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(3) == 50)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_objectsMan->animateSprite(0);
+ break;
+ }
+
+ case 205: {
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(4);
+ _vm->_soundMan->loadWav("SOUND69.WAV", 1);
+ bool playFl = false;
+ for (;;) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ switch (_vm->_objectsMan->getBobAnimDataIdx(4)) {
+ case 10:
+ if (!playFl) {
+ _vm->_soundMan->playWav(1);
+ playFl = true;
+ }
+ break;
+ case 11:
+ playFl = false;
+ break;
+ }
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(4) == 24)
+ break;
+ }
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->animateSprite(0);
+ break;
+ }
+
+ case 207:
+ _vm->_talkMan->animateObject("PANNEAU.PE2");
+ break;
+
+ case 208: {
+ _vm->_globals->_disableInventFl = true;
+ if (_vm->_globals->_saveData->_data[svLastPrevScreenId] != _vm->_globals->_saveData->_data[svField401]) {
+ _vm->_soundMan->_specialSoundNum = 208;
+ _vm->_animMan->playSequence("SORT.SEQ", 10, 4, 10, true, false);
+ _vm->_soundMan->_specialSoundNum = 0;
+ }
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 330, 418);
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_zoneNum = 0;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->setSpriteIndex(0, 64);
+ _vm->_globals->_exitId = _vm->_globals->_saveData->_data[svField401];
+ _vm->_globals->_disableInventFl = false;
+ break;
+ }
+
+ case 209: {
+ _vm->_objectsMan->setBobAnimDataIdx(1, 0);
+ _vm->_objectsMan->setBobAnimDataIdx(2, 0);
+ _vm->_objectsMan->setSpriteIndex(0, 60);
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->setBobAnimation(1);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(1) != 9);
+ _vm->_objectsMan->stopBobAnimation(1);
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 330, 314);
+ _vm->_objectsMan->_zoneNum = 0;
+ _vm->_globals->_checkDistanceFl = true;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->setSpriteIndex(0, 64);
+ _vm->_objectsMan->setBobAnimation(2);
+ _vm->_soundMan->playSoundFile("SOUND66.WAV");
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(2) != 10);
+ _vm->_objectsMan->stopBobAnimation(2);
+ _vm->_objectsMan->setBobAnimation(4);
+ break;
+ }
+
+ case 210:
+ _vm->_soundMan->_specialSoundNum = 210;
+ _vm->_animMan->playSequence2("SECRET1.SEQ", 1, 12, 1, true);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 192, 152, 0);
+ _vm->_objectsMan->setBobAnimation(9);
+ _vm->_objectsMan->loadLinkFile("IM73a", true);
+ _vm->_objectsMan->enableHidingBehavior();
+ _vm->_objectsMan->setHidingUseCount(0);
+ _vm->_objectsMan->setHidingUseCount(1);
+ _vm->_graphicsMan->setColorPercentage2(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage2(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage2(254, 0, 0, 0);
+ break;
+
+ case 211:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->disableHidingBehavior();
+ _vm->_soundMan->_specialSoundNum = 211;
+ _vm->_animMan->playSequence("SECRET2.SEQ", 1, 12, 100, false, true);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_graphicsMan->fadeOutLong();
+
+ for (int i = 1; i <= 39; i++) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ }
+
+ _vm->_graphicsMan->setColorPercentage2(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage2(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage2(254, 0, 0, 0);
+ break;
+
+ case 215:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("aviat.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 216:
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("aviat1.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ break;
+
+ case 229:
+ _vm->_soundMan->_specialSoundNum = 229;
+ _vm->_animMan->playSequence("MUR.SEQ", 1, 12, 1, false, false);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 340, 157, 2);
+ break;
+
+ case 230: {
+ _vm->_objectsMan->loadLinkFile("IM93a", true);
+ _vm->_objectsMan->enableHidingBehavior();
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_objectsMan->_oldCharacterPosX = _vm->_objectsMan->getSpriteX(0);
+ _vm->_objectsMan->resetOldDirection();
+ _vm->_objectsMan->resetHomeRateCounter();
+ _vm->_globals->_checkDistanceFl = true;
+ _vm->_linesMan->_route = (RouteItem *)NULL;
+ _vm->_linesMan->_route = _vm->_linesMan->findRoute(_vm->_objectsMan->getSpriteX(0), _vm->_objectsMan->getSpriteY(0), 488, 280);
+ _vm->_globals->_checkDistanceFl = true;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_objectsMan->goHome();
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_linesMan->_route != (RouteItem *)NULL);
+ _vm->_objectsMan->removeSprite(0);
+ bool playFl = false;
+ _vm->_objectsMan->setBobAnimation(7);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ if (_vm->_objectsMan->getBobAnimDataIdx(7) == 9 && !playFl) {
+ playFl = true;
+ _vm->_soundMan->playSoundFile("SOUND81.WAV");
+ }
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(7) != 15);
+ _vm->_objectsMan->stopBobAnimation(7);
+ _vm->_objectsMan->setSpriteX(0, 476);
+ _vm->_objectsMan->setSpriteY(0, 278);
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 337, 154, 3);
+ _vm->_objectsMan->loadLinkFile("IM93c", true);
+ _vm->_objectsMan->enableHidingBehavior();
+ break;
+ }
+
+ case 231:
+ _vm->_objectsMan->disableHidingBehavior();
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(12);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(12) != 6);
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("PRMORT.pe2");
+ _vm->_globals->_introSpeechOffFl = false;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(12) != 12);
+ _vm->_objectsMan->animateSprite(0);
+ _vm->_objectsMan->stopBobAnimation(12);
+ _vm->_objectsMan->enableHidingBehavior();
+ break;
+
+ case 233: {
+ _vm->_objectsMan->disableHidingBehavior();
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setBobAnimation(11);
+ bool playFl = false;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_objectsMan->getBobAnimDataIdx(11) == 10 && !playFl)
+ playFl = true;
+ } while (_vm->_objectsMan->getBobAnimDataIdx(11) != 13);
+ _vm->_objectsMan->stopBobAnimation(11);
+ _vm->_objectsMan->enableHidingBehavior();
+ _vm->_objectsMan->setBobAnimation(13);
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ } while (_vm->_objectsMan->getBobAnimDataIdx(13) != 48);
+ _vm->_globals->_introSpeechOffFl = true;
+ _vm->_talkMan->startAnimatedCharacterDialogue("HRADIO.PE2");
+ _vm->_globals->_introSpeechOffFl = false;
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_objectsMan->stopBobAnimation(13);
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_globals->_exitId = 94;
+ break;
+ }
+
+ case 236: {
+ if (_vm->_globals->_saveData->_data[svField341]) {
+ switch (_vm->_globals->_saveData->_data[svField341]) {
+ case 1:
+ vbobFrameIndex = 6;
+ break;
+ case 2:
+ vbobFrameIndex = 5;
+ break;
+ case 3:
+ vbobFrameIndex = 4;
+ break;
+ }
+ _vm->_soundMan->playSoundFile("SOUND83.WAV");
+ _vm->_objectsMan->setAndPlayAnim(vbobFrameIndex, 26, 50, false);
+
+ switch (_vm->_globals->_saveData->_data[svField341]) {
+ case 1:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 27, 117, 0);
+ _vm->_globals->_saveData->_data[svField338] = 0;
+ break;
+ case 2:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 145, 166, 2);
+ _vm->_globals->_saveData->_data[svField339] = 0;
+ break;
+ case 3:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 296, 212, 4);
+ _vm->_globals->_saveData->_data[svField340] = 0;
+ break;
+ }
+ }
+ _vm->_soundMan->playSoundFile("SOUND83.WAV");
+ _vm->_objectsMan->setAndPlayAnim(6, 0, 23, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 27, 117, 1);
+ break;
+ }
+
+ case 237: {
+ switch (_vm->_globals->_saveData->_data[svField341]) {
+ case 1:
+ vbobFrameIndex = 6;
+ break;
+ case 2:
+ vbobFrameIndex = 5;
+ break;
+ case 3:
+ vbobFrameIndex = 4;
+ break;
+ }
+
+ if (_vm->_globals->_saveData->_data[svField341]) {
+ _vm->_soundMan->playSoundFile("SOUND83.WAV");
+ _vm->_objectsMan->setAndPlayAnim(vbobFrameIndex, 26, 50, false);
+
+ switch (_vm->_globals->_saveData->_data[svField341]) {
+ case 1:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 27, 117, 0);
+ _vm->_globals->_saveData->_data[svField338] = 0;
+ break;
+ case 2:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 145, 166, 2);
+ _vm->_globals->_saveData->_data[svField339] = 0;
+ break;
+ case 3:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 296, 212, 4);
+ _vm->_globals->_saveData->_data[svField340] = 0;
+ break;
+ }
+ }
+
+ _vm->_soundMan->playSoundFile("SOUND83.WAV");
+ _vm->_objectsMan->setAndPlayAnim(5, 0, 23, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 145, 166, 3);
+ break;
+ }
+
+ case 238: {
+ switch (_vm->_globals->_saveData->_data[svField341]) {
+ case 1:
+ vbobFrameIndex = 6;
+ break;
+ case 2:
+ vbobFrameIndex = 5;
+ break;
+ case 3:
+ vbobFrameIndex = 4;
+ break;
+ }
+
+ if (_vm->_globals->_saveData->_data[svField341]) {
+ _vm->_soundMan->playSoundFile("SOUND83.WAV");
+ _vm->_objectsMan->setAndPlayAnim(vbobFrameIndex, 26, 50, false);
+ switch (_vm->_globals->_saveData->_data[svField341]) {
+ case 1:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 27, 117, 0);
+ _vm->_globals->_saveData->_data[svField338] = 0;
+ break;
+ case 2:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 145, 166, 2);
+ _vm->_globals->_saveData->_data[svField339] = 0;
+ break;
+ case 3:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 296, 212, 4);
+ _vm->_globals->_saveData->_data[svField340] = 0;
+ break;
+ }
+ }
+ _vm->_soundMan->playSoundFile("SOUND83.WAV");
+ _vm->_objectsMan->setAndPlayAnim(4, 0, 23, false);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 296, 212, 5);
+ break;
+ }
+
+ case 239:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_soundMan->playSoundFile("SOUND84.WAV");
+ _vm->_objectsMan->setAndPlayAnim(16, 0, 10, false);
+ break;
+
+ case 240: {
+ _vm->_objectsMan->setBobAnimation(1);
+ bool soundFlag = false;
+ do {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ switch (_vm->_objectsMan->getBobAnimDataIdx(1)) {
+ case 12:
+ if (!soundFlag) {
+ _vm->_soundMan->playSoundFile("SOUND86.WAV");
+ soundFlag = true;
+ }
+ break;
+ case 13:
+ // The original was starting then stopping sound at 25
+ // It looked wrong so the check was set on 26
+ case 26:
+ soundFlag = false;
+ break;
+ case 25:
+ if (!soundFlag) {
+ _vm->_soundMan->playSoundFile("SOUND85.WAV");
+ soundFlag = true;
+ }
+ break;
+ }
+ } while (_vm->_objectsMan->getBobAnimDataIdx(1) != 32);
+ _vm->_objectsMan->stopBobAnimation(1);
+ _vm->_objectsMan->setBobAnimation(2);
+ _vm->_fontMan->hideText(9);
+ bool displayedTxtFl = false;
+ if (!_vm->_soundMan->_textOffFl) {
+ _vm->_fontMan->initTextBuffers(9, 617, _vm->_globals->_textFilename, 91, 41, 3, 30, 253);
+ _vm->_fontMan->showText(9);
+ displayedTxtFl = true;
+ }
+ if (!_vm->_soundMan->_voiceOffFl)
+ _vm->_soundMan->mixVoice(617, 4, displayedTxtFl);
+ for (int i = 0; i <= 29; i++) {
+ if (_vm->shouldQuit())
+ return -1; // Exiting game
+
+ _vm->_events->refreshScreenAndEvents();
+ }
+ CharacterLocation *realHopkins = &_vm->_globals->_saveData->_realHopkins;
+ realHopkins->_pos.x = _vm->_objectsMan->getSpriteX(0);
+ realHopkins->_pos.y = _vm->_objectsMan->getSpriteY(0);
+ realHopkins->_startSpriteIndex = 57;
+ realHopkins->_location = 97;
+ _vm->_globals->_saveData->_data[svHopkinsCloneFl] = 1;
+ _vm->_globals->_saveData->_data[svField352] = 1;
+ _vm->_globals->_saveData->_data[svField353] = 1;
+ _vm->_globals->_saveData->_data[svField354] = 1;
+ break;
+ }
+
+ case 241:
+ _vm->_talkMan->startAnimatedCharacterDialogue("RECEP.PE2");
+ break;
+
+ // Resurrect Samantha's clone
+ case 242: {
+ _vm->_soundMan->playSoundFile("SOUND87.WAV");
+ _vm->_animMan->playSequence("RESUF.SEQ", 1, 24, 1, false, true);
+
+ CharacterLocation *samantha = &_vm->_globals->_saveData->_samantha;
+ samantha->_pos.x = 404;
+ samantha->_pos.y = 395;
+ samantha->_startSpriteIndex = 64;
+ samantha->_location = _vm->_globals->_screenId;
+ samantha->_zoomFactor = -(100 * (67 - (100 - abs(_vm->_globals->_spriteSize[790 / 2]))) / 67);
+
+ _vm->_globals->_saveData->_data[svField357] = 1;
+ _vm->_globals->_saveData->_data[svField354] = 0;
+ _vm->_globals->_saveData->_data[svField356] = 0;
+ _vm->_globals->_saveData->_data[svField355] = 1;
+ _vm->_objectsMan->_twoCharactersFl = true;
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 373, 191, 3);
+ _vm->_objectsMan->addStaticSprite(_vm->_objectsMan->_headSprites, samantha->_pos, 1, 3, samantha->_zoomFactor, false, 20, 127);
+ _vm->_objectsMan->animateSprite(1);
+ break;
+ }
+
+ case 243:
+ _vm->_soundMan->playSoundFile("SOUND88.WAV");
+ if (_vm->_globals->_saveData->_data[svField341] == 2) {
+ _vm->_animMan->playSequence("RESU.SEQ", 2, 24, 2, false, true);
+ } else {
+ _vm->_objectsMan->setAndPlayAnim(7, 0, 14, false);
+ }
+ break;
+
+ case 245:
+ _vm->_soundMan->playSoundFile("SOUND89.WAV");
+ _vm->_objectsMan->setAndPlayAnim(5, 0, 6, false);
+ _vm->_linesMan->_zone[4]._destX = 276;
+ _vm->_objectsMan->enableVerb(4, 19);
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 285, 379, 0);
+ _vm->_globals->_saveData->_data[svField399] = 1;
+ break;
+
+ case 246:
+ _vm->_objectsMan->removeSprite(0);
+ _vm->_objectsMan->setAndPlayAnim(6, 0, 15, false);
+ _vm->_objectsMan->_charactersEnabledFl = true;
+ _vm->_graphicsMan->displayScreen(true);
+ _vm->_animMan->playSequence2("TUNNEL.SEQ", 1, 18, 20, true);
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_graphicsMan->fadeOutLong();
+ _vm->_objectsMan->_charactersEnabledFl = false;
+ _vm->_globals->_exitId = 100;
+ break;
+
+ case 600:
+ if (!_vm->getIsDemo()) {
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_graphicsMan->_fadeDefaultSpeed = 1;
+ _vm->_animMan->playAnim("BOMBE1A.ANM", 100, 18, 100);
+ }
+ _vm->_graphicsMan->loadImage("BOMBEB");
+ _vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+ _vm->_graphicsMan->initScreen("BOMBE", 2, true);
+ _vm->_graphicsMan->fadeInShort();
+ break;
+
+ case 601:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 163, 7, false);
+ _vm->_objectsMan->setAndPlayAnim(2, 0, 16, true);
+ break;
+
+ case 602:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 163, 7, false);
+ _vm->_objectsMan->setAndPlayAnim(4, 0, 16, true);
+ break;
+
+ case 603:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 163, 7, false);
+ _vm->_objectsMan->setAndPlayAnim(3, 0, 16, true);
+ _vm->_soundMan->_specialSoundNum = 199;
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playAnim("BOMBE2A.ANM", 50, 14, 500);
+ _vm->_soundMan->_specialSoundNum = 0;
+ memset(_vm->_graphicsMan->_frontBuffer, 0, 614400);
+ _vm->_graphicsMan->_noFadingFl = true;
+ _vm->_globals->_exitId = 151;
+ break;
+
+ case 604:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 163, 7, false);
+ _vm->_objectsMan->setAndPlayAnim(1, 0, 16, true);
+ _vm->_soundMan->_specialSoundNum = 199;
+ _vm->_animMan->playAnim("BOMBE2A.ANM", 50, 14, 500);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->_noFadingFl = true;
+ memset(_vm->_graphicsMan->_frontBuffer, 0, 614400);
+ _vm->_globals->_exitId = 151;
+ break;
+
+ case 605:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 163, 7, false);
+ _vm->_objectsMan->setAndPlayAnim(5, 0, 16, true);
+ _vm->_graphicsMan->fadeOutShort();
+ _vm->_soundMan->_specialSoundNum = 199;
+ _vm->_graphicsMan->_fadingFl = true;
+ _vm->_animMan->playAnim("BOMBE2A.ANM", 50, 14, 500);
+ _vm->_soundMan->_specialSoundNum = 0;
+ _vm->_graphicsMan->_noFadingFl = true;
+ memset(_vm->_graphicsMan->_frontBuffer, 0, 614400);
+ _vm->_globals->_exitId = 151;
+ break;
+
+ case 606:
+ _vm->_graphicsMan->fastDisplay(_vm->_globals->_levelSpriteBuf, 513, 163, 7, false);
+ _vm->_objectsMan->setAndPlayAnim(6, 0, 16, true);
+ if ((_vm->getPlatform() != Common::kPlatformWindows) || !_vm->getIsDemo()) {
+ _vm->_animMan->playAnim("BOMBE3A.ANM", 50, 14, 500);
+ memset(_vm->_graphicsMan->_frontBuffer, 0, 614400);
+ }
+ _vm->_globals->_exitId = 6;
+ break;
+
+ case 607:
+ // Display bomb plan
+ if (!_vm->getIsDemo()) {
+ memcpy(_vm->_graphicsMan->_oldPalette, _vm->_graphicsMan->_palette, 769);
+ _vm->_animMan->playAnim2("PLAN.ANM", 50, 10, 800);
+ }
+ _vm->_graphicsMan->resetDirtyRects();
+ break;
+
+ case 608:
+ _vm->_objectsMan->stopBobAnimation(2);
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->stopBobAnimation(6);
+ _vm->_objectsMan->stopBobAnimation(11);
+ _vm->_objectsMan->stopBobAnimation(10);
+ break;
+
+ case 609:
+ _vm->_objectsMan->setBobAnimation(2);
+ _vm->_objectsMan->setBobAnimation(3);
+ _vm->_objectsMan->setBobAnimation(4);
+ _vm->_objectsMan->setBobAnimation(6);
+ _vm->_objectsMan->setBobAnimation(11);
+ _vm->_objectsMan->setBobAnimation(10);
+ break;
+
+ case 610:
+ _vm->_objectsMan->stopBobAnimation(5);
+ _vm->_objectsMan->stopBobAnimation(7);
+ _vm->_objectsMan->stopBobAnimation(8);
+ _vm->_objectsMan->stopBobAnimation(9);
+ _vm->_objectsMan->stopBobAnimation(12);
+ _vm->_objectsMan->stopBobAnimation(13);
+ break;
+
+ case 611:
+ _vm->_objectsMan->setBobAnimation(5);
+ _vm->_objectsMan->setBobAnimation(7);
+ _vm->_objectsMan->setBobAnimation(8);
+ _vm->_objectsMan->setBobAnimation(9);
+ _vm->_objectsMan->setBobAnimation(12);
+ _vm->_objectsMan->setBobAnimation(13);
+ break;
+ }
+ opcodeType = 1;
+ break;
+ case MKTAG24('E', 'I', 'F'):
+ opcodeType = 4;
+ break;
+ case MKTAG24('V', 'A', 'L'): {
+ opcodeType = 1;
+ int idx = READ_LE_INT16(dataP + 5);
+ assert(idx >= 0 && idx < 2050);
+ _vm->_globals->_saveData->_data[idx] = dataP[7];
+ break;
+ }
+ case MKTAG24('A', 'D', 'D'):
+ opcodeType = 1;
+ _vm->_globals->_saveData->_data[READ_LE_INT16(dataP + 5)] += dataP[7];
+ break;
+ case MKTAG24('B', 'O', 'S'):
+ opcodeType = 1;
+ _vm->_objectsMan->setBobOffset(READ_LE_INT16(dataP + 5), READ_LE_INT16(dataP + 7));
+ break;
+ case MKTAG24('V', 'O', 'N'):
+ _vm->_objectsMan->enableVerb(READ_LE_INT16(dataP + 5), READ_LE_INT16(dataP + 7));
+ opcodeType = 1;
+ break;
+ case MKTAG24('Z', 'C', 'H'):
+ _vm->_linesMan->_zone[READ_LE_INT16(dataP + 5)]._messageId = READ_LE_INT16(dataP + 7);
+ opcodeType = 1;
+ break;
+ case MKTAG24('J', 'U', 'M'):
+ _vm->_objectsMan->_jumpZone = READ_LE_INT16(dataP + 5);
+ _vm->_objectsMan->_jumpVerb = READ_LE_INT16(dataP + 7);
+ opcodeType = 6;
+ break;
+ case MKTAG24('S', 'O', 'U'): {
+ int soundNum = READ_LE_INT16(dataP + 5);
+
+ Common::String file = Common::String::format("SOUND%d.WAV", soundNum);
+ _vm->_soundMan->playSoundFile(file);
+ opcodeType = 1;
+ break;
+ }
+ case MKTAG24('V', 'O', 'F'):
+ _vm->_objectsMan->disableVerb(READ_LE_INT16(dataP + 5), READ_LE_INT16(dataP + 7));
+ opcodeType = 1;
+ break;
+ case MKTAG24('I', 'I', 'F'):
+ opcodeType = 3;
+ break;
+ default:
+ warning("Unhandled opcode %c%c%c", dataP[2], dataP[3], dataP[4]);
+ break;
+ }
+
+ return opcodeType;
+}
+
+
+int ScriptManager::handleGoto(const byte *dataP) {
+ return READ_LE_INT16(dataP + 5);
+}
+
+int ScriptManager::handleIf(const byte *dataP, int offset) {
+ int newOffset;
+ int curOffset = offset;
+ bool loopFl;
+ do {
+ loopFl = false;
+ int tmpOffset = curOffset;
+ int opcodeType;
+ do {
+ if (_vm->shouldQuit())
+ return 0; // Exiting game
+
+ ++tmpOffset;
+ if (tmpOffset > 400)
+ error("Control if failed");
+ opcodeType = checkOpcode(dataP + 20 * tmpOffset);
+ } while (opcodeType != 4); // EIF
+ newOffset = tmpOffset;
+ tmpOffset = curOffset;
+ do {
+ if (_vm->shouldQuit())
+ return 0; // Exiting game
+
+ ++tmpOffset;
+ if (tmpOffset > 400)
+ error("Control if failed ");
+ if (checkOpcode(dataP + 20 * tmpOffset) == 3) { // IIF
+ curOffset = newOffset;
+ loopFl = true;
+ break;
+ }
+ } while (newOffset != tmpOffset);
+ } while (loopFl);
+
+ const byte *buf = dataP + 20 * offset;
+ byte oper = buf[13];
+ byte oper2 = buf[14];
+ byte operType = buf[15];
+ int saveDataIdx1 = READ_LE_INT16(buf + 5);
+ int compVal1 = READ_LE_INT16(buf + 7);
+ bool check1Fl = false;
+ if ((oper == 1 && _vm->_globals->_saveData->_data[saveDataIdx1] == compVal1) ||
+ (oper == 2 && _vm->_globals->_saveData->_data[saveDataIdx1] != compVal1) ||
+ (oper == 3 && _vm->_globals->_saveData->_data[saveDataIdx1] <= compVal1) ||
+ (oper == 4 && _vm->_globals->_saveData->_data[saveDataIdx1] >= compVal1) ||
+ (oper == 5 && _vm->_globals->_saveData->_data[saveDataIdx1] > compVal1) ||
+ (oper == 6 && _vm->_globals->_saveData->_data[saveDataIdx1] < compVal1))
+ check1Fl = true;
+
+ bool check2Fl = false;
+ if (operType != 3) {
+ int saveDataIdx2 = READ_LE_INT16(buf + 9);
+ int compVal2 = READ_LE_INT16(buf + 11);
+ if ((oper2 == 1 && compVal2 == _vm->_globals->_saveData->_data[saveDataIdx2]) ||
+ (oper2 == 2 && compVal2 != _vm->_globals->_saveData->_data[saveDataIdx2]) ||
+ (oper2 == 3 && compVal2 >= _vm->_globals->_saveData->_data[saveDataIdx2]) ||
+ (oper2 == 4 && compVal2 <= _vm->_globals->_saveData->_data[saveDataIdx2]) ||
+ (oper2 == 5 && compVal2 < _vm->_globals->_saveData->_data[saveDataIdx2]) ||
+ (oper2 == 6 && compVal2 > _vm->_globals->_saveData->_data[saveDataIdx2]))
+ check2Fl = true;
+ }
+
+ if ((operType == 3) && check1Fl) {
+ return (offset + 1);
+ } else if ((operType == 1) && check1Fl && check2Fl) {
+ return (offset + 1);
+ } else if ((operType == 2) && (check1Fl || check2Fl)) {
+ return (offset + 1);
+ }
+
+ return (newOffset + 1);
+}
+
+int ScriptManager::checkOpcode(const byte *dataP) {
+ int result = 0;
+ if (READ_BE_UINT16(dataP) != MKTAG16('F', 'C'))
+ return result;
+
+ uint32 signature24 = READ_BE_UINT24(&dataP[2]);
+ switch (signature24) {
+ case MKTAG24('A', 'N', 'I'):
+ case MKTAG24('B', 'C', 'A'):
+ case MKTAG24('B', 'O', 'B'):
+ case MKTAG24('B', 'O', 'F'):
+ case MKTAG24('B', 'O', 'S'):
+ case MKTAG24('M', 'U', 'S'):
+ case MKTAG24('O', 'B', 'M'):
+ case MKTAG24('O', 'B', 'P'):
+ case MKTAG24('P', 'E', 'R'):
+ case MKTAG24('S', 'O', 'U'):
+ case MKTAG24('S', 'P', 'E'):
+ case MKTAG24('T', 'X', 'T'):
+ case MKTAG24('V', 'A', 'L'):
+ case MKTAG24('V', 'O', 'F'):
+ case MKTAG24('V', 'O', 'N'):
+ case MKTAG24('Z', 'C', 'H'):
+ case MKTAG24('Z', 'O', 'F'):
+ case MKTAG24('Z', 'O', 'N'):
+ result = 1;
+ break;
+ case MKTAG24('G', 'O', 'T'):
+ result = 2;
+ break;
+ case MKTAG24('I', 'I', 'F'):
+ result = 3;
+ break;
+ case MKTAG24('E', 'I', 'F'):
+ result = 4;
+ break;
+ case MKTAG24('E', 'X', 'I'):
+ case MKTAG24('S', 'O', 'R'):
+ result = 5;
+ break;
+ case MKTAG24('J', 'U', 'M'):
+ result = 6;
+ break;
+// default:
+// warning("Unhandled opcode %c%c%c", dataP[2], dataP[3], dataP[4]);
+ }
+ return result;
+}
+
+} // End of namespace Hopkins
diff --git a/engines/hopkins/script.h b/engines/hopkins/script.h
new file mode 100644
index 0000000000..2a22e18ccb
--- /dev/null
+++ b/engines/hopkins/script.h
@@ -0,0 +1,50 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_SCRIPT_H
+#define HOPKINS_SCRIPT_H
+
+#include "hopkins/globals.h"
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/str.h"
+
+namespace Hopkins {
+
+class ScriptManager {
+private:
+ HopkinsEngine *_vm;
+ int checkOpcode(const byte *dataP);
+public:
+ bool _tempObjectFl;
+
+ ScriptManager(HopkinsEngine *vm);
+
+ int handleOpcode(const byte *dataP);
+ int handleIf(const byte *dataP, int offset);
+ int handleGoto(const byte *dataP);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_SCRIPT_H */
diff --git a/engines/hopkins/sound.cpp b/engines/hopkins/sound.cpp
new file mode 100644
index 0000000000..d8dfba5246
--- /dev/null
+++ b/engines/hopkins/sound.cpp
@@ -0,0 +1,916 @@
+/* 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/sound.h"
+
+#include "hopkins/globals.h"
+#include "hopkins/hopkins.h"
+
+#include "audio/decoders/adpcm_intern.h"
+#include "common/system.h"
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/textconsole.h"
+#include "audio/audiostream.h"
+#include "audio/mods/module.h"
+#include "audio/mods/protracker.h"
+#include "audio/decoders/raw.h"
+
+namespace Hopkins {
+
+class APC_ADPCMStream : public Audio::DVI_ADPCMStream {
+public:
+ APC_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, int rate, int channels) : DVI_ADPCMStream(stream, disposeAfterUse, stream->size(), rate, channels, 0) {
+ stream->seek(-12, SEEK_CUR);
+ _status.ima_ch[0].last = _startValue[0] = stream->readUint32LE();
+ _status.ima_ch[1].last = _startValue[1] = stream->readUint32LE();
+ stream->seek(4, SEEK_CUR);
+ }
+
+ void reset() {
+ DVI_ADPCMStream::reset();
+ _status.ima_ch[0].last = _startValue[0];
+ _status.ima_ch[1].last = _startValue[1];
+ }
+
+private:
+ int16 _startValue[2];
+};
+
+Audio::RewindableAudioStream *makeAPCStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
+ if (stream->readUint32BE() != MKTAG('C', 'R', 'Y', 'O'))
+ return 0;
+ if (stream->readUint32BE() != MKTAG('_', 'A', 'P', 'C'))
+ return 0;
+ stream->readUint32BE(); // version
+ stream->readUint32LE(); // out size
+ uint32 rate = stream->readUint32LE();
+ stream->skip(8); // initial values, will be handled by the class
+ bool stereo = stream->readUint32LE() != 0;
+
+ return new APC_ADPCMStream(stream, disposeAfterUse, rate, stereo ? 2 : 1);
+}
+
+class TwaAudioStream : public Audio::AudioStream {
+public:
+ TwaAudioStream(Common::String name, Common::SeekableReadStream *stream) {
+ _name = name;
+ _cueSheet.clear();
+ _cueStream = NULL;
+ _cue = 0;
+ _loadedCue = -1;
+
+ for (;;) {
+ char buf[3];
+ stream->read(buf, 3);
+
+ if (buf[0] == 'x' || stream->eos())
+ break;
+
+ _cueSheet.push_back(atol(buf));
+ }
+
+ for (_cue = 0; _cue < _cueSheet.size(); _cue++) {
+ if (loadCue(_cue))
+ break;
+ }
+ }
+
+ ~TwaAudioStream() {
+ delete _cueStream;
+ _cueStream = NULL;
+ }
+
+ virtual bool isStereo() const {
+ return _cueStream ? _cueStream->isStereo() : true;
+ }
+
+ virtual int getRate() const {
+ return _cueStream ? _cueStream->getRate() : 22050;
+ }
+
+ virtual bool endOfData() const {
+ return _cueStream == NULL;
+ }
+
+ virtual int readBuffer(int16 *buffer, const int numSamples) {
+ if (!_cueStream)
+ return 0;
+
+ int16 *buf = buffer;
+ int samplesLeft = numSamples;
+
+ while (samplesLeft) {
+ if (_cueStream) {
+ int readSamples = _cueStream->readBuffer(buf, samplesLeft);
+ buf += readSamples;
+ samplesLeft -= readSamples;
+ }
+
+ if (samplesLeft > 0) {
+ if (++_cue >= _cueSheet.size()) {
+ _cue = 0;
+ }
+ loadCue(_cue);
+ }
+ }
+
+ return numSamples;
+ }
+
+protected:
+ bool loadCue(int nr) {
+ if (_loadedCue == _cueSheet[nr]) {
+ _cueStream->rewind();
+ return true;
+ }
+
+ delete _cueStream;
+ _cueStream = NULL;
+ _loadedCue = _cueSheet[nr];
+
+ Common::String filename = Common::String::format("%s_%02d", _name.c_str(), _cueSheet[nr]);
+ Common::File *file = new Common::File();
+
+ if (file->open(filename + ".APC")) {
+ _cueStream = makeAPCStream(file, DisposeAfterUse::YES);
+ return true;
+ }
+
+ if (file->open(filename + ".WAV")) {
+ _cueStream = Audio::makeWAVStream(file, DisposeAfterUse::YES);
+ return true;
+ }
+
+ if (file->open(filename + ".RAW")) {
+ _cueStream = Audio::makeRawStream(file, 22050, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+ return true;
+ }
+
+ warning("TwaAudioStream::loadCue: Missing cue %d (%s)", nr, filename.c_str());
+ _loadedCue = -1;
+ delete file;
+ return false;
+ }
+
+private:
+ Common::String _name;
+ Common::Array<int> _cueSheet;
+ Audio::RewindableAudioStream *_cueStream;
+ uint _cue;
+ int _loadedCue;
+};
+
+Audio::AudioStream *makeTwaStream(Common::String name, Common::SeekableReadStream *stream) {
+ return new TwaAudioStream(name, stream);
+}
+
+SoundManager::SoundManager(HopkinsEngine *vm) {
+ _vm = vm;
+
+ _specialSoundNum = 0;
+ _soundVolume = 0;
+ _voiceVolume = 0;
+ _musicVolume = 0;
+ _soundOffFl = true;
+ _musicOffFl = true;
+ _voiceOffFl = true;
+ _textOffFl = false;
+ _soundFl = false;
+ _skipRefreshFl = false;
+ _currentSoundIndex = 0;
+ _oldSoundNumber = 0;
+ _modPlayingFl = false;
+
+ for (int i = 0; i < VOICE_COUNT; ++i)
+ Common::fill((byte *)&_voice[i], (byte *)&_voice[i] + sizeof(VoiceItem), 0);
+ for (int i = 0; i < SWAV_COUNT; ++i)
+ Common::fill((byte *)&_sWav[i], (byte *)&_sWav[i] + sizeof(SwavItem), 0);
+ for (int i = 0; i < SOUND_COUNT; ++i)
+ Common::fill((byte *)&_sound[i], (byte *)&_sound[i] + sizeof(SoundItem), 0);
+ Common::fill((byte *)&_music, (byte *)&_music + sizeof(MusicItem), 0);
+}
+
+SoundManager::~SoundManager() {
+ stopMusic();
+ delMusic();
+ _vm->_mixer->stopHandle(_musicHandle);
+ _modPlayingFl = false;
+}
+
+void SoundManager::checkSoundEnd() {
+ if (!_soundOffFl && _soundFl) {
+ if (!checkVoiceStatus(1)) {
+ stopVoice(1);
+ delWav(_currentSoundIndex);
+ }
+ }
+}
+
+void SoundManager::loadAnimSound() {
+ switch (_specialSoundNum) {
+ case 2:
+ loadSample(5, "mitra1.wav");
+ loadSample(1, "tir2.wav");
+ loadSample(2, "sound6.wav");
+ loadSample(3, "sound5.WAV");
+ loadSample(4, "sound4.WAV");
+ break;
+ case 5:
+ loadWav("CRIE.WAV", 1);
+ break;
+ case 14:
+ loadWav("SOUND14.WAV", 1);
+ break;
+ case 16:
+ loadWav("SOUND16.WAV", 1);
+ break;
+ case 198:
+ loadWav("SOUND3.WAV", 1);
+ break;
+ case 199:
+ loadWav("SOUND22.WAV", 1);
+ break;
+ case 200:
+ mixVoice(682, 1);
+ break;
+ case 208:
+ loadWav("SOUND77.WAV", 1);
+ break;
+ case 210:
+ loadWav("SOUND78.WAV", 1);
+ break;
+ case 211:
+ loadWav("SOUND78.WAV", 1);
+ break;
+ case 229:
+ loadWav("SOUND80.WAV", 1);
+ loadWav("SOUND82.WAV", 2);
+ break;
+ }
+}
+
+void SoundManager::playAnimSound(int soundNumber) {
+ if (!_vm->_globals->_censorshipFl && _specialSoundNum == 2) {
+ switch (soundNumber) {
+ case 20:
+ playSample(5);
+ break;
+ case 57:
+ case 63:
+ case 69:
+ playSample(1);
+ break;
+ case 75:
+ playSample(2);
+ break;
+ case 109:
+ playSample(3);
+ break;
+ case 122:
+ playSample(4);
+ break;
+ }
+ } else if (_specialSoundNum == 1 && soundNumber == 17)
+ playSoundFile("SOUND42.WAV");
+ else if (_specialSoundNum == 5 && soundNumber == 19)
+ playWav(1);
+ else if (_specialSoundNum == 14 && soundNumber == 625)
+ playWav(1);
+ else if (_specialSoundNum == 16 && soundNumber == 25)
+ playWav(1);
+ else if (_specialSoundNum == 17) {
+ if (soundNumber == 6)
+ playSample(1);
+ else if (soundNumber == 14)
+ playSample(2);
+ else if (soundNumber == 67)
+ playSample(3);
+ } else if (_specialSoundNum == 198 && soundNumber == 15)
+ playWav(1);
+ else if (_specialSoundNum == 199 && soundNumber == 72)
+ playWav(1);
+ else if (_specialSoundNum == 208 && soundNumber == 40)
+ playWav(1);
+ else if (_specialSoundNum == 210 && soundNumber == 2)
+ playWav(1);
+ else if (_specialSoundNum == 211 && soundNumber == 22)
+ playWav(1);
+ else if (_specialSoundNum == 229) {
+ if (soundNumber == 15)
+ playWav(1);
+ else if (soundNumber == 91)
+ playWav(2);
+ }
+}
+
+static const char *const modSounds[] = {
+ "appart", "ville", "Rock", "police", "deep",
+ "purgat", "riviere", "SUSPENS", "labo", "cadavre",
+ "cabane", "purgat2", "foret", "ile", "ile2",
+ "hopkins", "peur", "URAVOLGA", "BASE", "cadavre2",
+ "usine", "chien", "coeur", "stand", "ocean",
+ "base3", "gloop", "cant", "feel", "lost",
+ "tobac"
+};
+
+void SoundManager::playSound(int soundNumber) {
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
+ if (soundNumber > 27)
+ return;
+ }
+
+ if (_oldSoundNumber != soundNumber || !_modPlayingFl) {
+ if (_modPlayingFl)
+ stopSound();
+
+ playMod(modSounds[soundNumber - 1]);
+ _oldSoundNumber = soundNumber;
+ }
+}
+
+void SoundManager::stopSound() {
+ stopVoice(0);
+ stopVoice(1);
+ stopVoice(2);
+ if (_soundFl)
+ delWav(_currentSoundIndex);
+
+ for (int i = 1; i <= 48; ++i)
+ removeWavSample(i);
+
+ if (_modPlayingFl) {
+ stopMusic();
+ delMusic();
+ _modPlayingFl = false;
+ }
+}
+
+void SoundManager::playMod(const Common::String &file) {
+ if (_musicOffFl)
+ return;
+ Common::String modFile = file;
+
+ // HACK
+ if (modFile == "URAVOLGA" && (_vm->getPlatform() == Common::kPlatformWindows || _vm->getPlatform() == Common::kPlatformLinux))
+ modFile = "peur";
+
+ // The Windows/Linux version chops off the music file names to 5 characters
+ if (modFile.size() > 5 && (_vm->getPlatform() == Common::kPlatformWindows || _vm->getPlatform() == Common::kPlatformLinux)) {
+ if (!modFile.hasSuffix("2")) {
+ while (modFile.size() > 5)
+ modFile.deleteLastChar();
+ } else {
+ while (modFile.size() > 4)
+ modFile.deleteLastChar();
+ modFile += "2";
+ }
+ }
+ if (_modPlayingFl) {
+ stopMusic();
+ delMusic();
+ _modPlayingFl = false;
+ }
+
+ loadMusic(modFile);
+ playMusic();
+ _modPlayingFl = true;
+}
+
+void SoundManager::loadMusic(const Common::String &file) {
+ if (_music._active)
+ delMusic();
+
+ Common::File f;
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
+ Common::String filename = Common::String::format("%s.MOD", file.c_str());
+
+ if (!f.open(filename))
+ error("Error opening file %s", filename.c_str());
+
+ Modules::Module *module;
+ Audio::AudioStream *modStream = Audio::makeProtrackerStream(&f, 0, 44100, true, &module);
+
+ // WORKAROUND: This song is played at the empty lot where the
+ // bank robbers have left the helicopter. The MOD file appears
+ // to be slightly broken. Almost half of it is just the same
+ // noise repeating. We fix this by only playing the working
+ // part of it. The result is pretty close to the Windows music.
+ if (file.equalsIgnoreCase("cadavre")) {
+ module->songlen = 3;
+ }
+
+ _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, modStream);
+
+ } else {
+ Common::String filename = Common::String::format("%s.TWA", file.c_str());
+
+ if (!f.open(filename))
+ error("Error opening file %s", filename.c_str());
+
+ Audio::AudioStream *twaStream = makeTwaStream(file.c_str(), &f);
+ _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, twaStream);
+ f.close();
+ }
+
+ _music._active = true;
+}
+
+void SoundManager::playMusic() {
+}
+
+void SoundManager::stopMusic() {
+ _vm->_mixer->stopHandle(_musicHandle);
+}
+
+void SoundManager::delMusic() {
+ _music._active = false;
+}
+
+void SoundManager::checkSounds() {
+ checkVoiceActivity();
+}
+
+/**
+ * Checks voices to see if they're finished
+ */
+void SoundManager::checkVoiceActivity() {
+ // Check the status of each voice.
+ bool hasActiveVoice = false;
+ for (int i = 0; i < VOICE_COUNT; ++i) {
+ checkVoiceStatus(i);
+ hasActiveVoice |= _voice[i]._status;
+ }
+
+ if (!hasActiveVoice && _soundFl) {
+ _soundFl = false;
+ _currentSoundIndex = 0;
+ }
+}
+
+bool SoundManager::mixVoice(int voiceId, int voiceMode, bool dispTxtFl) {
+ int fileNumber;
+ int oldMusicVol;
+ bool breakFlag;
+ Common::String prefix;
+ Common::String filename;
+ Common::File f;
+ size_t catPos, catLen;
+
+ fileNumber = voiceId;
+ if (_voiceOffFl)
+ return false;
+
+ if ((voiceMode == 1 || voiceMode == 2)
+ && ( voiceId == 4 || voiceId == 16 || voiceId == 121
+ || voiceId == 142 || voiceId == 182 || voiceId == 191
+ || voiceId == 212 || voiceId == 225 || voiceId == 239
+ || voiceId == 245 || voiceId == 297 || voiceId == 308
+ || voiceId == 333 || voiceId == 348 || voiceId == 352
+ || voiceId == 358 || voiceId == 364 || voiceId == 371
+ || voiceId == 394 || voiceId == 414 || voiceId == 429
+ || voiceId == 442 || voiceId == 446 || voiceId == 461
+ || voiceId == 468 || voiceId == 476 || voiceId == 484
+ || voiceId == 491 || voiceId == 497 || voiceId == 501
+ || voiceId == 511 || voiceId == 520 || voiceId == 536
+ || voiceId == 554 || voiceId == 566 || voiceId == 573
+ || voiceId == 632 || voiceId == 645))
+ fileNumber = 684;
+
+ if (voiceMode == 1 || voiceMode == 2)
+ prefix = "DF";
+ else if (voiceMode == 3)
+ prefix = "IF";
+ else if (voiceMode == 4)
+ prefix = "TF";
+ else if (voiceMode == 5)
+ prefix = "OF";
+
+ // BeOS and OS/2 versions are using a slightly different speech order during intro
+ // This map those values to the ones used by the Win95 and Linux versions
+ int mappedFileNumber = fileNumber;
+ if (voiceMode == 3 && (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)) {
+ if (fileNumber == 4)
+ mappedFileNumber = 0;
+ else if (fileNumber > 4)
+ mappedFileNumber = fileNumber - 1;
+ }
+
+ filename = Common::String::format("%s%d", prefix.c_str(), mappedFileNumber);
+
+ bool fileFoundFl = false;
+ _vm->_fileIO->searchCat(filename + ".WAV", RES_VOI, fileFoundFl);
+ if (fileFoundFl) {
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ filename = "ENG_VOI.RES";
+ // Win95 and Linux versions uses another set of names
+ else if (_vm->_globals->_language == LANG_FR)
+ filename = "RES_VFR.RES";
+ else if (_vm->_globals->_language == LANG_EN)
+ filename = "RES_VAN.RES";
+ else if (_vm->_globals->_language == LANG_SP)
+ filename = "RES_VES.RES";
+
+ catPos = _vm->_fileIO->_catalogPos;
+ catLen = _vm->_fileIO->_catalogSize;
+ } else {
+ _vm->_fileIO->searchCat(filename + ".APC", RES_VOI, fileFoundFl);
+ if (fileFoundFl) {
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ filename = "ENG_VOI.RES";
+ // Win95 and Linux versions uses another set of names
+ else if (_vm->_globals->_language == LANG_FR)
+ filename = "RES_VFR.RES";
+ else if (_vm->_globals->_language == LANG_EN)
+ filename = "RES_VAN.RES";
+ else if (_vm->_globals->_language == LANG_SP)
+ filename = "RES_VES.RES";
+
+ catPos = _vm->_fileIO->_catalogPos;
+ catLen = _vm->_fileIO->_catalogSize;
+ } else {
+ _vm->_fileIO->searchCat(filename + ".RAW", RES_VOI, fileFoundFl);
+ if (fileFoundFl) {
+ if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
+ filename = "ENG_VOI.RES";
+ // Win95 and Linux versions uses another set of names
+ else if (_vm->_globals->_language == LANG_FR)
+ filename = "RES_VFR.RES";
+ else if (_vm->_globals->_language == LANG_EN)
+ filename = "RES_VAN.RES";
+ else if (_vm->_globals->_language == LANG_SP)
+ filename = "RES_VES.RES";
+
+ catPos = _vm->_fileIO->_catalogPos;
+ catLen = _vm->_fileIO->_catalogSize;
+ } else {
+ if (!f.exists(filename + ".WAV")) {
+ if (!f.exists(filename + ".APC"))
+ return false;
+ filename = filename + ".APC";
+ } else
+ filename = filename + ".WAV";
+
+ catPos = 0;
+ catLen = 0;
+ }
+ }
+ }
+ oldMusicVol = _musicVolume;
+ if (!loadVoice(filename, catPos, catLen, _sWav[20])) {
+ // This case only concerns the English Win95 demo
+ // If it's not possible to load the voice, we force the active flag
+ // to false in order to make sure the missing buffer won't be played
+ // accidentally later
+ _sWav[20]._active = false;
+ } else {
+ _sWav[20]._active = true;
+
+ // Reduce music volume during speech
+ if (!_musicOffFl && _musicVolume > 2) {
+ _musicVolume -= _musicVolume * 9 / 20;
+ setMODMusicVolume(_musicVolume);
+ }
+ }
+ playVoice();
+
+ _vm->_events->_escKeyFl = false;
+
+ // Loop for playing voice
+ breakFlag = false;
+ do {
+ if (_specialSoundNum != 4 && !_skipRefreshFl)
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_events->getMouseButton())
+ break;
+ _vm->_events->refreshEvents();
+ if (_vm->_events->_escKeyFl)
+ break;
+ // We only check the voice status if the file has been loaded properly
+ // This avoids skipping completely the talk animations in the Win95 UK Demo
+ if (!checkVoiceStatus(2) && _sWav[20]._active)
+ breakFlag = true;
+ // This is specific to the Win95 UK Demo again: if nothing is displayed,
+ // don't wait for a click event.
+ if (!_sWav[20]._active && !dispTxtFl)
+ break;
+ } while (!_vm->shouldQuit() && !breakFlag);
+
+
+ stopVoice(2);
+ removeWavSample(20);
+
+ // Speech is over, set the music volume back to normal
+ _musicVolume = oldMusicVol;
+ if (!_musicOffFl && _musicVolume > 2) {
+ setMODMusicVolume(_musicVolume);
+ }
+ _vm->_events->_escKeyFl = false;
+ _skipRefreshFl = false;
+ return true;
+}
+
+void SoundManager::removeSample(int soundIndex) {
+ if (checkVoiceStatus(1))
+ stopVoice(1);
+ if (checkVoiceStatus(2))
+ stopVoice(2);
+ if (checkVoiceStatus(3))
+ stopVoice(3);
+ removeWavSample(soundIndex);
+ _sound[soundIndex]._active = false;
+}
+
+void SoundManager::playSoundFile(const Common::String &file) {
+ if (_soundOffFl)
+ return;
+
+ // Fallback for the menu option.
+ // The BeOS and OS/2 versions don't play sound at this point.
+ // sound20 sounds very close to bruit2 from the linux and Win95 versions.
+ Common::File f;
+ Common::String filename;
+ if (file == "bruit2.wav" && !f.exists(file))
+ filename = "sound20.wav";
+ else
+ filename = file;
+
+ if (_soundFl)
+ delWav(_currentSoundIndex);
+ loadWav(filename, 1);
+ playWav(1);
+}
+
+void SoundManager::directPlayWav(const Common::String &file) {
+ if (_soundOffFl)
+ return;
+
+ loadWav(file, 1);
+ playWav(1);
+}
+
+void SoundManager::setMODSampleVolume() {
+ for (int idx = 0; idx < SWAV_COUNT; ++idx) {
+ if (idx != 20 && _sWav[idx]._active) {
+ int volume = _soundVolume * 255 / 16;
+ _vm->_mixer->setChannelVolume(_sWav[idx]._soundHandle, volume);
+ }
+ }
+}
+
+void SoundManager::setMODVoiceVolume() {
+ if (_sWav[20]._active) {
+ int volume = _voiceVolume * 255 / 16;
+ _vm->_mixer->setChannelVolume(_sWav[20]._soundHandle, volume);
+ }
+}
+
+void SoundManager::setMODMusicVolume(int volume) {
+ if (_vm->_mixer->isSoundHandleActive(_musicHandle))
+ _vm->_mixer->setChannelVolume(_musicHandle, volume * 255 / 16);
+}
+
+void SoundManager::loadSample(int wavIndex, const Common::String &file) {
+ loadWavSample(wavIndex, file, false);
+ _sound[wavIndex]._active = true;
+}
+
+void SoundManager::playSample(int wavIndex, int voiceMode) {
+ if (_soundOffFl || !_sound[wavIndex]._active)
+ return;
+
+ if (_soundFl)
+ delWav(_currentSoundIndex);
+
+ switch (voiceMode) {
+ case 5:
+ case 8:
+ // Case added to identify the former PLAY_SAMPLE2 calls
+ case 9:
+ if (checkVoiceStatus(1))
+ stopVoice(1);
+ playWavSample(1, wavIndex);
+ break;
+ case 6:
+ if (checkVoiceStatus(2))
+ stopVoice(1);
+ playWavSample(2, wavIndex);
+ break;
+ case 7:
+ if (checkVoiceStatus(3))
+ stopVoice(1);
+ playWavSample(3, wavIndex);
+ break;
+ default:
+ break;
+ }
+}
+
+bool SoundManager::checkVoiceStatus(int voiceIndex) {
+ if (_voice[voiceIndex]._status) {
+ int wavIndex = _voice[voiceIndex]._wavIndex;
+ if (_sWav[wavIndex]._audioStream && _sWav[wavIndex]._audioStream->endOfStream())
+ stopVoice(voiceIndex);
+ }
+
+ return _voice[voiceIndex]._status;
+}
+
+void SoundManager::stopVoice(int voiceIndex) {
+ if (_voice[voiceIndex]._status) {
+ _voice[voiceIndex]._status = false;
+ int wavIndex = _voice[voiceIndex]._wavIndex;
+ if (_sWav[wavIndex]._active && _sWav[wavIndex]._freeSampleFl)
+ removeWavSample(wavIndex);
+ }
+ _voice[voiceIndex]._status = false;
+}
+
+void SoundManager::playVoice() {
+ if (!_sWav[20]._active)
+ return;
+
+ if (!_voice[2]._status) {
+ int wavIndex = _voice[2]._wavIndex;
+ if (_sWav[wavIndex]._active && _sWav[wavIndex]._freeSampleFl)
+ removeWavSample(wavIndex);
+ }
+
+ playWavSample(2, 20);
+}
+
+bool SoundManager::removeWavSample(int wavIndex) {
+ if (!_sWav[wavIndex]._active)
+ return false;
+
+ _vm->_mixer->stopHandle(_sWav[wavIndex]._soundHandle);
+ delete _sWav[wavIndex]._audioStream;
+ _sWav[wavIndex]._audioStream = NULL;
+ _sWav[wavIndex]._active = false;
+
+ return true;
+}
+
+bool SoundManager::loadVoice(const Common::String &filename, size_t fileOffset, size_t entryLength, SwavItem &item) {
+ Common::File f;
+ if (!f.open(filename)) {
+ // Fallback to APC...
+ if (!f.open(setExtension(filename, ".APC"))) {
+ // The English demo doesn't include the speech file.
+ // This avoids it to crash when discussing with other characters
+ if (!_vm->getIsDemo())
+ error("Could not open %s for reading", filename.c_str());
+ return false;
+ }
+ }
+
+ f.seek(fileOffset);
+ item._audioStream = makeSoundStream(f.readStream((entryLength == 0) ? f.size() : entryLength));
+ f.close();
+
+ return true;
+}
+
+void SoundManager::loadWavSample(int wavIndex, const Common::String &filename, bool freeSample) {
+ if (_sWav[wavIndex]._active)
+ removeWavSample(wavIndex);
+
+ if (loadVoice(filename, 0, 0, _sWav[wavIndex])) {
+ _sWav[wavIndex]._active = true;
+ _sWav[wavIndex]._freeSampleFl = freeSample;
+ } else{
+ _sWav[wavIndex]._active = false;
+ }
+}
+
+void SoundManager::loadWav(const Common::String &file, int wavIndex) {
+ loadWavSample(wavIndex, file, true);
+}
+
+void SoundManager::playWav(int wavIndex) {
+ if (_soundFl || _soundOffFl)
+ return;
+
+ _soundFl = true;
+ _currentSoundIndex = wavIndex;
+ playWavSample(1, wavIndex);
+}
+
+void SoundManager::delWav(int wavIndex) {
+ if (!removeWavSample(wavIndex))
+ return;
+
+ if (checkVoiceStatus(1))
+ stopVoice(1);
+
+ _currentSoundIndex = 0;
+ _soundFl = false;
+}
+
+void SoundManager::playWavSample(int voiceIndex, int wavIndex) {
+ if (!_sWav[wavIndex]._active)
+ warning("Bad handle");
+
+ if (_voice[voiceIndex]._status && _sWav[wavIndex]._active && _sWav[wavIndex]._freeSampleFl)
+ removeWavSample(wavIndex);
+
+ _voice[voiceIndex]._status = true;
+ _voice[voiceIndex]._wavIndex = wavIndex;
+
+ int volume = (voiceIndex == 2) ? _voiceVolume * 255 / 16 : _soundVolume * 255 / 16;
+
+ // If the handle is still in use, stop it. Otherwise we'll lose the
+ // handle to that sound. This can currently happen (but probably
+ // shouldn't) when skipping a movie.
+ if (_vm->_mixer->isSoundHandleActive(_sWav[wavIndex]._soundHandle))
+ _vm->_mixer->stopHandle(_sWav[wavIndex]._soundHandle);
+
+ // Start the voice playing
+ _sWav[wavIndex]._audioStream->rewind();
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sWav[wavIndex]._soundHandle,
+ _sWav[wavIndex]._audioStream, -1, volume, 0, DisposeAfterUse::NO);
+}
+
+void SoundManager::syncSoundSettings() {
+ bool muteAll = false;
+ if (ConfMan.hasKey("mute"))
+ muteAll = ConfMan.getBool("mute");
+
+ // Update the mute settings
+ _musicOffFl = muteAll || (ConfMan.hasKey("music_mute") && ConfMan.getBool("music_mute"));
+ _soundOffFl = muteAll || (ConfMan.hasKey("sfx_mute") && ConfMan.getBool("sfx_mute"));
+ _voiceOffFl = muteAll || (ConfMan.hasKey("speech_mute") && ConfMan.getBool("speech_mute"));
+
+ // Update the volume levels
+ _musicVolume = MIN(255, ConfMan.getInt("music_volume")) * 16 / 255;
+ _soundVolume = MIN(255, ConfMan.getInt("sfx_volume")) * 16 / 255;
+ _voiceVolume = MIN(255, ConfMan.getInt("speech_volume")) * 16 / 255;
+
+ // Update any active sounds
+ for (int idx = 0; idx < SWAV_COUNT; ++idx) {
+ if (_sWav[idx]._active) {
+ int volume = (idx == 20) ? (_voiceVolume * 255 / 16) : (_soundVolume * 255 / 16);
+ _vm->_mixer->setChannelVolume(_sWav[idx]._soundHandle, volume);
+ }
+ }
+ if (_vm->_mixer->isSoundHandleActive(_musicHandle)) {
+ _vm->_mixer->setChannelVolume(_musicHandle, _musicVolume * 255 / 16);
+ }
+}
+
+void SoundManager::updateScummVMSoundSettings() {
+ ConfMan.setBool("mute", _musicOffFl && _soundOffFl && _voiceOffFl);
+ ConfMan.setBool("music_mute", _musicOffFl);
+ ConfMan.setBool("sfx_mute", _soundOffFl);
+ ConfMan.setBool("speech_mute", _voiceOffFl);
+
+ ConfMan.setInt("music_volume", _musicVolume * 255 / 16);
+ ConfMan.setInt("sfx_volume", _soundVolume * 255 / 16);
+ ConfMan.setInt("speech_volume", _voiceVolume * 255 / 16);
+
+ ConfMan.flushToDisk();
+}
+
+/**
+ * Creates an audio stream based on a passed raw stream
+ */
+Audio::RewindableAudioStream *SoundManager::makeSoundStream(Common::SeekableReadStream *stream) {
+ if (_vm->getPlatform() == Common::kPlatformWindows)
+ return makeAPCStream(stream, DisposeAfterUse::YES);
+ else if (_vm->getPlatform() == Common::kPlatformLinux)
+ return Audio::makeWAVStream(stream, DisposeAfterUse::YES);
+ else
+ return Audio::makeRawStream(stream, 22050, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+}
+
+// Blatant rip from gob engine. Hi DrMcCoy!
+Common::String SoundManager::setExtension(const Common::String &str, const Common::String &ext) {
+ if (str.empty())
+ return str;
+
+ const char *dot = strrchr(str.c_str(), '.');
+ if (dot)
+ return Common::String(str.c_str(), dot - str.c_str()) + ext;
+
+ return str + ext;
+}
+} // End of namespace Hopkins
diff --git a/engines/hopkins/sound.h b/engines/hopkins/sound.h
new file mode 100644
index 0000000000..f1d047ae8b
--- /dev/null
+++ b/engines/hopkins/sound.h
@@ -0,0 +1,138 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_SOUND_H
+#define HOPKINS_SOUND_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/mixer.h"
+
+namespace Hopkins {
+
+class VoiceItem {
+public:
+ bool _status;
+ int _wavIndex;
+};
+
+class SwavItem {
+public:
+ bool _active;
+ Audio::RewindableAudioStream *_audioStream;
+ Audio::SoundHandle _soundHandle;
+ bool _freeSampleFl;
+};
+
+class MusicItem {
+public:
+ bool _active;
+};
+
+class SoundItem {
+public:
+ bool _active;
+};
+
+#define VOICE_COUNT 3
+#define SWAV_COUNT 50
+#define SOUND_COUNT 10
+
+class HopkinsEngine;
+
+class SoundManager {
+private:
+ HopkinsEngine *_vm;
+
+ Audio::SoundHandle _musicHandle;
+ int _currentSoundIndex;
+ bool _modPlayingFl;
+ int _oldSoundNumber;
+
+ VoiceItem _voice[VOICE_COUNT];
+ SwavItem _sWav[SWAV_COUNT];
+ SoundItem _sound[SOUND_COUNT];
+ MusicItem _music;
+
+ void playMod(const Common::String &file);
+ void loadMusic(const Common::String &file);
+ void playMusic();
+ void stopMusic();
+ void delMusic();
+ bool checkVoiceStatus(int voiceIndex);
+ bool loadVoice(const Common::String &filename, size_t fileOffset, size_t entryLength, SwavItem &item);
+ void stopVoice(int voiceIndex);
+ void playVoice();
+ void delWav(int wavIndex);
+ void checkVoiceActivity();
+ Common::String setExtension(const Common::String &str, const Common::String &ext);
+ Audio::RewindableAudioStream *makeSoundStream(Common::SeekableReadStream *stream);
+ bool removeWavSample(int wavIndex);
+ void loadWavSample(int wavIndex, const Common::String &filename, bool freeSample);
+ void playWavSample(int voiceIndex, int wavIndex);
+
+public:
+ bool _musicOffFl;
+ bool _soundOffFl;
+ bool _voiceOffFl;
+ bool _textOffFl;
+ bool _soundFl;
+ bool _skipRefreshFl;
+ int _musicVolume;
+ int _soundVolume;
+ int _voiceVolume;
+ int _specialSoundNum;
+public:
+ SoundManager(HopkinsEngine *vm);
+ ~SoundManager();
+
+ void loadAnimSound();
+ void playAnimSound(int soundNumber);
+
+ void loadSample(int wavIndex, const Common::String &file);
+ void playSample(int wavIndex, int voiceMode = 9);
+ void removeSample(int soundIndex);
+
+ void checkSoundEnd();
+ void checkSounds();
+ void playSoundFile(const Common::String &file);
+ void playSound(int soundNumber);
+ void stopSound();
+
+ void updateScummVMSoundSettings();
+ void syncSoundSettings();
+ bool mixVoice(int voiceId, int voiceMode, bool displTxtFl = false);
+
+ void setMODMusicVolume(int volume);
+ void setMODSampleVolume();
+ void setMODVoiceVolume();
+
+ void loadWav(const Common::String &file, int wavIndex);
+ void playWav(int wavIndex);
+ void directPlayWav(const Common::String &file2);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_SOUND_H */
diff --git a/engines/hopkins/talk.cpp b/engines/hopkins/talk.cpp
new file mode 100644
index 0000000000..736ec9865c
--- /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->display8BitRect(_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->display8BitRect(_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
diff --git a/engines/hopkins/talk.h b/engines/hopkins/talk.h
new file mode 100644
index 0000000000..678f52090a
--- /dev/null
+++ b/engines/hopkins/talk.h
@@ -0,0 +1,78 @@
+/* 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.
+ *
+ */
+
+#ifndef HOPKINS_TALK_H
+#define HOPKINS_TALK_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+
+namespace Hopkins {
+
+class HopkinsEngine;
+
+#define MIN_LETTERS_PER_LINE 65
+
+class TalkManager {
+private:
+ HopkinsEngine *_vm;
+
+ Common::String _questionsFilename;
+ Common::String _answersFilename;
+ byte *_characterBuffer;
+ byte *_characterPalette;
+ size_t _characterSize;
+ int _dialogueMesgId1, _dialogueMesgId2;
+ int _dialogueMesgId3, _dialogueMesgId4;
+ int _paletteBufferIdx;
+
+ void getStringFromBuffer(int srcStart, Common::String &dest, const char *srcData);
+ int dialogQuestion(bool animatedFl);
+ int dialogAnswer(int idx, bool animatedFl);
+ void searchCharacterPalette(int startIdx, bool dark);
+ void dialogWait();
+ void dialogTalk();
+ void dialogEndTalk();
+ void startCharacterAnim0(int startIndedx, bool readOnlyFl);
+ void initCharacterAnim();
+ void clearCharacterAnim();
+ bool searchCharacterAnim(int idx, const byte *bufPerso, int animId, int bufferSize);
+ int countBoxLines(int idx, const Common::String &file);
+ void dialogAnim();
+ void displayBobDialogAnim(int idx);
+
+public:
+ byte *_characterAnim;
+ byte *_characterSprite;
+
+ TalkManager(HopkinsEngine *vm);
+
+ void startStaticCharacterDialogue(const Common::String &filename);
+ void startAnimatedCharacterDialogue(const Common::String &filename);
+ void animateObject(const Common::String &filename);
+ void handleAnswer(int zone, int verb);
+ void handleForestAnswser(int zone, int verb);
+};
+
+} // End of namespace Hopkins
+
+#endif /* HOPKINS_TALK_H */