diff options
44 files changed, 23867 insertions, 3 deletions
diff --git a/audio/mods/protracker.cpp b/audio/mods/protracker.cpp index 1e18d5adf8..c947f256e0 100644 --- a/audio/mods/protracker.cpp +++ b/audio/mods/protracker.cpp @@ -90,6 +90,14 @@ private: public: ProtrackerStream(Common::SeekableReadStream *stream, int offs, int rate, bool stereo); + Modules::Module *getModule() { + // Ordinarily, the Module is not meant to be seen outside of + // this class, but occasionally, it's useful to be able to + // manipulate it directly. The Hopkins engine uses this to + // repair a broken song. + return &_module; + } + private: void interrupt(); @@ -462,8 +470,12 @@ void ProtrackerStream::interrupt() { namespace Audio { -AudioStream *makeProtrackerStream(Common::SeekableReadStream *stream, int offs, int rate, bool stereo) { - return new Modules::ProtrackerStream(stream, offs, rate, stereo); +AudioStream *makeProtrackerStream(Common::SeekableReadStream *stream, int offs, int rate, bool stereo, Modules::Module **module) { + Modules::ProtrackerStream *protrackerStream = new Modules::ProtrackerStream(stream, offs, rate, stereo); + if (module) { + *module = protrackerStream->getModule(); + } + return (AudioStream *)protrackerStream; } } // End of namespace Audio diff --git a/audio/mods/protracker.h b/audio/mods/protracker.h index 5f47c4453b..50528fc599 100644 --- a/audio/mods/protracker.h +++ b/audio/mods/protracker.h @@ -26,6 +26,7 @@ * - agos * - parallaction * - gob + * - hopkins */ #ifndef AUDIO_MODS_PROTRACKER_H @@ -35,6 +36,10 @@ namespace Common { class SeekableReadStream; } +namespace Modules { +class Module; +} + namespace Audio { class AudioStream; @@ -48,9 +53,10 @@ class AudioStream; * @param stream the ReadStream from which to read the ProTracker data * @param rate TODO * @param stereo TODO + * @param module can be used to return the Module object (rarely useful) * @return a new AudioStream, or NULL, if an error occurred */ -AudioStream *makeProtrackerStream(Common::SeekableReadStream *stream, int offs = 0, int rate = 44100, bool stereo = true); +AudioStream *makeProtrackerStream(Common::SeekableReadStream *stream, int offs = 0, int rate = 44100, bool stereo = true, Modules::Module **module = 0); } // End of namespace Audio diff --git a/common/platform.cpp b/common/platform.cpp index 9986048b48..899e3f45ae 100644 --- a/common/platform.cpp +++ b/common/platform.cpp @@ -50,6 +50,8 @@ const PlatformDescription g_platforms[] = { { "playstation", "psx", "psx", "Sony PlayStation", kPlatformPSX }, { "cdi", "cdi", "cdi", "Philips CD-i", kPlatformCDi }, { "ios", "ios", "ios", "Apple iOS", kPlatformIOS }, + { "os2", "os2", "os2", "OS/2", kPlatformOS2 }, + { "beos", "beos", "beos", "BeOS", kPlatformBeOS }, { 0, 0, 0, "Default", kPlatformUnknown } }; diff --git a/common/platform.h b/common/platform.h index 5a4f3f1802..72f0991409 100644 --- a/common/platform.h +++ b/common/platform.h @@ -55,6 +55,8 @@ enum Platform { kPlatformPSX, kPlatformCDi, kPlatformIOS, + kPlatformOS2, + kPlatformBeOS, kPlatformUnknown = -1 }; diff --git a/engines/configure.engines b/engines/configure.engines index 1f2a31b382..3ac287e23f 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -16,6 +16,7 @@ add_engine dreamweb "Dreamweb" yes add_engine gob "Gobli*ns" yes add_engine groovie "Groovie" yes "groovie2" "7th Guest" add_engine groovie2 "Groovie 2 games" no +add_engine hopkins "Hopkins FBI" no add_engine hugo "Hugo Trilogy" yes add_engine kyra "Kyra" yes "lol eob" "Legend of Kyrandia 1-3" add_engine lol "Lands of Lore" yes diff --git a/engines/engines.mk b/engines/engines.mk index 61004463fe..bcf97df991 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -75,6 +75,11 @@ DEFINES += -DENABLE_GROOVIE2 endif endif +ifdef ENABLE_HOPKINS +DEFINES += -DENABLE_HOPKINS=$(ENABLE_HOPKINS) +MODULES += engines/hopkins +endif + ifdef ENABLE_HUGO DEFINES += -DENABLE_HUGO=$(ENABLE_HUGO) MODULES += engines/hugo diff --git a/engines/hopkins/anim.cpp b/engines/hopkins/anim.cpp new file mode 100644 index 0000000000..fa6dd1c394 --- /dev/null +++ b/engines/hopkins/anim.cpp @@ -0,0 +1,910 @@ +/* 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() { + _clearAnimationFl = false; + NO_SEQ = false; + NO_COUL = false; +} + +/** + * 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) { + byte *screenCopy = NULL; + Common::File f; + + if (_vm->shouldQuit()) + return; + + _vm->_eventsManager.mouseOff(); + + bool hasScreenCopy = false; + byte *screenP = _vm->_graphicsManager._vesaScreen; + + 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->_graphicsManager._palette, 800); + f.skip(4); + size_t nbytes = f.readUint32LE(); + f.skip(14); + f.read(screenP, nbytes); + + if (_clearAnimationFl) { + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + } + if (_vm->_graphicsManager.WinScan / 2 > SCREEN_WIDTH) { + hasScreenCopy = true; + screenCopy = _vm->_globals.allocMemory(307200); + memcpy(screenCopy, screenP, 307200); + } + if (NO_SEQ) { + if (hasScreenCopy) + memcpy(screenCopy, _vm->_graphicsManager._vesaBuffer, 307200); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + } else { + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + _vm->_graphicsManager.lockScreen(); + if (hasScreenCopy) + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + else + _vm->_graphicsManager.m_scroll16(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + } + _vm->_eventsManager._rateCounter = 0; + _vm->_eventsManager._escKeyFl = false; + _vm->_soundManager.loadAnimSound(); + + if (_vm->_globals.iRegul == 1) { + // Do pre-animation delay + do { + if (_vm->_eventsManager._escKeyFl) + break; + + _vm->_eventsManager.refreshEvents(); + } while (!_vm->shouldQuit() && _vm->_eventsManager._rateCounter < rate1); + } + + if (!_vm->_eventsManager._escKeyFl) { + _vm->_eventsManager._rateCounter = 0; + int frameNumber = 0; + while (!_vm->shouldQuit()) { + ++frameNumber; + _vm->_soundManager.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.iRegul == 1) { + do { + if (_vm->_eventsManager._escKeyFl) + break; + + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (!_vm->shouldQuit() && _vm->_eventsManager._rateCounter < rate2); + } + + if (!_vm->_eventsManager._escKeyFl) { + _vm->_eventsManager._rateCounter = 0; + _vm->_graphicsManager.lockScreen(); + if (hasScreenCopy) { + if (*screenP != kByteStop) { + _vm->_graphicsManager.copyWinscanVbe3(screenP, screenCopy); + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + } + } else if (*screenP != kByteStop) { + _vm->_graphicsManager.copyVideoVbe16(screenP); + } + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + _vm->_soundManager.checkSoundEnd(); + } + } + } + + if (_vm->_globals.iRegul == 1 && !_vm->_eventsManager._escKeyFl) { + // Do post-animation delay + do { + if (_vm->_eventsManager._escKeyFl) + break; + + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (_vm->_eventsManager._rateCounter < rate3); + } + + if (!_vm->_eventsManager._escKeyFl) { + _vm->_eventsManager._rateCounter = 0; + _vm->_soundManager.checkSoundEnd(); + } + + if (_vm->_graphicsManager.FADE_LINUX == 2 && !hasScreenCopy) { + screenCopy = _vm->_globals.allocMemory(307200); + + f.seek(6); + f.read(_vm->_graphicsManager._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->_graphicsManager.copyWinscanVbe3(screenP, screenCopy); + } + _vm->_graphicsManager.fadeOutDefaultLength(screenCopy); + screenCopy = _vm->_globals.freeMemory(screenCopy); + } + if (hasScreenCopy) { + if (_vm->_graphicsManager.FADE_LINUX == 2) + _vm->_graphicsManager.fadeOutDefaultLength(screenCopy); + screenCopy = _vm->_globals.freeMemory(screenCopy); + } + + _vm->_graphicsManager.FADE_LINUX = 0; + f.close(); + _vm->_graphicsManager._skipVideoLockFl = false; + + _vm->_eventsManager.mouseOn(); +} + +/** + * Play Animation, type 2 + */ +void AnimationManager::playAnim2(const Common::String &filename, uint32 rate1, uint32 rate2, uint32 rate3) { + byte *screenCopy = NULL; + int oldScrollPosX = 0; + byte *screenP = NULL; + Common::File f; + + if (_vm->shouldQuit()) + return; + + _vm->_eventsManager.mouseOff(); + + bool hasScreenCopy = false; + while (!_vm->shouldQuit()) { + memcpy(_vm->_graphicsManager._oldPalette, _vm->_graphicsManager._palette, 769); + + if (_vm->_graphicsManager._lineNbr == SCREEN_WIDTH) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 307200); + else if (_vm->_graphicsManager._lineNbr == (SCREEN_WIDTH * 2)) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 614400); + + if (!_vm->_graphicsManager._lineNbr) + _vm->_graphicsManager._scrollOffset = 0; + + screenP = _vm->_graphicsManager._vesaScreen; + if (!f.open(filename)) + error("Error opening file - %s", filename.c_str()); + + f.skip(6); + f.read(_vm->_graphicsManager._palette, 800); + f.skip(4); + size_t nbytes = f.readUint32LE(); + f.skip(14); + + f.read(screenP, nbytes); + + _vm->_graphicsManager.clearPalette(); + oldScrollPosX = _vm->_graphicsManager._scrollPosX; + _vm->_graphicsManager.SCANLINE(SCREEN_WIDTH); + _vm->_graphicsManager.scrollScreen(0); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager._maxX = SCREEN_WIDTH; + if (_vm->_graphicsManager.WinScan / 2 > SCREEN_WIDTH) { + hasScreenCopy = true; + screenCopy = _vm->_globals.allocMemory(307200); + memcpy(screenCopy, screenP, 307200); + } + if (NO_SEQ) { + if (hasScreenCopy) + memcpy(screenCopy, _vm->_graphicsManager._vesaBuffer, 307200); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + } else { + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + _vm->_graphicsManager.lockScreen(); + if (hasScreenCopy) + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + else + _vm->_graphicsManager.m_scroll16(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + } + _vm->_eventsManager._rateCounter = 0; + _vm->_eventsManager._escKeyFl = false; + _vm->_soundManager.loadAnimSound(); + if (_vm->_globals.iRegul == 1) { + while (!_vm->_eventsManager._escKeyFl && _vm->_eventsManager._rateCounter < rate1) { + _vm->_eventsManager.refreshEvents(); + } + } + break; + } + + if (!_vm->_eventsManager._escKeyFl) { + _vm->_eventsManager._rateCounter = 0; + int frameNumber = 0; + for (;;) { + if (_vm->_eventsManager._escKeyFl) + break; + ++frameNumber; + _vm->_soundManager.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.iRegul == 1) { + while (!_vm->_eventsManager._escKeyFl && _vm->_eventsManager._rateCounter < rate2) { + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } + } + + _vm->_eventsManager._rateCounter = 0; + _vm->_graphicsManager.lockScreen(); + if (*screenP != kByteStop) { + if (hasScreenCopy) { + _vm->_graphicsManager.copyWinscanVbe3(screenP, screenCopy); + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + } else { + _vm->_graphicsManager.copyVideoVbe16(screenP); + } + } + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + _vm->_soundManager.checkSoundEnd(); + } + + if (_vm->_globals.iRegul == 1) { + while (!_vm->_eventsManager._escKeyFl && _vm->_eventsManager._rateCounter < rate3) { + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } + } + } + + _vm->_graphicsManager._skipVideoLockFl = false; + f.close(); + + if (_vm->_graphicsManager.FADE_LINUX == 2 && !hasScreenCopy) { + f.seek(6); + f.read(_vm->_graphicsManager._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->_graphicsManager.copyWinscanVbe3(screenP, ptra); + } + _vm->_graphicsManager.fadeOutDefaultLength(ptra); + ptra = _vm->_globals.freeMemory(ptra); + } + if (hasScreenCopy) { + if (_vm->_graphicsManager.FADE_LINUX == 2) + _vm->_graphicsManager.fadeOutDefaultLength(screenCopy); + _vm->_globals.freeMemory(screenCopy); + } + _vm->_graphicsManager.FADE_LINUX = 0; + + _vm->_saveLoadManager.load("TEMP.SCR", _vm->_graphicsManager._vesaScreen); + g_system->getSavefileManager()->removeSavefile("TEMP.SCR"); + + memcpy(_vm->_graphicsManager._palette, _vm->_graphicsManager._oldPalette, 769); + _vm->_graphicsManager.clearPalette(); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager._scrollPosX = oldScrollPosX; + _vm->_graphicsManager.scrollScreen(oldScrollPosX); + if (_vm->_graphicsManager._largeScreenFl) { + _vm->_graphicsManager.SCANLINE(2 * SCREEN_WIDTH); + _vm->_graphicsManager._maxX = 2 * SCREEN_WIDTH; + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaBuffer, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + } else { + _vm->_graphicsManager.SCANLINE(SCREEN_WIDTH); + _vm->_graphicsManager._maxX = SCREEN_WIDTH; + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + } + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.fadeInShort(); + _vm->_graphicsManager.DD_VBL(); + + _vm->_eventsManager.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) { + _vm->_globals._animBqe[idx]._data = _vm->_globals.freeMemory(_vm->_globals._animBqe[idx]._data); + _vm->_globals._animBqe[idx]._enabledFl = false; + } + + for (int idx = 0; idx < 8; ++idx) { + _vm->_globals.Bank[idx]._data = _vm->_globals.freeMemory(_vm->_globals.Bank[idx]._data); + _vm->_globals.Bank[idx]._loadedFl = false; + _vm->_globals.Bank[idx]._filename = ""; + _vm->_globals.Bank[idx]._fileHeader = 0; + } +} + +/** + * Load Sprite Bank + */ +int AnimationManager::loadSpriteBank(int idx, const Common::String &filename) { + int result = 0; + _vm->_globals.Bank[idx]._loadedFl = true; + _vm->_globals.Bank[idx]._filename = filename; + + byte *fileDataPtr = _vm->_fileManager.loadFile(filename); + + _vm->_globals.Bank[idx]._fileHeader = 0; + if (fileDataPtr[1] == 'L' && fileDataPtr[2] == 'E') + _vm->_globals.Bank[idx]._fileHeader = 1; + else if (fileDataPtr[1] == 'O' && fileDataPtr[2] == 'R') + _vm->_globals.Bank[idx]._fileHeader = 2; + + if (!_vm->_globals.Bank[idx]._fileHeader) { + _vm->_globals.freeMemory(fileDataPtr); + _vm->_globals.Bank[idx]._loadedFl = false; + result = -1; + } + + _vm->_globals.Bank[idx]._data = fileDataPtr; + + int objectDataIdx = 0; + for(objectDataIdx = 0; objectDataIdx <= 249; objectDataIdx++) { + int width = _vm->_objectsManager.getWidth(fileDataPtr, objectDataIdx); + int height = _vm->_objectsManager.getHeight(fileDataPtr, objectDataIdx); + if (!width && !height) + break; + } + + if (objectDataIdx > 249) { + _vm->_globals.freeMemory(fileDataPtr); + _vm->_globals.Bank[idx]._loadedFl = false; + result = -2; + } + _vm->_globals.Bank[idx]._objDataIdx = objectDataIdx; + + Common::String ofsFilename = _vm->_globals.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->_fileManager.loadFile(ofsFilename); + byte *curOfsData = ofsData; + for (int objIdx = 0; objIdx < _vm->_globals.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->_objectsManager.setOffsetXY(_vm->_globals.Bank[idx]._data, objIdx, x1, y1, 0); + if (_vm->_globals.Bank[idx]._fileHeader == 2) + _vm->_objectsManager.setOffsetXY(_vm->_globals.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) { + _vm->_globals._animBqe[animIndex]._enabledFl = false; + _vm->_globals._animBqe[animIndex]._data = g_PTRNUL; + return; + } + ++curBufferPos; + ++count; + } while (!innerLoopCond); + _vm->_globals._animBqe[animIndex]._data = _vm->_globals.allocMemory(count + 50); + _vm->_globals._animBqe[animIndex]._enabledFl = true; + memcpy(_vm->_globals._animBqe[animIndex]._data, data + dataIdx + 5, 20); + + byte *dataP = _vm->_globals._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) { + if (_vm->shouldQuit()) + return; + + bool hasScreenCopy = false; + _vm->_eventsManager._mouseFl = false; + if (!NO_COUL) { + _vm->_eventsManager.VBL(); + + if (_vm->_graphicsManager._lineNbr == SCREEN_WIDTH) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 307200); + else if (_vm->_graphicsManager._lineNbr == (SCREEN_WIDTH * 2)) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 614400); + if (!_vm->_graphicsManager._lineNbr) + _vm->_graphicsManager._scrollOffset = 0; + } + byte *screenP = _vm->_graphicsManager._vesaScreen; + Common::File f; + if (!f.open(file)) + error("Error opening file - %s", file.c_str()); + + f.skip(6); + f.read(_vm->_graphicsManager._palette, 800); + f.skip(4); + size_t nbytes = f.readUint32LE(); + f.skip(14); + f.read(screenP, nbytes); + + byte *screenCopy = NULL; + if (_vm->_graphicsManager.WinScan / 2 > SCREEN_WIDTH) { + hasScreenCopy = true; + screenCopy = _vm->_globals.allocMemory(307200); + memcpy(screenCopy, screenP, 307200); + } + if (NO_SEQ) { + if (hasScreenCopy) + memcpy(screenCopy, _vm->_graphicsManager._vesaBuffer, 307200); + if (!_vm->getIsDemo()) { + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + } + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + } else { + _vm->_graphicsManager.lockScreen(); + if (hasScreenCopy) + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + else + _vm->_graphicsManager.m_scroll16(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + } + bool skipFl = false; + if (_vm->getIsDemo()) { + _vm->_eventsManager._rateCounter = 0; + _vm->_eventsManager._escKeyFl = false; + _vm->_soundManager.loadAnimSound(); + if (_vm->_globals.iRegul == 1) { + do { + if (_vm->shouldQuit() || (_vm->_eventsManager._escKeyFl && !skipEscFl)) { + skipFl = true; + break; + } + + _vm->_eventsManager._escKeyFl = false; + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (_vm->_eventsManager._rateCounter < rate1); + } + } else { + if (NO_COUL) + _vm->_graphicsManager.fadeInDefaultLength(screenP); + _vm->_eventsManager._rateCounter = 0; + _vm->_eventsManager._escKeyFl = false; + _vm->_soundManager.loadAnimSound(); + if (_vm->_globals.iRegul == 1) { + do { + if (_vm->shouldQuit() || (_vm->_eventsManager._escKeyFl && !skipEscFl)) { + skipFl = true; + break; + } + + _vm->_eventsManager._escKeyFl = false; + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (_vm->_eventsManager._rateCounter < rate1); + } + } + _vm->_eventsManager._rateCounter = 0; + int soundNumber = 0; + if (!skipFl) { + for (;;) { + ++soundNumber; + _vm->_soundManager.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.iRegul == 1) { + do { + if (_vm->shouldQuit() || (_vm->_eventsManager._escKeyFl && !skipEscFl)) { + skipFl = true; + break; + } + + _vm->_eventsManager._escKeyFl = false; + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (_vm->_eventsManager._rateCounter < rate2); + } + + if (skipFl) + break; + + _vm->_eventsManager._rateCounter = 0; + _vm->_graphicsManager.lockScreen(); + if (hasScreenCopy) { + if (*screenP != kByteStop) { + _vm->_graphicsManager.copyWinscanVbe(screenP, screenCopy); + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + } + } else if (*screenP != kByteStop) { + _vm->_graphicsManager.copyVideoVbe16a(screenP); + } + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + _vm->_soundManager.checkSoundEnd(); + } + } + + if (_vm->_globals.iRegul == 1 && !skipFl) { + do { + if (_vm->shouldQuit() || (_vm->_eventsManager._escKeyFl && !skipEscFl)) { + skipFl = true; + break; + } + + _vm->_eventsManager._escKeyFl = false; + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (_vm->_eventsManager._rateCounter < rate3); + } + + if (!skipFl) + _vm->_eventsManager._rateCounter = 0; + + _vm->_graphicsManager._skipVideoLockFl = false; + f.close(); + + if (!NO_COUL) { + _vm->_saveLoadManager.load("TEMP.SCR", _vm->_graphicsManager._vesaScreen); + g_system->getSavefileManager()->removeSavefile("TEMP.SCR"); + + _vm->_eventsManager._mouseFl = true; + } + if (hasScreenCopy) + _vm->_globals.freeMemory(screenCopy); +} + +/** + * Play Sequence type 2 + */ +void AnimationManager::playSequence2(const Common::String &file, uint32 rate1, uint32 rate2, uint32 rate3) { + byte *screenCopy = NULL; + byte *screenP; + int frameNumber; + Common::File f; + + bool multiScreenFl = false; + for (;;) { + if (_vm->shouldQuit()) + return; + + _vm->_eventsManager._mouseFl = false; + screenP = _vm->_graphicsManager._vesaScreen; + + if (!f.open(file)) + error("File not found - %s", file.c_str()); + + f.skip(6); + f.read(_vm->_graphicsManager._palette, 800); + f.skip(4); + size_t nbytes = f.readUint32LE(); + f.skip(14); + f.read(screenP, nbytes); + + if (_vm->_graphicsManager.WinScan / 2 > SCREEN_WIDTH) { + multiScreenFl = true; + screenCopy = _vm->_globals.allocMemory(307200); + memcpy((void *)screenCopy, screenP, 307200); + } + if (NO_SEQ) { + if (multiScreenFl) { + assert(screenCopy != NULL); + memcpy((void *)screenCopy, _vm->_graphicsManager._vesaBuffer, 307200); + } + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + } else { + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + if (multiScreenFl) + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + else + _vm->_graphicsManager.m_scroll16(screenP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + } + _vm->_eventsManager._rateCounter = 0; + _vm->_eventsManager._escKeyFl = false; + _vm->_soundManager.loadAnimSound(); + if (_vm->_globals.iRegul == 1) { + do { + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (!_vm->shouldQuit() && !_vm->_eventsManager._escKeyFl && _vm->_eventsManager._rateCounter < rate1); + } + break; + } + + if (!_vm->_eventsManager._escKeyFl) { + _vm->_eventsManager._rateCounter = 0; + frameNumber = 0; + while (!_vm->shouldQuit()) { + _vm->_soundManager.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.iRegul == 1) { + do { + _vm->_eventsManager.refreshEvents(); + } while (!_vm->shouldQuit() && !_vm->_eventsManager._escKeyFl && _vm->_eventsManager._rateCounter < rate2); + } + + _vm->_eventsManager._rateCounter = 0; + _vm->_graphicsManager.lockScreen(); + if (multiScreenFl) { + if (*screenP != kByteStop) { + _vm->_graphicsManager.copyWinscanVbe(screenP, screenCopy); + _vm->_graphicsManager.m_scroll16A(screenCopy, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + } + } else if (*screenP != kByteStop) { + _vm->_graphicsManager.copyVideoVbe16a(screenP); + } + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + _vm->_soundManager.checkSoundEnd(); + } + } + + if (_vm->_globals.iRegul == 1) { + // Wait for third rate delay + do { + _vm->_eventsManager.refreshEvents(); + _vm->_soundManager.checkSoundEnd(); + } while (!_vm->shouldQuit() && !_vm->_eventsManager._escKeyFl && _vm->_eventsManager._rateCounter < rate3); + } + + _vm->_eventsManager._rateCounter = 0; + + if (_vm->_graphicsManager.FADE_LINUX == 2 && !multiScreenFl) { + byte *ptra = _vm->_globals.allocMemory(307200); + + f.seek(6); + f.read(_vm->_graphicsManager._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->_graphicsManager.copyWinscanVbe(screenP, ptra); + } + _vm->_graphicsManager.fadeOutDefaultLength(ptra); + ptra = _vm->_globals.freeMemory(ptra); + } + if (multiScreenFl) { + if (_vm->_graphicsManager.FADE_LINUX == 2) + _vm->_graphicsManager.fadeOutDefaultLength(screenCopy); + _vm->_globals.freeMemory(screenCopy); + } + _vm->_graphicsManager.FADE_LINUX = 0; + + f.close(); + _vm->_eventsManager._mouseFl = true; +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/anim.h b/engines/hopkins/anim.h new file mode 100644 index 0000000000..c0a62b711d --- /dev/null +++ b/engines/hopkins/anim.h @@ -0,0 +1,60 @@ +/* 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 { + +class HopkinsEngine; + +class AnimationManager { +private: + HopkinsEngine *_vm; + + int loadSpriteBank(int idx, const Common::String &filename); + void searchAnim(const byte *data, int animIndex, int count); + +public: + bool _clearAnimationFl; + bool NO_SEQ; + bool NO_COUL; + + AnimationManager(); + void setParent(HopkinsEngine *vm) { _vm = vm; } + + void loadAnim(const Common::String &animName); + void clearAnim(); + void playAnim(const Common::String &filename, uint32 rate1, uint32 rate2, uint32 rate3); + 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 = false); + void playSequence2(const Common::String &file, uint32 rate1, uint32 rate2, uint32 rate3); +}; + +} // 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..2e911152bb --- /dev/null +++ b/engines/hopkins/computer.cpp @@ -0,0 +1,1221 @@ +/* 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() { + 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 = NULL; + _breakoutBrickNbr = 0; + _breakoutScore = 0; + _breakoutLives = 0; + _breakoutSpeed = 0; + _ballRightFl = false; + _ballUpFl = false; + _breakoutLevelNbr = 0; + _padPositionX = 0; + _minBreakoutMoveSpeed = 0; + _maxBreakoutMoveSpeed = 0; + _lastBreakoutMoveSpeed = 0; +} + +void ComputerManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +/** + * 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->_graphicsManager.clearPalette(); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + + _vm->_graphicsManager._lineNbr = SCREEN_WIDTH; + _vm->_fontManager._font = _vm->_globals.freeMemory(_vm->_fontManager._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->_fontManager._font = _vm->_fileManager.loadFile(filename); + _vm->_fontManager._fontFixedWidth = 8; + _vm->_fontManager._fontFixedHeight = 8; + + _vm->_graphicsManager.loadImage("WINTEXT"); + _vm->_graphicsManager.fadeInLong(); + loadMenu(); + _vm->_eventsManager._mouseFl = false; +} + +/** + * Clear the screen + */ +void ComputerManager::clearScreen() { + _vm->_graphicsManager.loadImage("WINTEXT"); + _vm->_graphicsManager.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->_eventsManager._escKeyFl = false; + _vm->_graphicsManager.resetVesaSegment(); + 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->_eventsManager._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->_eventsManager.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->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + restoreFBIRoom(); + } else { + // Password doesn't match - Access Denied + setTextColor(4); + setTextPosition(16, 25); + outText(Common::String(_menuText[5]._line)); + _vm->_eventsManager.VBL(); + _vm->_eventsManager.delay(1000); + + memset(_vm->_graphicsManager._vesaBuffer, 0, 307199); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.DD_VBL(); + restoreFBIRoom(); + _vm->_eventsManager.mouseOff(); + } + + if (mode == COMPUTER_HOPKINS) + _vm->_globals._exitId = 13; + else // Free access or Samantha + _vm->_globals._exitId = 14; + + _vm->_graphicsManager.resetVesaSegment(); +} + +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->_fileManager.fileExists("COMPUTAN.TXT")) { + ptr = (char *)_vm->_fileManager.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->_eventsManager._mouseFl; + _vm->_eventsManager._mouseFl = false; + + _vm->_fontManager.displayTextVesa(xp, yp, "_", 252); + do { + curChar = _vm->_eventsManager.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->_fontManager._fontFixedWidth; + x2 = x1 + 2 * _vm->_fontManager._fontFixedWidth; + _vm->_graphicsManager.Copy_Mem(_vm->_graphicsManager._vesaScreen, x1, yp, 3 * _vm->_fontManager._fontFixedWidth, 12, _vm->_graphicsManager._vesaBuffer, x1, yp); + _vm->_graphicsManager.addVesaSegment(x1, yp, x2, yp + 12); + _vm->_fontManager.displayTextVesa(x1, yp, "_", 252); + } + if (mappedChar != '*') { + char newChar = mappedChar; + _vm->_graphicsManager.Copy_Mem(_vm->_graphicsManager._vesaScreen, x1, yp, _vm->_fontManager._fontFixedWidth, 12, _vm->_graphicsManager._vesaBuffer, x1, yp); + _vm->_graphicsManager.addVesaSegment(x1, yp, _vm->_fontManager._fontFixedWidth + x1, yp + 12); + _inputBuf[textIndex] = newChar; + + Common::String charString = Common::String::format("%c_", newChar); + _vm->_fontManager.displayTextVesa(x1, yp, charString, 252); + ++textIndex; + x1 += _vm->_fontManager._fontFixedWidth; + } + _vm->_eventsManager.VBL(); + } while (textIndex != textIdx && curChar != 13); + + _vm->_graphicsManager.Copy_Mem(_vm->_graphicsManager._vesaScreen, x1, yp, _vm->_fontManager._fontFixedWidth, 12, _vm->_graphicsManager._vesaBuffer, x1, yp); + _vm->_graphicsManager.addVesaSegment(x1, yp, _vm->_fontManager._fontFixedWidth + x1, yp + 12); + + _vm->_eventsManager.VBL(); + _inputBuf[textIndex] = 0; + _vm->_eventsManager._mouseFl = oldMouseFlag; +} + +/** + * Outputs a text string + */ +void ComputerManager::outText(const Common::String &msg) { + _vm->_fontManager.renderTextDisplay(_textPosition.x, _textPosition.y, msg, _textColor); +} + +/** + * Outputs a text string + */ +void ComputerManager::outText2(const Common::String &msg) { + _vm->_fontManager.displayTextVesa(_textPosition.x, _textPosition.y, msg, _textColor); +} + +/** + * Restores the scene for the FBI headquarters room + */ +void ComputerManager::restoreFBIRoom() { + _vm->_globals.freeMemory(_vm->_fontManager._font); + _vm->_fontManager._font = _vm->_fileManager.loadFile("FONTE3.SPR"); + _vm->_fontManager._fontFixedWidth = 12; + _vm->_fontManager._fontFixedHeight = 21; + + _vm->_eventsManager._mouseFl = true; +} + +/** + * Display texts for the given menu entry + */ +void ComputerManager::readText(int idx) { + _vm->_eventsManager._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->_fileManager.loadFile(filename); + uint16 fileSize = _vm->_fileManager.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->_eventsManager.VBL(); + curStr = ""; + } else if (curChar != '%') { + curStr += curChar; + } + ++pos; + assert(pos <= fileSize); + } while (curChar != '%'); + + _vm->_eventsManager.waitKeyPress(); + ptr = _vm->_globals.freeMemory(ptr); +} + +/** + * Display breakout when Games sub-menu is selected + */ +void ComputerManager::displayGamesSubMenu() { + const byte *oldSpriteData = _vm->_objectsManager._sprite[0]._spriteData; + uint oldSpeed = _vm->_globals._speed; + + _vm->_globals._speed = 1; + _vm->_eventsManager.changeMouseCursor(0); + _breakoutSpr = g_PTRNUL; + _vm->_eventsManager._breakoutFl = true; + _breakoutLevel = (int16 *)g_PTRNUL; + _breakoutBrickNbr = 0; + _breakoutScore = 0; + _breakoutLives = 5; + _breakoutSpeed = 1; + _ballRightFl = false; + _ballUpFl = false; + _breakoutLevelNbr = 0; + _vm->_graphicsManager._minY = 0; + _vm->_graphicsManager._maxX = 320; + _vm->_graphicsManager._maxY = 200; + _vm->_soundManager.loadSample(1, "SOUND37.WAV"); + _vm->_soundManager.loadSample(2, "SOUND38.WAV"); + _vm->_soundManager.loadSample(3, "SOUND39.WAV"); + _breakoutSpr = _vm->_fileManager.loadFile("CASSE.SPR"); + loadHiscore(); + setModeVGA256(); + newLevel(); + _vm->_graphicsManager.resetVesaSegment(); + playBreakout(); + _vm->_graphicsManager.resetVesaSegment(); + _breakoutSpr = _vm->_globals.freeMemory(_breakoutSpr); + _breakoutLevel = (int16 *)_vm->_globals.freeMemory((byte *)_breakoutLevel); + _vm->_objectsManager._sprite[0]._spriteData = oldSpriteData; + + _vm->_soundManager.removeSample(1); + _vm->_soundManager.removeSample(2); + _vm->_soundManager.removeSample(3); + _vm->_globals._speed = oldSpeed; + _vm->_eventsManager._breakoutFl = false; + setVideoMode(); + setTextColor(15); + clearScreen(); + _vm->_graphicsManager._maxX = 680; + _vm->_graphicsManager._minY = 0; + _vm->_graphicsManager._maxY = 460; +} + +/** + * Load Highscore from file + */ +void ComputerManager::loadHiscore() { + byte *ptr = _vm->_globals.allocMemory(100); + _vm->_saveLoadManager.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->_graphicsManager.lockScreen(); + _vm->_graphicsManager.clearScreen(); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.clearPalette(); + _vm->_graphicsManager.SCANLINE(320); +} + +/** + * Load new level + */ +void ComputerManager::newLevel() { + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.removeSprite(1); + ++_breakoutLives; + if (_breakoutLives > 11) + _breakoutLives = 11; + _vm->_graphicsManager.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->_fileManager.loadFile(file); + displayBricks(); + _vm->_objectsManager.addStaticSprite(_breakoutSpr, Common::Point(150, 192), 0, 13, 0, false, 0, 0); + _vm->_objectsManager.addStaticSprite(_breakoutSpr, Common::Point(164, 187), 1, 14, 0, false, 0, 0); + _ballPosition = Common::Point(164, 187); + _padPositionX = 150; + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.animateSprite(1); + _vm->_eventsManager.mouseOn(); + _vm->_soundManager.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 = level[levelIdx]; + if (cellLeft == -1) + break; + cellTop = level[levelIdx + 1]; + cellType = level[levelIdx + 4]; + + if (cellType <= 6) + ++_breakoutBrickNbr; + + switch (cellType) { + case 1: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 21); + break; + case 2: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 22); + break; + case 3: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 17); + break; + case 4: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 20); + break; + case 5: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 19); + break; + case 6: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 18); + break; + case 31: + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, cellLeft, cellTop, 23); + break; + } + + levelIdx += 6; + } + + displayScore(); +} + +/** + * Display Lives in breakout game + */ +void ComputerManager::displayLives() { + for (int i = 0, xp = 10; i <= 11; i++, xp += 7) + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, xp, 10, 15); + + for (int i = 0, xp = 10; i < _breakoutLives - 1; i++, xp += 7) + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_breakoutSpr, xp, 10, 14); +} + +/** + * Main function for breakout game + */ +void ComputerManager::playBreakout() { + int lastBreakoutEvent = 0; + while (!_vm->shouldQuit()) { + while (!_vm->shouldQuit()) { + // Set up the racket and ball + _vm->_eventsManager.mouseOff(); + _ballPosition = Common::Point(_padPositionX + 14, 187); + _vm->_objectsManager.setSpriteY(1, 187); + _vm->_objectsManager.setSpriteX(1, _ballPosition.x); + _vm->_graphicsManager.resetVesaSegment(); + _vm->_eventsManager.VBL(); + _vm->_graphicsManager.fadeInBreakout(); + + // Wait for mouse press to start playing + do { + _padPositionX = _vm->_eventsManager.getMouseX(); + if (_vm->_eventsManager._mousePos.x <= 4) + _padPositionX = 5; + if (_padPositionX > 282) + _padPositionX = 282; + _vm->_objectsManager.setSpriteX(0, _padPositionX); + _vm->_objectsManager.setSpriteX(1, _padPositionX + 14); + _vm->_objectsManager.setSpriteY(1, 187); + _vm->_eventsManager.VBL(); + } while (!_vm->shouldQuit() && _vm->_eventsManager.getMouseButton() != 1); + + _breakoutSpeed = 1; + _ballPosition = Common::Point(_padPositionX + 14, 187); + _ballRightFl = (_padPositionX > 135); + _ballUpFl = false; + + // Play loop + do { + _vm->_soundManager.checkSounds(); + + _padPositionX = _vm->_eventsManager.getMouseX(); + if (_vm->_eventsManager._mousePos.x <= 4) + _padPositionX = 5; + if (_padPositionX > 282) + _padPositionX = 282; + _vm->_objectsManager.setSpriteX(0, _padPositionX); + lastBreakoutEvent = moveBall(); + _vm->_eventsManager.VBL(); + } while (!_vm->shouldQuit() && !lastBreakoutEvent); + if (lastBreakoutEvent != 1) + break; + _vm->_graphicsManager.fateOutBreakout(); + --_breakoutLives; + + if (_breakoutLives) { + displayLives(); + if (_breakoutLives) + continue; + } + _vm->_eventsManager.mouseOn(); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.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->_graphicsManager.fateOutBreakout(); + newLevel(); + } +} + +/** + * Show the high scores for the Breakout game + * @return The selected button index: 1 = Game, 2 = Quit + */ +int ComputerManager::displayHiscores() { + _vm->_graphicsManager.resetVesaSegment(); + loadHiscore(); + _vm->_graphicsManager.loadVgaImage("HISCORE.PCX"); + byte *ptr = _vm->_fileManager.loadFile("ALPHA.SPR"); + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(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->_graphicsManager.fadeInBreakout(); + _vm->_graphicsManager.resetVesaSegment(); + int buttonIndex = 0; + do { + _vm->_eventsManager.refreshEvents(); + xp = _vm->_eventsManager.getMouseX(); + yp = _vm->_eventsManager.getMouseY(); + + if (_vm->_eventsManager.getMouseButton() == 1 && ABS(xp - 79) <= 33 && ABS(yp - 396) <= 13) + buttonIndex = 1; + else if (_vm->_eventsManager.getMouseButton() == 1 && ABS(xp - 583) <= 32 && ABS(yp - 396) <= 13) + buttonIndex = 2; + + _vm->_eventsManager.VBL(); + } while (!buttonIndex && !_vm->shouldQuit()); + + _vm->_eventsManager.mouseOff(); + _vm->_graphicsManager.fateOutBreakout(); + _vm->_globals.freeMemory(ptr); + return buttonIndex; +} + +/** + * Display a screen to enter player name in the case of a new hiscore + */ +void ComputerManager::getScoreName() { + _vm->_graphicsManager.loadVgaImage("NAME.PCX"); + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + byte *ptr = _vm->_fileManager.loadFile("ALPHA.SPR"); + _vm->_graphicsManager.fadeInBreakout(); + for (int strPos = 0; strPos <= 4; strPos++) { + displayHiscoreLine(ptr, 9 * strPos + 140, 78, 1); + + char curChar = toupper(_vm->_eventsManager.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->_eventsManager.VBL(); + } + _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->_graphicsManager.fateOutBreakout(); + _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->_graphicsManager.AFFICHE_SPEEDVGA(_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->_saveLoadManager.saveFile("HISCORE.DAT", ptr, 100); + _vm->_globals.freeMemory(ptr); +} + +/** + * Display parts of the hiscore line + */ +void ComputerManager::displayHiscoreLine(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->_graphicsManager.AFFICHE_SPEEDVGA(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->_soundManager.playSample(2, 6); + _ballPosition.x = randVal + 6; + _ballRightFl = !_ballRightFl; + } else if (_ballPosition.x > 307) { + _vm->_soundManager.playSample(2, 6); + _ballPosition.x = 307 - randVal; + _ballRightFl = !_ballRightFl; + } + + if (_ballPosition.y <= 6) { + _vm->_soundManager.playSample(2, 6); + _ballPosition.y = randVal + 7; + _ballUpFl = !_ballUpFl; + } else if (_ballPosition.y >= 186 && _ballPosition.y <= 194) { + _vm->_soundManager.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->_objectsManager.setSpriteX(1, _ballPosition.x); + _vm->_objectsManager.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->_soundManager.playSample(2, 6); + } else { + _vm->_soundManager.playSample(1, 5); + _vm->_graphicsManager.AFFICHE_SPEEDVGA(_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..b46fdd16b0 --- /dev/null +++ b/engines/hopkins/computer.h @@ -0,0 +1,109 @@ +/* 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(); + void displayScore(); + int displayHiscores(); + void displayHiscoreLine(byte *objectData, int x, int y, int curChar); + void playBreakout(); + void saveScore(); + int moveBall(); + void checkBallCollisions(); + void getScoreName(); + + void displayMessage(int xp, int yp, int textIdx); + + void displayScoreChar(int charPos, int charDisp); + +public: + ComputerManager(); + void setParent(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..0abfd1f62e --- /dev/null +++ b/engines/hopkins/debugger.cpp @@ -0,0 +1,39 @@ +/* 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() : GUI::Debugger() { + DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); +} + +void Debugger::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/debugger.h b/engines/hopkins/debugger.h new file mode 100644 index 0000000000..aabc95c5f1 --- /dev/null +++ b/engines/hopkins/debugger.h @@ -0,0 +1,45 @@ +/* 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(); + virtual ~Debugger() {} + void setParent(HopkinsEngine *vm); +}; + +} // 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..050bc82e6e --- /dev/null +++ b/engines/hopkins/detection_tables.h @@ -0,0 +1,227 @@ +/* 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) + }, + }, + + { 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..6102c8645a --- /dev/null +++ b/engines/hopkins/dialogs.cpp @@ -0,0 +1,754 @@ +/* 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() { + _inventFl = false; + _inventDisplayedFl = false; + _removeInventFl = false; + _inventX = _inventY = 0; + _inventWidth = _inventHeight = 0; + _inventWin1 = g_PTRNUL; + _inventBuf2 = g_PTRNUL; + _inventoryIcons = g_PTRNUL; +} + +DialogsManager::~DialogsManager() { + _vm->_globals.freeMemory(_inventWin1); + _vm->_globals.freeMemory(_inventoryIcons); +} + +void DialogsManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +void DialogsManager::showOptionsDialog() { + _vm->_eventsManager.changeMouseCursor(0); + _vm->_eventsManager.VBL(); + 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->_fileManager.loadFile(filename); + _vm->_globals._optionDialogFl = true; + + bool doneFlag = false; + do { + if (_vm->_eventsManager.getMouseButton()) { + Common::Point mousePos(_vm->_eventsManager.getMouseX(), _vm->_eventsManager.getMouseY()); + mousePos.x = _vm->_eventsManager.getMouseX(); + mousePos.y = _vm->_eventsManager.getMouseY(); + + if (!_vm->_soundManager._musicOffFl) { + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 300 && mousePos.y > 113 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 327 && mousePos.y <= 138) { + // Change the music volume + ++_vm->_soundManager._musicVolume; + + if (_vm->_soundManager._musicVolume <= 12) + _vm->_soundManager.playSoundFile("bruit2.wav"); + else + _vm->_soundManager._musicVolume = 12; + _vm->_soundManager.setMODMusicVolume(_vm->_soundManager._musicVolume); + + _vm->_soundManager.updateScummVMSoundSettings(); + } + + if (!_vm->_soundManager._musicOffFl && mousePos.x >= _vm->_graphicsManager._scrollOffset + 331 && mousePos.y > 113 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 358 && mousePos.y <= 138) { + --_vm->_soundManager._musicVolume; + if (_vm->_soundManager._musicVolume >= 0) + _vm->_soundManager.playSoundFile("bruit2.wav"); + else + _vm->_soundManager._musicVolume = 0; + + _vm->_soundManager.setMODMusicVolume(_vm->_soundManager._musicVolume); + + _vm->_soundManager.updateScummVMSoundSettings(); + } + } + if (!_vm->_soundManager._soundOffFl) { + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 300 && mousePos.y > 140 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 327 && mousePos.y <= 165) { + ++_vm->_soundManager._soundVolume; + if (_vm->_soundManager._soundVolume <= 16) + _vm->_soundManager.playSoundFile("bruit2.wav"); + else + _vm->_soundManager._soundVolume = 16; + _vm->_soundManager.setMODSampleVolume(); + + _vm->_soundManager.updateScummVMSoundSettings(); + } + + if (!_vm->_soundManager._soundOffFl && mousePos.x >= _vm->_graphicsManager._scrollOffset + 331 && mousePos.y > 140 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 358 && mousePos.y <= 165) { + --_vm->_soundManager._soundVolume; + if (_vm->_soundManager._soundVolume >= 0) + _vm->_soundManager.playSoundFile("bruit2.wav"); + else + _vm->_soundManager._soundVolume = 0; + _vm->_soundManager.setMODSampleVolume(); + + _vm->_soundManager.updateScummVMSoundSettings(); + } + } + + if (!_vm->_soundManager._voiceOffFl) { + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 300 && mousePos.y > 167 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 327 && mousePos.y <= 192) { + ++_vm->_soundManager._voiceVolume; + + if (_vm->_soundManager._voiceVolume <= 16) + _vm->_soundManager.playSoundFile("bruit2.wav"); + else + _vm->_soundManager._voiceVolume = 16; + _vm->_soundManager.setMODVoiceVolume(); + + _vm->_soundManager.updateScummVMSoundSettings(); + } + + if (!_vm->_soundManager._voiceOffFl && mousePos.x >= _vm->_graphicsManager._scrollOffset + 331 && mousePos.y > 167 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 358 && mousePos.y <= 192) { + --_vm->_soundManager._voiceVolume; + if (_vm->_soundManager._voiceVolume >= 0) + _vm->_soundManager.playSoundFile("bruit2.wav"); + else + _vm->_soundManager._voiceVolume = 0; + _vm->_soundManager.setMODVoiceVolume(); + + _vm->_soundManager.updateScummVMSoundSettings(); + } + } + + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 431) { + if (mousePos.y > 194 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 489 && mousePos.y <= 219) + _vm->_soundManager._textOffFl = !_vm->_soundManager._textOffFl; + + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 431) { + if (mousePos.y > 167 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 489 && mousePos.y <= 192) { + _vm->_soundManager._voiceOffFl = !_vm->_soundManager._voiceOffFl; + + _vm->_soundManager.updateScummVMSoundSettings(); + } + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 431) { + if (mousePos.y > 113 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 489 && mousePos.y <= 138) { + if (_vm->_soundManager._musicOffFl) { + _vm->_soundManager._musicOffFl = false; + _vm->_soundManager.setMODMusicVolume(_vm->_soundManager._musicVolume); + } else { + _vm->_soundManager._musicOffFl = true; + _vm->_soundManager.setMODMusicVolume(0); + } + + _vm->_soundManager.updateScummVMSoundSettings(); + } + + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 431 && mousePos.y > 140 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 489 && mousePos.y <= 165) { + _vm->_soundManager._soundOffFl = !_vm->_soundManager._soundOffFl; + + _vm->_soundManager.updateScummVMSoundSettings(); + } + } + } + } + + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 175 && mousePos.y > 285 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 281 && mousePos.y <= 310) { + _vm->_globals._exitId = 300; + doneFlag = true; + } + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 355 && mousePos.y > 285 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 490 && mousePos.y <= 310) + doneFlag = true; + if (mousePos.x >= _vm->_graphicsManager._scrollOffset + 300 && mousePos.y > 194 && mousePos.x <= _vm->_graphicsManager._scrollOffset + 358 && mousePos.y <= 219) { + switch (_vm->_graphicsManager._scrollSpeed) { + case 1: + _vm->_graphicsManager._scrollSpeed = 2; + break; + case 2: + _vm->_graphicsManager._scrollSpeed = 4; + break; + case 4: + _vm->_graphicsManager._scrollSpeed = 8; + break; + case 8: + _vm->_graphicsManager._scrollSpeed = 16; + break; + case 16: + _vm->_graphicsManager._scrollSpeed = 32; + break; + case 32: + _vm->_graphicsManager._scrollSpeed = 48; + break; + case 48: + _vm->_graphicsManager._scrollSpeed = 64; + break; + case 64: + _vm->_graphicsManager._scrollSpeed = 128; + break; + case 128: + _vm->_graphicsManager._scrollSpeed = 160; + break; + case 160: + _vm->_graphicsManager._scrollSpeed = 320; + break; + case 320: + _vm->_graphicsManager._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 < _vm->_graphicsManager._scrollOffset + 165 || mousePos.x > _vm->_graphicsManager._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->_soundManager._textOffFl ? 7 : 8; + _vm->_globals._menuVoiceOff = !_vm->_soundManager._voiceOffFl ? 7 : 8; + _vm->_globals._menuSoundOff = !_vm->_soundManager._soundOffFl ? 7 : 8; + _vm->_globals._menuMusicOff = !_vm->_soundManager._musicOffFl ? 7 : 8; + + _vm->_globals._menuDisplayType = 9; + + switch (_vm->_graphicsManager._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->_eventsManager.VBL(); + } while (!doneFlag); + + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, _vm->_graphicsManager._scrollOffset + 164, + 107, 335, 215, _vm->_graphicsManager._vesaBuffer, _vm->_graphicsManager._scrollOffset + 164, 107); + _vm->_graphicsManager.addVesaSegment(_vm->_graphicsManager._scrollOffset + 164, 107, + _vm->_graphicsManager._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->_graphicsManager._scrollStatus = 1; + _vm->_objectsManager._eraseVisibleCounter = 4; + _vm->_objectsManager._visibleFl = false; + for (int i = 0; i <= 1; i++) { + inventAnim(); + _vm->_eventsManager.getMouseX(); + _vm->_eventsManager.getMouseY(); + _vm->_eventsManager.VBL(); + } + _inventWin1 = g_PTRNUL; + + bool loopFl; + do { + loopFl = false; + _vm->_eventsManager._curMouseButton = 0; + _vm->_eventsManager._mouseButton = 0; + _vm->_globals._disableInventFl = true; + _vm->_graphicsManager.SETCOLOR4(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->_fileManager.readStream(f, _inventWin1, filesize); + f.close(); + + _inventBuf2 = _vm->_fileManager.loadFile("INVENT2.SPR"); + + _inventX = _vm->_graphicsManager._scrollOffset + 152; + _inventY = 114; + _inventWidth = _vm->_objectsManager.getWidth(_inventWin1, 0); + _inventHeight = _vm->_objectsManager.getHeight(_inventWin1, 0); + + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, _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->_objectsManager.loadObjectFromFile(inventIdx, false); + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, obj, _inventX + curPosX + 6, + curPosY + 120, _vm->_globals._objectWidth, _vm->_globals._objectHeight); + _vm->_globals.freeMemory(obj); + } + curPosX += 54; + }; + curPosY += 38; + } + _vm->_graphicsManager.copySurfaceRect(_vm->_graphicsManager._vesaBuffer, _inventWin1, _inventX, _inventY, _inventWidth, _inventHeight); + _vm->_eventsManager._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->_eventsManager.getMouseX(); + int mousePosY = _vm->_eventsManager.getMouseY(); + int mouseButton = _vm->_eventsManager.getMouseButton(); + int oldInventoryItem = newInventoryItem; + newInventoryItem = _vm->_linesManager.checkInventoryHotspots(mousePosX, mousePosY); + if (newInventoryItem != oldInventoryItem) + _vm->_objectsManager.initBorder(newInventoryItem); + if (_vm->_eventsManager._mouseCursorId != 1 && _vm->_eventsManager._mouseCursorId != 2 && _vm->_eventsManager._mouseCursorId != 3 && _vm->_eventsManager._mouseCursorId != 16) { + if (mouseButton == 2) { + _vm->_objectsManager.nextObjectIcon(newInventoryItem); + if (_vm->_eventsManager._mouseCursorId != 23) + _vm->_eventsManager.changeMouseCursor(_vm->_eventsManager._mouseCursorId); + } + } + if (mouseButton == 1) { + if (_vm->_eventsManager._mouseCursorId == 1 || _vm->_eventsManager._mouseCursorId == 2 || _vm->_eventsManager._mouseCursorId == 3 || _vm->_eventsManager._mouseCursorId == 16 || !_vm->_eventsManager._mouseCursorId) + break; + _vm->_objectsManager.takeInventoryObject(_vm->_globals._inventory[newInventoryItem]); + if (_vm->_eventsManager._mouseCursorId == 8) + break; + + _vm->_scriptManager._tempObjectFl = true; + _vm->_globals._saveData->_data[svField3] = _vm->_objectsManager._curObjectIndex; + _vm->_globals._saveData->_data[svField8] = _vm->_globals._inventory[newInventoryItem]; + _vm->_globals._saveData->_data[svField9] = _vm->_eventsManager._mouseCursorId; + _vm->_objectsManager.OPTI_OBJET(); + _vm->_scriptManager._tempObjectFl = false; + + if (_vm->_soundManager._voiceOffFl) { + do + _vm->_eventsManager.VBL(); + while (!_vm->_globals._exitId && _vm->_eventsManager.getMouseButton() != 1); + _vm->_fontManager.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->_eventsManager.VBL(); + if (_vm->_globals._screenId >= 35 && _vm->_globals._screenId <= 40) + _vm->_objectsManager.handleSpecialGames(); + } + } while (loopFl); + + _vm->_fontManager.hideText(9); + if (_inventDisplayedFl) { + _inventDisplayedFl = false; + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, _inventX, 114, _inventWidth, _inventHeight, _vm->_graphicsManager._vesaBuffer, _inventX, 114); + _vm->_graphicsManager.addVesaSegment(_inventX, 114, _inventX + _inventWidth, _inventWidth + 114); + _vm->_objectsManager.BOBTOUS = true; + } + + _inventWin1 = _vm->_globals.freeMemory(_inventWin1); + _inventBuf2 = _vm->_globals.freeMemory(_inventBuf2); + + if (_vm->_eventsManager._mouseCursorId == 1) + showOptionsDialog(); + else if (_vm->_eventsManager._mouseCursorId == 3) + showLoadGame(); + else if (_vm->_eventsManager._mouseCursorId == 2) + showSaveGame(); + + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.changeMouseCursor(4); + _vm->_objectsManager._oldBorderPos = Common::Point(0, 0); + _vm->_objectsManager._borderPos = Common::Point(0, 0); + _vm->_globals._disableInventFl = false; + _vm->_graphicsManager._scrollStatus = 0; +} + +/** + * Inventory Animations + */ +void DialogsManager::inventAnim() { + if (_vm->_globals._disableInventFl) + return; + + if (_vm->_objectsManager._eraseVisibleCounter && !_vm->_objectsManager._visibleFl) { + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, _vm->_objectsManager._oldInventoryPosX, 27, 48, 38, + _vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._oldInventoryPosX, 27); + _vm->_graphicsManager.addVesaSegment(_vm->_objectsManager._oldInventoryPosX, 27, _vm->_objectsManager._oldInventoryPosX + 48, 65); + --_vm->_objectsManager._eraseVisibleCounter; + } + + if (_vm->_objectsManager._visibleFl) { + if (_vm->_objectsManager._oldInventoryPosX <= 1) + _vm->_objectsManager._oldInventoryPosX = 2; + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, _vm->_objectsManager._oldInventoryPosX, 27, 48, 38, + _vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._oldInventoryPosX, 27); + + _vm->_graphicsManager.addVesaSegment(_vm->_objectsManager._oldInventoryPosX, 27, _vm->_objectsManager._oldInventoryPosX + 48, 65); + int newOffset = _vm->_graphicsManager._scrollOffset + 2; + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _inventoryIcons, newOffset + 300, 327, 0); + _vm->_graphicsManager.addVesaSegment(newOffset, 27, newOffset + 45, 62); + _vm->_objectsManager._oldInventoryPosX = newOffset; + } + + if (_vm->_globals._saveData->_data[svField357] == 1) { + if (_vm->_globals._saveData->_data[svField353] == 1) + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._headSprites, 832, 325, 0, 0, 0, false); + if (_vm->_globals._saveData->_data[svField355] == 1) + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._headSprites, 866, 325, 1, 0, 0, false); + _vm->_graphicsManager.addVesaSegment(532, 25, 560, 60); + _vm->_graphicsManager.addVesaSegment(566, 25, 594, 60); + } + if (_vm->_globals._saveData->_data[svField356] == 1) { + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._headSprites, 832, 325, 0, 0, 0, false); + _vm->_graphicsManager.addVesaSegment(532, 25, 560, 60); + } + + if (_vm->_globals._saveData->_data[svField354] == 1) { + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._headSprites, 832, 325, 0, 0, 0, false); + _vm->_graphicsManager.addVesaSegment(532, 25, 560, 60); + } +} + +/** + * Test dialog opening + */ +void DialogsManager::testDialogOpening() { + if (_vm->_globals._cityMapEnabledFl) + _vm->_eventsManager._gameKey = KEY_NONE; + + if ((_vm->_eventsManager._gameKey == KEY_NONE) || _inventFl) + return; + + DIALOG_KEY key = _vm->_eventsManager._gameKey; + _vm->_eventsManager._gameKey = KEY_NONE; + _inventFl = true; + + switch (key) { + case KEY_INVENTORY: + showInventory(); + break; + case KEY_OPTIONS: + _vm->_graphicsManager._scrollStatus = 1; + showOptionsDialog(); + _vm->_graphicsManager._scrollStatus = 0; + break; + case KEY_LOAD: + _vm->_graphicsManager._scrollStatus = 1; + showLoadGame(); + _vm->_graphicsManager._scrollStatus = 0; + break; + case KEY_SAVE: + _vm->_graphicsManager._scrollStatus = 1; + showSaveGame(); + _vm->_graphicsManager._scrollStatus = 0; + break; + default: + break; + } + + _inventFl = false; + _vm->_eventsManager._gameKey = KEY_NONE; +} + +/** + * Load Game dialog + */ +void DialogsManager::showLoadGame() { + _vm->_eventsManager.VBL(); + showSaveLoad(2); + + int slotNumber; + do { + slotNumber = searchSavegames(); + _vm->_eventsManager.VBL(); + } while (!_vm->shouldQuit() && (!slotNumber || _vm->_eventsManager.getMouseButton() != 1)); + _vm->_objectsManager._saveLoadFl = false; + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, _vm->_eventsManager._startPos.x + 183, 60, 274, 353, _vm->_graphicsManager._vesaBuffer, _vm->_eventsManager._startPos.x + 183, 60); + _vm->_graphicsManager.addVesaSegment(_vm->_eventsManager._startPos.x + 183, 60, 457, 413); + _vm->_objectsManager.BOBTOUS = true; + _vm->_objectsManager._saveLoadSprite = _vm->_globals.freeMemory(_vm->_objectsManager._saveLoadSprite); + _vm->_objectsManager._saveLoadSprite2 = _vm->_globals.freeMemory(_vm->_objectsManager._saveLoadSprite2); + _vm->_objectsManager._saveLoadX = 0; + _vm->_objectsManager._saveLoadY = 0; + + if (slotNumber != 7) { + _vm->_saveLoadManager.loadGame(slotNumber); + } + + _vm->_objectsManager.changeObject(14); +} + +/** + * Save Game dialog + */ +void DialogsManager::showSaveGame() { + _vm->_eventsManager.VBL(); + + showSaveLoad(1); + int slotNumber; + do { + slotNumber = searchSavegames(); + _vm->_eventsManager.VBL(); + } while (!_vm->shouldQuit() && (!slotNumber || _vm->_eventsManager.getMouseButton() != 1)); + + _vm->_objectsManager._saveLoadFl = false; + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, _vm->_eventsManager._startPos.x + 183, 60, 274, 353, _vm->_graphicsManager._vesaBuffer, _vm->_eventsManager._startPos.x + 183, 60); + _vm->_graphicsManager.addVesaSegment(_vm->_eventsManager._startPos.x + 183, 60, _vm->_eventsManager._startPos.x + 457, 413); + _vm->_objectsManager.BOBTOUS = true; + _vm->_objectsManager._saveLoadSprite = _vm->_globals.freeMemory(_vm->_objectsManager._saveLoadSprite); + _vm->_objectsManager._saveLoadSprite2 = _vm->_globals.freeMemory(_vm->_objectsManager._saveLoadSprite2); + _vm->_objectsManager._saveLoadX = 0; + _vm->_objectsManager._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->_saveLoadManager.saveGame(slotNumber, saveName); + } +} + +/** + * Load/Save dialog + */ +void DialogsManager::showSaveLoad(int a1) { + 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->_objectsManager._saveLoadSprite = _vm->_objectsManager.loadSprite(filename); + _vm->_objectsManager._saveLoadSprite2 = _vm->_objectsManager.loadSprite("SAVE2.SPR"); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._saveLoadSprite, _vm->_eventsManager._startPos.x + 483, 360, 0); + + if (_vm->_globals._language == LANG_FR) { + if (a1 == 1) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._saveLoadSprite, _vm->_eventsManager._startPos.x + 525, 375, 1); + else if (a1 == 2) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._saveLoadSprite, _vm->_eventsManager._startPos.x + 515, 375, 2); + } else { + if (a1 == 1) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._saveLoadSprite, _vm->_eventsManager._startPos.x + 535, 372, 1); + else if (a1 == 2) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._saveLoadSprite, _vm->_eventsManager._startPos.x + 539, 372, 2); + } + + for (int slotNumber = 1; slotNumber <= 6; ++slotNumber) { + hopkinsSavegameHeader header; + if (_vm->_saveLoadManager.readSavegameHeader(slotNumber, header)) { + Graphics::Surface thumb8; + _vm->_saveLoadManager.convertThumb16To8(header._thumbnail, &thumb8); + + byte *thumb = (byte *)thumb8.pixels; + + switch (slotNumber) { + case 1: + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, thumb, _vm->_eventsManager._startPos.x + 190, 112, 128, 87); + break; + case 2: + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, thumb, _vm->_eventsManager._startPos.x + 323, 112, 128, 87); + break; + case 3: + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, thumb, _vm->_eventsManager._startPos.x + 190, 203, 128, 87); + break; + case 4: + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, thumb, _vm->_eventsManager._startPos.x + 323, 203, 128, 87); + break; + case 5: + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, thumb, _vm->_eventsManager._startPos.x + 190, 294, 128, 87); + break; + case 6: + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, thumb, _vm->_eventsManager._startPos.x + 323, 294, 128, 87); + break; + } + + thumb8.free(); + header._thumbnail->free(); + delete header._thumbnail; + } + } + + _vm->_graphicsManager.copySurfaceRect(_vm->_graphicsManager._vesaBuffer, _vm->_objectsManager._saveLoadSprite, _vm->_eventsManager._startPos.x + 183, 60, 274, 353); + _vm->_objectsManager._saveLoadFl = true; + _vm->_objectsManager._saveLoadX = 0; + _vm->_objectsManager._saveLoadY = 0; +} + +/** + * Search savegames + */ +int DialogsManager::searchSavegames() { + int xp = _vm->_eventsManager.getMouseX(); + int yp = _vm->_eventsManager.getMouseY(); + + _vm->_graphicsManager._scrollOffset = _vm->_eventsManager._startPos.x; + + int slotNumber = 0; + if (yp >= 112 && yp <= 198) { + if (xp > _vm->_eventsManager._startPos.x + 189 && xp < _vm->_eventsManager._startPos.x + 318) { + slotNumber = 1; + _vm->_objectsManager._saveLoadX = 189; + _vm->_objectsManager._saveLoadY = 111; + } else if (xp > _vm->_graphicsManager._scrollOffset + 322 && xp < _vm->_graphicsManager._scrollOffset + 452) { + slotNumber = 2; + _vm->_objectsManager._saveLoadX = 322; + _vm->_objectsManager._saveLoadY = 111; + } + } else if (yp >= 203 && yp <= 289) { + if (xp > _vm->_graphicsManager._scrollOffset + 189 && xp < _vm->_graphicsManager._scrollOffset + 318) { + slotNumber = 3; + _vm->_objectsManager._saveLoadX = 189; + _vm->_objectsManager._saveLoadY = 202; + } else if (xp > _vm->_graphicsManager._scrollOffset + 322 && xp < _vm->_graphicsManager._scrollOffset + 452) { + slotNumber = 4; + _vm->_objectsManager._saveLoadX = 322; + _vm->_objectsManager._saveLoadY = 202; + } + } else if (yp >= 294 && yp <= 380) { + if (xp > _vm->_graphicsManager._scrollOffset + 189 && xp < _vm->_graphicsManager._scrollOffset + 318) { + slotNumber = 5; + _vm->_objectsManager._saveLoadX = 189; + _vm->_objectsManager._saveLoadY = 293; + } else if (xp > _vm->_graphicsManager._scrollOffset + 322 && xp < _vm->_graphicsManager._scrollOffset + 452) { + slotNumber = 6; + _vm->_objectsManager._saveLoadX = 322; + _vm->_objectsManager._saveLoadY = 293; + } + } else if (yp >= 388 && yp <= 404 && xp > _vm->_graphicsManager._scrollOffset + 273 && xp < _vm->_graphicsManager._scrollOffset + 355) { + slotNumber = 7; + _vm->_objectsManager._saveLoadX = 0; + _vm->_objectsManager._saveLoadY = 0; + } else { + slotNumber = 0; + _vm->_objectsManager._saveLoadX = 0; + _vm->_objectsManager._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..fd35eca687 --- /dev/null +++ b/engines/hopkins/dialogs.h @@ -0,0 +1,66 @@ +/* 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" + +namespace Hopkins { + +class HopkinsEngine; + +/** + * Class for manging game dialogs + */ +class DialogsManager { +private: + HopkinsEngine *_vm; + + void showSaveLoad(int a1); + int searchSavegames(); +public: + byte *_inventWin1; + byte *_inventBuf2; + bool _removeInventFl; + bool _inventDisplayedFl; + bool _inventFl; + int _inventX, _inventY; + int _inventWidth, _inventHeight; + byte *_inventoryIcons; + + DialogsManager(); + ~DialogsManager(); + void setParent(HopkinsEngine *vm); + void inventAnim(); + void showInventory(); + void showLoadGame(); + void showSaveGame(); + void showOptionsDialog(); + void testDialogOpening(); +}; + +} // 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..d13f545eb5 --- /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() { + _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 = 0; + _priorFrameTime = 0; +} + +EventsManager::~EventsManager() { + _vm->_globals.freeMemory(_objectBuf); + _vm->_globals.freeMemory(_mouseCursor); +} + +void EventsManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +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->_fileManager.loadFile("SOUAN.SPR"); + else + _mouseCursor = _vm->_fileManager.loadFile("LSOUAN.SPR"); + break; + case LANG_FR: + if (!_mouseLinuxFl) + _mouseCursor = _vm->_fileManager.loadFile("SOUFR.SPR"); + else + _mouseCursor = _vm->_fileManager.loadFile("LSOUFR.SPR"); + break; + case LANG_SP: + _mouseCursor = _vm->_fileManager.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->_soundManager.checkSounds(); + + pollEvents(); +} + +void EventsManager::checkForNextFrameCounter() { + // 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; + g_system->updateScreen(); + + // Signal the ScummVM debugger + _vm->_debugger.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(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->_debugger.attach(); + _vm->_debugger.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 = ' '; + + VBL(); + } + + // Wait for keypress release + while (_keyState[(byte)foundChar] && !_vm->shouldQuit()) { + VBL(); + g_system->delayMillis(10); + } + + // Return character + return foundChar; +} + +void EventsManager::VBL() { + 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->_globals._objectWidth; + height = _vm->_globals._objectHeight; + } else { + if (_breakoutFl) { + if (xp < _vm->_graphicsManager._minX) + xp = _vm->_graphicsManager._minX; + if (_mousePos.y < _vm->_graphicsManager._minY) + yp = _vm->_graphicsManager._minY; + if (_mouseSizeX + xp >= _vm->_graphicsManager._maxX) + width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsManager._maxX); + if (yp + _mouseSizeY >= _vm->_graphicsManager._maxY) + height = _vm->_graphicsManager._maxY - yp; + } else { + if (xp < _vm->_graphicsManager._minX) + xp = _vm->_graphicsManager._minX - mouseWidth; + mouseHeight = (int16)mouseHeight; + if (_mousePos.y < _vm->_graphicsManager._minY - mouseHeight) + yp = _vm->_graphicsManager._minY - mouseHeight; + if (_mouseSizeX + xp >= _vm->_graphicsManager._maxX) + width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsManager._maxX - mouseWidth); + if (yp + _mouseSizeY >= mouseHeight + _vm->_graphicsManager._maxY) + height = _vm->_graphicsManager._maxY - mouseHeight - yp; + } + right = xp + width; + bottom = yp + height; + } + } + + if (!_vm->_globals._linuxEndDemoFl) + _vm->_objectsManager.displaySprite(); + if (!_mouseFl) { + updateCursor(); + } else if (_mouseCursorId == 23) { + if (yp < _vm->_graphicsManager._maxY && xp < _vm->_graphicsManager._maxX) { + if (width + xp > _vm->_graphicsManager._maxX) + width = _vm->_graphicsManager._maxX - xp; + if (yp + height > _vm->_graphicsManager._maxY) + height = _vm->_graphicsManager._maxY - yp; + if (width > 1 && height > 1) { + _vm->_eventsManager.updateCursor(); + } + } + } else if (yp < _vm->_graphicsManager._maxY && xp < _vm->_graphicsManager._maxX && width > 1 && height > 1) { + _vm->_eventsManager.updateCursor(); + _vm->_graphicsManager.addVesaSegment(xp, yp, right, bottom); + } + + _vm->_globals._speed = 2; + bool externalLoopFl = false; + do { + while (!_vm->shouldQuit()) { + checkForNextFrameCounter(); + bool innerLoopFl = false; + + while (_breakoutFl || _vm->_globals.iRegul != 1) { + 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.iRegul == 3 && _rateCounter <= 15); + _vm->_globals._speed = 2; + _rateCounter = 0; + if (!_vm->_graphicsManager._largeScreenFl || _vm->_graphicsManager._scrollStatus == 1) { + _vm->_graphicsManager.displayVesaSegment(); + } else { + if (_vm->_graphicsManager._scrollStatus != 2) { + if (getMouseX() > _vm->_graphicsManager._scrollPosX + 620) + _vm->_graphicsManager._scrollPosX += _vm->_graphicsManager._scrollSpeed; + if (getMouseX() < _vm->_graphicsManager._scrollPosX + 10) + _vm->_graphicsManager._scrollPosX -= _vm->_graphicsManager._scrollSpeed; + } + if (_vm->_graphicsManager._scrollPosX < 0) + _vm->_graphicsManager._scrollPosX = 0; + if (_vm->_graphicsManager._scrollPosX > SCREEN_WIDTH) + _vm->_graphicsManager._scrollPosX = SCREEN_WIDTH; + if (_vm->_graphicsManager._oldScrollPosX == _vm->_graphicsManager._scrollPosX) { + _vm->_graphicsManager.displayVesaSegment(); + } else { + _vm->_fontManager.hideText(9); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaBuffer, _vm->_graphicsManager._scrollPosX, 20, SCREEN_WIDTH, 440, 0, 20); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.dstrect[0] = Common::Rect(0, 20, SCREEN_WIDTH, 460); + + _vm->_graphicsManager.resetVesaSegment(); + + _startPos.x = _vm->_graphicsManager._scrollPosX; + _vm->_graphicsManager._scrollOffset = _vm->_graphicsManager._scrollPosX; + _vm->_graphicsManager._scrollPosX = _vm->_graphicsManager._scrollPosX; + } + _vm->_graphicsManager._oldScrollPosX = _vm->_graphicsManager._scrollPosX; + _startPos.x = _vm->_graphicsManager._scrollPosX; + _vm->_graphicsManager._scrollOffset = _vm->_graphicsManager._scrollPosX; + } + _curMouseButton = _mouseButton; + _mouseButton = 0; + _vm->_soundManager.checkSoundEnd(); + refreshEvents(); +} + +void EventsManager::updateCursor() { + // Backup the current sprite clipping bounds and reset them + Common::Rect clipBounds(_vm->_graphicsManager._minX, _vm->_graphicsManager._minY, + _vm->_graphicsManager._maxX, _vm->_graphicsManager._maxY); + _vm->_graphicsManager._minX = _vm->_graphicsManager._minY = 0; + _vm->_graphicsManager._maxX = _vm->_globals._objectWidth; + _vm->_graphicsManager._maxY = _vm->_globals._objectHeight; + int pitch = _vm->_graphicsManager._lineNbr2; + _vm->_graphicsManager._lineNbr2 = _vm->_globals._objectWidth; + + // Create the temporary cursor surface + byte *cursorSurface = new byte[_vm->_globals._objectHeight * _vm->_globals._objectWidth]; + Common::fill(cursorSurface, cursorSurface + _vm->_globals._objectHeight * _vm->_globals._objectWidth, 0); + + if (_mouseCursorId != 23) { + // Draw standard cursor + _vm->_graphicsManager.Sprite_Vesa(cursorSurface, _mouseCursor, 300, 300, _mouseSpriteId); + } else { + // Draw the active inventory object + _vm->_graphicsManager.Affiche_Perfect(cursorSurface, _objectBuf, 300, 300, 0, 0, 0, false); + } + + // Reset the clipping bounds + _vm->_graphicsManager._minX = clipBounds.left; + _vm->_graphicsManager._minY = clipBounds.top; + _vm->_graphicsManager._maxX = clipBounds.right; + _vm->_graphicsManager._maxY = clipBounds.bottom; + _vm->_graphicsManager._lineNbr2 = pitch; + + // Create a cursor palette + Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); + + byte *cursorPalette = new byte[3 * PALETTE_SIZE]; + uint16 *paletteColors = (uint16 *)_vm->_graphicsManager.PAL_PIXELS; + + 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->_globals._objectWidth, _vm->_globals._objectHeight, + 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..d4759dfe1b --- /dev/null +++ b/engines/hopkins/events.h @@ -0,0 +1,95 @@ +/* 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(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(); + ~EventsManager(); + void setParent(HopkinsEngine *vm); + 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 VBL(); +}; + +} // 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..e0cd1a3995 --- /dev/null +++ b/engines/hopkins/files.cpp @@ -0,0 +1,261 @@ +/* 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() { +} + +void FileManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +/** + * 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, int a2) { + byte *ptr = NULL; + Common::File f; + + Common::String filename = file; + Common::String secondaryFilename = ""; + filename.toUppercase(); + + switch (a2) { + case 1: + if (!f.exists("RES_INI.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_INI.CAT"); + secondaryFilename = "RES_INI.RES"; + break; + + case 2: + if (!f.exists("RES_REP.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_REP.CAT"); + secondaryFilename = "RES_REP.RES"; + break; + + case 3: + if (!f.exists("RES_LIN.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_LIN.CAT"); + secondaryFilename = "RES_LIN.RES"; + break; + + case 4: + if (!f.exists("RES_ANI.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_ANI.CAT"); + secondaryFilename = "RES_ANI.RES"; + break; + + case 5: + if (!f.exists("RES_PER.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_PER.CAT"); + secondaryFilename = "RES_PER.RES"; + break; + + case 6: + if (!f.exists("PIC.CAT")) + return g_PTRNUL; + + ptr = loadFile("PIC.CAT"); + break; + + case 7: + if (!f.exists("RES_SAN.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_SAN.CAT"); + break; + + case 8: + if (!f.exists("RES_SLI.CAT")) + return g_PTRNUL; + + ptr = loadFile("RES_SLI.CAT"); + break; + + case 9: { + 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)) + return g_PTRNUL; + + ptr = loadFile(tmpFilename); + break; + } + // Deliberate fall-through to + 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; + _vm->_globals._catalogPos = READ_LE_UINT32(pData + 15); + _vm->_globals._catalogSize = READ_LE_UINT32(pData + 19); + matchFlag = true; + } + + if (name == "FINIS") { + _vm->_globals.freeMemory(ptr); + return g_PTRNUL; + } + + offsetVal += 23; + } + + _vm->_globals.freeMemory(ptr); + + if (secondaryFilename != "") { + if (!f.open(secondaryFilename)) + error("CHARGE_FICHIER"); + + f.seek(_vm->_globals._catalogPos); + + byte *catData = _vm->_globals.allocMemory(_vm->_globals._catalogSize); + if (catData == g_PTRNUL) + error("CHARGE_FICHIER"); + + readStream(f, catData, _vm->_globals._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..55a57955b2 --- /dev/null +++ b/engines/hopkins/files.h @@ -0,0 +1,52 @@ +/* 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; + +class FileManager { +public: + HopkinsEngine *_vm; + + FileManager(); + void setParent(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, int a2); + 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..89d197b46b --- /dev/null +++ b/engines/hopkins/font.cpp @@ -0,0 +1,480 @@ +/* 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() { + clearAll(); +} + +FontManager::~FontManager() { + _vm->_globals.freeMemory(_font); +} + +void FontManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +void FontManager::clearAll() { + _font = g_PTRNUL; + _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 = g_PTRNUL; +} + +void FontManager::initData() { + _font = _vm->_fileManager.loadFile("FONTE3.SPR"); + _fontFixedWidth = 12; + _fontFixedHeight = 21; + +} +/** + * 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; + + _vm->_globals._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->_graphicsManager.restoreSurfaceRect( + _vm->_graphicsManager._vesaBuffer, + _text[idx]._textBlock, + xp, + yp, + _text[idx]._width, + _text[idx]._height); + _vm->_graphicsManager.addVesaSegment(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 == g_PTRNUL) + 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, _vm->_globals.BUF_ZONE + _index[messageId], 96); + WRITE_LE_UINT16((uint16 *)_tempText + 48, READ_LE_INT16(_vm->_globals.BUF_ZONE + _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; + _vm->_globals._boxWidth = 0; + + for (int curStrIdx = 0; curStrIdx < textLength + 1; curStrIdx++) { + byte curChar = _tempText[curStrIdx]; + if (curChar <= 31) + curChar = ' '; + _vm->_globals._boxWidth += _vm->_objectsManager.getWidth(_font, curChar - 32); + } + + _vm->_globals._boxWidth += 2; + _text[idx]._pos.x = 320 - abs(_vm->_globals._boxWidth / 2); + textPosX = _vm->_eventsManager._startPos.x + _text[idx]._pos.x; + lineCount = 1; + _text[idx]._lines[0] = Common::String((const char *)_tempText, textLength); + } else { + if (!_vm->_globals._boxWidth) + _vm->_globals._boxWidth = 240; + int tempTextIdx = 0; + int lineSize; + byte curChar; + do { + int curLineSize = 0; + int ptrb = _vm->_globals._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->_objectsManager.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]) + _vm->_globals._boxWidth = _textSortArray[i]; + } + + if ((_text[idx]._textType < 2) || (_text[idx]._textType > 3)) { + int i; + for (i = xp - _vm->_eventsManager._startPos.x; _vm->_globals._boxWidth + i > 638 && i > -2 && _text[idx]._textType; i -= 2) + ; + _text[idx]._pos.x = i; + textPosX = _vm->_eventsManager._startPos.x + i; + } else { + _text[idx]._pos.x = textPosX; + } + } + int posX = textPosX; + int posY = yp; + int saveWidth = _vm->_globals._boxWidth + 10; + int saveHeight = (_fontFixedHeight + 1) * lineCount + 12; + if (_text[idx]._textType == 6) { + _text[idx]._pos.x = 315 - abs(saveWidth / 2); + textPosX = posX = _vm->_eventsManager._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 == g_PTRNUL) + error("Cutting a block for text box (%d)", size); + + _vm->_graphicsManager.copySurfaceRect(_vm->_graphicsManager._vesaBuffer, ptrd, posX, posY, saveWidth, saveHeight); + _vm->_graphicsManager.Trans_bloc2(ptrd, _vm->_graphicsManager._colorTable, size); + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, ptrd, posX, posY, saveWidth, saveHeight); + _vm->_globals.freeMemory(ptrd); + + _vm->_graphicsManager.drawHorizontalLine(_vm->_graphicsManager._vesaBuffer, posX, posY, saveWidth, (byte)-2); + _vm->_graphicsManager.drawHorizontalLine(_vm->_graphicsManager._vesaBuffer, posX, saveHeight + posY, saveWidth, (byte)-2); + _vm->_graphicsManager.drawVerticalLine(_vm->_graphicsManager._vesaBuffer, posX, posY, saveHeight, (byte)-2); + _vm->_graphicsManager.drawVerticalLine(_vm->_graphicsManager._vesaBuffer, 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 == g_PTRNUL) + error("Cutting a block for text box (%d)", blockSize); + + _text[idx]._textBlock = ptre; + _text[idx]._width = blockWidth; + _text[idx]._height = blockHeight; + _vm->_graphicsManager.copySurfaceRect(_vm->_graphicsManager._vesaBuffer, _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 (;;) { + char currChar = *srcP++; + if (!currChar) + break; + if (currChar >= 32) { + charIndex = currChar - 32; + _vm->_graphicsManager.displayFont(_vm->_graphicsManager._vesaBuffer, _font, currentX, yp, currChar - 32, col); + currentX += _vm->_objectsManager.getWidth(_font, charIndex); + } + } + + _vm->_graphicsManager.addVesaSegment(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) { + char currentChar = message[idx]; + + if (currentChar > 31) { + int characterIndex = currentChar - 32; + _vm->_graphicsManager.displayFont(_vm->_graphicsManager._vesaBuffer, _font, xp, yp, characterIndex, col); + xp += _vm->_objectsManager.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->_graphicsManager.displayFont(_vm->_graphicsManager._vesaBuffer, _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->_objectsManager.getWidth(_font, printChar) - 1; + else if (curChar == 'm' || curChar == 'w') + charWidth = _vm->_objectsManager.getWidth(_font, printChar); + else + charWidth = 6; + } else + charWidth = _vm->_objectsManager.getWidth(_font, printChar); + + int charStartPosX = charEndPosX; + charEndPosX += charWidth; + _vm->_graphicsManager.addVesaSegment(charStartPosX, yp, charEndPosX, yp + 12); + if (_vm->_eventsManager._escKeyFl) { + _vm->_globals.iRegul = 1; + _vm->_eventsManager.VBL(); + } else { + _vm->_globals.iRegul = 4; + _vm->_eventsManager.VBL(); + _vm->_globals.iRegul = 1; + } + } + curChar = *srcP++; + } +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/font.h b/engines/hopkins/font.h new file mode 100644 index 0000000000..837539dd2f --- /dev/null +++ b/engines/hopkins/font.h @@ -0,0 +1,96 @@ +/* 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; + +public: + byte *_font; + int _fontFixedWidth; + int _fontFixedHeight; + TxtItem _text[12]; + TxtItemList _textList[12]; + + FontManager(); + ~FontManager(); + void setParent(HopkinsEngine *vm); + 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..a9a39e2b50 --- /dev/null +++ b/engines/hopkins/globals.cpp @@ -0,0 +1,431 @@ +/* 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 { + +// Global null pointer. This is needed by the engine to recognise NULL pointers, since +// there are places that differentiate between it and a 0 'error' value +byte *g_PTRNUL; + +// 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() { + // Set up the special g_PTRNUL variable + g_PTRNUL = (byte *)malloc(16); + strcpy((char *)g_PTRNUL, "POINTERNULL"); + + // Initialize array properties + for (int i = 0; i < 35; ++i) + Common::fill((byte *)&_animBqe[i], (byte *)&_animBqe[i] + sizeof(BqeAnimItem), 0); + for (int i = 0; i < 8; ++i) + Common::fill((byte *)&Bank[i], (byte *)&Bank[i] + sizeof(BankItem), 0); + 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); + for (int i = 0; i < 30; ++i) { + Common::fill((byte *)&_lockedAnims[i], (byte *)&_lockedAnims[i] + sizeof(LockAnimItem), 0); + Common::fill((byte *)&VBob[i], (byte *)&VBob[i] + sizeof(VBobItem), 0); + } + for (int i = 0; i < 300; ++i) + Common::fill((byte *)&_objectAuthIcons[i], (byte *)&_objectAuthIcons[i] + sizeof(ObjectAuthIcon), 0); + for (int i = 0; i < 25; ++i) + Common::fill((byte *)&_hidingItem[i], (byte *)&_hidingItem[i] + sizeof(HidingItem), 0); + + 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; + for (int i = 0; i < 51; ++i) + Common::fill((byte *)&_sortedDisplay[i], (byte *)&_sortedDisplay[i] + sizeof(SortItem), 0); + + // Initialize fields + _language = LANG_EN; + + _linuxEndDemoFl = false; + _speed = 1; + _oldFrameIndex = 0; + _oldDirection = DIR_NONE; + _oldDirectionSpriteIdx = 59; + _lastDirection = DIR_NONE; + _curObjectFileNum = 0; + _boxWidth = 0; + _objectWidth = _objectHeight = 0; + _catalogPos = 0; + _catalogSize = 0; + iRegul = 0; + _exitId = 0; + PERSO = 0; + _screenId = 0; + _prevScreenId = 0; + _characterMaxPosY = 0; + _menuScrollSpeed = 0; + _menuSpeed = 0; + _menuSoundOff = 0; + _menuVoiceOff = 0; + _menuMusicOff = 0; + _menuTextOff = 0; + _menuDisplayType = 0; + _sortedDisplayCount = 0; + _checkDistanceFl = false; + _characterType = 0; + _actionMoveTo = false; + Compteur = 0; + _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 + for (int i = 0; i < 6; ++i) + _hidingItemData[i] = g_PTRNUL; + BUF_ZONE = NULL; + SPRITE_ECRAN = NULL; + _saveData = NULL; + _answerBuffer = g_PTRNUL; + _objectDataBuf = NULL; + PERSO = NULL; + _optionDialogSpr = NULL; + + // Reset flags + _censorshipFl = false; + _disableInventFl = false; + _freezeCharacterFl = false; + _optionDialogFl = false; + _hidingActiveFl = false; + _introSpeechOffFl = false; + _baseMapColor = 50; + + // Reset indexed variables + _hotspotTextColor = 0; + _oldRouteFromX = 0; + _oldRouteFromY = 0; + _oldRouteDestX = 0; + _oldRouteDestY = 0; + _oldMouseZoneId = 0; + _oldZoneNum = 0; + _oldMouseX = 0; + _oldMouseY = 0; + compteur_71 = 0; + _forceHideText = false; +} + +Globals::~Globals() { + freeMemory(BUF_ZONE); + for (int idx = 0; idx < 6; ++idx) + _hidingItemData[idx] = freeMemory(_hidingItemData[idx]); + freeMemory(SPRITE_ECRAN); + freeMemory((byte *)_saveData); + freeMemory(_answerBuffer); + freeMemory(_objectDataBuf); + freeMemory(PERSO); + + clearVBob(); + + free(g_PTRNUL); +} + +void Globals::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +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() { + for (int idx = 0; idx < 6; ++idx) + _hidingItemData[idx] = g_PTRNUL; + + initAnimBqe(); + + _boxWidth = 0; + + _vm->_fontManager.clearAll(); + + initVBob(); + _objectDataBuf = g_PTRNUL; + _curObjectFileNum = 0; + _vm->_eventsManager._objectBuf = g_PTRNUL; + _vm->_dialogsManager._inventWin1 = g_PTRNUL; + _vm->_dialogsManager._inventBuf2 = g_PTRNUL; + _answerBuffer = g_PTRNUL; + SPRITE_ECRAN = g_PTRNUL; + _saveData = (Sauvegarde *)g_PTRNUL; + _vm->_objectsManager._curObjectIndex = 0; + + _vm->_linesManager.clearAll(); + _vm->_objectsManager.clearAll(); + + _saveData = (Sauvegarde *)malloc(sizeof(Sauvegarde)); + memset(_saveData, 0, sizeof(Sauvegarde)); + + _boxWidth = 240; + + _vm->_eventsManager._objectBuf = allocMemory(2500); + + _objectDataBuf = g_PTRNUL; +} + +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++; + } + + _oldFrameIndex = -1; + _oldDirection = DIR_NONE; +} + +void Globals::initAnimBqe() { + for (int idx = 0; idx < 35; ++idx) { + _animBqe[idx]._data = g_PTRNUL; + _animBqe[idx]._enabledFl = false; + } + + for (int idx = 0; idx < 8; ++idx) { + Bank[idx]._data = g_PTRNUL; + Bank[idx]._loadedFl = false; + Bank[idx]._filename = ""; + Bank[idx]._fileHeader = 0; + } +} + +void Globals::initVBob() { + for (int idx = 0; idx < 30; ++idx) { + VBob[idx].field4 = 0; + VBob[idx]._xp = 0; + VBob[idx]._yp = 0; + VBob[idx]._frameIndex = 0; + VBob[idx]._surface = g_PTRNUL; + VBob[idx]._spriteData = g_PTRNUL; + VBob[idx]._oldSpriteData = g_PTRNUL; + } +} + +void Globals::clearVBob() { + for (int idx = 0; idx < 30; ++idx) { + VBob[idx].field4 = 0; + VBob[idx]._xp = 0; + VBob[idx]._yp = 0; + VBob[idx]._frameIndex = 0; + VBob[idx]._surface = freeMemory(VBob[idx]._surface); + VBob[idx]._spriteData = g_PTRNUL; + VBob[idx]._oldSpriteData = g_PTRNUL; + } +} + +// Load Object +void Globals::loadObjects() { + byte *data = _vm->_fileManager.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++; + } + + freeMemory(data); +} + +byte *Globals::allocMemory(int count) { + byte *result = (byte *)malloc(count); + if (!result) + result = g_PTRNUL; + return result; +} + +byte *Globals::freeMemory(byte *p) { + if (p != g_PTRNUL) + free(p); + return g_PTRNUL; +} + +// Reset Hiding Items +void Globals::resetHidingItems() { + + for (int idx = 1; idx <= 5; ++idx) { + _hidingItemData[idx] = freeMemory(_hidingItemData[idx]); + } + + for (int idx = 0; idx <= 20; ++idx) { + HidingItem *hid = &_hidingItem[idx]; + hid->_spriteData = g_PTRNUL; + hid->_x = 0; + hid->_y = 0; + hid->_spriteIndex = 0; + hid->_useCount = 0; + hid->_width = 0; + hid->_height = 0; + hid->field10 = false; + hid->field14 = 0; + } + + _hidingActiveFl = false; +} + +void Globals::enableHiding() { + _hidingActiveFl = true; +} + +void Globals::disableHiding() { + _hidingActiveFl = false; +} + +void Globals::B_CACHE_OFF(int idx) { + assert(idx < 36); + _vm->_objectsManager._bob[idx].field34 = true; +} + +void Globals::resetHidingUseCount(int idx) { + _hidingItem[idx]._useCount = 0; +} + +void Globals::setHidingUseCount(int idx) { + _hidingItem[idx]._useCount = 1; +} + +// Load Hiding Items +void Globals::loadHidingItems(const Common::String &file) { + resetHidingItems(); + byte *ptr = _vm->_fileManager.loadFile(file); + Common::String filename = Common::String((const char *)ptr); + + Common::File f; + if (!f.exists(filename)) + return; + + byte *spriteData = _vm->_fileManager.loadFile(filename); + _hidingItemData[1] = spriteData; + int curBufIdx = 60; + for (int i = 0; i <= 21; i++) { + _hidingItem[i]._spriteIndex = READ_LE_INT16((uint16 *)ptr + curBufIdx); + _hidingItem[i]._x = READ_LE_INT16((uint16 *)ptr + curBufIdx + 1); + _hidingItem[i]._y = READ_LE_INT16((uint16 *)ptr + curBufIdx + 2); + _hidingItem[i].field14 = READ_LE_INT16((uint16 *)ptr + curBufIdx + 4); + if (spriteData == g_PTRNUL) { + _hidingItem[i]._useCount = 0; + } else { + _hidingItem[i]._spriteData = spriteData; + _hidingItem[i]._width = _vm->_objectsManager.getWidth(spriteData, _hidingItem[i]._spriteIndex); + _hidingItem[i]._height = _vm->_objectsManager.getHeight(spriteData, _hidingItem[i]._spriteIndex); + _hidingItem[i]._useCount = 1; + } + + if ( !_hidingItem[i]._x && !_hidingItem[i]._y && !_hidingItem[i]._spriteIndex) + _hidingItem[i]._useCount = 0; + curBufIdx += 5; + } + enableHiding(); + freeMemory(ptr); +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/globals.h b/engines/hopkins/globals.h new file mode 100644 index 0000000000..9986abb810 --- /dev/null +++ b/engines/hopkins/globals.h @@ -0,0 +1,353 @@ +/* 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 BqeAnimItem { + byte *_data; + bool _enabledFl; +}; + +struct BankItem { + byte *_data; + bool _loadedFl; + Common::String _filename; + int _fileHeader; + int _objDataIdx; +}; + +struct ListeItem { + bool _visibleFl; + int _posX; + int _posY; + int _width; + int _height; +}; + +struct LockAnimItem { + bool _enableFl; + int _posX; +}; + +struct VBobItem { + byte *_spriteData; + int field4; + int _xp; + int _yp; + int _frameIndex; + byte *_surface; + int _oldX; + int _oldY; + int _oldFrameIndex; + byte *_oldSpriteData; +}; + +struct ObjectAuthIcon { + byte _objectFileNum; + byte _idx; + byte _flag1; + byte _flag2; + byte _flag3; + byte _flag4; + byte _flag5; + byte _flag6; +}; + +/** + * 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; +}; + +struct HidingItem { + int _x; + int _y; + int _spriteIndex; + int _width; + int _height; + int _useCount; + byte *_spriteData; + bool field10; + int field14; +}; + +struct HopkinsItem { + int _speedX; + int _speedY; +}; + +struct CharacterLocation { + Common::Point _pos; + int _startSpriteIndex; + int _location; + int _zoomFactor; +}; + +enum SauvegardeOffset { + svField1 = 1 + , svField2 = 2 + , svField3 = 3 + , svField4 = 4 + , svField5 = 5 + , svField6 = 6 + , svField8 = 8 + , svField9 = 9 + , svField10 = 10 + , svField13 = 13 + , svField80 = 80 + , svField94 = 94 + , svField95 = 95 + , svField113 = 113 + , svField117 = 117 + , svField121 = 121 + , svField122 = 122 + , svField123 = 123 + , svField132 = 132 + , svField133 = 133 + , svField135 = 135 + , svField166 = 166 + , svField167 = 167 + , svField170 = 170 + , svField171 = 171 + , svField172 = 172 + , svField173 = 173 + , svField176 = 176 + , svField177 = 177 + , svField180 = 180 + , svField181 = 181 + , svField182 = 182 + , svField183 = 183 + , svField184 = 184 + , svField185 = 185 + , svField186 = 186 + , svField187 = 187 + , svField188 = 188 + , svField189 = 189 + , svField190 = 190 + , svField191 = 191 + , svField192 = 192 + , svField193 = 193 + , svField194 = 194 + , svField220 = 220 + , svField225 = 225 + , svField228 = 228 + , svField231 = 231 + , svField253 = 253 + , svField261 = 261 + , svField270 = 270 + , svField300 = 300 + , svField311 = 311 + , svField312 = 312 + , svField318 = 318 + , svField320 = 320 + , svField330 = 330 + , svField333 = 333 + , svField338 = 338 + , svField339 = 339 + , svField340 = 340 + , svField341 = 341 + , svField349 = 349 + , svField352 = 352 + , svField353 = 353 + , svField354 = 354 + , svField355 = 355 + , svField356 = 356 + , svField357 = 357 + , svField399 = 399 + , svField401 = 401 +}; + +// TODO: Sauvegrade1 fields should really be mapped into data array +struct Sauvegarde { + 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 _colour; + 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 +}; + + +class HopkinsEngine; + +/** + * Engine Globals + */ +class Globals { +private: + HopkinsEngine *_vm; + + void initAnimBqe(); + void initVBob(); + +public: + bool _disableInventFl; + bool _cityMapEnabledFl; + bool _linuxEndDemoFl; + bool _censorshipFl; + bool _introSpeechOffFl; + bool _hidingActiveFl; + bool _forceHideText; + int _exitId; + Directions _oceanDirection; + Directions _oldDirection; + int _oldDirectionSpriteIdx; + int _actionDirection; + Directions _lastDirection; + int _oldFrameIndex; + int _hotspotTextColor; + int _inventory[36]; + int _objectWidth, _objectHeight; + int _screenId; + int _prevScreenId; + int _boxWidth; + int _characterMaxPosY; + int _baseMapColor; + int _spriteSize[500]; + int _sortedDisplayCount; + int _oldMouseZoneId; + int _oldMouseX, _oldMouseY; + int _characterType; + uint _speed; + byte *_answerBuffer; + Sauvegarde *_saveData; + Language _language; + HopkinsItem _hopkinsItem[70]; + SortItem _sortedDisplay[51]; + + 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; + uint32 _catalogPos; + uint32 _catalogSize; + LockAnimItem _lockedAnims[30]; + int _oldRouteFromX; + int _oldRouteFromY; + int _oldRouteDestX; + int _oldRouteDestY; + int _oldZoneNum; + + bool _actionMoveTo; + bool _freezeCharacterFl; + bool _checkDistanceFl; + byte *_hidingItemData[6]; + HidingItem _hidingItem[25]; + BqeAnimItem _animBqe[35]; + ObjectAuthIcon _objectAuthIcons[300]; + int _curObjectFileNum; + byte *_objectDataBuf; + Common::String _zoneFilename; + Common::String _textFilename; + + int iRegul; + byte *BUF_ZONE; + byte *SPRITE_ECRAN; + byte *PERSO; + ListeItem Liste[6]; + ListeItem Liste2[35]; + BankItem Bank[8]; + VBobItem VBob[30]; + int Compteur; + int compteur_71; + + Globals(); + ~Globals(); + void setParent(HopkinsEngine *vm); + byte *allocMemory(int count); + byte *freeMemory(byte *p); + void setConfig(); + void loadObjects(); + void clearAll(); + void loadCharacterData(); + void resetHidingItems(); + void loadHidingItems(const Common::String &file); + void enableHiding(); + void disableHiding(); + void resetHidingUseCount(int idx); + void setHidingUseCount(int idx); + void clearVBob(); + + void B_CACHE_OFF(int idx); +}; + +// Global null pointer +extern byte *g_PTRNUL; + +} // 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..b299082394 --- /dev/null +++ b/engines/hopkins/graphics.cpp @@ -0,0 +1,1828 @@ +/* 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() { + _lockCounter = 0; + _initGraphicsFl = false; + _screenWidth = _screenHeight = 0; + WinScan = 0; + PAL_PIXELS = NULL; + _lineNbr = 0; + _videoPtr = NULL; + _scrollOffset = 0; + _scrollPosX = 0; + _largeScreenFl = false; + _oldScrollPosX = 0; + NBBLOC = 0; + + _lineNbr2 = 0; + Agr_x = Agr_y = 0; + Agr_Flag_x = Agr_Flag_y = false; + _fadeDefaultSpeed = 15; + FADE_LINUX = 0; + _skipVideoLockFl = false; + _scrollStatus = 0; + _minX = 0; + _minY = 20; + _maxX = SCREEN_WIDTH * 2; + _maxY = SCREEN_HEIGHT - 20; + _posXClipped = _posYClipped = 0; + clip_x1 = clip_y1 = 0; + _clipFl = false; + Red_x = Red_y = 0; + Red = 0; + _width = 0; + _specialWidth = 0; + + Common::fill(&SD_PIXELS[0], &SD_PIXELS[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); + + for (int i = 0; i < 250; ++i) + Common::fill((byte *)&BLOC[i], (byte *)&BLOC[i] + sizeof(BlocItem), 0); + +} + +GraphicsManager::~GraphicsManager() { + _vm->_globals.freeMemory(_vesaScreen); + _vm->_globals.freeMemory(_vesaBuffer); +} + +void GraphicsManager::setParent(HopkinsEngine *vm) { + _vm = vm; + + if (_vm->getIsDemo()) { + if (_vm->getPlatform() == Common::kPlatformLinux) + // CHECKME: Should be false? + MANU_SCROLL = true; + else + MANU_SCROLL = false; + _scrollSpeed = 16; + } else { + MANU_SCROLL = false; + _scrollSpeed = 32; + } +} + +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 + _vesaScreen = _vm->_globals.allocMemory(SCREEN_WIDTH * 2 * SCREEN_HEIGHT); + _vesaBuffer = _vm->_globals.allocMemory(SCREEN_WIDTH * 2 * SCREEN_HEIGHT); + + _videoPtr = NULL; + _screenWidth = width; + _screenHeight = height; + + // Clear the screen pitch. This will be set on the first lockScreen call + WinScan = 0; + + PAL_PIXELS = SD_PIXELS; + _lineNbr = width; + + _initGraphicsFl = true; + } else { + error("setGraphicalMode called multiple times"); + } +} + +/** + * (try to) Lock Screen + */ +void GraphicsManager::lockScreen() { + if (!_skipVideoLockFl) { + if (_lockCounter++ == 0) { + _videoPtr = g_system->lockScreen(); + if (WinScan == 0) + WinScan = _videoPtr->pitch; + } + } +} + +/** + * (try to) Unlock Screen + */ +void GraphicsManager::unlockScreen() { + assert(_videoPtr); + if (--_lockCounter == 0) { + g_system->unlockScreen(); + _videoPtr = NULL; + } +} + +/** + * Clear Screen + */ +void GraphicsManager::clearScreen() { + assert(_videoPtr); + _videoPtr->fillRect(Common::Rect(0, 0, _screenWidth, _screenHeight), 0); +} + +/** + * 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) { + SCANLINE(SCREEN_WIDTH); + lockScreen(); + clearScreen(); + unlockScreen(); + loadPCX320(_vesaScreen, file, _palette); + memcpy(_vesaBuffer, _vesaScreen, 64000); + SCANLINE(320); + _maxX = 320; + + lockScreen(); + copy16bFromSurfaceScaleX2(_vesaBuffer); + unlockScreen(); + + fadeInBreakout(); +} + +/** + * Load Screen + */ +void GraphicsManager::loadScreen(const Common::String &file) { + Common::File f; + + bool flag = true; + if (_vm->_fileManager.searchCat(file, 6) == g_PTRNUL) { + if (!f.open(file)) + error("loadScreen - %s", file.c_str()); + + f.seek(0, SEEK_END); + f.close(); + flag = false; + } + + scrollScreen(0); + loadPCX640(_vesaScreen, file, _palette, flag); + + _scrollPosX = 0; + _oldScrollPosX = 0; + clearPalette(); + + if (!_largeScreenFl) { + SCANLINE(SCREEN_WIDTH); + _maxX = SCREEN_WIDTH; + lockScreen(); + clearScreen(); + m_scroll16(_vesaScreen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + unlockScreen(); + } else { + SCANLINE(SCREEN_WIDTH * 2); + _maxX = SCREEN_WIDTH * 2; + lockScreen(); + clearScreen(); + unlockScreen(); + + if (MANU_SCROLL) { + lockScreen(); + m_scroll16(_vesaScreen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + unlockScreen(); + } + } + + memcpy(_vesaBuffer, _vesaScreen, SCREEN_WIDTH * 2 * SCREEN_HEIGHT); +} + +void GraphicsManager::initColorTable(int minIndex, int maxIndex, byte *palette) { + for (int idx = 0; idx < 256; ++idx) + _colorTable[idx] = idx; + + Trans_bloc(_colorTable, palette, 256, minIndex, maxIndex); + + for (int idx = 0; idx < 256; ++idx) { + byte v = _colorTable[idx]; + if (v > 27) + _colorTable[idx] = 0; + if (!v) + _colorTable[idx] = 0; + } + + _colorTable[0] = 1; +} + +/** + * Scroll Screen + */ +void GraphicsManager::scrollScreen(int amount) { + int result = CLIP(amount, 0, SCREEN_WIDTH); + _vm->_eventsManager._startPos.x = result; + _scrollOffset = result; + _scrollPosX = result; +} + +void GraphicsManager::Trans_bloc(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::Trans_bloc2(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->_globals._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 +// CHECKME: Some versions of the game don't include it, some contains nothing more than +// than a loop doing nothing, some others just map the last value. While debugging, it +// seems that this function is called once the palette is already cleared, so it would be useless +// This code could most likely be removed. +void GraphicsManager::clearPalette() { + uint16 col0 = mapRGB(0, 0, 0); + for (int i = 0; i < 512; i += 2) + WRITE_LE_UINT16(&SD_PIXELS[i], col0); +} + +void GraphicsManager::SCANLINE(int pitch) { + _lineNbr = _lineNbr2 = pitch; +} + +/** + * Copies data from a 8-bit palette surface into the 16-bit screen + */ +void GraphicsManager::m_scroll16(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->pixels + destX * 2 + WinScan * 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] = PAL_PIXELS[lineSrcP[0] * 2]; + lineDestP[1] = PAL_PIXELS[(lineSrcP[0] * 2) + 1]; + lineDestP += 2; + lineSrcP++; + } + // Move to the start of the next line + srcP += _lineNbr2; + destP += WinScan; + } + + unlockScreen(); +} + +// TODO: See if PAL_PIXELS can be converted to a uint16 array +void GraphicsManager::m_scroll16A(const byte *surface, int xs, int ys, int width, int height, int destX, int destY) { + int xCtr; + const byte *palette; + int yCtr; + const byte *srcCopyP; + byte *destCopyP; + + assert(_videoPtr); + const byte *srcP = xs + _lineNbr2 * ys + surface; + byte *destP = (byte *)_videoPtr->pixels + destX + destX + WinScan * destY; + int yNext = height; + Agr_x = 0; + Agr_y = 0; + Agr_Flag_y = false; + + do { + for (;;) { + destCopyP = destP; + srcCopyP = srcP; + xCtr = width; + yCtr = yNext; + palette = PAL_PIXELS; + Agr_x = 0; + + do { + destP[0] = palette[2 * srcP[0]]; + destP[1] = palette[(2 * srcP[0]) + 1]; + destP += 2; + if (Agr_x >= 100) { + Agr_x -= 100; + destP[0] = palette[2 * srcP[0]]; + destP[1] = palette[(2 * srcP[0]) + 1]; + destP += 2; + } + ++srcP; + --xCtr; + } while (xCtr); + + yNext = yCtr; + srcP = srcCopyP; + destP = WinScan + destCopyP; + if (Agr_Flag_y) + break; + + if (Agr_y >= 0 && Agr_y < 100) + break; + + Agr_y -= 100; + Agr_Flag_y = true; + } + + Agr_Flag_y = false; + srcP = _lineNbr2 + srcCopyP; + yNext = yCtr - 1; + } while (yCtr != 1); +} + +void GraphicsManager::Copy_Vga16(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->pixels + 30 * WinScan + destX + destX + destX + destX + WinScan * 2 * destY; + int yCount = height; + int xCount = width; + + do { + yCtr = yCount; + xCtr = xCount; + loopSrcP = srcP; + loopDestP = destP; + savedXCount = xCount; + palette = PAL_PIXELS; + + do { + destP[0] = destP[2] = destP[WinScan] = destP[WinScan + 2] = palette[2 * srcP[0]]; + destP[1] = destP[3] = destP[WinScan + 1] = destP[WinScan + 3] = palette[(2 * srcP[0]) + 1]; + ++srcP; + destP += 4; + --xCtr; + } while (xCtr); + + xCount = savedXCount; + destP = loopDestP + WinScan * 2; + srcP = loopSrcP + 320; + yCount = yCtr - 1; + } while (yCtr != 1); +} + +/** + * 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); + m_scroll16(surface, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + DD_VBL(); + + // Added a delay in order to see the fading + _vm->_eventsManager.delay(20); + } + + // Set the final palette + setPaletteVGA256(palette); + + // Refresh the screen + m_scroll16(surface, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + DD_VBL(); +} + +/** + * 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->_eventsManager._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); + m_scroll16(surface, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + DD_VBL(); + + _vm->_eventsManager.delay(20); + } + } + + // No initial palette, or end of fading + for (int i = 0; i < PALETTE_BLOCK_SIZE; i++) + palData[i] = 0; + + setPaletteVGA256(palData); + m_scroll16(surface, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + return DD_VBL(); +} + +/** + * 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 *)_vesaBuffer); +} + +/** + * 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 *)_vesaBuffer); +} + +/** + * 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 *)_vesaBuffer); +} + +/** + * 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 *)_vesaBuffer); +} + +/** + * 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); + lockScreen(); + copy16bFromSurfaceScaleX2(_vesaBuffer); + unlockScreen(); + DD_VBL(); +} + +/** + * Fade out used by for the breakout mini-game + */ +void GraphicsManager::fateOutBreakout() { + byte palette[PALETTE_EXT_BLOCK_SIZE]; + + memset(palette, 0, PALETTE_EXT_BLOCK_SIZE); + setPaletteVGA256(palette); + + lockScreen(); + copy16bFromSurfaceScaleX2(_vesaBuffer); + unlockScreen(); + DD_VBL(); +} + +void GraphicsManager::setPaletteVGA256(const byte *palette) { + changePalette(palette); +} + +void GraphicsManager::setPaletteVGA256WithRefresh(const byte *palette, const byte *surface) { + changePalette(palette); + m_scroll16(surface, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + DD_VBL(); +} + +void GraphicsManager::SETCOLOR3(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::SETCOLOR4(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_LE_UINT16(&SD_PIXELS[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_LE_UINT16(&SD_PIXELS[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::DD_VBL() { + // TODO: Is this okay here? + 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; + assert(_videoPtr); + + for (;;) { + byte srcByte = srcP[0]; + if (srcByte >= 222) { + if (srcByte == kByteStop) + return; + 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); + return; + } + + if (srcByte > 210) { + if (srcByte == 211) { + int pixelCount = srcP[1]; + int pixelIndex = srcP[2]; + byte *destP = (byte *)_videoPtr->pixels + destOffset * 2; + destOffset += pixelCount; + + while (pixelCount--) { + destP[0] = PAL_PIXELS[2 * pixelIndex]; + destP[1] = PAL_PIXELS[(2 * pixelIndex) + 1]; + destP += 2; + } + + srcP += 3; + } else { + int pixelCount = srcByte - 211; + int pixelIndex = srcP[1]; + byte *destP = (byte *)_videoPtr->pixels + destOffset * 2; + destOffset += pixelCount; + + while (pixelCount--) { + destP[0] = PAL_PIXELS[2 * pixelIndex]; + destP[1] = PAL_PIXELS[(2 * pixelIndex) + 1]; + destP += 2; + } + + srcP += 2; + } + } else { + byte *destP = (byte *)_videoPtr->pixels + destOffset * 2; + destP[0] = PAL_PIXELS[2 * srcByte]; + destP[1] = PAL_PIXELS[(2 * srcByte) + 1]; + ++srcP; + ++destOffset; + } + } +} + +void GraphicsManager::copyVideoVbe16a(const byte *srcData) { + byte srcByte; + int destOffset = 0; + const byte *srcP = srcData; + + for (;;) { + srcByte = srcP[0]; + if (srcByte == kByteStop) + return; + 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->pixels + destOffset * 2, READ_LE_UINT16(PAL_PIXELS + 2 * srcByte)); + ++srcP; + ++destOffset; + } +} + +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::Sprite_Vesa(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 + clip_x1 = width; + if ((xp + width) <= _minX + 300) + return; + if (xp < _minX + 300) { + _posXClipped = _minX + 300 - xp; + _clipFl = true; + } + + // Clip Y + clip_y1 = 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; + + clip_x1 = 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; + + // clip_y1 is always positive thanks to the previous check + clip_y1 = 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 < clip_y1; ++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 < clip_x1) + *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->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.hideBob(idx); + } + + _vm->_eventsManager.VBL(); + _vm->_eventsManager.VBL(); + + for (int idx = 1; idx <= 20; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.resetBob(idx); + } + + for (int idx = 1; idx <= 29; ++idx) { + _vm->_globals._lockedAnims[idx]._enableFl = false; + } + + for (int idx = 1; idx <= 20; ++idx) { + _vm->_globals._animBqe[idx]._enabledFl = false; + } +} + +void GraphicsManager::displayAllBob() { + for (int idx = 1; idx <= 20; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.displayBob(idx); + } +} + +void GraphicsManager::resetVesaSegment() { + for (int idx = 0; idx <= NBBLOC; idx++) + BLOC[idx]._activeFl = false; + + NBBLOC = 0; +} + +// Add VESA Segment +void GraphicsManager::addVesaSegment(int x1, int y1, int x2, int y2) { + int tempX = x1; + bool addFlag = true; + if (x2 > _maxX) + x2 = _maxX; + if (y2 > _maxY) + y2 = _maxY; + if (x1 < _minX) + tempX = _minX; + if (y1 < _minY) + y1 = _minY; + + for (int blocIndex = 0; blocIndex <= NBBLOC; blocIndex++) { + BlocItem &bloc = BLOC[blocIndex]; + if (bloc._activeFl && tempX >= bloc._x1 && x2 <= bloc._x2 && y1 >= bloc._y1 && y2 <= bloc._y2) + addFlag = false; + }; + + if (addFlag) { + assert(NBBLOC < 250); + BlocItem &bloc = BLOC[++NBBLOC]; + + bloc._activeFl = true; + bloc._x1 = tempX; + bloc._x2 = x2; + bloc._y1 = y1; + bloc._y2 = y2; + } +} + +// Display VESA Segment +void GraphicsManager::displayVesaSegment() { + if (NBBLOC == 0) + return; + + lockScreen(); + + for (int idx = 1; idx <= NBBLOC; ++idx) { + BlocItem &bloc = BLOC[idx]; + Common::Rect &dstRect = dstrect[idx - 1]; + if (!bloc._activeFl) + continue; + + if (_vm->_eventsManager._breakoutFl) { + Copy_Vga16(_vesaBuffer, bloc._x1, bloc._y1, bloc._x2 - bloc._x1, bloc._y2 - bloc._y1, bloc._x1, bloc._y1); + dstRect.left = bloc._x1 * 2; + dstRect.top = bloc._y1 * 2 + 30; + dstRect.setWidth((bloc._x2 - bloc._x1) * 2); + dstRect.setHeight((bloc._y2 - bloc._y1) * 2); + } else if (bloc._x2 > _vm->_eventsManager._startPos.x && bloc._x1 < _vm->_eventsManager._startPos.x + SCREEN_WIDTH) { + if (bloc._x1 < _vm->_eventsManager._startPos.x) + bloc._x1 = _vm->_eventsManager._startPos.x; + if (bloc._x2 > _vm->_eventsManager._startPos.x + SCREEN_WIDTH) + bloc._x2 = _vm->_eventsManager._startPos.x + SCREEN_WIDTH; + + // WORKAROUND: Original didn't lock the screen for access + lockScreen(); + m_scroll16(_vesaBuffer, bloc._x1, bloc._y1, bloc._x2 - bloc._x1, bloc._y2 - bloc._y1, bloc._x1 - _vm->_eventsManager._startPos.x, bloc._y1); + + dstRect.left = bloc._x1 - _vm->_eventsManager._startPos.x; + dstRect.top = bloc._y1; + dstRect.setWidth(bloc._x2 - bloc._x1); + dstRect.setHeight(bloc._y2 - bloc._y1); + + unlockScreen(); + } + + BLOC[idx]._activeFl = false; + } + + NBBLOC = 0; + unlockScreen(); +} + +void GraphicsManager::AFFICHE_SPEEDVGA(const byte *objectData, int xp, int yp, int idx, bool addSegment) { + int width = _vm->_objectsManager.getWidth(objectData, idx); + int height = _vm->_objectsManager.getHeight(objectData, idx); + if (*objectData == 78) { + Affiche_Perfect(_vesaScreen, objectData, xp + 300, yp + 300, idx, 0, 0, false); + Affiche_Perfect(_vesaBuffer, objectData, xp + 300, yp + 300, idx, 0, 0, false); + } else { + Sprite_Vesa(_vesaBuffer, objectData, xp + 300, yp + 300, idx); + Sprite_Vesa(_vesaScreen, objectData, xp + 300, yp + 300, idx); + } + if (addSegment) + addVesaSegment(xp, yp, xp + width, yp + height); +} + +/** + * Copy from surface to video buffer, scale 2x. + */ +void GraphicsManager::copy16bFromSurfaceScaleX2(const byte *surface) { + byte *palPtr; + int curPixel; + + assert(_videoPtr); + const byte *curSurface = surface; + byte *destPtr = 30 * WinScan + (byte *)_videoPtr->pixels; + for (int y = 200; y; y--) { + byte *oldDestPtr = destPtr; + for (int x = 320; x; x--) { + curPixel = 2 * *curSurface; + palPtr = PAL_PIXELS + curPixel; + destPtr[0] = destPtr[2] = destPtr[WinScan] = destPtr[WinScan + 2] = palPtr[0]; + destPtr[1] = destPtr[3] = destPtr[WinScan + 1] = destPtr[WinScan + 3] = palPtr[1]; + ++curSurface; + destPtr += 4; + } + destPtr = WinScan * 2 + oldDestPtr; + } +} + +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::Affiche_Perfect(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; + clip_x1 = 0; + clip_y1 = 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 + clip_x1 = _maxX + 300 - xp300; + clip_y1 = _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) { + Agr_x = 0; + Agr_y = 0; + Agr_Flag_y = false; + Agr_Flag_x = false; + _width = spriteWidth; + int zoomedWidth = zoomIn(spriteWidth, zoom2); + int zoomedHeight = zoomIn(spriteHeight1, zoom2); + if (flipFl) { + byte *v29 = zoomedWidth + dest1P; + if (_posYClipped) { + if (_posYClipped < 0 || _posYClipped >= zoomedHeight) + return; + int v30 = 0; + while (zoomIn(++v30, zoom2) < _posYClipped) + ; + spritePixelsP += _width * v30; + v29 += _lineNbr2 * _posYClipped; + zoomedHeight -= _posYClipped; + } + if (zoomedHeight > clip_y1) + zoomedHeight = clip_y1; + if (_posXClipped) { + if (_posXClipped >= zoomedWidth) + return; + zoomedWidth -= _posXClipped; + } + if (zoomedWidth > clip_x1) { + int v32 = zoomedWidth - clip_x1; + v29 -= v32; + int v33 = 0; + while (zoomIn(++v33, zoom2) < v32) + ; + spritePixelsP += v33; + zoomedWidth = clip_x1; + } + int v63; + do { + for (;;) { + v63 = zoomedHeight; + byte *v53 = v29; + const byte *oldSpritePixelsP = spritePixelsP; + Agr_Flag_x = false; + Agr_x = 0; + for (int v35 = zoomedWidth; v35; Agr_Flag_x = false, v35--) { + for (;;) { + if (*spritePixelsP) + *v29 = *spritePixelsP; + --v29; + ++spritePixelsP; + if (!Agr_Flag_x) + Agr_x += zoom2; + if (Agr_x >= 0 && Agr_x < 100) + break; + Agr_x -= 100; + --spritePixelsP; + Agr_Flag_x = true; + --v35; + if (!v35) + break; + } + } + spritePixelsP = _width + oldSpritePixelsP; + v29 = _lineNbr2 + v53; + if (!Agr_Flag_y) + Agr_y += zoom2; + if ((uint16)Agr_y < 100) + break; + Agr_y -= 100; + spritePixelsP = oldSpritePixelsP; + Agr_Flag_y = true; + zoomedHeight = v63 - 1; + if (v63 == 1) + return; + } + Agr_Flag_y = false; + zoomedHeight = v63 - 1; + } while (v63 != 1); + } else { + if (_posYClipped) { + if (_posYClipped >= zoomedHeight) + return; + int v23 = 0; + while (zoomIn(++v23, zoom2) < _posYClipped) + ; + spritePixelsP += _width * v23; + dest1P += _lineNbr2 * _posYClipped; + zoomedHeight -= _posYClipped; + } + if (zoomedHeight > clip_y1) + zoomedHeight = clip_y1; + if (_posXClipped) { + if (_posXClipped >= zoomedWidth) + return; + int v26 = 0; + while (zoomIn(++v26, zoom2) < _posXClipped) + ; + spritePixelsP += v26; + dest1P += _posXClipped; + zoomedWidth = zoomedWidth - _posXClipped; + } + if (zoomedWidth > clip_x1) + zoomedWidth = clip_x1; + + int v60; + do { + for (;;) { + v60 = zoomedHeight; + byte *oldDest1P = dest1P; + const byte *oldSpritePixelsP = spritePixelsP; + Agr_Flag_x = false; + Agr_x = 0; + for (int v28 = zoomedWidth; v28; Agr_Flag_x = false, v28--) { + for (;;) { + if (*spritePixelsP) + *dest1P = *spritePixelsP; + ++dest1P; + ++spritePixelsP; + if (!Agr_Flag_x) + Agr_x += zoom2; + if ((uint16)Agr_x < 100) + break; + Agr_x -= 100; + --spritePixelsP; + Agr_Flag_x = true; + --v28; + if (!v28) + break; + } + } + spritePixelsP = _width + oldSpritePixelsP; + dest1P = _lineNbr2 + oldDest1P; + if (!Agr_Flag_y) + Agr_y += zoom2; + if ((uint16)Agr_y < 100) + break; + Agr_y -= 100; + spritePixelsP = oldSpritePixelsP; + Agr_Flag_y = true; + zoomedHeight = v60 - 1; + if (v60 == 1) + return; + } + Agr_Flag_y = false; + zoomedHeight = v60 - 1; + } while (v60 != 1); + } + } else if (zoom1) { + Red_x = 0; + Red_y = 0; + _width = spriteWidth; + Red = zoom1; + if (zoom1 < 100) { + int v37 = zoomOut(spriteWidth, Red); + if (flipFl) { + byte *v40 = v37 + dest1P; + do { + int v65 = spriteHeight2; + byte *v55 = v40; + Red_y += Red; + if ((uint16)Red_y < 100) { + Red_x = 0; + int v42 = v37; + for (int v41 = _width; v41; v41--) { + Red_x += Red; + if ((uint16)Red_x < 100) { + if (v42 >= _posXClipped && v42 < clip_x1 && *spritePixelsP) + *v40 = *spritePixelsP; + --v40; + ++spritePixelsP; + --v42; + } else { + Red_x -= 100; + ++spritePixelsP; + } + } + spriteHeight2 = v65; + v40 = _lineNbr2 + v55; + } else { + Red_y -= 100; + spritePixelsP += _width; + } + --spriteHeight2; + } while (spriteHeight2); + } else { + do { + int oldSpriteHeight = spriteHeight2; + byte *oldDest1P = dest1P; + Red_y += Red; + if ((uint16)Red_y < 100) { + Red_x = 0; + int v39 = 0; + for (int i = _width; i; i--) { + Red_x += Red; + if ((uint16)Red_x < 100) { + if (v39 >= _posXClipped && v39 < clip_x1 && *spritePixelsP) + *dest1P = *spritePixelsP; + ++dest1P; + ++spritePixelsP; + ++v39; + } else { + Red_x -= 100; + ++spritePixelsP; + } + } + spriteHeight2 = oldSpriteHeight; + dest1P = _lineNbr2 + oldDest1P; + } else { + Red_y -= 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 > clip_y1) + spriteHeight1 = clip_y1; + + if (_posXClipped >= spriteWidth) + return; + spriteWidth -= _posXClipped; + + if (spriteWidth > clip_x1) { + int clippedWidth = spriteWidth - clip_x1; + spritePixelsP += clippedWidth; + dest2P -= clippedWidth; + spriteWidth = clip_x1; + } + 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 > clip_y1) + spriteHeight1 = clip_y1; + if (_posXClipped) { + if (_posXClipped >= spriteWidth) + return; + spritePixelsP += _posXClipped; + dest1P += _posXClipped; + spriteWidth -= _posXClipped; + } + if (spriteWidth > clip_x1) + spriteWidth = clip_x1; + 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); + } + } +} + +/** + * Fast Display + */ +void GraphicsManager::fastDisplay(const byte *spriteData, int xp, int yp, int spriteIndex, bool addSegment) { + int width = _vm->_objectsManager.getWidth(spriteData, spriteIndex); + int height = _vm->_objectsManager.getHeight(spriteData, spriteIndex); + + if (*spriteData == 78) { + Affiche_Perfect(_vesaScreen, spriteData, xp + 300, yp + 300, spriteIndex, 0, 0, false); + Affiche_Perfect(_vesaBuffer, spriteData, xp + 300, yp + 300, spriteIndex, 0, 0, false); + } else { + Sprite_Vesa(_vesaBuffer, spriteData, xp + 300, yp + 300, spriteIndex); + Sprite_Vesa(_vesaScreen, spriteData, xp + 300, yp + 300, spriteIndex); + } + if (addSegment) + addVesaSegment(xp, yp, xp + width, yp + height); +} + +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; + Copy_Mem(surface, left, top, croppedWidth, croppedHeight, destSurface, destX, destY); + addVesaSegment(left, top, left + croppedWidth, top + height2); + } +} + +void GraphicsManager::Copy_Mem(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 colour) { + 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 = colour; + *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"; + byte *ptr = _vm->_fileManager.searchCat(filename, 1); + + if (ptr == g_PTRNUL) { + ptr = _vm->_fileManager.loadFile(filename); + } + if (!mode) { + filename = file + ".spr"; + _vm->_globals.SPRITE_ECRAN = _vm->_globals.freeMemory(_vm->_globals.SPRITE_ECRAN); + if (initializeScreen) { + _vm->_globals.SPRITE_ECRAN = _vm->_fileManager.searchCat(filename, 8); + if (_vm->_globals.SPRITE_ECRAN) { + _vm->_globals.SPRITE_ECRAN = _vm->_fileManager.loadFile(filename); + } else { + _vm->_globals.SPRITE_ECRAN = _vm->_fileManager.loadFile("RES_SLI.RES"); + } + } + } + if (READ_BE_UINT24(ptr) != MKTAG24('I', 'N', 'I')) { + error("Error, file not ini"); + } else { + bool doneFlag = false; + int dataOffset = 1; + + do { + int dataVal1 = _vm->_scriptManager.handleOpcode(ptr + 20 * dataOffset); + if (_vm->shouldQuit()) + return; + + if (dataVal1 == 2) + dataOffset = _vm->_scriptManager.handleGoto((ptr + 20 * dataOffset)); + if (dataVal1 == 3) + dataOffset = _vm->_scriptManager.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"; + byte *dataP = _vm->_fileManager.searchCat(filename, 2); + if (dataP == g_PTRNUL) + dataP = _vm->_fileManager.loadFile(filename); + + _vm->_globals._answerBuffer = dataP; + _vm->_objectsManager._forceZoneFl = true; + _vm->_objectsManager._changeVerbFl = false; +} + +void GraphicsManager::NB_SCREEN(bool initPalette) { + if (initPalette) + initColorTable(50, 65, _palette); + + if (_lineNbr == SCREEN_WIDTH) + Trans_bloc2(_vesaBuffer, _colorTable, SCREEN_WIDTH * SCREEN_HEIGHT); + else if (_lineNbr == (SCREEN_WIDTH * 2)) + Trans_bloc2(_vesaBuffer, _colorTable, SCREEN_WIDTH * SCREEN_HEIGHT * 2); + + lockScreen(); + m_scroll16(_vesaBuffer, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + unlockScreen(); + + memcpy(_vesaScreen, _vesaBuffer, 614399); + DD_VBL(); +} + +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::Reduc_Ecran(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; + Red = zoom; + _width = width; + Red_x = 0; + Red_y = 0; + if (zoom < 100) { + for (int yCtr = 0; yCtr < height; ++yCtr, srcP += _lineNbr2) { + Red_y += Red; + if (Red_y < 100) { + Red_x = 0; + const byte *lineSrcP = srcP; + + for (int xCtr = 0; xCtr < _width; ++xCtr) { + Red_x += Red; + if (Red_x < 100) { + *destP++ = *lineSrcP++; + } else { + Red_x -= 100; + ++lineSrcP; + } + } + } else { + Red_y -= 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; + } +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/graphics.h b/engines/hopkins/graphics.h new file mode 100644 index 0000000000..6dc8ec6849 --- /dev/null +++ b/engines/hopkins/graphics.h @@ -0,0 +1,178 @@ +/* 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/endian.h" +#include "common/rect.h" +#include "common/str.h" +#include "graphics/surface.h" + +namespace Hopkins { + +#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; +}; + +struct BlocItem { + uint16 _activeFl; + int _x1; + int _y1; + int _x2; + int _y2; +}; + +class HopkinsEngine; + +class GraphicsManager { +private: + HopkinsEngine *_vm; + + int _lockCounter; + bool _initGraphicsFl; + int _screenWidth; + int _screenHeight; + Graphics::Surface *_videoPtr; + int _width; + int _posXClipped, _posYClipped; + bool _clipFl; + int _specialWidth; + + byte SD_PIXELS[PALETTE_SIZE * 2]; + int Agr_x, Agr_y; + bool Agr_Flag_x, Agr_Flag_y; + int clip_x1, clip_y1; + int Red_x, Red_y; + int Red; + + 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 Trans_bloc(byte *destP, const byte *srcP, int count, int minThreshold, int maxThreshold); + void Copy_Vga16(const byte *surface, int xp, int yp, int width, int height, int destX, int destY); + void copy16bFromSurfaceScaleX2(const byte *surface); +public: + int _lineNbr; + byte _colorTable[PALETTE_EXT_BLOCK_SIZE]; + byte _palette[PALETTE_EXT_BLOCK_SIZE]; + byte _oldPalette[PALETTE_EXT_BLOCK_SIZE]; + byte *_vesaScreen; + byte *_vesaBuffer; + int _scrollOffset; + int _scrollPosX; + bool _largeScreenFl; + int _oldScrollPosX; + int _scrollSpeed; + int _lineNbr2; + int _minX, _minY; + int _maxX, _maxY; + bool _noFadingFl; + Common::Rect dstrect[50]; + int _scrollStatus; + bool _skipVideoLockFl; + int _fadeDefaultSpeed; + + int NBBLOC; + BlocItem BLOC[250]; + int WinScan; + byte *PAL_PIXELS; + bool MANU_SCROLL; + int FADE_LINUX; +public: + GraphicsManager(); + ~GraphicsManager(); + + void setParent(HopkinsEngine *vm); + void lockScreen(); + void unlockScreen(); + void clearPalette(); + void clearScreen(); + void addVesaSegment(int x1, int y1, int x2, int y2); + 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 fateOutBreakout(); + void fadeOutLong(); + void fadeOutShort(); + void fastDisplay(const byte *spriteData, int xp, int yp, int spriteIndex, bool addSegment = true); + void displayVesaSegment(); + void resetVesaSegment(); + 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 colour); + 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 SETCOLOR3(int palIndex, int r, int g, int b); + void SETCOLOR4(int palIndex, int r, int g, int b); + void AFFICHE_SPEEDVGA(const byte *objectData, int xp, int yp, int idx, bool addSegment = true); + void DD_VBL(); + void Affiche_Perfect(byte *surface, const byte *srcData, int xp300, int yp300, int frameIndex, int zoom1, int zoom2, bool flipFl); + void Copy_Mem(const byte *srcSurface, int x1, int y1, uint16 width, int height, byte *destSurface, int destX, int destY); + void SCANLINE(int pitch); + void Sprite_Vesa(byte *surface, const byte *spriteData, int xp, int yp, int spriteIndex); + void m_scroll16(const byte *surface, int xs, int ys, int width, int height, int destX, int destY); + void m_scroll16A(const byte *surface, int xs, int ys, int width, int height, int destX, int destY); + void Trans_bloc2(byte *surface, byte *col, int size); + void NB_SCREEN(bool initPalette); + void Reduc_Ecran(const byte *srcSruface, byte *destSurface, int xp, int yp, int width, int height, int zoom); +}; + +} // 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..3d4d152229 --- /dev/null +++ b/engines/hopkins/hopkins.cpp @@ -0,0 +1,2890 @@ +/* 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"), _animationManager() { + g_vm = this; + _debugger.setParent(this); + _animationManager.setParent(this); + _computerManager.setParent(this); + _dialogsManager.setParent(this); + _eventsManager.setParent(this); + _fileManager.setParent(this); + _fontManager.setParent(this); + _globals.setParent(this); + _graphicsManager.setParent(this); + _linesManager.setParent(this); + _menuManager.setParent(this); + _objectsManager.setParent(this); + _saveLoadManager.setParent(this); + _scriptManager.setParent(this); + _soundManager.setParent(this); + _talkManager.setParent(this); +} + +HopkinsEngine::~HopkinsEngine() { +} + +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 && _eventsManager._mouseFl; +} + +/** + * Returns true if it is currently okay to save the game + */ +bool HopkinsEngine::canSaveGameStateCurrently() { + return !_globals._exitId && !_globals._cityMapEnabledFl && _eventsManager._mouseFl; +} + +/** + * Load the savegame at the specified slot index + */ +Common::Error HopkinsEngine::loadGameState(int slot) { + return _saveLoadManager.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 _saveLoadManager.saveGame(slot, desc); +} + +Common::Error HopkinsEngine::run() { + _saveLoadManager.initSaves(); + + _globals.setConfig(); + _fileManager.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() { + _globals.loadObjects(); + _objectsManager.changeObject(14); + _objectsManager.addObject(14); + _objectsManager._helicopterFl = false; + + _globals.iRegul = 1; + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + + _graphicsManager.loadImage("H2"); + _graphicsManager.fadeInLong(); + + if (!_eventsManager._escKeyFl) + playIntro(); + + _eventsManager._rateCounter = 0; + _globals.iRegul = 1; + _globals._speed = 1; + + for (int i = 1; i < 50; i++) { + _graphicsManager.copySurface(_graphicsManager._vesaScreen, 0, 0, 640, 440, _graphicsManager._vesaBuffer, 0, 0); + _eventsManager.VBL(); + } + + _globals.iRegul = 0; + if (_eventsManager._rateCounter > 475) + _globals._speed = 2; + if (_eventsManager._rateCounter > 700) + _globals._speed = 3; + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + _globals.PERSO = _fileManager.loadFile("PERSO.SPR"); + _globals._characterType = 0; + _objectsManager._mapCarPosX = _objectsManager._mapCarPosY = 0; + memset(_globals._saveData, 0, 2000); + _globals._exitId = 0; + + if (getLanguage() != Common::PL_POL) + if (!displayAdultDisclaimer()) + return Common::kNoError; + + for (;;) { + if (_globals._exitId == 300) + _globals._exitId = 0; + + if (!_globals._exitId) { + _globals._exitId = _menuManager.menu(); + if (_globals._exitId == -1) { + _globals.PERSO = _globals.freeMemory(_globals.PERSO); + restoreSystem(); + return false; + } + } + + if (g_system->getEventManager()->shouldQuit()) + return false; + + switch (_globals._exitId) { + case 1: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM01", "IM01", "ANIM01", "IM01", 2, true); + break; + + case 3: + if (!_globals._saveData->_data[svField170]) { + _soundManager.playSound(3); + if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS) + _graphicsManager.loadImage("fond"); + else { + if (_globals._language == LANG_FR) + _graphicsManager.loadImage("fondfr"); + else if (_globals._language == LANG_EN) + _graphicsManager.loadImage("fondan"); + else if (_globals._language == LANG_SP) + _graphicsManager.loadImage("fondes"); + } + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + _soundManager._specialSoundNum = 2; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + if (!_globals._censorshipFl) + _animationManager.playAnim("BANQUE.ANM", 200, 28, 200); + else + _animationManager.playAnim("BANKUK.ANM", 200, 28, 200); + _soundManager._specialSoundNum = 0; + _soundManager.removeSample(1); + _soundManager.removeSample(2); + _soundManager.removeSample(3); + _soundManager.removeSample(4); + _graphicsManager.fadeOutLong(); + _globals._saveData->_data[svField170] = 1; + } + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM03", "IM03", "ANIM03", "IM03", 2, false); + break; + + case 4: + _globals._disableInventFl = true; + _objectsManager.handleCityMap(); + _globals._disableInventFl = false; + break; + + case 5: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 455; + + if (_globals._saveData->_data[svField80]) { + if (_globals._saveData->_data[svField80] == 1) + _objectsManager.PERSONAGE2("IM05", "IM05A", "ANIM05B", "IM05", 3, false); + } else { + _objectsManager.PERSONAGE2("IM05", "IM05", "ANIM05", "IM05", 3, false); + } + break; + + case 6: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 460; + _objectsManager.PERSONAGE2("IM06", "IM06", "ANIM06", "IM06", 2, true); + break; + + case 7: + if (_globals._saveData->_data[svField220]) + _objectsManager.PERSONAGE("BOMBEB", "BOMBE", "BOMBE", "BOMBE", 2, true); + else + _objectsManager.PERSONAGE("BOMBEA", "BOMBE", "BOMBE", "BOMBE", 2, true); + break; + + case 8: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM08", "IM08", "ANIM08", "IM08", 2, true); + break; + + case 9: + _globals._characterMaxPosY = 440; + _linesManager.setMaxLineIdx(20); + if (_globals._saveData->_data[svField225]) + _objectsManager.PERSONAGE2("IM09", "IM09", "ANIM09", "IM09", 10, true); + else + bombExplosion(); + break; + + case 10: + _objectsManager.PERSONAGE("IM10", "IM10", "ANIM10", "IM10", 9, false); + break; + + case 11: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM11", "IM11", "ANIM11", "IM11", 2, false); + break; + + case 12: + _globals._characterMaxPosY = 450; + _linesManager.setMaxLineIdx(20); + if (_globals._saveData->_data[svField225]) { + if (_globals._language == LANG_FR) + _graphicsManager.loadImage("ENDFR"); + else + _graphicsManager.loadImage("ENDUK"); + _graphicsManager.fadeInLong(); + _eventsManager.mouseOn(); + do + _eventsManager.VBL(); + while (_eventsManager.getMouseButton() != 1); + _graphicsManager.fadeOutLong(); + restoreSystem(); + } + 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: + _objectsManager.PERSONAGE("IM111", "IM111", "ANIM111", "IM111", 10, false); + break; + + case 112: + _objectsManager.PERSONAGE("IM112", "IM112", "ANIM112", "IM112", 10, false); + break; + + case 113: + _globals._exitId = 0; + _globals._prevScreenId = _globals._screenId; + _globals._saveData->_data[svField6] = _globals._screenId; + _globals._screenId = 113; + _globals._saveData->_data[svField5] = _globals._screenId; + _computerManager.showComputer(COMPUTER_HOPKINS); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.DD_VBL(); + memset(_graphicsManager._vesaBuffer, 0, 307200); + memset(_graphicsManager._vesaScreen, 0, 307200); + _graphicsManager.clearPalette(); + _graphicsManager.resetVesaSegment(); + break; + + case 114: + _globals._prevScreenId = _globals._screenId; + _globals._saveData->_data[svField6] = _globals._screenId; + _globals._screenId = 114; + _globals._saveData->_data[svField5] = _globals._screenId; + _globals._exitId = 0; + _computerManager.showComputer(COMPUTER_SAMANTHA); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + break; + + case 115: + _globals._exitId = 0; + _globals._prevScreenId = _globals._screenId; + _globals._saveData->_data[svField6] = _globals._screenId; + _globals._screenId = 115; + _globals._saveData->_data[svField5] = _globals._screenId; + _computerManager.showComputer(COMPUTER_PUBLIC); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + break; + + case 150: + _soundManager.playSound(28); + _globals.iRegul = 4; // CHECKME! + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _animationManager.playAnim("JOUR1A.anm", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + + case 151: + _soundManager.playSound(28); + _globals.iRegul = 4; // CHECKME! + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _graphicsManager.loadImage("njour3a"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(5000); + _graphicsManager.fadeOutLong(); + _globals._exitId = 300; + _globals.iRegul = 0; + break; + + case 152: + _soundManager.playSound(28); + _globals.iRegul = 4; // CHECKME! + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _animationManager.playAnim("JOUR4A.anm", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + } + } + return true; +} + +bool HopkinsEngine::runLinuxDemo() { + _globals.loadObjects(); + _objectsManager.changeObject(14); + _objectsManager.addObject(14); + _objectsManager._helicopterFl = false; + + _eventsManager.mouseOff(); + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + + _graphicsManager.loadImage("LINUX"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(1500); + _graphicsManager.fadeOutLong(); + + _graphicsManager.loadImage("H2"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + + if (!_eventsManager._escKeyFl) + playIntro(); + + _globals.iRegul = 0; + _globals.PERSO = _fileManager.loadFile("PERSO.SPR"); + _globals._characterType = 0; + _objectsManager._mapCarPosX = _objectsManager._mapCarPosY = 0; + memset(_globals._saveData, 0, 2000); + _globals._exitId = 0; + + for (;;) { + if (_globals._exitId == 300) + _globals._exitId = 0; + + if (!_globals._exitId) { + _globals._exitId = _menuManager.menu(); + if (_globals._exitId == -1) { + if (!g_system->getEventManager()->shouldQuit()) + endLinuxDemo(); + _globals.PERSO = _globals.freeMemory(_globals.PERSO); + restoreSystem(); + } + } + + if (g_system->getEventManager()->shouldQuit()) + return false; + + 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: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM01", "IM01", "ANIM01", "IM01", 1, true); + break; + + case 3: + if (!_globals._saveData->_data[svField170]) { + _soundManager.playSound(3); + if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS) + _graphicsManager.loadImage("fond"); + else { + if (_globals._language == LANG_FR) + _graphicsManager.loadImage("fondfr"); + else if (_globals._language == LANG_EN) + _graphicsManager.loadImage("fondan"); + else if (_globals._language == LANG_SP) + _graphicsManager.loadImage("fondes"); + } + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + _soundManager._specialSoundNum = 2; + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _graphicsManager.FADE_LINUX = 2; + + if (!_globals._censorshipFl) + _animationManager.playAnim("BANQUE.ANM", 200, 28, 200); + else + _animationManager.playAnim("BANKUK.ANM", 200, 28, 200); + _soundManager._specialSoundNum = 0; + _soundManager.removeSample(1); + _soundManager.removeSample(2); + _soundManager.removeSample(3); + _soundManager.removeSample(4); + _globals._saveData->_data[svField170] = 1; + } + + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM03", "IM03", "ANIM03", "IM03", 2, false); + break; + + case 4: + _globals._disableInventFl = true; + _objectsManager.handleCityMap(); + _globals._disableInventFl = false; + break; + + case 5: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 455; + if (_globals._saveData->_data[svField80] == 1) + _objectsManager.PERSONAGE2("IM05", "IM05A", "ANIM05B", "IM05", 3, false); + else + _objectsManager.PERSONAGE2("IM05", "IM05", "ANIM05", "IM05", 3, false); + break; + + case 6: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 460; + _objectsManager.PERSONAGE2("IM06", "IM06", "ANIM06", "IM06", 2, true); + break; + + case 7: + if (_globals._saveData->_data[svField220]) + _objectsManager.PERSONAGE("BOMBEB", "BOMBE", "BOMBE", "BOMBE", 2, true); + else + _objectsManager.PERSONAGE("BOMBEA", "BOMBE", "BOMBE", "BOMBE", 2, true); + break; + + case 8: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM08", "IM08", "ANIM08", "IM08", 2, true); + break; + + case 9: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 440; + + if (!_globals._saveData->_data[svField225]) + bombExplosion(); + + _objectsManager.PERSONAGE2("IM09", "IM09", "ANIM09", "IM09", 10, true); + break; + + case 10: + _objectsManager.PERSONAGE("IM10", "IM10", "ANIM10", "IM10", 9, false); + break; + + case 11: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM11", "IM11", "ANIM11", "IM11", 2, false); + break; + + case 12: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 450; + if (_globals._saveData->_data[svField225]) + _objectsManager.PERSONAGE2("IM12", "IM12", "ANIM12", "IM12", 1, false); + else + bombExplosion(); + break; + + case 13: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM13", "IM13", "ANIM13", "IM13", 1, true); + break; + + case 14: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM14", "IM14", "ANIM14", "IM14", 1, true); + break; + + case 15: + _objectsManager.PERSONAGE("IM15", "IM15", "ANIM15", "IM15", 29, false); + break; + + case 16: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + + if (_globals._saveData->_data[svField113] == 1) { + _objectsManager.PERSONAGE2("IM16", "IM16A", "ANIM16", "IM16", 7, true); + } else if (!_globals._saveData->_data[svField113]) { + _objectsManager.PERSONAGE2("IM16", "IM16", "ANIM16", "IM16", 7, true); + } + break; + + case 25: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM25", "IM25", "ANIM25", "IM25", 30, true); + break; + + case 26: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM26", "IM26", "ANIM26", "IM26", 30, true); + + case 33: + _objectsManager.PERSONAGE("IM33", "IM33", "ANIM33", "IM33", 8, false); + break; + + case 35: + displayEndDemo(); + break; + + case 111: + _objectsManager.PERSONAGE("IM111", "IM111", "ANIM111", "IM111", 10, false); + break; + + case 112: + _objectsManager.PERSONAGE("IM112", "IM112", "ANIM112", "IM112", 10, false); + break; + + case 113: + _globals._exitId = 0; + _globals._prevScreenId = _globals._screenId; + _globals._saveData->_data[svField6] = _globals._screenId; + _globals._screenId = 113; + _globals._saveData->_data[svField5] = 113; + _computerManager.showComputer(COMPUTER_HOPKINS); + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.DD_VBL(); + memset(_graphicsManager._vesaBuffer, 0, 307200); + memset(_graphicsManager._vesaScreen, 0, 307200); + _graphicsManager.clearPalette(); + _graphicsManager.resetVesaSegment(); + break; + + case 114: + _globals._exitId = 0; + _globals._prevScreenId = _globals._screenId; + _globals._saveData->_data[svField6] = _globals._screenId; + _globals._screenId = 114; + _globals._saveData->_data[svField5] = 114; + _computerManager.showComputer(COMPUTER_SAMANTHA); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + break; + + case 115: + _globals._exitId = 0; + _globals._prevScreenId = _globals._screenId; + _globals._saveData->_data[svField6] = _globals._screenId; + _globals._screenId = 115; + _globals._saveData->_data[svField5] = 115; + _computerManager.showComputer(COMPUTER_PUBLIC); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + break; + + case 150: + _soundManager.playSound(16); + _globals.iRegul = 1; + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR1A.anm", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + + case 151: + _soundManager.playSound(16); + _globals.iRegul = 1; + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR3A.anm", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + + case 152: + _soundManager.playSound(16); + _globals.iRegul = 1; + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR4A.anm", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + } + } + return true; +} + +bool HopkinsEngine::runFull() { + if (getPlatform() == Common::kPlatformLinux) + _soundManager.playSound(16); + + _globals.loadObjects(); + _objectsManager.changeObject(14); + _objectsManager.addObject(14); + + if (getPlatform() == Common::kPlatformLinux) { + _objectsManager._helicopterFl = false; + _eventsManager.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) { + _objectsManager._helicopterFl = false; + _globals.iRegul = 1; + // 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 + _graphicsManager.loadImage("VERSW"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + } else { + // This piece of code, though named "display_version" in the original, + // displays a "loading please wait" screen. + _graphicsManager.loadImage("VERSW"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + } + + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + + if (getPlatform() == Common::kPlatformLinux) { + _graphicsManager.loadImage("H2"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + + _globals._speed = 2; + _globals.iRegul = 1; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("MP.ANM", 10, 16, 200); + } else { + _animationManager.playAnim("MP.ANM", 10, 16, 200); + _graphicsManager.fadeOutLong(); + } + + if (!_eventsManager._escKeyFl) + playIntro(); + if (getPlatform() != Common::kPlatformLinux) { + _graphicsManager.fadeOutShort(); + _graphicsManager.loadImage("H2"); + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + } + _globals.iRegul = 0; + _globals.PERSO = _fileManager.loadFile("PERSO.SPR"); + _globals._characterType = 0; + _objectsManager._mapCarPosX = _objectsManager._mapCarPosY = 0; + memset(_globals._saveData, 0, 2000); + + _globals._exitId = 0; + + for (;;) { + if (_globals._exitId == 300) + _globals._exitId = 0; + if (!_globals._exitId) { + _globals._exitId = _menuManager.menu(); + if (_globals._exitId == -1) { + _globals.PERSO = _globals.freeMemory(_globals.PERSO); + restoreSystem(); + return false; + } + } + + if (g_system->getEventManager()->shouldQuit()) + return false; + + switch (_globals._exitId) { + case 1: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM01", "IM01", "ANIM01", "IM01", 1, true); + break; + + case 3: + if (!_globals._saveData->_data[svField170]) { + _soundManager.playSound(3); + if (getPlatform() == Common::kPlatformOS2 || getPlatform() == Common::kPlatformBeOS) + _graphicsManager.loadImage("fond"); + else { + if (_globals._language == LANG_FR) + _graphicsManager.loadImage("fondfr"); + else if (_globals._language == LANG_EN) + _graphicsManager.loadImage("fondan"); + else if (_globals._language == LANG_SP) + _graphicsManager.loadImage("fondes"); + } + _graphicsManager.fadeInLong(); + _eventsManager.delay(500); + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + _soundManager._specialSoundNum = 2; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) { + if (getPlatform() == Common::kPlatformLinux) + _graphicsManager.FADE_LINUX = 2; + + if (!_globals._censorshipFl) + _animationManager.playAnim("BANQUE.ANM", 200, 28, 200); + else + _animationManager.playAnim("BANKUK.ANM", 200, 28, 200); + } else { + _animationManager.playAnim("BANQUE.ANM", 200, 28, 200); + } + _soundManager._specialSoundNum = 0; + _soundManager.removeSample(1); + _soundManager.removeSample(2); + _soundManager.removeSample(3); + _soundManager.removeSample(4); + if (getPlatform() != Common::kPlatformLinux) + _graphicsManager.fadeOutLong(); + _globals._saveData->_data[svField170] = 1; + } + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM03", "IM03", "ANIM03", "IM03", 2, false); + break; + + case 4: + _globals._disableInventFl = true; + _objectsManager.handleCityMap(); + _globals._disableInventFl = false; + break; + + case 5: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 455; + if (_globals._saveData->_data[svField80] == 1) + _objectsManager.PERSONAGE2("IM05", "IM05A", "ANIM05B", "IM05", 3, false); + else + _objectsManager.PERSONAGE2("IM05", "IM05", "ANIM05", "IM05", 3, false); + break; + + case 6: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 460; + _objectsManager.PERSONAGE2("IM06", "IM06", "ANIM06", "IM06", 2, true); + break; + + case 7: + if (_globals._saveData->_data[svField220]) + _objectsManager.PERSONAGE("BOMBEB", "BOMBE", "BOMBE", "BOMBE", 2, true); + else + _objectsManager.PERSONAGE("BOMBEA", "BOMBE", "BOMBE", "BOMBE", 2, true); + break; + + case 8: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM08", "IM08", "ANIM08", "IM08", 2, true); + break; + + case 9: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 440; + if (_globals._saveData->_data[svField225]) + _objectsManager.PERSONAGE2("IM09", "IM09", "ANIM09", "IM09", 10, true); + else + bombExplosion(); + break; + + case 10: + _objectsManager.PERSONAGE("IM10", "IM10", "ANIM10", "IM10", 9, false); + break; + + case 11: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 450; + _objectsManager.PERSONAGE2("IM11", "IM11", "ANIM11", "IM11", 2, false); + break; + + case 12: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 450; + if (_globals._saveData->_data[svField225]) + _objectsManager.PERSONAGE2("IM12", "IM12", "ANIM12", "IM12", 1, false); + else + bombExplosion(); + break; + + case 13: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM13", "IM13", "ANIM13", "IM13", 1, true); + break; + + case 14: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM14", "IM14", "ANIM14", "IM14", 1, true); + break; + + case 15: + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) + _objectsManager.PERSONAGE("IM15", "IM15", "ANIM15", "IM15", 29, false); + else + _objectsManager.PERSONAGE("IM15", "IM15", "ANIM15", "IM15", 18, false); + break; + + case 16: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + if (_globals._saveData->_data[svField113] == 1) + _objectsManager.PERSONAGE2("IM16", "IM16A", "ANIM16", "IM16", 7, true); + else + _objectsManager.PERSONAGE2("IM16", "IM16", "ANIM16", "IM16", 7, true); + break; + + case 17: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 440; + if (_globals._saveData->_data[svField117] == 1) + _objectsManager.PERSONAGE2("IM17", "IM17A", "ANIM17", "IM17", 11, true); + else if (!_globals._saveData->_data[svField117]) + _objectsManager.PERSONAGE2("IM17", "IM17", "ANIM17", "IM17", 11, true); + if (_globals._exitId == 18) { + _globals.iRegul = 1; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _soundManager.stopSound(); + if (getPlatform() == Common::kPlatformLinux) { + _soundManager.playSound(29); + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("PURG1A.ANM", 12, 18, 50); + } else if (getPlatform() == Common::kPlatformWindows) { + _soundManager.playSound(29); + _animationManager.playAnim("PURG1A.ANM", 12, 18, 50); + _graphicsManager.fadeOutShort(); + } else { + _soundManager.playSound(6); + _animationManager.playAnim("PURG1A.ANM", 12, 18, 50); + _graphicsManager.fadeOutShort(); + } + _globals.iRegul = 0; + } + break; + + case 18: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) + _objectsManager.PERSONAGE2("IM18", "IM18", "ANIM18", "IM18", 29, false); + else + _objectsManager.PERSONAGE2("IM18", "IM18", "ANIM18", "IM18", 6, false); + break; + + case 19: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 440; + if (_globals._saveData->_data[svField123]) + _objectsManager.PERSONAGE2("IM19", "IM19A", "ANIM19", "IM19", 6, true); + else + _objectsManager.PERSONAGE2("IM19", "IM19", "ANIM19", "IM19", 6, true); + break; + + case 20: + _linesManager.setMaxLineIdx(10); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM20", "IM20", "ANIM20", "IM20", 6, true); + if (_globals._exitId == 17) { + _globals.iRegul = 1; + _soundManager.stopSound(); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _soundManager.playSound(6); + if (getPlatform() == Common::kPlatformLinux) + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("PURG2A.ANM", 12, 18, 50); + if (getPlatform() != Common::kPlatformLinux) + _graphicsManager.fadeOutShort(); + _globals.iRegul = 0; + } + break; + + case 22: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM22", "IM22", "ANIM22", "IM22", 6, true); + break; + + case 23: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM23", "IM23", "ANIM23", "IM23", 6, true); + break; + + case 24: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + if (_globals._saveData->_data[svField181] == 1) + _objectsManager.PERSONAGE2("IM24", "IM24A", "ANIM24", "IM24", 1, true); + else + _objectsManager.PERSONAGE2("IM24", "IM24", "ANIM24", "IM24", 1, true); + break; + + case 25: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 445; + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) + _objectsManager.PERSONAGE2("IM25", "IM25", "ANIM25", "IM25", 30, true); + else + _objectsManager.PERSONAGE2("IM25", "IM25", "ANIM25", "IM25", 8, true); + break; + + case 26: + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 435; + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) + _objectsManager.PERSONAGE2("IM26", "IM26", "ANIM26", "IM26", 30, true); + else + _objectsManager.PERSONAGE2("IM26", "IM26", "ANIM26", "IM26", 8, true); + break; + + case 27: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 440; + if (_globals._saveData->_data[svField177] == 1) + _objectsManager.PERSONAGE2("IM27", "IM27A", "ANIM27", "IM27", 27, true); + else + _objectsManager.PERSONAGE2("IM27", "IM27", "ANIM27", "IM27", 27, true); + break; + + case 28: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 450; + if (_globals._saveData->_data[svField166] != 1 || _globals._saveData->_data[svField167] != 1) + _objectsManager.PERSONAGE2("IM28", "IM28", "ANIM28", "IM28", 1, false); + else + _objectsManager.PERSONAGE2("IM28A", "IM28", "ANIM28", "IM28", 1, false); + break; + + case 29: + _linesManager.setMaxLineIdx(50); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM29", "IM29", "ANIM29", "IM29", 1, true); + break; + + case 30: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM30", "IM30", "ANIM30", "IM30", 24, false); + break; + + case 31: + _objectsManager.PERSONAGE("IM31", "IM31", "ANIM31", "IM31", 10, true); + break; + + case 32: + _linesManager.setMaxLineIdx(20); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM32", "IM32", "ANIM32", "IM32", 2, true); + break; + + case 33: + _objectsManager.PERSONAGE("IM33", "IM33", "ANIM33", "IM33", 8, false); + break; + + case 34: + _objectsManager.PERSONAGE("IM34", "IM34", "ANIM34", "IM34", 2, false); + break; + + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: { + _linesManager.setMaxLineIdx(40); + _globals._characterMaxPosY = 435; + _globals._disableInventFl = false; + _objectsManager._forestFl = true; + Common::String im = Common::String::format("IM%d", _globals._exitId); + _soundManager.playSound(13); + if (_objectsManager._forestSprite == g_PTRNUL) { + _objectsManager._forestSprite = _objectsManager.loadSprite("HOPDEG.SPR"); + _soundManager.loadSample(1, "SOUND41.WAV"); + } + _objectsManager.PERSONAGE2(im, im, "BANDIT", im, 13, false); + if (_globals._exitId < 35 || _globals._exitId > 49) { + _objectsManager._forestSprite = _globals.freeMemory(_objectsManager._forestSprite); + _objectsManager._forestFl = false; + _soundManager.removeSample(1); + } + break; + } + + case 50: + displayPlane(); + _globals._exitId = 51; + break; + + case 51: + _linesManager.setMaxLineIdx(10); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM51", "IM51", "ANIM51", "IM51", 14, true); + break; + + case 52: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM52", "IM52", "ANIM52", "IM52", 14, true); + break; + + case 54: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM54", "IM54", "ANIM54", "IM54", 14, true); + break; + + case 55: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 460; + _objectsManager.PERSONAGE2("IM55", "IM55", "ANIM55", "IM55", 14, false); + break; + + case 56: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM56", "IM56", "ANIM56", "IM56", 14, false); + break; + + case 57: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM57", "IM57", "ANIM57", "IM57", 14, true); + break; + + case 58: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM58", "IM58", "ANIM58", "IM58", 14, false); + break; + + case 59: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM59", "IM59", "ANIM59", "IM59", 21, false); + break; + + case 60: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM60", "IM60", "ANIM60", "IM60", 21, false); + break; + + case 61: + if (_globals._saveData->_data[svField311] == 1 && !_globals._saveData->_data[svField312]) + handleConflagration(); + _objectsManager.PERSONAGE("IM61", "IM61", "ANIM61", "IM61", 21, false); + break; + + case 62: + _linesManager.setMaxLineIdx(8); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM62", "IM62", NULL, "IM62", 21, false); + break; + + case 63: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM63", "IM63", "ANIM63", "IM63", 21, false); + break; + + case 64: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM64", "IM64", "ANIM64", "IM64", 21, true); + break; + + case 65: + _linesManager.setMaxLineIdx(30); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM65", "IM65", "ANIM65", "IM65", 21, false); + break; + + case 66: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM66", "IM66", "ANIM66", "IM66", 21, false); + break; + + case 67: + _linesManager.setMaxLineIdx(8); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM67", "IM67", NULL, "IM67", 21, false); + break; + + case 68: + _linesManager.setMaxLineIdx(8); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM68", "IM68", "ANIM68", "IM68", 21, true); + break; + + case 69: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM69", "IM69", "ANIM69", "IM69", 21, false); + break; + + case 70: + _linesManager.setMaxLineIdx(8); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM70", "IM70", NULL, "IM70", 21, false); + break; + + case 71: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 445; + _objectsManager.PERSONAGE2("IM71", "IM71", "ANIM71", "IM71", 21, false); + break; + + case 73: + _linesManager.setMaxLineIdx(15); + _globals._characterMaxPosY = 445; + if (_globals._saveData->_data[svField318] == 1) + _objectsManager.PERSONAGE2("IM73", "IM73A", "ANIM73", "IM73", 21, true); + else + _objectsManager.PERSONAGE2("IM73", "IM73", "ANIM73", "IM73", 21, true); + break; + + case 75: + BASE(); + 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: + BASED(); + break; + + case 91: + handleOceanMaze(91, "OCEAN15", DIR_RIGHT, 78, 81, 86, 0, 25); + break; + + case 93: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 445; + if (_globals._saveData->_data[svField330]) { + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) + _objectsManager.PERSONAGE2("IM93", "IM93C", "ANIM93", "IM93", 29, true); + else + _objectsManager.PERSONAGE2("IM93", "IM93C", "ANIM93", "IM93", 26, true); + } else { + if (getPlatform() == Common::kPlatformLinux || getPlatform() == Common::kPlatformWindows) + _objectsManager.PERSONAGE2("IM93", "IM93", "ANIM93", "IM93", 29, true); + else + _objectsManager.PERSONAGE2("IM93", "IM93", "ANIM93", "IM93", 26, true); + } + break; + + case 94: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 440; + _objectsManager.PERSONAGE2("IM94", "IM94", "ANIM94", "IM94", 19, true); + break; + + case 95: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM95", "IM95", "ANIM95", "IM95", 19, false); + break; + + case 96: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM96", "IM96", "ANIM96", "IM96", 19, false); + break; + + case 97: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM97", "IM97", "ANIM97", "IM97", 19, false); + if (_globals._exitId == 18) { + _globals.iRegul = 1; + _soundManager.stopSound(); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _soundManager.playSound(6); + _animationManager.playAnim("PURG1A.ANM", 12, 18, 50); + _graphicsManager.fadeOutShort(); + _globals.iRegul = 0; + } + break; + + case 98: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM98", "IM98", "ANIM98", "IM98", 19, true); + break; + + case 99: + _linesManager.setMaxLineIdx(5); + _globals._characterMaxPosY = 435; + _objectsManager.PERSONAGE2("IM99", "IM99", "ANIM99", "IM99", 19, true); + break; + + case 100: + playEnding(); + break; + + case 111: + _objectsManager.PERSONAGE("IM111", "IM111", "ANIM111", "IM111", 10, false); + break; + + case 112: + _objectsManager.PERSONAGE("IM112", "IM112", "ANIM112", "IM112", 10, false); + break; + + case 113: + _globals._prevScreenId = _globals._screenId; + _globals._screenId = 113; + _globals._saveData->_data[svField6] = _globals._prevScreenId; + _globals._saveData->_data[svField5] = _globals._screenId; + _globals._exitId = 0; + _computerManager.showComputer(COMPUTER_HOPKINS); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.DD_VBL(); + memset(_graphicsManager._vesaBuffer, 0, 307200); + memset(_graphicsManager._vesaScreen, 0, 307200); + _graphicsManager.clearPalette(); + _graphicsManager.resetVesaSegment(); + break; + + case 114: + _globals._exitId = 0; + _globals._prevScreenId = _globals._screenId; + _globals._screenId = 114; + _globals._saveData->_data[svField6] = _globals._prevScreenId; + _globals._saveData->_data[svField5] = _globals._screenId; + _computerManager.showComputer(COMPUTER_SAMANTHA); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + break; + + case 115: + _globals._prevScreenId = _globals._screenId; + _globals._screenId = 115; + _globals._saveData->_data[svField6] = _globals._prevScreenId; + _globals._saveData->_data[svField5] = _globals._screenId; + _globals._exitId = 0; + _computerManager.showComputer(COMPUTER_PUBLIC); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + break; + + case 150: + _soundManager.playSound(16); + _globals.iRegul = 1; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + if (getPlatform() == Common::kPlatformLinux) + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR1A.ANM", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + + case 151: + _soundManager.playSound(16); + _globals.iRegul = 1; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + if (getPlatform() == Common::kPlatformLinux) + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR3A.ANM", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + + case 152: + _soundManager.playSound(16); + _globals.iRegul = 1; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + if (getPlatform() == Common::kPlatformLinux) + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR4A.ANM", 12, 12, 2000); + _globals.iRegul = 0; + _globals._exitId = 300; + break; + + case 194: + case 195: + case 196: + case 197: + case 198: + case 199: + _globals.PERSO = _globals.freeMemory(_globals.PERSO); + _globals.iRegul = 1; + _soundManager.stopSound(); + _soundManager.playSound(23); + _globals._exitId = handleBaseMap(); // Handles the base map (non-Windows) + //_globals._exitId = WBASE(); // Handles the 3D Doom level (Windows) + _soundManager.stopSound(); + _globals.PERSO = _fileManager.loadFile("PERSO.SPR"); + _globals._characterType = 0; + _globals.iRegul = 0; + _graphicsManager._lineNbr = SCREEN_WIDTH; + break; + } + } + _globals.PERSO = _globals.freeMemory(_globals.PERSO); + 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 + _graphicsManager.setGraphicalMode(SCREEN_WIDTH, SCREEN_HEIGHT); + + // Synchronize the sound settings from ScummVM + _soundManager.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(); + + _eventsManager.initMouseData(); + _fontManager.initData(); + + _dialogsManager._inventoryIcons = _fileManager.loadFile("ICONE.SPR"); + _objectsManager._headSprites = _fileManager.loadFile("TETE.SPR"); + + switch (_globals._language) { + case LANG_EN: + _globals.BUF_ZONE = _fileManager.loadFile("ZONEAN.TXT"); + break; + case LANG_FR: + _globals.BUF_ZONE = _fileManager.loadFile("ZONE01.TXT"); + break; + case LANG_SP: + _globals.BUF_ZONE = _fileManager.loadFile("ZONEES.TXT"); + break; + } + + _eventsManager.setMouseOn(); + _eventsManager._mouseFl = false; + + _globals.loadCharacterData(); + + _eventsManager._mouseOffset.x = 0; + _eventsManager._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); + _eventsManager.VBL(); + _eventsManager._mouseFl = false; + _globals.iRegul = 1; + _eventsManager.VBL(); + _soundManager.playSound(16); + _animationManager._clearAnimationFl = true; + _animationManager.playAnim("J1.anm", 12, 12, 50); + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _soundManager.mixVoice(1, 3); + _animationManager.playAnim("J2.anm", 12, 12, 50); + + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _soundManager.mixVoice(2, 3); + _animationManager.playAnim("J3.anm", 12, 12, 50); + + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _soundManager.mixVoice(3, 3); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _graphicsManager.DD_VBL(); + _soundManager.playSound(11); + _graphicsManager.loadImage("intro1"); + _graphicsManager.scrollScreen(0); + _graphicsManager._scrollOffset = 0; + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + for (int i = 0; i <= 4; i++) + _eventsManager.VBL(); + + _globals.iRegul = 1; + _graphicsManager.fadeInLong(); + if (_graphicsManager._largeScreenFl) { + _graphicsManager._scrollStatus = 2; + _graphicsManager._scrollPosX = 0; + + bool loopCond = false; + do { + _graphicsManager._scrollPosX += 2; + if (_graphicsManager._scrollPosX > (SCREEN_WIDTH - 2)) { + _graphicsManager._scrollPosX = SCREEN_WIDTH; + loopCond = true; + } + + if (_eventsManager.getMouseX() < _graphicsManager._scrollPosX + 10) + _eventsManager.setMouseXY(_eventsManager._mousePos.x + 4, _eventsManager.getMouseY()); + _eventsManager.VBL(); + } while (!shouldQuit() && !loopCond && _graphicsManager._scrollPosX != SCREEN_WIDTH); + + _eventsManager.VBL(); + _graphicsManager._scrollStatus = 0; + + if (shouldQuit()) + return; + } + + _soundManager.mixVoice(4, 3); + _graphicsManager.fadeOutLong(); + _graphicsManager._scrollStatus = 0; + _graphicsManager.loadImage("intro2"); + _graphicsManager.scrollScreen(0); + _animationManager.loadAnim("INTRO2"); + _graphicsManager.displayAllBob(); + _soundManager.playSound(23); + _objectsManager.stopBobAnimation(3); + _objectsManager.stopBobAnimation(5); + _graphicsManager._scrollOffset = 0; + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + + for (int i = 0; i <= 4; i++) + _eventsManager.VBL(); + + _globals.iRegul = 1; + _graphicsManager.fadeInLong(); + for (uint i = 0; i < 200 / _globals._speed; ++i) + _eventsManager.VBL(); + + _objectsManager.setBobAnimation(3); + _soundManager.mixVoice(5, 3); + _objectsManager.stopBobAnimation(3); + _eventsManager.VBL(); + memcpy(&paletteData2, _graphicsManager._palette, 796); + + _graphicsManager.setPaletteVGA256WithRefresh(paletteData, _graphicsManager._vesaBuffer); + _graphicsManager.endDisplayBob(); + + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _soundManager._specialSoundNum = 5; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("ELEC.ANM", 10, 26, 200); + _soundManager._specialSoundNum = 0; + + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _graphicsManager.loadImage("intro2"); + _graphicsManager.scrollScreen(0); + _animationManager.loadAnim("INTRO2"); + _graphicsManager.displayAllBob(); + _soundManager.playSound(23); + _objectsManager.stopBobAnimation(3); + _objectsManager.stopBobAnimation(5); + _objectsManager.stopBobAnimation(1); + _graphicsManager._scrollOffset = 0; + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + + for (int i = 0; i <= 3; i++) + _eventsManager.VBL(); + + _globals.iRegul = 1; + _graphicsManager.setPaletteVGA256WithRefresh(paletteData2, _graphicsManager._vesaBuffer); + + int introIndex = 0; + while (!shouldQuit() && !_eventsManager._escKeyFl) { + if (introIndex == 12) { + _objectsManager.setBobAnimation(3); + _eventsManager.VBL(); + _soundManager.mixVoice(6, 3); + _eventsManager.VBL(); + _objectsManager.stopBobAnimation(3); + } + + Common::copy(&paletteData2[0], &paletteData2[PALETTE_BLOCK_SIZE], &_graphicsManager._palette[0]); + + for (int i = 1, v12 = 4 * introIndex; i <= PALETTE_BLOCK_SIZE; i++) { + if (_graphicsManager._palette[i] > v12) + _graphicsManager._palette[i] -= v12; + } + + _graphicsManager.setPaletteVGA256WithRefresh(_graphicsManager._palette, _graphicsManager._vesaBuffer); + + for (int i = 1; i < 2 * introIndex; i++) + _eventsManager.VBL(); + + _graphicsManager.setPaletteVGA256WithRefresh(paletteData2, _graphicsManager._vesaBuffer); + + for (int i = 1; i < 20 - introIndex; i++) + _eventsManager.VBL(); + + introIndex += 2; + if (introIndex > 15) { + _graphicsManager.setPaletteVGA256WithRefresh(paletteData, _graphicsManager._vesaBuffer); + for (uint j = 1; j < 100 / _globals._speed; ++j) + _eventsManager.VBL(); + + _objectsManager.setBobAnimation(3); + _soundManager.mixVoice(7, 3); + _objectsManager.stopBobAnimation(3); + + for (uint k = 1; k < 60 / _globals._speed; ++k) + _eventsManager.VBL(); + _objectsManager.setBobAnimation(5); + for (uint l = 0; l < 20 / _globals._speed; ++l) + _eventsManager.VBL(); + + Common::copy(&paletteData2[0], &paletteData2[PALETTE_BLOCK_SIZE], &_graphicsManager._palette[0]); + _graphicsManager.setPaletteVGA256WithRefresh(_graphicsManager._palette, _graphicsManager._vesaBuffer); + + for (uint m = 0; m < 50 / _globals._speed; ++m) { + if (m == 30 / _globals._speed) { + _objectsManager.setBobAnimation(3); + _soundManager.mixVoice(8, 3); + _objectsManager.stopBobAnimation(3); + } + + _eventsManager.VBL(); + } + + _graphicsManager.fadeOutLong(); + _graphicsManager.endDisplayBob(); + _animationManager._clearAnimationFl = true; + _soundManager.playSound(3); + _soundManager._specialSoundNum = 1; + _animationManager.playAnim("INTRO1.anm", 10, 24, 18); + _soundManager._specialSoundNum = 0; + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _animationManager.playAnim("INTRO2.anm", 10, 24, 18); + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _animationManager.playAnim("INTRO3.anm", 10, 24, 200); + if (shouldQuit() || _eventsManager._escKeyFl) + return; + + _animationManager._clearAnimationFl = false; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("J4.anm", 12, 12, 1000); + break; + } + } + + _eventsManager._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) + _graphicsManager.loadImage("ndfr"); + else + _graphicsManager.loadImage("nduk"); + + _graphicsManager.fadeInLong(); + if (_soundManager._voiceOffFl) + _eventsManager.delay(500); + else + _soundManager.mixVoice(628, 4); + + _graphicsManager.fadeOutLong(); + _globals._exitId = 4; +} + +void HopkinsEngine::handleNotAvailable(int sortie) { + // 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 = sortie; +} + +void HopkinsEngine::displayEndDemo() { + _soundManager.playSound(28); + if (_globals._language == LANG_FR) + _graphicsManager.loadImage("endfr"); + else + _graphicsManager.loadImage("enduk"); + + _graphicsManager.fadeInLong(); + _eventsManager.delay(1500); + _graphicsManager.fadeOutLong(); + _globals._exitId = 0; +} + +void HopkinsEngine::bombExplosion() { + _graphicsManager._lineNbr = SCREEN_WIDTH; + _graphicsManager.SCANLINE(SCREEN_WIDTH); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + + _globals.iRegul = 1; + _soundManager._specialSoundNum = 199; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("BOMBE2A.ANM", 50, 14, 500); + _soundManager._specialSoundNum = 0; + _graphicsManager.loadImage("IM15"); + _animationManager.loadAnim("ANIM15"); + _graphicsManager.displayAllBob(); + _objectsManager.stopBobAnimation(7); + + for (int idx = 0; idx < 5; ++idx) { + _eventsManager.VBL(); + } + + _graphicsManager.fadeInLong(); + _eventsManager.mouseOff(); + + for (int idx = 0; idx < 20; ++idx) { + _eventsManager.VBL(); + } + + _globals._introSpeechOffFl = true; + _talkManager.startStaticCharacterDialogue("vire.pe2"); + _globals._introSpeechOffFl = false; + _objectsManager.setBobAnimation(7); + + for (int idx = 0; idx < 100; ++idx) { + _eventsManager.VBL(); + } + + _graphicsManager.fadeOutLong(); + _graphicsManager.endDisplayBob(); + _globals.iRegul = 0; + _globals._exitId = 151; +} + +void HopkinsEngine::restoreSystem() { + quitGame(); + _eventsManager.refreshEvents(); +} + +void HopkinsEngine::endLinuxDemo() { + _globals._linuxEndDemoFl = true; + _graphicsManager.resetVesaSegment(); + _objectsManager._forestFl = false; + _eventsManager._breakoutFl = false; + _globals._disableInventFl = true; + _graphicsManager.loadImage("BOX"); + _soundManager.playSound(28); + _graphicsManager.fadeInLong(); + _eventsManager.mouseOn(); + _eventsManager.changeMouseCursor(0); + _eventsManager._mouseCursorId = 0; + _eventsManager._mouseSpriteId = 0; + + bool mouseClicked = false; + + do { + _eventsManager.VBL(); + + if (_eventsManager.getMouseButton() == 1) + mouseClicked = true; + } while (!mouseClicked && !g_system->getEventManager()->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 + + _graphicsManager.fadeOutLong(); +} + +void HopkinsEngine::handleConflagration() { + _globals._disableInventFl = true; + _globals.iRegul = 1; + _graphicsManager.loadImage("IM71"); + _animationManager.loadAnim("ANIM71"); + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + _graphicsManager.displayAllBob(); + + for (int cpt = 0; cpt <= 4; cpt++) + _eventsManager.VBL(); + + _graphicsManager.fadeInLong(); + _globals.iRegul = 1; + + for (int cpt = 0; cpt <= 249; cpt++) + _eventsManager.VBL(); + + _globals._introSpeechOffFl = true; + _talkManager.startAnimatedCharacterDialogue("SVGARD1.pe2"); + _globals._introSpeechOffFl = false; + + for (int cpt = 0; cpt <= 49; cpt++) + _eventsManager.VBL(); + + _graphicsManager.fadeOutLong(); + _graphicsManager.endDisplayBob(); + _globals._saveData->_data[svField312] = 1; + _globals._disableInventFl = false; +} + +void HopkinsEngine::BASE() { + _globals.iRegul = 1; + _graphicsManager._lineNbr = SCREEN_WIDTH; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _animationManager._clearAnimationFl = true; + _soundManager.playSound(25); + _animationManager.playAnim("base00a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("base05a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("base10a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("base20a.anm", 10, 18, 18); + // CHECKME: The original code was doing the opposite test, which was a bug. + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("base30a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("base40a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("base50a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("OC00a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("OC05a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("OC10a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("OC20a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) { + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("OC30a.anm", 10, 18, 18); + } + + _eventsManager._escKeyFl = false; + _animationManager._clearAnimationFl = false; + _globals._exitId = 85; +} + +void HopkinsEngine::BASED() { + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _animationManager.NO_SEQ = false; + _soundManager.playSound(26); + _globals.iRegul = 1; + _globals._disableInventFl = true; + _animationManager.NO_COUL = true; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playSequence("abase.seq", 50, 15, 50); + _animationManager.NO_COUL = false; + _graphicsManager.loadImage("IM92"); + _animationManager.loadAnim("ANIM92"); + _graphicsManager.displayAllBob(); + _objectsManager.loadLinkFile("IM92"); + + for (int cpt = 0; cpt <= 4; cpt++) + _eventsManager.VBL(); + + _graphicsManager.fadeInLong(); + _globals.enableHiding(); + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(8) != 22); + + _graphicsManager.fadeOutLong(); + _graphicsManager.endDisplayBob(); + _globals.resetHidingItems(); + _globals._disableInventFl = false; + _globals._exitId = 93; + _globals.iRegul = 0; +} + +void HopkinsEngine::playEnding() { + _globals.PERSO = _globals.freeMemory(_globals.PERSO); + _dialogsManager._removeInventFl = true; + _globals._disableInventFl = true; + _graphicsManager._scrollOffset = 0; + _globals._cityMapEnabledFl = false; + _globals.iRegul = 1; + _soundManager.playSound(26); + _linesManager._route = (RouteItem *)g_PTRNUL; + _globals._freezeCharacterFl = true; + _globals._exitId = 0; + _soundManager.loadSample(1, "SOUND90.WAV"); + _graphicsManager.loadImage("IM100"); + _animationManager.loadAnim("ANIM100"); + _graphicsManager.displayAllBob(); + _eventsManager.mouseOn(); + _objectsManager.stopBobAnimation(7); + _objectsManager.stopBobAnimation(8); + _objectsManager.stopBobAnimation(9); + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + _eventsManager.changeMouseCursor(0); + + for (int cpt = 0; cpt <= 4; cpt++) + _eventsManager.VBL(); + + _graphicsManager.fadeInLong(); + _globals.iRegul = 1; + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(6) != 54); + + _globals._introSpeechOffFl = true; + _talkManager.startAnimatedCharacterDialogue("GM4.PE2"); + _globals._disableInventFl = true; + _objectsManager.stopBobAnimation(6); + _objectsManager.stopBobAnimation(10); + _objectsManager.setBobAnimation(9); + _objectsManager.setBobAnimation(7); + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(7) != 54); + + _soundManager.playSample(1); + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(7) != 65); + + _globals._introSpeechOffFl = true; + _talkManager.startAnimatedCharacterDialogue("DUELB4.PE2"); + _eventsManager.mouseOff(); + _globals._disableInventFl = true; + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(7) != 72); + + _globals._introSpeechOffFl = true; + _talkManager.startAnimatedCharacterDialogue("DUELH1.PE2"); + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(7) != 81); + + _globals._introSpeechOffFl = true; + _talkManager.startAnimatedCharacterDialogue("DUELB5.PE2"); + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(7) != 120); + + _objectsManager.stopBobAnimation(7); + if (_globals._saveData->_data[svField135] == 1) { + _soundManager._specialSoundNum = 200; + _soundManager._skipRefreshFl = true; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("BERM.ANM", 100, 24, 300); + _graphicsManager.endDisplayBob(); + _soundManager.removeSample(1); + _graphicsManager.loadImage("PLAN3"); + _graphicsManager.fadeInLong(); + + _eventsManager._rateCounter = 0; + if (!_eventsManager._escKeyFl) { + do + _eventsManager.refreshEvents(); + while (_eventsManager._rateCounter < 2000 / _globals._speed && !_eventsManager._escKeyFl); + } + _eventsManager._escKeyFl = false; + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + _soundManager._specialSoundNum = 0; + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("JOUR2A.anm", 12, 12, 1000); + _soundManager.playSound(11); + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + _animationManager.playAnim("FF1a.anm", 18, 18, 9); + _animationManager.playAnim("FF1a.anm", 9, 18, 9); + _animationManager.playAnim("FF1a.anm", 9, 18, 18); + _animationManager.playAnim("FF1a.anm", 9, 18, 9); + _animationManager.playAnim("FF2a.anm", 24, 24, 100); + displayCredits(); + _globals.iRegul = 0; + _globals._exitId = 300; + _dialogsManager._removeInventFl = false; + _globals._disableInventFl = false; + } else { + _soundManager._specialSoundNum = 200; + _soundManager._skipRefreshFl = true; + _animationManager.playAnim2("BERM.ANM", 100, 24, 300); + _objectsManager.stopBobAnimation(7); + _objectsManager.setBobAnimation(8); + _globals._introSpeechOffFl = true; + _talkManager.startAnimatedCharacterDialogue("GM5.PE2"); + _globals._disableInventFl = true; + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(8) != 5); + + _soundManager.directPlayWav("SOUND41.WAV"); + + do + _eventsManager.VBL(); + while (_objectsManager.getBobAnimDataIdx(8) != 21); + + _graphicsManager.fadeOutLong(); + _graphicsManager.endDisplayBob(); + _soundManager.removeSample(1); + _soundManager.playSound(16); + _globals.iRegul = 1; + _soundManager._specialSoundNum = 0; + _dialogsManager._removeInventFl = false; + _globals._disableInventFl = false; + _animationManager.playAnim("JOUR4A.anm", 12, 12, 1000); + _globals.iRegul = 0; + _globals._exitId = 300; + } + _globals.PERSO = _fileManager.loadFile("PERSO.SPR"); + _globals._characterType = 0; + _globals.iRegul = 0; +} + +void HopkinsEngine::displayPlane() { + _soundManager.playSound(28); + _globals.iRegul = 1; + _graphicsManager.lockScreen(); + _graphicsManager.clearScreen(); + _graphicsManager.unlockScreen(); + _graphicsManager.clearPalette(); + + _animationManager._clearAnimationFl = false; + _animationManager.playAnim("aerop00a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("serop10a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("aerop20a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("aerop30a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("aerop40a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("aerop50a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("aerop60a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("aerop70a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("trans00a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("trans10a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("trans15a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("trans20a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("trans30a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) + _animationManager.playAnim("trans40a.anm", 10, 18, 18); + if (!_eventsManager._escKeyFl) { + _graphicsManager.FADE_LINUX = 2; + _animationManager.playAnim("PARA00a.anm", 9, 9, 9); + } + + _eventsManager._escKeyFl = false; + _animationManager._clearAnimationFl = false; +} + +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 + _graphicsManager.loadImage("PBASE"); + } else { + // PBASE file doesn't exist, so draw a substitute screen + drawBaseMap(); + } +} + +void HopkinsEngine::drawBaseMap() { + memset(_graphicsManager._vesaScreen, 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 = _graphicsManager._vesaScreen + yp * SCREEN_WIDTH + r.left; + Common::fill(pDest, pDest + r.width(), 0xff); + } + } + + // Copy the calculated screen + memcpy(_graphicsManager._vesaBuffer, _graphicsManager._vesaScreen, SCREEN_WIDTH * 2 * SCREEN_HEIGHT); + + // Write some explanatory text + _fontManager.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 colours + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + _eventsManager.changeMouseCursor(0); + _graphicsManager.fadeInLong(); + bool loopCond = false; + int zone; + do { + if (shouldQuit()) + return 0; + + int mouseButton = _eventsManager.getMouseButton(); + int posX = _eventsManager.getMouseX(); + int posY = _eventsManager.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) { + _eventsManager.changeMouseCursor(4); + _globals._baseMapColor += 25; + if (_globals._baseMapColor > 100) + _globals._baseMapColor = 0; + _graphicsManager.SETCOLOR4(251, _globals._baseMapColor, _globals._baseMapColor, _globals._baseMapColor); + } else { + _eventsManager.changeMouseCursor(0); + _graphicsManager.SETCOLOR4(251, 100, 100, 100); + } + _eventsManager.VBL(); + if ((mouseButton == 1) && zone) + loopCond = true; + } while (!loopCond); + + _globals._disableInventFl = false; + _graphicsManager.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 = _fileManager.loadFile("CREAN.TXT"); + break; + case LANG_FR: + bufPtr = _fileManager.loadFile("CREFR.TXT"); + break; + case LANG_SP: + bufPtr = _fileManager.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]._colour = 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 colour) { + byte *bufPtr = buffer; + int strWidth = 0; + byte curChar; + for (;;) { + curChar = *bufPtr++; + if (!curChar) + break; + if (curChar > 31) + strWidth += _objectsManager.getWidth(_fontManager._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; + } + if (startPosX < _globals._creditsStartX) + _globals._creditsStartX = startPosX; + if (endPosX > _globals._creditsEndX) + _globals._creditsEndX = endPosX; + if (_globals._creditsStartY > startPosY) + _globals._creditsStartY = startPosY; + if (endPosY > _globals._creditsEndY) + _globals._creditsEndY = endPosY; + + bufPtr = buffer; + for (;;) { + curChar = *bufPtr++; + if (!curChar) + break; + if (curChar > 31) { + _graphicsManager.displayFont(_graphicsManager._vesaBuffer, _fontManager._font, startPosX, startPosY, curChar - 32, colour); + startPosX += _objectsManager.getWidth(_fontManager._font, curChar - 32); + } + } +} + +void HopkinsEngine::displayCredits() { + loadCredits(); + _globals._creditsPosY = 436; + _graphicsManager.loadImage("GENERIC"); + _graphicsManager.fadeInLong(); + _soundManager.playSound(28); + _eventsManager._mouseFl = false; + _globals.iRegul = 3; + _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]._colour) { + case '1': + col = 163; + break; + case '2': + col = 161; + break; + case '3': + col = 162; + break; + default: + warning("Unknown colour, 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) { + _eventsManager.VBL(); + _graphicsManager.copySurface(_graphicsManager._vesaScreen, 60, 50, 520, 380, _graphicsManager._vesaBuffer, 60, 50); + } else { + _eventsManager.VBL(); + } + if (_globals._creditsItem[_globals._creditsLineNumb - 1]._linePosY <= 39) { + _globals._creditsPosY = 440; + ++soundId; + if (soundId > 31) + soundId = 28; + _soundManager.playSound(soundId); + } + _globals._creditsStartX = -1; + _globals._creditsEndX = -1; + _globals._creditsStartY = -1; + _globals._creditsEndY = -1; + } while ((_eventsManager.getMouseButton() != 1) && (!g_system->getEventManager()->shouldQuit())); + _graphicsManager.fadeOutLong(); + _globals.iRegul = 1; + _eventsManager._mouseFl = true; +} + +void HopkinsEngine::handleOceanMouseEvents() { + _fontManager.hideText(9); + if (_eventsManager._mouseCursorId != 16) + return; + + _eventsManager.getMouseX(); + if (_objectsManager._zoneNum <= 0) + return; + + int oldPosX = _eventsManager.getMouseX(); + int oldPosY = _eventsManager.getMouseY(); + bool displAnim = false; + int oldX; + switch (_objectsManager._zoneNum) { + case 1: + switch (_globals._oceanDirection) { + case DIR_UP: + _objectsManager.SPACTION(_globals.PERSO, "27,26,25,24,23,22,21,20,19,18,-1,", 0, 0, 6, false); + break; + case DIR_RIGHT: + _objectsManager.SPACTION(_globals.PERSO, "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,-1,", 0, 0, 6, false); + break; + case DIR_DOWN: + _objectsManager.SPACTION(_globals.PERSO, "9,10,11,12,13,14,15,16,17,18,-1,", 0, 0, 6, false); + break; + default: + break; + } + + _globals._oceanDirection = DIR_LEFT; + _globals._exitId = 1; + oldX = _objectsManager.getSpriteX(0); + for (;;) { + if (_globals._speed == 1) + oldX -= 2; + else if (_globals._speed == 2) + oldX -= 4; + else if (_globals._speed == 3) + oldX -= 6; + _objectsManager.setSpriteX(0, oldX); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_eventsManager.getMouseButton() == 1 && oldPosX == _eventsManager.getMouseX() && _eventsManager.getMouseY() == oldPosY) { + displAnim = true; + break; + } + + if (oldX <= -100) + break; + } + break; + case 2: + switch (_globals._oceanDirection) { + case DIR_UP: + _objectsManager.SPACTION(_globals.PERSO, "27,28,29,30,31,32,33,34,35,36,-1,", 0, 0, 6, false); + break; + case DIR_DOWN: + _objectsManager.SPACTION(_globals.PERSO, "9,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 6, false); + break; + case DIR_LEFT: + _objectsManager.SPACTION(_globals.PERSO, "18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,-1,", 0, 0, 6, false); + break; + default: + break; + } + _globals._oceanDirection = DIR_RIGHT; + _globals._exitId = 2; + oldX = _objectsManager.getSpriteX(0); + for (;;) { + if (_globals._speed == 1) + oldX += 2; + else if (_globals._speed == 2) + oldX += 4; + else if (_globals._speed == 3) + oldX += 6; + _objectsManager.setSpriteX(0, oldX); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_eventsManager.getMouseButton() == 1 && oldPosX == _eventsManager.getMouseX() && _eventsManager.getMouseY() == oldPosY) { + displAnim = true; + break; + } + if (oldX > 499) + break; + } + break; + case 3: + switch (_globals._oceanDirection) { + case DIR_RIGHT: + oldX = _objectsManager.getSpriteX(0); + do { + if (_globals._speed == 1) + oldX += 2; + else if (_globals._speed == 2) + oldX += 4; + else if (_globals._speed == 3) + oldX += 6; + _objectsManager.setSpriteX(0, oldX); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_eventsManager.getMouseButton() == 1 && oldPosX == _eventsManager.getMouseX() && _eventsManager.getMouseY() == oldPosY) { + displAnim = true; + break; + } + } while (oldX <= 235); + if (!displAnim) + _objectsManager.SPACTION(_globals.PERSO, "36,35,34,33,32,31,30,29,28,27,-1,", 0, 0, 6, false); + break; + case DIR_DOWN: + _objectsManager.SPACTION(_globals.PERSO, "9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,-1,", 0, 0, 6, false); + break; + case DIR_LEFT: + oldX = _objectsManager.getSpriteX(0); + do { + if (_globals._speed == 1) + oldX -= 2; + else if (_globals._speed == 2) + oldX -= 4; + else if (_globals._speed == 3) + oldX -= 6; + _objectsManager.setSpriteX(0, oldX); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_eventsManager.getMouseButton() == 1 && oldPosX == _eventsManager.getMouseX() && _eventsManager.getMouseY() == oldPosY) { + displAnim = true; + break; + } + } while (oldX > 236); + if (!displAnim) + _objectsManager.SPACTION(_globals.PERSO, "18,19,20,21,22,23,24,25,26,27,-1,", 0, 0, 6, false); + break; + default: + break; + } + _globals._oceanDirection = DIR_UP; + _globals._exitId = 3; + break; + case 4: + switch (_globals._oceanDirection) { + case DIR_UP: + _objectsManager.SPACTION(_globals.PERSO, "27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,-1,", 0, 0, 6, false); + break; + case DIR_RIGHT: + oldX = _objectsManager.getSpriteX(0); + do { + if (_globals._speed == 1) + oldX += 2; + else if (_globals._speed == 2) + oldX += 4; + else if (_globals._speed == 3) + oldX += 6; + _objectsManager.setSpriteX(0, oldX); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_eventsManager.getMouseButton() == 1 && oldPosX == _eventsManager.getMouseX() && _eventsManager.getMouseY() == oldPosY) { + displAnim = true; + break; + } + } while (oldX <= 235); + if (!displAnim) + _objectsManager.SPACTION(_globals.PERSO, "0,1,2,3,4,5,6,7,8,9,-1,", 0, 0, 6, false); + break; + case DIR_LEFT: + oldX = _objectsManager.getSpriteX(0); + for (;;) { + if (_globals._speed == 1) + oldX -= 2; + else if (_globals._speed == 2) + oldX -= 4; + else if (_globals._speed == 3) + oldX -= 6; + _objectsManager.setSpriteX(0, oldX); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_eventsManager.getMouseButton() == 1 && oldPosX == _eventsManager.getMouseX() && _eventsManager.getMouseY() == oldPosY) + break; + + if (oldX <= 236) { + if (!displAnim) + _objectsManager.SPACTION(_globals.PERSO, "18,17,16,15,14,13,12,11,10,9,-1,", 0, 0, 6, false); + break; + } + } + break; + default: + break; + } + _globals._oceanDirection = DIR_DOWN; + _globals._exitId = 4; + break; + } +} + +void HopkinsEngine::setSubmarineSprites() { + switch (_globals._oceanDirection) { + case DIR_UP: + _objectsManager.setSpriteIndex(0, 27); + break; + case DIR_RIGHT: + _objectsManager.setSpriteIndex(0, 0); + break; + case DIR_DOWN: + _objectsManager.setSpriteIndex(0, 9); + break; + case DIR_LEFT: + _objectsManager.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; + _graphicsManager._noFadingFl = false; + _globals._freezeCharacterFl = false; + _globals._exitId = 0; + _globals._disableInventFl = true; + _soundManager.playSound(soundId); + _globals.PERSO = _fileManager.loadFile("VAISSEAU.SPR"); + if (backgroundFilename.size()) + _graphicsManager.loadImage(backgroundFilename); + + if (curExitId == 77) + _objectsManager.loadLinkFile("IM77"); + else if (curExitId == 84) + _objectsManager.loadLinkFile("IM84"); + else if (curExitId == 91) + _objectsManager.loadLinkFile("IM91"); + else + _objectsManager.loadLinkFile("ocean"); + + if (!exit1) + _linesManager.disableZone(1); + if (!exit2) + _linesManager.disableZone(2); + if (!exit3) + _linesManager.disableZone(3); + if (!exit4) + _linesManager.disableZone(4); + + if (!_globals._oceanDirection) + _globals._oceanDirection = defaultDirection; + + switch (_globals._oceanDirection) { + case DIR_UP: + _objectsManager._characterPos.x = 236; + _objectsManager._startSpriteIndex = 27; + break; + case DIR_RIGHT: + _objectsManager._characterPos.x = -20; + _objectsManager._startSpriteIndex = 0; + break; + case DIR_DOWN: + _objectsManager._characterPos.x = 236; + _objectsManager._startSpriteIndex = 9; + break; + case DIR_LEFT: + _objectsManager._characterPos.x = 415; + _objectsManager._startSpriteIndex = 18; + break; + default: + break; + } + + _objectsManager.addStaticSprite(_globals.PERSO, Common::Point(_objectsManager._characterPos.x, 110), 0, _objectsManager._startSpriteIndex, 0, false, 0, 0); + _graphicsManager.SETCOLOR3(252, 100, 100, 100); + _graphicsManager.SETCOLOR3(253, 100, 100, 100); + _graphicsManager.SETCOLOR3(251, 100, 100, 100); + _graphicsManager.SETCOLOR3(254, 0, 0, 0); + _objectsManager.animateSprite(0); + _linesManager._route = (RouteItem *)g_PTRNUL; + _eventsManager.mouseOn(); + _eventsManager.changeMouseCursor(4); + + for (int cpt = 0; cpt <= 4; cpt++) + _eventsManager.VBL(); + + if (!_graphicsManager._noFadingFl) + _graphicsManager.fadeInLong(); + _graphicsManager._noFadingFl = false; + _globals.iRegul = 1; + + for (;;) { + int mouseButton = _eventsManager.getMouseButton(); + if (mouseButton && mouseButton == 1) + handleOceanMouseEvents(); + _linesManager.checkZone(); + setSubmarineSprites(); + _eventsManager.VBL(); + if (_globals._exitId || g_system->getEventManager()->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; + _graphicsManager.fadeOutLong(); + _objectsManager.removeSprite(0); + _objectsManager.clearScreen(); + _globals.PERSO = _fileManager.loadFile("PERSO.SPR"); + _globals._characterType = 0; +} + +void HopkinsEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + + _soundManager.syncSoundSettings(); +} + +bool HopkinsEngine::displayAdultDisclaimer() { + int xp, yp; + int buttonIndex; + + _graphicsManager._minX = 0; + _graphicsManager._minY = 0; + _graphicsManager._maxX = SCREEN_WIDTH; + _graphicsManager._maxY = SCREEN_HEIGHT - 1; + _eventsManager._breakoutFl = false; + _objectsManager._forestFl = false; + _globals._disableInventFl = true; + _globals._exitId = 0; + + _graphicsManager.loadImage("ADULT"); + _graphicsManager.fadeInLong(); + _eventsManager.mouseOn(); + _eventsManager.changeMouseCursor(0); + _eventsManager._mouseCursorId = 0; + _eventsManager._mouseSpriteId = 0; + + do { + xp = _eventsManager.getMouseX(); + yp = _eventsManager.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; + + _eventsManager.VBL(); + } while (!shouldQuit() && (buttonIndex == 0 || _eventsManager.getMouseButton() != 1)); + + _globals._disableInventFl = false; + _graphicsManager.fadeOutLong(); + + if (buttonIndex != 2) { + // Quit game + return false; + } else { + // Continue + _graphicsManager._minX = 0; + _graphicsManager._maxY = 20; + _graphicsManager._maxX = SCREEN_WIDTH; + _graphicsManager._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..324d36bbea --- /dev/null +++ b/engines/hopkins/hopkins.h @@ -0,0 +1,199 @@ +/* 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 BASE(); + void BASED(); + void playEnding(); + void displayPlane(); + + /** + * 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 colour); + void displayCredits(); + void handleNotAvailable(int sortie); + + 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: + Debugger _debugger; + AnimationManager _animationManager; + ComputerManager _computerManager; + DialogsManager _dialogsManager; + EventsManager _eventsManager; + FontManager _fontManager; + Globals _globals; + FileManager _fileManager; + GraphicsManager _graphicsManager; + LinesManager _linesManager; + MenuManager _menuManager; + ObjectsManager _objectsManager; + SaveLoadManager _saveLoadManager; + ScriptManager _scriptManager; + SoundManager _soundManager; + TalkManager _talkManager; + +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); + + /** + * Run the introduction sequence + */ + void playIntro(); + + /** + * Synchronises the sound settings from ScummVM into the engine + */ + virtual void syncSoundSettings(); +}; + +// Global reference to the HopkinsEngine object +extern HopkinsEngine *g_vm; + +#define GLOBALS g_vm->_globals + +} // 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..ebf48a7d21 --- /dev/null +++ b/engines/hopkins/lines.cpp @@ -0,0 +1,2966 @@ +/* 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 { + + +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; +} + + +LinesManager::LinesManager() { + 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; + BOBZONE_FLAG[i] = false; + } + + for (int i = 0; i < 106; ++i) + Common::fill((byte *)&ZONEP[i], (byte *)&ZONEP[i] + sizeof(ZonePItem), 0); + + _linesNumb = 0; + _newLineIdx = 0; + _newLineDataIdx = 0; + _newRouteIdx = 0; + _newPosX = 0; + _newPosY = 0; + _smoothMoveDirection = DIR_NONE; + _lastLine = 0; + _maxLineIdx = 0; + _pathFindingMaxDepth = 0; + essai0 = NULL; + essai1 = NULL; + essai2 = NULL; + _lineBuf = (int16 *)g_PTRNUL; + _route = (RouteItem *)g_PTRNUL; + _currentSegmentId = 0; + _largeBuf = g_PTRNUL; +} + +LinesManager::~LinesManager() { + _vm->_globals.freeMemory(_largeBuf); +} + +void LinesManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +/** + * Load lines + */ +void LinesManager::loadLines(const Common::String &file) { + resetLines(); + _linesNumb = 0; + _lastLine = 0; + byte *ptr = _vm->_fileManager.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->_graphicsManager._scrollOffset + 424 && posX <= _vm->_graphicsManager._scrollOffset + 478) + hotspotId = 30; + if (posY >= 290 && posY <= 306 && posX >= _vm->_graphicsManager._scrollOffset + 424 && posX <= _vm->_graphicsManager._scrollOffset + 478) + hotspotId = 31; + if (posY < 114 || posY > 306 || posX < _vm->_graphicsManager._scrollOffset + 152 || posX > _vm->_graphicsManager._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->_graphicsManager._scrollOffset + 158 && posX < _vm->_graphicsManager._scrollOffset + 208) + return result; + + if (posX >= _vm->_graphicsManager._scrollOffset + 208 && posX < _vm->_graphicsManager._scrollOffset + 266) { + result += 1; + return result; + } + + if (posX >= _vm->_graphicsManager._scrollOffset + 266 && posX < _vm->_graphicsManager._scrollOffset + 320) { + result += 2; + return result; + } + + if (posX >= _vm->_graphicsManager._scrollOffset + 320 && posX < _vm->_graphicsManager._scrollOffset + 370) { + result += 3; + return result; + } + + if (posX >= _vm->_graphicsManager._scrollOffset + 370 && posX < _vm->_graphicsManager._scrollOffset + 424) { + result += 4; + return result; + } + + if (!lastRow && posX >= _vm->_graphicsManager._scrollOffset + 424 && posX <= _vm->_graphicsManager._scrollOffset + 478) { + result += 5; + return result; + } + + return 0; +} + +/** + * Add Zone Line + */ +void LinesManager::addZoneLine(int idx, int a2, int a3, int a4, int a5, int bobZoneIdx) { + int16 *zoneData; + + if (a2 == a3 && a3 == a4 && a3 == a5) { + BOBZONE_FLAG[bobZoneIdx] = true; + BOBZONE[bobZoneIdx] = a3; + } else { + assert (idx <= MAX_LINES); + _zoneLine[idx]._zoneData = (int16 *)_vm->_globals.freeMemory((byte *)_zoneLine[idx]._zoneData); + + int v8 = abs(a2 - a4); + int v9 = abs(a3 - a5); + int v20 = 1; + if (v8 <= v9) + v20 += v9; + else + v20 += v8; + + zoneData = (int16 *)_vm->_globals.allocMemory(2 * sizeof(int16) * v20 + (4 * sizeof(int16))); + assert(zoneData != (int16 *)g_PTRNUL); + + _zoneLine[idx]._zoneData = zoneData; + + int16 *dataP = zoneData; + int v23 = 1000 * v8 / v20; + int v22 = 1000 * v9 / v20; + if (a4 < a2) + v23 = -v23; + if (a5 < a3) + v22 = -v22; + int v13 = 1000 * a2; + int v16 = 1000 * a3; + for (int i = 0; i < v20; i++) { + *dataP++ = v13 / 1000; + *dataP++ = v16 / 1000; + + v13 += v23; + v16 += v22; + } + *dataP++ = -1; + *dataP++ = -1; + + _zoneLine[idx]._count = v20; + _zoneLine[idx]._bobZoneIdx = bobZoneIdx; + } +} + +/** + * Add Line + */ +void LinesManager::addLine(int idx, Directions direction, int a3, int a4, int a5, int a6) { + assert (idx <= MAX_LINES); + + if (_linesNumb < idx) + _linesNumb = idx; + + _lineItem[idx]._lineData = (int16 *)_vm->_globals.freeMemory((byte *)_lineItem[idx]._lineData); + int v8 = abs(a3 - a5) + 1; + int v34 = abs(a4 - a6) + 1; + int v33 = v34; + if (v8 > v34) + v34 = v8; + + byte *v10 = _vm->_globals.allocMemory(4 * v34 + 8); + assert (v10 != g_PTRNUL); + + Common::fill(v10, v10 + 4 * v34 + 8, 0); + _lineItem[idx]._lineData = (int16 *)v10; + + int16 *v32 = _lineItem[idx]._lineData; + int v36 = 1000 * v8; + int v39 = 1000 * v8 / (v34 - 1); + int v37 = 1000 * v33 / (v34 - 1); + if (a5 < a3) + v39 = -v39; + if (a6 < a4) + v37 = -v37; + int v11 = (int)v39 / 1000; + int v12 = (int)v37 / 1000; + if (!v11) { + if (v12 == -1) { + _lineItem[idx]._directionRouteInc = DIR_UP; + _lineItem[idx]._directionRouteDec = DIR_DOWN; + } + if (v12 == 1) { + _lineItem[idx]._directionRouteInc = DIR_DOWN; + _lineItem[idx]._directionRouteDec = DIR_UP; + } + } + if (v11 == 1) { + if (v12 == -1) { + _lineItem[idx]._directionRouteInc = DIR_UP_RIGHT; + _lineItem[idx]._directionRouteDec = DIR_DOWN_LEFT; + } + if (!v12) { + _lineItem[idx]._directionRouteInc = DIR_RIGHT; + _lineItem[idx]._directionRouteDec = DIR_LEFT; + } + if (v12 == 1) { + _lineItem[idx]._directionRouteInc = DIR_DOWN_RIGHT; + _lineItem[idx]._directionRouteDec = DIR_UP_LEFT; + } + } + if (v11 == -1) { + if (v12 == 1) { + _lineItem[idx]._directionRouteInc = DIR_DOWN_LEFT; + _lineItem[idx]._directionRouteDec = DIR_UP_RIGHT; + } + if (!v12) { + _lineItem[idx]._directionRouteInc = DIR_LEFT; + _lineItem[idx]._directionRouteDec = DIR_RIGHT; + } + if (v12 == -1) { + _lineItem[idx]._directionRouteInc = DIR_UP_LEFT; + _lineItem[idx]._directionRouteDec = DIR_DOWN_RIGHT; + } + } + if (v11 == 1 && v37 > 250 && v37 <= 999) { + _lineItem[idx]._directionRouteInc = DIR_DOWN_RIGHT; + _lineItem[idx]._directionRouteDec = DIR_UP_LEFT; + } + if (v11 == -1 && v37 > 250 && v37 <= 999) { + _lineItem[idx]._directionRouteInc = DIR_DOWN_LEFT; + _lineItem[idx]._directionRouteDec = DIR_UP_RIGHT; + } + if (v11 == 1 && v37 < -250 && v37 > -1000) { + _lineItem[idx]._directionRouteInc = DIR_UP_RIGHT; + _lineItem[idx]._directionRouteDec = DIR_DOWN_LEFT; + } + // This condition is impossible to meet! + // Code present in the Linux and BeOS executables + // CHECKME: maybe it should be checking negative values? + if (v11 == -1 && v37 <= 249 && v37 > 1000) { + _lineItem[idx]._directionRouteInc = DIR_UP_LEFT; + _lineItem[idx]._directionRouteDec = DIR_DOWN_RIGHT; + } + int v40 = v36 / v34; + int v38 = 1000 * v33 / v34; + if (a5 < a3) + v40 = -v40; + if (a6 < a4) + v38 = -v38; + int v24 = 1000 * a3; + int v25 = 1000 * a4; + int v31 = 1000 * a3 / 1000; + int v30 = 1000 * a4 / 1000; + int v35 = v34 - 1; + for (int v26 = 0; v26 < v35; v26++) { + v32[0] = v31; + v32[1] = v30; + v32 += 2; + + v24 += v40; + v25 += v38; + v31 = v24 / 1000; + v30 = v25 / 1000; + } + v32[0] = a5; + v32[1] = a6; + + v32 += 2; + v32[0] = -1; + v32[1] = -1; + + _lineItem[idx]._lineDataEndIdx = v35 + 1; + _lineItem[idx]._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 == (int16 *)g_PTRNUL) + 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->_graphicsManager._maxX == curLineX || _vm->_graphicsManager._maxY == curLineY || + _vm->_graphicsManager._minX == curLineX || _vm->_graphicsManager._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[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 +int LinesManager::CONTOURNE(int a1, int a2, int a3, int a4, int a5, RouteItem *route) { + int v36 = a1; + int v7 = a2; + int v8 = a3; + if (a1 < a4) { + v8 = _lineItem[a1].appendToRouteInc(a2, -1, route, v8); + + for (int i = a1 + 1; i < a4; i++) + v8 = _lineItem[i].appendToRouteInc(0, -1, route, v8); + + v7 = 0; + v36 = a4; + } + if (v36 > a4) { + v8 = _lineItem[v36].appendToRouteDec(v7, 0, route, v8); + for (int i = v36 - 1; i > a4; i--) + v8 = _lineItem[i].appendToRouteDec(-1, 0, route, v8); + v7 = _lineItem[a4]._lineDataEndIdx - 1; + v36 = a4; + } + if (v36 == a4) { + if (a5 >= v7) { + v8 = _lineItem[a4].appendToRouteInc(v7, a5, route, v8); + } else { + v8 = _lineItem[a4].appendToRouteDec(v7, a5, route, v8); + } + } + return v8; +} + +// Avoid 1 +int LinesManager::CONTOURNE1(int a1, int a2, int a3, int a4, int a5, RouteItem *route, int a8, int a9) { + int v9 = a1; + int v10 = a2; + int v40 = a3; + if (a4 < a1) { + v40 = _lineItem[a1].appendToRouteInc(a2, -1, route, v40); + int v15 = a1 + 1; + if (v15 == a9 + 1) + v15 = a8; + while (a4 != v15) { + v40 = _lineItem[v15].appendToRouteInc(0, -1, route, v40); + ++v15; + if (a9 + 1 == v15) + v15 = a8; + } + v10 = 0; + v9 = a4; + } + if (a4 > v9) { + v40 = _lineItem[v9].appendToRouteDec(v10, 0, route, v40); + int v24 = v9 - 1; + if (v24 == a8 - 1) + v24 = a9; + while (a4 != v24) { + v40 = _lineItem[v24].appendToRouteDec(-1, 0, route, v40); + --v24; + if (a8 - 1 == v24) + v24 = a9; + } + v10 = _lineItem[a4]._lineDataEndIdx - 1; + v9 = a4; + } + if (a4 == v9) { + if (a5 >= v10) { + v40 = _lineItem[a4].appendToRouteInc(v10, a5, route, v40); + } else { + v40 = _lineItem[a4].appendToRouteDec(v10, a5, route, v40); + } + } + return v40; +} + +bool LinesManager::MIRACLE(int fromX, int fromY, int a3, int a4, int a5) { + int v35 = 0; + int v36 = 0; + int v42 = 0; + int v43 = 0; + int v44 = 0; + int v45 = 0; + int v46 = 0; + int v47 = 0; + int v48 = 0; + int v49 = 0; + + int curX = fromX; + int curY = fromY; + int v50 = a3; + int v7 = a5; + int v51; + if (checkCollisionLine(fromX, fromY, &v51, &v50, 0, _linesNumb)) { + switch (_lineItem[v50]._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 v41 = curX; + int v40 = curY; + int v9 = 0; + int v10 = v40; + for (int i = v40; v40 + 200 > v10; i = v10) { + if (checkCollisionLine(v41, i, &v49, &v48, 0, _lastLine) == 1 && v48 <= _lastLine) + break; + v49 = 0; + v48 = -1; + ++v9; + ++v10; + } + int v37 = v9; + int v12 = 0; + int v13 = v40; + for (int j = v40; v40 - 200 < v13; j = v13) { + if (checkCollisionLine(v41, j, &v47, &v46, 0, _lastLine) == 1 && v46 <= _lastLine) + break; + v47 = 0; + v46 = -1; + ++v12; + --v13; + } + int v39 = v12; + int v15 = 0; + int v16 = v41; + for (int k = v41; v41 + 200 > v16; k = v16) { + if (checkCollisionLine(k, v40, &v45, &v44, 0, _lastLine) == 1 && v44 <= _lastLine) + break; + v45 = 0; + v44 = -1; + ++v15; + ++v16; + } + int v38 = v15; + int v18 = 0; + int v19 = v41; + for (int l = v41; v41 - 200 < v19; l = v19) { + if (checkCollisionLine(l, v40, &v43, &v42, 0, _lastLine) == 1 && v42 <= _lastLine) + break; + v43 = 0; + v42 = -1; + ++v18; + --v19; + } + if (a4 > v50) { + if (v46 != -1 && v46 <= v50) + v46 = -1; + if (v44 != -1 && v50 >= v44) + v44 = -1; + if (v48 != -1 && v50 >= v48) + v48 = -1; + if (v42 != -1 && v50 >= v42) + v42 = -1; + if (v46 != -1 && a4 < v46) + v46 = -1; + if (v44 != -1 && a4 < v44) + v44 = -1; + if (v48 != -1 && a4 < v48) + v48 = -1; + if (v42 != -1 && a4 < v42) + v42 = -1; + } else if (a4 < v50) { + if (v46 != -1 && v46 >= v50) + v46 = -1; + if (v44 != -1 && v50 <= v44) + v44 = -1; + if (v48 != -1 && v50 <= v48) + v48 = -1; + if (v42 != -1 && v50 <= v42) + v42 = -1; + if (v46 != -1 && a4 > v46) + v46 = -1; + if (v44 != -1 && a4 > v44) + v44 = -1; + if (v48 != -1 && a4 > v48) + v48 = -1; + if (v42 != -1 && a4 > v42) + v42 = -1; + } + if (v46 != -1 || v44 != -1 || v48 != -1 || v42 != -1) { + Directions newDir = DIR_NONE; + if (a4 > v50) { + if (v48 <= v46 && v44 <= v46 && v42 <= v46 && v46 > v50) + newDir = DIR_UP; + if (v48 <= v44 && v46 <= v44 && v42 <= v44 && v50 < v44) + newDir = DIR_RIGHT; + if (v46 <= v48 && v44 <= v48 && v42 <= v48 && v50 < v48) + newDir = DIR_DOWN; + if (v48 <= v42 && v44 <= v42 && v46 <= v42 && v50 < v42) + newDir = DIR_LEFT; + } else if (a4 < v50) { + if (v46 == -1) + v46 = 1300; + if (v44 == -1) + v44 = 1300; + if (v48 == -1) + v48 = 1300; + if (v42 == -1) + v42 = 1300; + if (v46 != 1300 && v48 >= v46 && v44 >= v46 && v42 >= v46 && v46 < v50) + newDir = DIR_UP; + if (v44 != 1300 && v48 >= v44 && v46 >= v44 && v42 >= v44 && v50 > v44) + newDir = DIR_RIGHT; + if (v48 != 1300 && v46 >= v48 && v44 >= v48 && v42 >= v48 && v50 > v48) + newDir = DIR_DOWN; + if (v42 != 1300 && v48 >= v42 && v44 >= v42 && v46 >= v42 && v50 > v42) + newDir = DIR_LEFT; + } + + switch(newDir) { + case DIR_UP: + v36 = v46; + v35 = v47; + for (int v22 = 0; v22 < v39; v22++) { + if (checkCollisionLine(v41, v40 - v22, &v47, &v46, _lastLine + 1, _linesNumb) && _lastLine < v46) { + int v23 = GENIAL(v46, v47, v41, v40 - v22, v41, v40 - v39, v7, &_bestRoute[0]); + if (v23 == -1) + return false; + v7 = v23; + if (_newPosY != -1) + v22 = _newPosY - v40; + } + _bestRoute[v7].set(v41, v40 - v22, DIR_UP); + v7++; + } + _newLineIdx = v36; + _newLineDataIdx = v35; + _newRouteIdx = v7; + return true; + break; + case DIR_RIGHT: + v36 = v44; + v35 = v45; + for (int v31 = 0; v31 < v38; v31++) { + if (checkCollisionLine(v31 + v41, v40, &v47, &v46, _lastLine + 1, _linesNumb) && _lastLine < v46) { + int v32 = GENIAL(v46, v47, v31 + v41, v40, v38 + v41, v40, v7, &_bestRoute[0]); + if (v32 == -1) + return false; + v7 = v32; + if (_newPosX != -1) + v31 = _newPosX - v41; + } + _bestRoute[v7].set(v31 + v41, v40, DIR_RIGHT); + v7++; + } + _newLineIdx = v36; + _newLineDataIdx = v35; + _newRouteIdx = v7; + return true; + break; + case DIR_DOWN: + v36 = v48; + v35 = v49; + for (int v25 = 0; v25 < v37; v25++) { + if (checkCollisionLine(v41, v25 + v40, &v47, &v46, _lastLine + 1, _linesNumb) && _lastLine < v46) { + int v26 = GENIAL(v46, v47, v41, v25 + v40, v41, v37 + v40, v7, &_bestRoute[0]); + if (v26 == -1) + return false; + v7 = v26; + if (_newPosY != -1) + v25 = v40 - _newPosY; + } + _bestRoute[v7].set(v41, v25 + v40, DIR_DOWN); + v7++; + } + _newLineIdx = v36; + _newLineDataIdx = v35; + _newRouteIdx = v7; + return true; + break; + case DIR_LEFT: + v36 = v42; + v35 = v43; + for (int v28 = 0; v28 < v18; v28++) { + if (checkCollisionLine(v41 - v28, v40, &v47, &v46, _lastLine + 1, _linesNumb) && _lastLine < v46) { + int v29 = GENIAL(v46, v47, v41 - v28, v40, v41 - v18, v40, v7, &_bestRoute[0]); + if (v29 == -1) + return false; + v7 = v29; + if (_newPosX != -1) + v28 = v41 - _newPosX; + } + _bestRoute[v7].set(v41 - v28, v40, DIR_LEFT); + v7++; + } + _newLineIdx = v36; + _newLineDataIdx = v35; + _newRouteIdx = v7; + return true; + break; + default: + break; + } + } + return false; +} + +int LinesManager::GENIAL(int lineIdx, int dataIdx, int a3, int a4, int a5, int a6, int a7, RouteItem *route) { + int result = a7; + int v80 = -1; + ++_pathFindingMaxDepth; + if (_pathFindingMaxDepth > 10) { + warning("PathFinding - Max depth reached"); + route[a7].invalidate(); + return -1; + } + int16 *v10 = _lineItem[lineIdx]._lineData; + int v98 = v10[0]; + int v97 = v10[1]; + int v92 = lineIdx; + + int v65; + bool loopCond = false; + for (;;) { + int v86 = v92 - 1; + int v11 = 2 * _lineItem[v92 - 1]._lineDataEndIdx; + + int16 *v12 = _lineItem[v92 - 1]._lineData; + if (v12 == (int16 *)g_PTRNUL) + break; + while (v12[v11 - 2] != v98 || v97 != v12[v11 - 1]) { + --v86; + if (_lastLine - 1 != v86) { + v11 = 2 * _lineItem[v86]._lineDataEndIdx; + v12 = _lineItem[v86]._lineData; + if (v12 != (int16 *)g_PTRNUL) + continue; + } + loopCond = true; + break; + } + if (loopCond) + break; + + v92 = v86; + v98 = v12[0]; + v97 = v12[1]; + } + + int16 *v13 = _lineItem[lineIdx]._lineData; + int v95 = v13[2 * _lineItem[lineIdx]._lineDataEndIdx - 2]; + int v93 = v13[2 * _lineItem[lineIdx]._lineDataEndIdx - 1]; + int v91 = lineIdx; + int foundLineIdx, foundDataIdx; + loopCond = false; + for (;;) { + int v87 = v91 + 1; + int v15 = 2 * _lineItem[v91 + 1]._lineDataEndIdx; + int16 *v16 = _lineItem[v91 + 1]._lineData; + if (v16 == (int16 *)g_PTRNUL) + break; + int v17; + for (;;) { + v65 = v15; + v17 = v16[v15 - 2]; + if (v16[0] == v95 && v93 == v16[1]) + break; + + ++v87; + if (v87 != _linesNumb + 1) { + v15 = 2 * _lineItem[v87]._lineDataEndIdx; + v16 = _lineItem[v87]._lineData; + if (v16 != (int16 *)g_PTRNUL) + continue; + } + loopCond = true; + break; + } + if (loopCond) + break; + + v91 = v87; + v95 = v17; + v93 = v16[v65 - 1]; + } + + int v58 = abs(a3 - a5) + 1; + int v85 = abs(a4 - a6) + 1; + int v20 = v85; + if (v58 > v20) + v85 = v58; + int v84 = 1000 * v58 / v85; + int v83 = 1000 * v20 / v85; + int v21 = 1000 * a3; + int v22 = 1000 * a4; + int v82 = a3; + int v81 = a4; + if (a5 < a3) + v84 = -v84; + if (a6 < a4) + v83 = -v83; + if (v85 > 800) + v85 = 800; + + Common::fill(&_lineBuf[0], &_lineBuf[1000], 0); + int bugLigIdx = 0; + for (int v88 = 0; v88 < v85 + 1; v88++) { + _lineBuf[bugLigIdx] = v82; + _lineBuf[bugLigIdx + 1] = v81; + v21 += v84; + v22 += v83; + v82 = v21 / 1000; + v81 = v22 / 1000; + bugLigIdx += 2; + } + bugLigIdx -= 2; + int v77 = 0; + int v78 = 0; + int v79 = 0; + for (int v89 = v85 + 1; v89 > 0; v89--) { + if (checkCollisionLine(_lineBuf[bugLigIdx], _lineBuf[bugLigIdx + 1], &foundDataIdx, &foundLineIdx, v92, v91) && _lastLine < foundLineIdx) { + v80 = foundLineIdx; + v77 = foundDataIdx; + v78 = _lineBuf[bugLigIdx]; + v79 = _lineBuf[bugLigIdx + 1]; + break; + } + bugLigIdx -= 2; + } + int v66 = 0; + int v68 = 0; + int v70 = 0; + int v72 = 0; + for (int i = v92; i <= v91; ++i) { + int16 *lineData = _lineItem[i]._lineData; + if (lineData == (int16 *)g_PTRNUL) + error("error in genial routine"); + if (i == v92) { + v72 = lineData[2 * _lineItem[i]._lineDataEndIdx - 1]; + if (lineData[1] <= lineData[2 * _lineItem[i]._lineDataEndIdx - 1]) + v72 = lineData[1]; + v70 = lineData[2 * _lineItem[i]._lineDataEndIdx - 1]; + if (lineData[1] >= lineData[2 * _lineItem[i]._lineDataEndIdx - 1]) + v70 = lineData[1]; + v68 = lineData[2 * _lineItem[i]._lineDataEndIdx - 2]; + if (lineData[0] <= lineData[2 * _lineItem[i]._lineDataEndIdx - 2]) + v68 = lineData[0]; + v66 = lineData[2 * _lineItem[i]._lineDataEndIdx - 2]; + if (lineData[0] >= lineData[2 * _lineItem[i]._lineDataEndIdx - 2]) + v66 = lineData[0]; + } else { + if (lineData[1] < lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] < v72) + v72 = lineData[1]; + if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] < v72) + v72 = lineData[2 * _lineItem[i]._lineDataEndIdx - 1]; + if (lineData[1] > lineData[2 * _lineItem[i]._lineDataEndIdx - 1] && lineData[1] > v70) + v70 = lineData[1]; + if (lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > lineData[1] && lineData[2 * _lineItem[i]._lineDataEndIdx - 1] > v70) + v70 = lineData[2 * _lineItem[i]._lineDataEndIdx - 1]; + if (lineData[0] < lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && v68 > lineData[0]) + v68 = lineData[0]; + if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] < lineData[0] && v68 > lineData[2 * _lineItem[i]._lineDataEndIdx - 2]) + v68 = lineData[2 * _lineItem[i]._lineDataEndIdx - 2]; + if (lineData[0] > lineData[2 * _lineItem[i]._lineDataEndIdx - 2] && v66 < lineData[0]) + v66 = lineData[0]; + if (lineData[2 * _lineItem[i]._lineDataEndIdx - 2] > lineData[0] && v66 < lineData[2 * _lineItem[i]._lineDataEndIdx - 2]) + v66 = lineData[2 * _lineItem[i]._lineDataEndIdx - 2]; + } + } + int v69 = v68 - 2; + int v73 = v72 - 2; + int v67 = v66 + 2; + int v71 = v70 + 2; + if (a5 >= v69 && a5 <= v67 && a6 >= v73 && a6 <= v71) { + int v34 = a6; + int v76 = -1; + for (;;) { + --v34; + if (!checkCollisionLine(a5, v34, &foundDataIdx, &foundLineIdx, v92, v91)) + break; + + v76 = foundLineIdx; + if (!v34 || v73 > v34) + break; + } + int v35 = a6; + int v75 = -1; + for (;;) { + ++v35; + if (!checkCollisionLine(a5, v35, &foundDataIdx, &foundLineIdx, v92, v91)) + break; + + v75 = foundLineIdx; + if (_vm->_globals._characterMaxPosY <= v35 || v71 <= v35) + break; + } + int v36 = a5; + int v74 = -1; + for (;;) { + ++v36; + if (!checkCollisionLine(v36, a6, &foundDataIdx, &foundLineIdx, v92, v91)) + break; + + v74 = foundLineIdx; + + if (_vm->_graphicsManager._maxX <= v36 || v67 <= v36) + break; + } + int v37 = a5; + int v38 = -1; + for(;;) { + --v37; + if (!checkCollisionLine(v37, a6, &foundDataIdx, &foundLineIdx, v92, v91)) + break; + v38 = foundLineIdx; + if (v37 <= 0 || v69 >= v37) + break;; + } + if (v74 != -1 && v38 != -1 && v76 != -1 && v75 != -1) { + route[a7].invalidate(); + return -1; + } + } + if (v78 < a3 - 1 || v78 > a3 + 1 || v79 < a4 - 1 || v79 > a4 + 1) { + _newPosX = v78; + _newPosY = v79; + if (lineIdx < v80) { + int v43 = 0; + int v42 = lineIdx; + do { + if (v42 == v92 - 1) + v42 = v91; + ++v43; + --v42; + if (v42 == v92 - 1) + v42 = v91; + } while (v80 != v42); + if (abs(v80 - lineIdx) == v43) { + if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) { + result = CONTOURNE(lineIdx, dataIdx, a7, v80, v77, route); + } else { + result = CONTOURNE1(lineIdx, dataIdx, a7, v80, v77, route, v92, v91); + } + } + if (abs(v80 - lineIdx) < v43) + result = CONTOURNE(lineIdx, dataIdx, result, v80, v77, route); + if (v43 < abs(v80 - lineIdx)) + result = CONTOURNE1(lineIdx, dataIdx, result, v80, v77, route, v92, v91); + } + if (lineIdx > v80) { + int v45 = abs(lineIdx - v80); + int v47 = lineIdx; + int v48 = 0; + do { + if (v47 == v91 + 1) + v47 = v92; + ++v48; + ++v47; + if (v47 == v91 + 1) + v47 = v92; + } while (v80 != v47); + if (v45 == v48) { + if (dataIdx > abs(_lineItem[lineIdx]._lineDataEndIdx / 2)) { + result = CONTOURNE1(lineIdx, dataIdx, result, v80, v77, route, v92, v91); + } else { + result = CONTOURNE(lineIdx, dataIdx, result, v80, v77, route); + } + } + if (v45 < v48) + result = CONTOURNE(lineIdx, dataIdx, result, v80, v77, route); + if (v48 < v45) + result = CONTOURNE1(lineIdx, dataIdx, result, v80, v77, route, v92, v91); + } + if (lineIdx == v80) + result = CONTOURNE(lineIdx, dataIdx, result, lineIdx, v77, 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; +} + +// Avoid 2 +RouteItem *LinesManager::PARCOURS2(int fromX, int fromY, int destX, int destY) { + int foundLineIdx; + int foundDataIdx; + int curLineY = 0; + int curLineX = 0; + int v126[9]; + int v131[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; + int v111 = 0; + if (destY <= 24) + clipDestY = 25; + if (!_vm->_globals._checkDistanceFl) { + if (abs(fromX - _vm->_globals._oldRouteFromX) <= 4 && abs(fromY - _vm->_globals._oldRouteFromY) <= 4 && + abs(_vm->_globals._oldRouteDestX - destX) <= 4 && abs(_vm->_globals._oldRouteDestY - clipDestY) <= 4) + return (RouteItem *)g_PTRNUL; + + if (abs(fromX - destX) <= 4 && abs(fromY - clipDestY) <= 4) + return (RouteItem *)g_PTRNUL; + + if (_vm->_globals._oldZoneNum > 0 && _vm->_objectsManager._zoneNum > 0 && _vm->_globals._oldZoneNum == _vm->_objectsManager._zoneNum) + return (RouteItem *)g_PTRNUL; + } + _vm->_globals._checkDistanceFl = false; + _vm->_globals._oldZoneNum = _vm->_objectsManager._zoneNum; + _vm->_globals._oldRouteFromX = fromX; + _vm->_globals._oldRouteDestX = destX; + _vm->_globals._oldRouteFromY = fromY; + _vm->_globals._oldRouteDestY = clipDestY; + _pathFindingMaxDepth = 0; + int routeIdx = 0; + if (destX <= 19) + clipDestX = 20; + if (clipDestY <= 19) + clipDestY = 20; + if (clipDestX > _vm->_graphicsManager._maxX - 10) + clipDestX = _vm->_graphicsManager._maxX - 10; + if (clipDestY > _vm->_globals._characterMaxPosY) + clipDestY = _vm->_globals._characterMaxPosY; + + if (abs(fromX - clipDestX) <= 3 && abs(fromY - clipDestY) <= 3) + return (RouteItem *)g_PTRNUL; + + for (int i = 0; i <= 8; ++i) { + collLineIdxArr[i] = -1; + collLineDataIdxArr[i] = 0; + v131[i] = 1300; + v126[i] = 1300; + } + + if (characterRoute(fromX, fromY, clipDestX, clipDestY, -1, -1, 0) == 1) + return _bestRoute; + + int v14 = 0; + for (int tmpY = clipDestY; tmpY < _vm->_graphicsManager._maxY; tmpY++, v14++) { + if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[5], &collLineIdxArr[5], 0, _lastLine) && collLineIdxArr[5] <= _lastLine) + break; + collLineDataIdxArr[5] = 0; + collLineIdxArr[5] = -1; + } + v131[5] = v14; + + v14 = 0; + for (int tmpY = clipDestY; tmpY > _vm->_graphicsManager._minY; tmpY--, v14++) { + if (checkCollisionLine(clipDestX, tmpY, &collLineDataIdxArr[1], &collLineIdxArr[1], 0, _lastLine) && collLineIdxArr[1] <= _lastLine) + break; + collLineDataIdxArr[1] = 0; + collLineIdxArr[1] = -1; + if (v131[5] < v14 && collLineIdxArr[5] != -1) + break; + } + v131[1] = v14; + + v14 = 0; + for (int tmpX = clipDestX; tmpX < _vm->_graphicsManager._maxX; tmpX++) { + if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[3], &collLineIdxArr[3], 0, _lastLine) && collLineIdxArr[3] <= _lastLine) + break; + collLineDataIdxArr[3] = 0; + collLineIdxArr[3] = -1; + ++v14; + if (v131[1] < v14 && collLineIdxArr[1] != -1) + break; + if (v131[5] < v14 && collLineIdxArr[5] != -1) + break; + } + v131[3] = v14; + + v14 = 0; + for (int tmpX = clipDestX; tmpX > _vm->_graphicsManager._minX; tmpX--) { + if (checkCollisionLine(tmpX, clipDestY, &collLineDataIdxArr[7], &collLineIdxArr[7], 0, _lastLine) && collLineIdxArr[7] <= _lastLine) + break; + collLineDataIdxArr[7] = 0; + collLineIdxArr[7] = -1; + ++v14; + if (v131[1] < v14 && collLineIdxArr[1] != -1) + break; + if (v131[5] < v14 && collLineIdxArr[5] != -1) + break; + if (v131[3] < v14 && collLineIdxArr[3] != -1) + break; + } + v131[7] = v14; + + if (collLineIdxArr[1] < 0 || _lastLine < collLineIdxArr[1]) + collLineIdxArr[1] = -1; + if (collLineIdxArr[3] < 0 || _lastLine < collLineIdxArr[3]) + collLineIdxArr[3] = -1; + if (collLineIdxArr[5] < 0 || _lastLine < collLineIdxArr[5]) + collLineIdxArr[5] = -1; + if (collLineIdxArr[7] < 0 || _lastLine < collLineIdxArr[7]) + collLineIdxArr[7] = -1; + if (collLineIdxArr[1] < 0) + v131[1] = 1300; + if (collLineIdxArr[3] < 0) + v131[3] = 1300; + if (collLineIdxArr[5] < 0) + v131[5] = 1300; + if (collLineIdxArr[7] < 0) + v131[7] = 1300; + if (collLineIdxArr[1] == -1 && collLineIdxArr[3] == -1 && collLineIdxArr[5] == -1 && collLineIdxArr[7] == -1) + return (RouteItem *)g_PTRNUL; + + if (collLineIdxArr[5] != -1 && v131[1] >= v131[5] && v131[3] >= v131[5] && v131[7] >= v131[5]) { + curLineIdx = collLineIdxArr[5]; + curLineDataIdx = collLineDataIdxArr[5]; + } else if (collLineIdxArr[1] != -1 && v131[5] >= v131[1] && v131[3] >= v131[1] && v131[7] >= v131[1]) { + curLineIdx = collLineIdxArr[1]; + curLineDataIdx = collLineDataIdxArr[1]; + } else if (collLineIdxArr[3] != -1 && v131[1] >= v131[3] && v131[5] >= v131[3] && v131[7] >= v131[3]) { + curLineIdx = collLineIdxArr[3]; + curLineDataIdx = collLineDataIdxArr[3]; + } else if (collLineIdxArr[7] != -1 && v131[5] >= v131[7] && v131[3] >= v131[7] && v131[1] >= v131[7]) { + curLineIdx = collLineIdxArr[7]; + curLineDataIdx = collLineDataIdxArr[7]; + } + + for (int i = 0; i <= 8; ++i) { + collLineIdxArr[i] = -1; + collLineDataIdxArr[i] = 0; + v131[i] = 1300; + v126[i] = 1300; + } + + v14 = 0; + for (int tmpY = fromY; tmpY < _vm->_graphicsManager._maxY; tmpY++, v14++) { + if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[5], &collLineIdxArr[5], 0, _lastLine) && collLineIdxArr[5] <= _lastLine) + break; + collLineDataIdxArr[5] = 0; + collLineIdxArr[5] = -1; + } + v131[5] = v14 + 1; + + v14 = 0; + for (int tmpY = fromY; tmpY > _vm->_graphicsManager._minY; tmpY--) { + if (checkCollisionLine(fromX, tmpY, &collLineDataIdxArr[1], &collLineIdxArr[1], 0, _lastLine) && collLineIdxArr[1] <= _lastLine) + break; + collLineDataIdxArr[1] = 0; + collLineIdxArr[1] = -1; + ++v14; + if (collLineIdxArr[5] != -1 && v14 > 80) + break; + } + v131[1] = v14 + 1; + + v14 = 0; + for (int tmpX = fromX; tmpX < _vm->_graphicsManager._maxX; tmpX++) { + if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[3], &collLineIdxArr[3], 0, _lastLine) && collLineIdxArr[3] <= _lastLine) + break; + collLineDataIdxArr[3] = 0; + collLineIdxArr[3] = -1; + ++v14; + if ((collLineIdxArr[5] != -1 || collLineIdxArr[1] != -1) && (v14 > 100)) + break; + } + v131[3] = v14 + 1; + + v14 = 0; + for (int tmpX = fromX; tmpX > _vm->_graphicsManager._minX; tmpX--) { + if (checkCollisionLine(tmpX, fromY, &collLineDataIdxArr[7], &collLineIdxArr[7], 0, _lastLine) && collLineIdxArr[7] <= _lastLine) + break; + collLineDataIdxArr[7] = 0; + collLineIdxArr[7] = -1; + ++v14; + if ((collLineIdxArr[5] != -1 || collLineIdxArr[1] != -1 || collLineIdxArr[3] != -1) && (v14 > 100)) + break; + } + v131[7] = v14 + 1; + + if (collLineIdxArr[1] != -1) + v126[1] = abs(collLineIdxArr[1] - curLineIdx); + + if (collLineIdxArr[3] != -1) + v126[3] = abs(collLineIdxArr[3] - curLineIdx); + + if (collLineIdxArr[5] != -1) + v126[5] = abs(collLineIdxArr[5] - curLineIdx); + + if (collLineIdxArr[7] != -1) + v126[7] = abs(collLineIdxArr[7] - curLineIdx); + + if (collLineIdxArr[1] == -1 && collLineIdxArr[3] == -1 && collLineIdxArr[5] == -1 && collLineIdxArr[7] == -1) + error("Nearest point not found"); + + if (collLineIdxArr[1] != -1 && v126[3] >= v126[1] && v126[5] >= v126[1] && v126[7] >= v126[1]) { + lineIdx = collLineIdxArr[1]; + v111 = v131[1]; + newDir = DIR_UP; + lineDataIdx = collLineDataIdxArr[1]; + } else if (collLineIdxArr[5] != -1 && v126[3] >= v126[5] && v126[1] >= v126[5] && v126[7] >= v126[5]) { + lineIdx = collLineIdxArr[5]; + v111 = v131[5]; + newDir = DIR_DOWN; + lineDataIdx = collLineDataIdxArr[5]; + } else if (collLineIdxArr[3] != -1 && v126[1] >= v126[3] && v126[5] >= v126[3] && v126[7] >= v126[3]) { + lineIdx = collLineIdxArr[3]; + v111 = v131[3]; + newDir = DIR_RIGHT; + lineDataIdx = collLineDataIdxArr[3]; + } else if (collLineIdxArr[7] != -1 && v126[1] >= v126[7] && v126[5] >= v126[7] && v126[3] >= v126[7]) { + lineIdx = collLineIdxArr[7]; + v111 = v131[7]; + newDir = DIR_LEFT; + lineDataIdx = collLineDataIdxArr[7]; + } + + int v55 = characterRoute(fromX, fromY, clipDestX, clipDestY, lineIdx, curLineIdx, 0); + + if (v55 == 1) + return _bestRoute; + + if (v55 == 2) { + lineIdx = _newLineIdx; + lineDataIdx = _newLineDataIdx; + routeIdx = _newRouteIdx; + } else { + if (newDir == DIR_UP) { + for (int deltaY = 0; deltaY < v111; deltaY++) { + if (checkCollisionLine(fromX, fromY - deltaY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) { + int tmpRouteIdx = GENIAL(foundLineIdx, foundDataIdx, fromX, fromY - deltaY, fromX, fromY - v111, 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++; + } + } + if (newDir == DIR_DOWN) { + for (int deltaY = 0; deltaY < v111; deltaY++) { + if (checkCollisionLine(fromX, deltaY + fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) + && _lastLine < foundLineIdx) { + int tmpRouteIdx = GENIAL(foundLineIdx, foundDataIdx, fromX, deltaY + fromY, fromX, v111 + 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++; + } + } + if (newDir == DIR_LEFT) { + for (int deltaX = 0; deltaX < v111; deltaX++) { + if (checkCollisionLine(fromX - deltaX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) { + int tmpRouteIdx = GENIAL(foundLineIdx, foundDataIdx, fromX - deltaX, fromY, fromX - v111, 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++; + } + } + if (newDir == DIR_RIGHT) { + for (int deltaX = 0; deltaX < v111; deltaX++) { + if (checkCollisionLine(deltaX + fromX, fromY, &foundDataIdx, &foundLineIdx, _lastLine + 1, _linesNumb) && _lastLine < foundLineIdx) { + int tmpRouteIdx = GENIAL(foundLineIdx, foundDataIdx, deltaX + fromX, fromY, v111 + 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++; + } + } + } + + + 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) { + int v78 = characterRoute(_lineItem[idx]._lineData[2 * dataIdx], _lineItem[idx]._lineData[2 * dataIdx + 1], clipDestX, clipDestY, idx, curLineIdx, routeIdx); + if (v78 == 1) + return &_bestRoute[0]; + if (v78 == 2 || MIRACLE(curLineX, curLineY, idx, curLineIdx, routeIdx)) { + lineIdx = _newLineIdx; + lineDataIdx = _newLineDataIdx; + routeIdx = _newRouteIdx; + loopCond = true; + break; + } + } + } + + if (loopCond) + break; + + int v79 = characterRoute(curLineX, curLineY, clipDestX, clipDestY, idx, curLineIdx, routeIdx); + if (v79 == 1) + return &_bestRoute[0]; + if (v79 == 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 v117 = lineIdx - 1; v117 > curLineIdx; v117--) { + for (int dataIdx = _lineItem[v117]._lineDataEndIdx - 1; dataIdx > -1; dataIdx--) { + curLineX = _lineItem[v117]._lineData[2 * dataIdx]; + curLineY = _lineItem[v117]._lineData[2 * dataIdx + 1]; + _bestRoute[routeIdx].set(_lineItem[v117]._lineData[2 * dataIdx], _lineItem[v117]._lineData[2 * dataIdx + 1], _lineItem[v117]._directionRouteDec); + routeIdx++; + if (_lineItem[v117]._lineDataEndIdx > 30 && dataIdx == _lineItem[v117]._lineDataEndIdx / 2) { + int v88 = characterRoute(curLineX, curLineY, clipDestX, clipDestY, v117, curLineIdx, routeIdx); + if (v88 == 1) + return &_bestRoute[0]; + if (v88 == 2 || MIRACLE(curLineX, curLineY, v117, curLineIdx, routeIdx)) { + lineIdx = _newLineIdx; + lineDataIdx = _newLineDataIdx; + routeIdx = _newRouteIdx; + loopCond = true; + break; + } + } + } + + if (loopCond) + break; + + int v89 = characterRoute(curLineX, curLineY, clipDestX, clipDestY, v117, curLineIdx, routeIdx); + if (v89 == 1) + return &_bestRoute[0]; + if (v89 == 2 || MIRACLE(curLineX, curLineY, v117, 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]; +} + +int LinesManager::characterRoute(int fromX, int fromY, int destX, int destY, int a5, int a6, int a7) { + int v18; + int v19; + int v20; + int v21; + int v22; + int v23; + int v24; + int v33; + bool v45; + int v54; + int v55; + Directions newDirection; + int v92; + int v93; + int v94; + int v95; + int v96; + int v97; + int v98; + int v99; + int v100; + int v101; + int v102; + int v103; + int v104; + int v105; + int v106; + int v107; + int v108; + int v109; + int v111; + int v114; + int v115; + int v117; + int collLineIdx; + int collDataIdx = 0; + int v140; + int v142; + bool colResult = false; + + int curX = fromX; + int curY = fromY; + int v137 = a7; + bool v136 = false; + if (a5 == -1 && a6 == -1) + v136 = true; + int foundDataIdx; + int foundLineIdx = a5; + 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; + } + } + v98 = curX; + v97 = curY; + v115 = 0; + v142 = -1; + v140 = -1; + collLineIdx = -1; + + int distX, v10, distY, v12, v13, v14; + int repeatFlag = 0; + int v143 = 0; + int v141 = 0; + for (;;) { + v111 = curX; + v109 = curY; + if (destX >= curX - 2 && destX <= curX + 2 && destY >= curY - 2 && destY <= curY + 2) { + essai0[v115].invalidate(); + goto retLABEL_essai0; + } + distX = abs(curX - destX); + v10 = distX + 1; + distY = abs(curY - destY); + v107 = distY + 1; + if (v10 > v107) + v107 = v10; + v12 = v107 - 1; + assert(v12 != 0); + v101 = 1000 * v10 / v12; + v99 = 1000 * (distY + 1) / v12; + if (destX < curX) + v101 = -v101; + if (destY < curY) + v99 = -v99; + v13 = (int16)v101 / 1000; + v94 = (int16)v99 / 1000; + newDirection = DIR_NONE; + if (v94 == -1 && (v101 >= 0 && v101 <= 150)) + newDirection = DIR_UP; + if (v13 == 1 && (v99 >= -1 && v99 <= 150)) + newDirection = DIR_RIGHT; + if (v94 == 1 && (v101 >= -150 && v101 <= 150)) + newDirection = DIR_DOWN; + if (v13 == -1 && (v99 >= -150 && v99 <= 150)) + newDirection = DIR_LEFT; + if (v94 == -1 && (v101 >= -150 && v101 <= 0)) + newDirection = DIR_UP; + + if (newDirection == DIR_NONE && !checkSmoothMove(curX, v109, destX, destY) && !makeSmoothMove(curX, v109, destX, destY)) { + newDirection = _smoothMoveDirection; + v14 = 0; + for (v14 = 0; _smoothRoute[v14]._posX != -1 && _smoothRoute[v14]._posY != -1; ++v14) { + if (checkCollisionLine(_smoothRoute[v14]._posX, _smoothRoute[v14]._posY, &v143, &v142, 0, _linesNumb)) { + if (v142 > _lastLine) + v142 = -1; + break; + } + + essai0[v115].set(_smoothRoute[v14]._posX, _smoothRoute[v14]._posY, newDirection); + v115++; + + if (repeatFlag == 1) { + repeatFlag = 2; + break; + } + } + + if (repeatFlag != 2 && _smoothRoute[v14]._posX != -1 && _smoothRoute[v14]._posY != -1) + break; + + repeatFlag = 1; + v18 = v14 - 1; + v111 = _smoothRoute[v18]._posX; + v109 = _smoothRoute[v18]._posY; + } + v19 = abs(v111 - destX); + v20 = v19 + 1; + v95 = abs(v109 - destY); + v108 = v95 + 1; + if (v20 > (v95 + 1)) + v108 = v20; + if (v108 <= 10) { + essai0[v115].invalidate(); + goto retLABEL_essai0; + } + v21 = v108 - 1; + v102 = 1000 * v20 / v21; + v100 = 1000 * (v95 + 1) / v21; + if (destX < v111) + v102 = -v102; + if (destY < v109) + v100 = -v100; + v22 = v102 / 1000; + v96 = v100 / 1000; + v106 = 1000 * v111; + v105 = 1000 * v109; + v104 = 1000 * v111 / 1000; + v103 = v105 / 1000; + if (!(v102 / 1000) && v96 == -1) + newDirection = DIR_UP; + if (v22 == 1) { + if (v96 == -1) + newDirection = DIR_UP_RIGHT; + if (!v96) + newDirection = DIR_RIGHT; + if (v96 == 1) + newDirection = DIR_DOWN_RIGHT; + } + if (!v22 && v96 == 1) + newDirection = DIR_DOWN; + if ((v22 != -1) && (v96 == -1)) { + if (v102 >= 0 && v102 < 510) + newDirection = DIR_UP; + else if (v102 >= 510 && v102 <= 1000) + newDirection = DIR_UP_RIGHT; + } else { + if (v96 == 1) + newDirection = DIR_DOWN_LEFT; + else if (!v96) + newDirection = DIR_LEFT; + else if (v96 == -1) { + if (v102 >= 0 && v102 < 510) + newDirection = DIR_UP; + else if (v102 >= 510 && v102 <= 1000) + newDirection = DIR_UP_RIGHT; + else + newDirection = DIR_UP_LEFT; + } + } + if (v22 == 1) { + if (v100 >= -1000 && v100 <= -510) + newDirection = DIR_UP_RIGHT; + if (v100 >= -510 && v100 <= 510) + newDirection = DIR_RIGHT; + if (v100 >= 510 && v100 <= 1000) + newDirection = DIR_DOWN_RIGHT; + } + if (v96 == 1) { + if (v102 >= 510 && v102 <= 1000) + newDirection = DIR_DOWN_RIGHT; + if (v102 >= -510 && v102 <= 510) + newDirection = DIR_DOWN; + if (v102 >= -1000 && v102 <= -510) + newDirection = DIR_DOWN_LEFT; + } + if (v22 == -1) { + if (v100 >= 510 && v100 <= 1000) + newDirection = DIR_DOWN_LEFT; + if (v100 >= -510 && v100 <= 510) + newDirection = DIR_LEFT; + if (v100 >= -1000 && v100 <= -510) + newDirection = DIR_UP_LEFT; + } + if (v96 == -1) { + if (v102 >= -1000 && v102 <= -510) + newDirection = DIR_UP_LEFT; + if (v102 >= -510 && v102 <= 0) + newDirection = DIR_UP; + } + v23 = 0; + if (v108 + 1 <= 0) { + essai0[v115].invalidate(); + goto retLABEL_essai0; + } + while (!checkCollisionLine(v104, v103, &v143, &v142, 0, _linesNumb)) { + essai0[v115].set(v104, v103, newDirection); + v106 += v102; + v105 += v100; + v104 = v106 / 1000; + v103 = v105 / 1000; + v115++; + ++v23; + if (v23 >= v108 + 1) { + essai0[v115].invalidate(); + goto retLABEL_essai0; + } + } + if (_lastLine >= v142) + break; + v24 = GENIAL(v142, v143, v104, v103, destX, destY, v115, essai0); + if (v24 == -1) + goto retLABEL_essai0; + v115 = v24; + if (_newPosX != -1 || _newPosY != -1) { + v142 = -1; + break; + } + curX = -1; + curY = -1; + } + + essai0[v115].invalidate(); + + v117 = 0; + v33 = v98; + v92 = v97; + + while (true) { + + if (destX >= v33 - 2 && destX <= v33 + 2 && destY >= v92 - 2 && destY <= v92 + 2) { + essai1[v117].invalidate(); + goto retLABEL_essai1; + } + while (v33 != destX) { + if (checkCollisionLine(v33, v92, &v141, &v140, 0, _linesNumb)) { + if (v140 > _lastLine) + v140 = -1; + break; + } + + if (v33 < destX) + essai1[v117++].set(v33++, v92, DIR_RIGHT); + else + essai1[v117++].set(v33--, v92, DIR_LEFT); + } + if (v33 != destX) + break; + + int v43 = v92; + while (v43 != destY) { + if (checkCollisionLine(destX, v43, &v141, &v140, 0, _linesNumb)) { + if (v140 <= _lastLine) + break; + + int v44 = GENIAL(v140, v141, destX, v43, destX, destY, v117, essai1); + if (v44 == -1) + goto retLABEL_essai1; + v117 = v44; + if (_newPosX != -1 && _newPosY != -1) + break; + } + + if (v43 < destY) + essai1[v117++].set(destX, v43++, DIR_DOWN); + else + essai1[v117++].set(destX, v43--, DIR_UP); + } + if (v43 == destY) { + essai1[v117].invalidate(); + goto retLABEL_essai1; + } + if (v140 <= _lastLine) + break; + v33 = _newPosX; + v92 = _newPosY; + v45 = checkCollisionLine(_newPosX, _newPosY, &v141, &v140, 0, _lastLine); + if (v45 && v140 <= _lastLine) + break; + } + + essai1[v117].invalidate(); + v117 = 0; + v54 = v98; + v93 = v97; + while (true) { + int v61; + v114 = v54; + if (destX >= v54 - 2 && destX <= v54 + 2 && destY >= v93 - 2 && destY <= v93 + 2) { + essai2[v117].invalidate(); + goto retLABEL_essai2; + } + + v55 = v93; + while (v55 != destY) { + if (checkCollisionLine(v114, v55, &collDataIdx, &collLineIdx, 0, _linesNumb)) { + if (collLineIdx > _lastLine) + collLineIdx = -1; + break; + } + + if (v55 < destY) + essai2[v117++].set(v114, v55++, DIR_DOWN); + else + essai2[v117++].set(v114, v55--, DIR_UP); + } + if (v55 != destY) + break; + + v61 = v114; + while (v61 != destX) { + if (checkCollisionLine(v61, destY, &collDataIdx, &collLineIdx, 0, _linesNumb)) { + if (collLineIdx <= _lastLine) + break; + + int v62 = GENIAL(collLineIdx, collDataIdx, v61, destY, destX, destY, v117, essai2); + if (v62 == -1) { + // CHECKME: This goto was to retLABEL_essai1... + goto retLABEL_essai2; + } + v117 = v62; + if (_newPosX != -1 && _newPosY != -1) + break; + } + + if (v61 < destX) + essai2[v117++].set(v61++, destY, DIR_RIGHT); + else + essai2[v117++].set(v61--, destY, DIR_LEFT); + } + if (v61 == destX) { + collLineIdx = -1; + essai2[v117].invalidate(); + goto retLABEL_essai2; + } + if (collLineIdx <= _lastLine) + break; + + v54 = _newPosX; + v93 = _newPosY; + colResult = checkCollisionLine(_newPosX, _newPosY, &collDataIdx, &collLineIdx, 0, _lastLine); + if (colResult && collLineIdx <= _lastLine) + break; + } + + essai2[v117].invalidate(); + + if (!v136) { + if (a6 > foundLineIdx) { + if (essai0[0]._x != -1 && v142 > foundLineIdx && v140 <= v142 && collLineIdx <= v142 && a6 >= v142) { + _newLineIdx = v142; + _newLineDataIdx = v143; + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai0[i++]; + } while (essai0[i].isValid()); + _newRouteIdx = v137; + return 2; + } + if (essai1[0]._x != -1 && foundLineIdx < v140 && collLineIdx <= v140 && v142 <= v140 && a6 >= v140) { + _newLineIdx = v140; + _newLineDataIdx = v141; + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai1[i++]; + } while (essai1[i].isValid()); + _newRouteIdx = v137; + return 2; + } + if (essai2[0]._x != -1 && foundLineIdx < collLineIdx && v140 < collLineIdx && v142 < collLineIdx && a6 >= collLineIdx) { + _newLineIdx = collLineIdx; + _newLineDataIdx = collDataIdx; + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai2[i++]; + } while (essai2[i].isValid()); + _newRouteIdx = v137; + return 2; + } + } + if (a6 < foundLineIdx) { + if (v142 == -1) + v142 = 1300; + if (v140 == -1) + v142 = 1300; + if (collLineIdx == -1) + v142 = 1300; + if (essai1[0]._x != -1 && v140 < foundLineIdx && collLineIdx >= v140 && v142 >= v140 && a6 <= v140) { + _newLineIdx = v140; + _newLineDataIdx = v141; + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai1[i++]; + } while (essai1[i].isValid()); + _newRouteIdx = v137; + return 2; + } + if (essai2[0]._x != -1 && foundLineIdx > collLineIdx && v140 >= collLineIdx && v142 >= collLineIdx && a6 <= collLineIdx) { + _newLineIdx = collLineIdx; + _newLineDataIdx = collDataIdx; + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai2[i++]; + } while (essai2[i].isValid()); + _newRouteIdx = v137; + return 2; + } + // CHECKME: Checking essai0[0]._X might make more sense here? + if (essai1[0]._x != -1 && foundLineIdx > v142 && v140 >= v142 && collLineIdx >= v142 && a6 <= v142) { + _newLineIdx = v142; + _newLineDataIdx = v143; + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai0[i++]; + } while (essai0[i].isValid()); + _newRouteIdx = v137; + return 2; + } + } + } + return 0; + +retLABEL_essai0: + if (v115) { + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai0[i++]; + } while (essai0[i].isValid()); + } + _bestRoute[v137].invalidate(); + return 1; + +retLABEL_essai1: + if (v117) { + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai1[i++]; + } while (essai1[i].isValid()); + } + _bestRoute[v137].invalidate(); + return 1; + +retLABEL_essai2: + if (v117) { + int i = 0; + do { + assert(v137 <= 8000); + _bestRoute[v137++] = essai2[i++]; + } while (essai2[i].isValid()); + } + _bestRoute[v137].invalidate(); + return 1; +} + +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; + int superRouteIdx = 0; + if (x2 <= 14) + clipX2 = 15; + if (y2 <= 14) + clipY2 = 15; + if (clipX2 > _vm->_graphicsManager._maxX - 10) + clipX2 = _vm->_graphicsManager._maxX - 10; + if (clipY2 > 445) + clipY2 = 440; + + int delta = 0; + for (delta = 0; clipY2 + delta < _vm->_graphicsManager._maxY; delta++) { + if (checkCollisionLine(clipX2, clipY2 + delta, &arrDataIdx[5], &arrLineIdx[5], 0, _lastLine) && arrLineIdx[5] <= _lastLine) + break; + arrDataIdx[5] = 0; + arrLineIdx[5] = -1; + } + arrDelta[5] = delta; + + for (delta = 0; clipY2 - delta > _vm->_graphicsManager._minY; delta++) { + if (checkCollisionLine(clipX2, clipY2 - delta , &arrDataIdx[1], &arrLineIdx[1], 0, _lastLine) && arrLineIdx[1] <= _lastLine) + break; + arrDataIdx[1] = 0; + arrLineIdx[1] = -1; + if (arrDelta[5] < delta && arrLineIdx[5] != -1) + break; + } + arrDelta[1] = delta; + + for (delta = 0; clipX2 + delta < _vm->_graphicsManager._maxX; delta++) { + if (checkCollisionLine(clipX2 + delta, clipY2, &arrDataIdx[3], &arrLineIdx[3], 0, _lastLine) && arrLineIdx[3] <= _lastLine) + break; + arrDataIdx[3] = 0; + arrLineIdx[3] = -1; + if (arrDelta[1] <= delta && arrLineIdx[1] != -1) + break; + if (arrDelta[5] <= delta && arrLineIdx[5] != -1) + break; + } + arrDelta[3] = delta; + + for (delta = 0; clipX2 - delta > _vm->_graphicsManager._minX; delta++) { + if (checkCollisionLine(clipX2 - delta, clipY2, &arrDataIdx[7], &arrLineIdx[7], 0, _lastLine) && arrLineIdx[7] <= _lastLine) + break; + arrDataIdx[7] = 0; + arrLineIdx[7] = -1; + if ((arrDelta[1] <= delta && arrLineIdx[1] != -1) || (arrDelta[3] <= delta && arrLineIdx[3] != -1) || (arrDelta[5] <= delta && arrLineIdx[5] != -1)) + break; + } + arrDelta[7] = delta; + + int v68 = 0; + int v69 = 0; + int v72 = 0; + int v73 = 0; + + if (arrLineIdx[1] == -1) + arrDelta[1] = 1300; + if (arrLineIdx[3] == -1) + arrDelta[3] = 1300; + if (arrLineIdx[5] == -1) + arrDelta[5] = 1300; + if (arrLineIdx[7] == -1) + arrDelta[7] = 1300; + if (arrLineIdx[1] != -1 || arrLineIdx[3] != -1 || arrLineIdx[5] != -1 || arrLineIdx[7] != -1) { + bool v23 = false; + if (arrLineIdx[5] != -1 && arrDelta[1] >= arrDelta[5] && arrDelta[3] >= arrDelta[5] && arrDelta[7] >= arrDelta[5]) { + v73 = arrLineIdx[5]; + v72 = arrDataIdx[5]; + v23 = true; + } + if (arrLineIdx[1] != -1 && !v23 && arrDelta[5] >= arrDelta[1] && arrDelta[3] >= arrDelta[1] && arrDelta[7] >= arrDelta[1]) { + v73 = arrLineIdx[1]; + v72 = arrDataIdx[1]; + v23 = true; + } + if (arrLineIdx[3] != -1 && !v23 && arrDelta[1] >= arrDelta[3] && arrDelta[5] >= arrDelta[3] && arrDelta[7] >= arrDelta[3]) { + v73 = arrLineIdx[3]; + v72 = arrDataIdx[3]; + v23 = true; + } + if (arrLineIdx[7] != -1 && !v23 && arrDelta[5] >= arrDelta[7] && arrDelta[3] >= arrDelta[7] && arrDelta[1] >= arrDelta[7]) { + v73 = arrLineIdx[7]; + v72 = arrDataIdx[7]; + } + for (int v24 = 0; v24 <= 8; v24++) { + arrLineIdx[v24] = -1; + arrDataIdx[v24] = 0; + arrDelta[v24] = 1300; + } + if (checkCollisionLine(x1, y1, &arrDataIdx[1], &arrLineIdx[1], 0, _lastLine)) { + v69 = arrLineIdx[1]; + v68 = arrDataIdx[1]; + } else if (checkCollisionLine(x1, y1, &arrDataIdx[1], &arrLineIdx[1], 0, _linesNumb)) { + int v27 = 0; + int v28; + for (;;) { + v28 = essai2[v27]._x; + int v29 = essai2[v27]._y; + Directions v66 = essai2[v27]._dir; + v27++; + + if (checkCollisionLine(v28, v29, &arrDataIdx[1], &arrLineIdx[1], 0, _lastLine)) + break; + + _bestRoute[superRouteIdx].set(v28, v29, v66); + + essai0[superRouteIdx].set(v28, v29, v66); + superRouteIdx++; + if (v28 == -1) + break;; + } + if (v28 != -1) { + v69 = arrLineIdx[1]; + v68 = arrDataIdx[1]; + } + } else { + v69 = 1; + v68 = 1; + superRouteIdx = 0; + } + bool loopFl = true; + while (loopFl) { + loopFl = false; + if (v69 < v73) { + superRouteIdx = _lineItem[v69].appendToRouteInc(v68, _lineItem[v69]._lineDataEndIdx - 2, _bestRoute, superRouteIdx); + for (int j = v69 + 1; j < v73; ++j) { + if (PLAN_TEST(_lineItem[j]._lineData[0], _lineItem[j]._lineData[1], superRouteIdx, j, v73)) { + v69 = _newLineIdx; + v68 = _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; + v68 = 0; + v69 = v73; + } + if (v69 > v73) { + superRouteIdx = _lineItem[v69].appendToRouteDec(v68, 0, _bestRoute, superRouteIdx); + for (int l = v69 - 1; l > v73; --l) { + if (PLAN_TEST(_lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 2], _lineItem[l]._lineData[2 * _lineItem[l]._lineDataEndIdx - 1], superRouteIdx, l, v73)) { + v69 = _newLineIdx; + v68 = _newLineDataIdx; + superRouteIdx = _newRouteIdx; + loopFl = true; + break; + } + + superRouteIdx = _lineItem[l].appendToRouteDec(_lineItem[l]._lineDataEndIdx - 2, 0, _bestRoute, superRouteIdx); + } + if (loopFl) + continue; + + v68 = _lineItem[v73]._lineDataEndIdx - 1; + v69 = v73; + } + if (v69 == v73) { + if (v68 <= v72) { + superRouteIdx = _lineItem[v73].appendToRouteInc(v68, v72, _bestRoute, superRouteIdx); + } else { + superRouteIdx = _lineItem[v73].appendToRouteDec(v68, v72, _bestRoute, superRouteIdx); + } + } + } + _bestRoute[superRouteIdx].invalidate(); + result = &_bestRoute[0]; + } else { + result = (RouteItem *)g_PTRNUL; + } + return result; +} + +bool LinesManager::checkSmoothMove(int fromX, int fromY, int destX, int destY) { + int foundLineIdx; + int foundDataIdx; + + 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; + 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 v25 = _vm->_globals._hopkinsItem[hopkinsIdx]._speedX; + int v40 = _vm->_globals._hopkinsItem[hopkinsIdx]._speedY; + int spriteSize = _vm->_globals._spriteSize[curY]; + if (spriteSize < 0) { + v25 = _vm->_graphicsManager.zoomOut(v25, -spriteSize); + v40 = _vm->_graphicsManager.zoomOut(v40, -spriteSize); + } else if (spriteSize > 0) { + v25 = _vm->_graphicsManager.zoomIn(v25, spriteSize); + v40 = _vm->_graphicsManager.zoomIn(v40, spriteSize); + } + for (int i = 0; i < v25; i++) { + --curX; + _smoothRoute[smoothIdx]._posX = curX; + if (curY != curY + v40) + 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 v14 = _vm->_globals._hopkinsItem[hopkinsIdx]._speedX; + int v39 = _vm->_globals._hopkinsItem[hopkinsIdx]._speedY; + int spriteSize = _vm->_globals._spriteSize[curY]; + if (spriteSize < 0) { + v14 = _vm->_graphicsManager.zoomOut(v14, -spriteSize); + v39 = _vm->_graphicsManager.zoomOut(v39, -spriteSize); + } else if (spriteSize > 0) { + v14 = _vm->_graphicsManager.zoomIn(v14, spriteSize); + v39 = _vm->_graphicsManager.zoomIn(v39, spriteSize); + } + for (int i = 0; i < v14; i++) { + ++curX; + _smoothRoute[smoothIdx]._posX = curX; + if (curY != curY + v39) + 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 v11 = _vm->_graphicsManager.zoomOut(_vm->_globals._hopkinsItem[hopkinsIdx]._speedX, 25); + int v38 = _vm->_graphicsManager.zoomOut(_vm->_globals._hopkinsItem[hopkinsIdx]._speedY, 25); + int oldY = curY; + for (int v12 = 0; v12 < v11; v12++) { + --curX; + _smoothRoute[smoothIdx]._posX = curX; + if ((uint16)curY != (uint16)oldY + v38) + 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 v7 = _vm->_graphicsManager.zoomOut(_vm->_globals._hopkinsItem[hopkinsIdx]._speedX, 25); + int v37 = _vm->_graphicsManager.zoomOut(_vm->_globals._hopkinsItem[hopkinsIdx]._speedY, 25); + for (int i = 0; i < v7; i++) { + ++curX; + _smoothRoute[smoothIdx]._posX = curX; + if ((uint16)curY != (uint16)oldY + v37) + 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 a3, int a4, int a5) { + int v42; + int v43; + int v44; + int v45; + int dataIdxTestUp; + int dataIdxTestDown; + int dataIdxTestLeft; + int dataIdxTestRight; + int lineIdxTestUp; + int lineIdxTestDown; + int lineIdxTestLeft; + int lineIdxTestRight; + + int idxTestUp = testLine(paramX, paramY - 2, &v42, &lineIdxTestUp, &dataIdxTestUp); + int idxTestDown = testLine(paramX, paramY + 2, &v43, &lineIdxTestDown, &dataIdxTestDown); + int idxTestLeft = testLine(paramX - 2, paramY, &v44, &lineIdxTestLeft, &dataIdxTestLeft); + int idxTestRight = testLine(paramX + 2, paramY, &v45, &lineIdxTestRight, &dataIdxTestRight); + if (idxTestUp == -1 && idxTestDown == -1 && idxTestLeft == -1 && idxTestRight == -1) + return false; + + int v8; + if (a4 == -1 || a5 == -1) { + if (idxTestUp != -1) + v8 = 1; + else if (idxTestDown != -1) + v8 = 2; + else if (idxTestLeft != -1) + v8 = 3; + else if (idxTestRight != -1) + v8 = 4; + else + return false; + } else { + int v28 = 100; + int v7 = 100; + int v35 = 100; + int v27 = 100; + int v36 = abs(a4 - a5); + if (idxTestUp != -1) { + v28 = abs(lineIdxTestUp - a5); + } + if (idxTestDown != -1) { + v7 = abs(lineIdxTestDown - a5); + } + if (idxTestLeft != -1) { + v35 = abs(lineIdxTestLeft - a5); + } + if (idxTestRight != -1) { + v27 = abs(lineIdxTestRight - a5); + } + + if (v28 < v36 && v28 <= v7 && v28 <= v35 && v28 <= v27) + v8 = 1; + else if (v36 > v7 && v28 >= v7 && v35 >= v7 && v27 >= v7) + v8 = 2; + else if (v35 < v36 && v35 <= v28 && v35 <= v7 && v35 <= v27) + v8 = 3; + else if (v27 < v36 && v27 <= v28 && v27 <= v7 && v27 <= v35) + v8 = 4; + else + return false; + } + + int v33 = 0; + int idxTest = 0; + if (v8 == 1) { + idxTest = idxTestUp; + v33 = v42; + _newLineIdx = lineIdxTestUp; + _newLineDataIdx = dataIdxTestUp; + } else if (v8 == 2) { + idxTest = idxTestDown; + v33 = v43; + _newLineIdx = lineIdxTestDown; + _newLineDataIdx = dataIdxTestDown; + } else if (v8 == 3) { + idxTest = idxTestLeft; + v33 = v44; + _newLineIdx = lineIdxTestLeft; + _newLineDataIdx = dataIdxTestLeft; + } else if (v8 == 4) { + idxTest = idxTestRight; + v33 = v45; + _newLineIdx = lineIdxTestRight; + _newLineDataIdx = dataIdxTestRight; + } + + int superRouteIdx = a3; + if (v33 == 1) { + superRouteIdx = _lineItem[idxTest].appendToRouteInc(0, -1, _bestRoute, superRouteIdx); + } else if (v33 == 2) { + superRouteIdx = _lineItem[idxTest].appendToRouteDec(-1, -1, _bestRoute, superRouteIdx); + } + _newRouteIdx = superRouteIdx; + return true; +} + +// Test line +int LinesManager::testLine(int paramX, int paramY, int *a3, 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[0] == paramX && lineData[1] == paramY) { + *a3 = 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 (lineData[2 * (lineDataEndIdx - 1)] == paramX && lineData[2 * (lineDataEndIdx - 1) + 1] == paramY) { + *a3 = 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::CALC_PROPRE(int idx) { + int size = _vm->_globals._spriteSize[idx]; + if (_vm->_globals._characterType == 1) { + if (size < 0) + size = -size; + size = 20 * (5 * size - 100) / -80; + } else if (_vm->_globals._characterType == 2) { + if (size < 0) + size = -size; + size = 20 * (5 * size - 165) / -67; + } + + int retVal = 25; + if (size < 0) + retVal = _vm->_graphicsManager.zoomOut(25, -size); + else if (size > 0) + retVal = _vm->_graphicsManager.zoomIn(25, size); + + return retVal; +} + +void LinesManager::PACOURS_PROPRE(RouteItem *route) { + int routeIdx = 0; + Directions oldDir = DIR_NONE; + int route0Y = route[0]._y; + Directions curDir = route[0]._dir; + if (route[0]._x == -1 && route0Y == -1) + return; + + for (;;) { + if (oldDir != DIR_NONE && curDir != oldDir) { + int oldRouteIdx = routeIdx; + int routeCount = 0; + int v10 = CALC_PROPRE(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 < v10) { + 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->_eventsManager._mousePos.x + _vm->_eventsManager._mouseOffset.x; + int yp = _vm->_eventsManager._mousePos.y + _vm->_eventsManager._mouseOffset.y; + if ((_vm->_eventsManager._mousePos.y + _vm->_eventsManager._mouseOffset.y) > 19) { + for (int bobZoneId = 0; bobZoneId <= 48; bobZoneId++) { + int bobId = BOBZONE[bobZoneId]; + if (bobId && BOBZONE_FLAG[bobZoneId] && _vm->_objectsManager._bob[bobId].field0 && _vm->_objectsManager._bob[bobId]._frameIndex != 250 && + !_vm->_objectsManager._bob[bobId]._disabledAnimationFl && xp > _vm->_objectsManager._bob[bobId]._oldX && + xp < _vm->_objectsManager._bob[bobId]._oldWidth + _vm->_objectsManager._bob[bobId]._oldX && yp > _vm->_objectsManager._bob[bobId]._oldY) { + if (yp < _vm->_objectsManager._bob[bobId]._oldHeight + _vm->_objectsManager._bob[bobId]._oldY) { + if (ZONEP[bobZoneId]._spriteIndex == -1) { + ZONEP[bobZoneId]._destX = 0; + ZONEP[bobZoneId]._destY = 0; + } + if (!ZONEP[bobZoneId]._destX && !ZONEP[bobZoneId]._destY) { + ZONEP[bobZoneId]._destX = _vm->_objectsManager._bob[bobId]._oldWidth + _vm->_objectsManager._bob[bobId]._oldX; + ZONEP[bobZoneId]._destY = _vm->_objectsManager._bob[bobId]._oldHeight + _vm->_objectsManager._bob[bobId]._oldY + 6; + ZONEP[bobZoneId]._spriteIndex = -1; + } + return bobZoneId; + } + } + } + _currentSegmentId = 0; + for (int squareZoneId = 0; squareZoneId <= 99; squareZoneId++) { + if (ZONEP[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 && ZONEP[colRes1]._enabledFl) + break; + } + + if (colRes1 == -1) + return -1; + + int colRes2 = 0; + for (int j = yp; j < _vm->_graphicsManager._maxY; ++j) { + colRes2 = checkCollision(xp, j); + if (colRes2 != -1 && ZONEP[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 && ZONEP[colRes1]._enabledFl) + break; + } + if (colRes3 == -1) + return -1; + + int colRes4 = 0; + for (int xCurrent = xp; _vm->_graphicsManager._maxX > xCurrent; ++xCurrent) { + colRes4 = checkCollision(xCurrent, yp); + if (colRes4 != -1 && ZONEP[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 { + int16 *dataP = _zoneLine[curZoneLineIdx]._zoneData; + if (dataP != (int16 *)g_PTRNUL) { + int count = _zoneLine[curZoneLineIdx]._count; + int v1 = dataP[0]; + int v2 = dataP[1]; + int v3 = dataP[count * 2 - 2]; + int v4 = dataP[count * 2 - 1]; + + bool flag = true; + if (v1 < v3 && (xMax < v1 || xMin > v3)) + flag = false; + if (v1 >= v3 && (xMin > v1 || xMax < v3)) + flag = false; + if (v2 < v4 && (yMax < v2 || yMin > v4)) + flag = false; + if (v2 >= v4 && (yMin > v2 || yMax < v4)) + flag = false; + + if (flag && _zoneLine[curZoneLineIdx]._count > 0) { + for (int i = 0; i < count; ++i) { + int xCheck = *dataP++; + int yCheck = *dataP++; + + if ((xp == xCheck || (xp + 1) == xCheck) && (yp == yCheck)) + return _zoneLine[curZoneLineIdx]._bobZoneIdx; + } + } + } + } while (++curZoneLineIdx <= _segment[idx]._maxZoneLineIdx); + } + + return -1; +} + +// Square Zone +void LinesManager::CARRE_ZONE() { + for (int idx = 0; idx < 100; ++idx) { + _squareZone[idx]._enabledFl = false; + _squareZone[idx]._squareZoneFl = false; + _squareZone[idx]._left = 1280; + _squareZone[idx]._right = 0; + _squareZone[idx]._top = 460; + _squareZone[idx]._bottom = 0; + _squareZone[idx]._minZoneLineIdx = 401; + _squareZone[idx]._maxZoneLineIdx = 0; + } + + for (int idx = 0; idx < MAX_LINES; ++idx) { + int16 *dataP = _zoneLine[idx]._zoneData; + if (dataP == (int16 *)g_PTRNUL) + continue; + + int carreZoneId = _zoneLine[idx]._bobZoneIdx; + _squareZone[carreZoneId]._enabledFl = true; + if (_squareZone[carreZoneId]._maxZoneLineIdx < idx) + _squareZone[carreZoneId]._maxZoneLineIdx = idx; + if (_squareZone[carreZoneId]._minZoneLineIdx > idx) + _squareZone[carreZoneId]._minZoneLineIdx = idx; + + for (int i = 0; i < _zoneLine[idx]._count; i++) { + int zoneX = *dataP++; + int zoneY = *dataP++; + + if (_squareZone[carreZoneId]._left >= zoneX) + _squareZone[carreZoneId]._left = zoneX; + if (_squareZone[carreZoneId]._right <= zoneX) + _squareZone[carreZoneId]._right = zoneX; + if (_squareZone[carreZoneId]._top >= zoneY) + _squareZone[carreZoneId]._top = zoneY; + if (_squareZone[carreZoneId]._bottom <= zoneY) + _squareZone[carreZoneId]._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) { + ZONEP[idx]._destX = 0; + ZONEP[idx]._destY = 0; + ZONEP[idx]._spriteIndex = 0; + } + + essai0 = (RouteItem *)g_PTRNUL; + essai1 = (RouteItem *)g_PTRNUL; + essai2 = (RouteItem *)g_PTRNUL; + _lineBuf = (int16 *)g_PTRNUL; + _route = (RouteItem *)g_PTRNUL; + + 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 = (int16 *)g_PTRNUL; + + _zoneLine[idx]._count = 0; + _zoneLine[idx]._bobZoneIdx = 0; + _zoneLine[idx]._zoneData = (int16 *)g_PTRNUL; + } + + for (int idx = 0; idx < 100; ++idx) + _squareZone[idx]._enabledFl = false; + + // FIXME: Delete these somewhere + _vm->_linesManager.essai0 = new RouteItem[8334]; + _vm->_linesManager.essai1 = new RouteItem[8334]; + _vm->_linesManager.essai2 = new RouteItem[8334]; + if (!_vm->_linesManager.essai0) + _vm->_linesManager.essai0 = (RouteItem*)g_PTRNUL; + if (!_vm->_linesManager.essai1) + _vm->_linesManager.essai1 = (RouteItem*)g_PTRNUL; + if (!_vm->_linesManager.essai2) + _vm->_linesManager.essai2 = (RouteItem*)g_PTRNUL; + + _largeBuf = _vm->_globals.allocMemory(10000); + _vm->_linesManager._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 = (int16 *)g_PTRNUL; + } +} + +// 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]) { + BOBZONE_FLAG[idx] = true; + } else { + ZONEP[idx]._enabledFl = true; + } +} + +void LinesManager::disableZone(int idx) { + if (BOBZONE[idx]) { + BOBZONE_FLAG[idx] = false; + } else { + ZONEP[idx]._enabledFl = false; + } +} + +void LinesManager::checkZone() { + int mouseX = _vm->_eventsManager.getMouseX(); + int mouseY = _vm->_eventsManager.getMouseY(); + int oldMouseY = mouseY; + if (_vm->_globals._cityMapEnabledFl + || _vm->_eventsManager._startPos.x >= mouseX + || (mouseY = _vm->_graphicsManager._scrollOffset + 54, mouseX >= mouseY) + || (mouseY = oldMouseY - 1, mouseY < 0 || mouseY > 59)) { + if (_vm->_objectsManager._visibleFl) + _vm->_objectsManager._eraseVisibleCounter = 4; + _vm->_objectsManager._visibleFl = false; + } else { + _vm->_objectsManager._visibleFl = true; + } + if (_vm->_objectsManager._forceZoneFl) { + _vm->_globals.compteur_71 = 100; + _vm->_globals._oldMouseZoneId = -1; + _vm->_globals._oldMouseX = -200; + _vm->_globals._oldMouseY = -220; + _vm->_objectsManager._forceZoneFl = false; + } + + _vm->_globals.compteur_71++; + if (_vm->_globals.compteur_71 <= 1) + return; + + if (_vm->_globals._freezeCharacterFl || (_route == (RouteItem *)g_PTRNUL) || _vm->_globals.compteur_71 > 4) { + _vm->_globals.compteur_71 = 0; + int zoneId; + if (_vm->_globals._oldMouseX != mouseX || _vm->_globals._oldMouseY != oldMouseY) { + zoneId = getMouseZone(); + } else { + zoneId = _vm->_globals._oldMouseZoneId; + } + if (_vm->_globals._oldMouseZoneId != zoneId) { + _vm->_graphicsManager.SETCOLOR4(251, 100, 100, 100); + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.changeMouseCursor(4); + if (_vm->_globals._forceHideText) { + _vm->_fontManager.hideText(5); + _vm->_globals._forceHideText = false; + return; + } + } + if (zoneId != -1) { + if (ZONEP[zoneId]._verbFl1 || ZONEP[zoneId]._verbFl2 || + ZONEP[zoneId]._verbFl3 || ZONEP[zoneId]._verbFl4 || + ZONEP[zoneId]._verbFl5 || ZONEP[zoneId]._verbFl6 || + ZONEP[zoneId]._verbFl7 || ZONEP[zoneId]._verbFl8 || + ZONEP[zoneId]._verbFl9 || ZONEP[zoneId]._verbFl10) { + if (_vm->_globals._oldMouseZoneId != zoneId) { + _vm->_fontManager.initTextBuffers(5, ZONEP[zoneId]._messageId, _vm->_globals._zoneFilename, 0, 430, 0, 0, 252); + _vm->_fontManager.showText(5); + _vm->_globals._forceHideText = true; + } + _vm->_globals._hotspotTextColor += 25; + if (_vm->_globals._hotspotTextColor > 100) + _vm->_globals._hotspotTextColor = 0; + _vm->_graphicsManager.SETCOLOR4(251, _vm->_globals._hotspotTextColor, _vm->_globals._hotspotTextColor, + _vm->_globals._hotspotTextColor); + if (_vm->_eventsManager._mouseCursorId == 4) { + if (ZONEP[zoneId]._verbFl1 == 2) { + _vm->_eventsManager.changeMouseCursor(16); + _vm->_eventsManager._mouseCursorId = 16; + _vm->_objectsManager.setVerb(16); + } + } + } else { + _vm->_graphicsManager.SETCOLOR4(251, 100, 100, 100); + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.changeMouseCursor(4); + } + } + _vm->_objectsManager._zoneNum = zoneId; + _vm->_globals._oldMouseX = mouseX; + _vm->_globals._oldMouseY = oldMouseY; + _vm->_globals._oldMouseZoneId = zoneId; + if (_vm->_globals._freezeCharacterFl && (_vm->_eventsManager._mouseCursorId == 4)) { + if (zoneId != -1 && zoneId != 0) + _vm->_objectsManager.handleRightButton(); + } + if ((_vm->_globals._cityMapEnabledFl && zoneId == -1) || !zoneId) { + _vm->_objectsManager.setVerb(0); + _vm->_eventsManager._mouseCursorId = 0; + _vm->_eventsManager.changeMouseCursor(0); + } + } +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/lines.h b/engines/hopkins/lines.h new file mode 100644 index 0000000000..3d07aea91c --- /dev/null +++ b/engines/hopkins/lines.h @@ -0,0 +1,183 @@ +/* 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; +}; + +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 ZonePItem { + 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; + + 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; + + byte *_largeBuf; + RouteItem *essai0; + RouteItem *essai1; + int16 *_lineBuf; + LigneItem _lineItem[400]; + RouteItem _bestRoute[8001]; + + 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 a5, int a6, int a7); + int testLine(int paramX, int paramY, int *a3, int *foundLineIdx, int *foundDataIdx); + + int CALC_PROPRE(int idx); + int CONTOURNE1(int a1, int a2, int a3, int a4, int a5, RouteItem *route, int a8, int a9); + int CONTOURNE(int a1, int a2, int a3, int a4, int a5, RouteItem *route); + bool MIRACLE(int fromX, int fromY, int a3, int a4, int a5); + int GENIAL(int lineIdx, int dataIdx, int a3, int a4, int a5, int a6, int a7, RouteItem *route); + bool PLAN_TEST(int paramX, int paramY, int a3, int a4, int a5); + +public: + RouteItem *_route; + RouteItem *essai2; + + int BOBZONE[105]; + bool BOBZONE_FLAG[105]; + ZonePItem ZONEP[106]; + + LinesManager(); + ~LinesManager(); + void setParent(HopkinsEngine *vm); + void clearAll(); + + void setMaxLineIdx(int idx); + int checkInventoryHotspots(int posX, int posY); + void addZoneLine(int idx, int a2, int a3, int a4, int a5, int bobZoneIdx); + void loadLines(const Common::String &file); + void addLine(int idx, Directions direction, int a3, int a4, int a5, int a6); + void initRoute(); + RouteItem *cityMapCarRoute(int x1, int y1, int x2, int y2); + void clearAllZones(); + void resetLines(); + void resetLinesNumb(); + void resetLastLine(); + void enableZone(int idx); + void disableZone(int idx); + void checkZone(); + int getMouseZone(); + + void CARRE_ZONE(); + RouteItem *PARCOURS2(int fromX, int fromY, int destX, int destY); + void PACOURS_PROPRE(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..20b531ff7e --- /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 { + +void MenuManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +enum MenuSelection { MENU_NONE = 0, PLAY_GAME = 1, LOAD_GAME = 2, OPTIONS = 3, INTRODUCTION = 4, QUIT = 5 }; + +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->_objectsManager._forestFl = false; + _vm->_eventsManager._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->_objectsManager.addObject(14); + memset(frameIndex, 0, sizeof(int) * ARRAYSIZE(frameIndex)); + + if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) + _vm->_graphicsManager.loadImage("MENU"); + else if (_vm->_globals._language == LANG_EN) + _vm->_graphicsManager.loadImage("MENUAN"); + else if (_vm->_globals._language == LANG_FR) + _vm->_graphicsManager.loadImage("MENUFR"); + else if (_vm->_globals._language == LANG_SP) + _vm->_graphicsManager.loadImage("MENUES"); + + _vm->_graphicsManager.fadeInLong(); + + if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) + spriteData = _vm->_objectsManager.loadSprite("MENU.SPR"); + else if (_vm->_globals._language == LANG_EN) + spriteData = _vm->_objectsManager.loadSprite("MENUAN.SPR"); + else if (_vm->_globals._language == LANG_FR) + spriteData = _vm->_objectsManager.loadSprite("MENUFR.SPR"); + else if (_vm->_globals._language == LANG_SP) + spriteData = _vm->_objectsManager.loadSprite("MENUES.SPR"); + + _vm->_eventsManager.mouseOn(); + _vm->_eventsManager.changeMouseCursor(0); + _vm->_eventsManager._mouseCursorId = 0; + _vm->_eventsManager._mouseSpriteId = 0; + + _vm->_soundManager.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->_eventsManager.getMouseX(), _vm->_eventsManager.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->_graphicsManager.fastDisplay(spriteData, 230, 259, frameIndex[0]); + _vm->_graphicsManager.fastDisplay(spriteData, 230, 291, frameIndex[1] + 2); + _vm->_graphicsManager.fastDisplay(spriteData, 230, 322, frameIndex[2] + 4); + _vm->_graphicsManager.fastDisplay(spriteData, 230, 354, frameIndex[3] + 6); + _vm->_graphicsManager.fastDisplay(spriteData, 230, 386, frameIndex[4] + 8); + _vm->_eventsManager.VBL(); + + if (_vm->_eventsManager.getMouseButton() == 1 && menuIndex != MENU_NONE) + selectionMade = true; + } while (!selectionMade); + + if (menuIndex > MENU_NONE) { + _vm->_graphicsManager.fastDisplay(spriteData, 230, 259 + 32 * (menuIndex - 1), 10 + (menuIndex - 1)); + _vm->_eventsManager.VBL(); + _vm->_eventsManager.delay(200); + } + + if (menuIndex == PLAY_GAME) { + result = 1; + break; + } else if (menuIndex == LOAD_GAME) { + _vm->_globals._exitId = -1; + _vm->_dialogsManager.showLoadGame(); + + if (_vm->_globals._exitId != -1) { + result = _vm->_globals._exitId; + break; + } + _vm->_globals._exitId = 0; + } else if (menuIndex == OPTIONS) { + _vm->_dialogsManager.showOptionsDialog(); + } else if (menuIndex == INTRODUCTION) { + _vm->playIntro(); + } else if (menuIndex == QUIT) { + result = -1; + break; + } + } + + _vm->_globals.freeMemory(spriteData); + _vm->_globals._disableInventFl = false; + _vm->_graphicsManager.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..aeb3aa17cd --- /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: + void setParent(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..b37dac2f6e --- /dev/null +++ b/engines/hopkins/objects.cpp @@ -0,0 +1,3910 @@ +/* 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() { + 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); + + _helicopterFl = false; + _priorityFl = false; + _oldBorderPos = Common::Point(0, 0); + _oldBorderSpriteIndex = 0; + _borderPos = Common::Point(0, 0); + _borderSpriteIndex = 0; + _saveLoadX = _saveLoadY = 0; + _oldInventoryPosX = _oldInventoryPosY = 0; + _oldCharacterPosX = _oldCharacterPosY = 0; + _eraseVisibleCounter = 0; + _saveLoadSprite = g_PTRNUL; + _saveLoadSprite2 = g_PTRNUL; + _spritePtr = g_PTRNUL; + _oldSpriteData = g_PTRNUL; + PERSO_ON = false; + _saveLoadFl = false; + _visibleFl = false; + BOBTOUS = false; + _zoneNum = 0; + _forceZoneFl = false; + _changeVerbFl = false; + _verb = 0; + _changeHeadFl = false; + _disableFl = false; + _twoCharactersFl = false; + _characterPos = Common::Point(0, 0); + _startSpriteIndex = 0; + OBSSEUL = false; + _jumpVerb = 0; + _jumpZone = 0; + _oldSpriteIndex = 0; + _oldFlipFl = false; + _curObjectIndex = 0; + _forestFl = false; + _mapCarPosX = _mapCarPosY = 0; + _forestSprite = NULL; + _gestureBuf = NULL; + _curGestureFile = 0; + _headSprites = NULL; +} + +ObjectsManager::~ObjectsManager() { + _vm->_globals.freeMemory(_forestSprite); + _vm->_globals.freeMemory(_gestureBuf); + _vm->_globals.freeMemory(_headSprites); +} + +void ObjectsManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +void ObjectsManager::clearAll() { + _forestFl = false; + _forestSprite = _vm->_globals.freeMemory(_forestSprite); + _curGestureFile = 0; + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); +} + +/** + * Change Object + */ +void ObjectsManager::changeObject(int objIndex) { + _vm->_eventsManager._objectBuf = loadObjectFromFile(objIndex, true); + _curObjectIndex = objIndex; +} + +byte *ObjectsManager::loadObjectFromFile(int objIndex, bool mode) { + byte *dataP = NULL; + int objectFileNum = _vm->_globals._objectAuthIcons[objIndex]._objectFileNum; + int idx = _vm->_globals._objectAuthIcons[objIndex]._idx; + + if (mode) + ++idx; + + if (objectFileNum != _vm->_globals._curObjectFileNum) { + if (_vm->_globals._objectDataBuf != g_PTRNUL) + ObjectsManager::removeObjectDataBuf(); + if (objectFileNum == 1) { + _vm->_globals._objectDataBuf = ObjectsManager::loadSprite("OBJET1.SPR"); + } + _vm->_globals._curObjectFileNum = objectFileNum; + } + + int width = ObjectsManager::getWidth(_vm->_globals._objectDataBuf, idx); + int height = ObjectsManager::getHeight(_vm->_globals._objectDataBuf, idx); + _vm->_globals._objectWidth = width; + _vm->_globals._objectHeight = height; + + if (mode) { + sprite_alone(_vm->_globals._objectDataBuf, _vm->_eventsManager._objectBuf, idx); + dataP = _vm->_eventsManager._objectBuf; + } else { + dataP = _vm->_globals.allocMemory(height * width); + if (dataP == g_PTRNUL) + error("CAPTURE_OBJET"); + + capture_mem_sprite(_vm->_globals._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 *v3 = spriteData + 3; + for (int i = spriteIndex; i; --i) + v3 += READ_LE_UINT32(v3) + 16; + + const byte *v5 = v3 + 8; + int result = READ_LE_INT16(v5); + if (isSize) + result = READ_LE_INT16(v5 + 4); + + return result; +} + +int ObjectsManager::getOffsetY(const byte *spriteData, int spriteIndex, bool isSize) { + const byte *v3 = spriteData + 3; + for (int i = spriteIndex; i; --i) + v3 += READ_LE_UINT32(v3) + 16; + + const byte *v5 = v3 + 10; + int result = READ_LE_INT16(v5); + if (isSize) + result = READ_LE_INT16(v5 + 4); + + 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() { + _vm->_globals._curObjectFileNum = 0; + _vm->_globals._objectDataBuf = _vm->_globals.freeMemory(_vm->_globals._objectDataBuf); +} + +/** + * Load Sprite from file + */ +byte *ObjectsManager::loadSprite(const Common::String &file) { + return _vm->_fileManager.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 + _vm->_globals._sortedDisplayCount = 0; + for (int idx = 0; idx <= 10; ++idx) { + if (_vm->_fontManager._textList[idx]._enabledFl && _vm->_fontManager._text[idx]._textType != 2) { + clipX = _vm->_fontManager._textList[idx]._pos.x - 2; + + if (clipX < _vm->_graphicsManager._minX) + clipX = _vm->_graphicsManager._minX; + + clipY = _vm->_fontManager._textList[idx]._pos.y - 2; + if (clipY < _vm->_graphicsManager._minY) + clipY = _vm->_graphicsManager._minY; + + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, clipX, clipY, + _vm->_fontManager._textList[idx]._width + 4, _vm->_fontManager._textList[idx]._height + 4, + _vm->_graphicsManager._vesaBuffer, clipX, clipY); + _vm->_fontManager._textList[idx]._enabledFl = false; + } + } + + if (!PERSO_ON) { + for (int idx = 0; idx < MAX_SPRITE; ++idx) { + if (_vm->_globals.Liste[idx]._visibleFl) { + clipX = _vm->_globals.Liste[idx]._posX - 2; + if (clipX < _vm->_graphicsManager._minX) + clipX = _vm->_graphicsManager._minX; + + clipY = _vm->_globals.Liste[idx]._posY - 2; + if (clipY < _vm->_graphicsManager._minY) + clipY = _vm->_graphicsManager._minY; + + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, clipX, clipY, + _vm->_globals.Liste[idx]._width + 4, _vm->_globals.Liste[idx]._height + 4, + _vm->_graphicsManager._vesaBuffer, clipX, clipY); + _vm->_globals.Liste[idx]._visibleFl = false; + } + } + } + + displayBobAnim(); + displayVBob(); + + if (!PERSO_ON) { + // Handle drawing characters on the screen + for (int idx = 0; idx < MAX_SPRITE; ++idx) { + _vm->_globals.Liste[idx]._visibleFl = false; + if (_sprite[idx]._animationType == 1) { + computeSprite(idx); + if (_sprite[idx]._activeFl) + beforeSort(SORT_SPRITE, idx, _sprite[idx]._height + _sprite[idx]._destY); + } + } + + if (_vm->_globals._hidingActiveFl) + checkHidingItem(); + } + + if (_priorityFl && _vm->_globals._sortedDisplayCount) { + for (int i = 1; i <= 48; i++) + arr[i] = i; + + do { + loopCondFl = false; + for (int sortIdx = 1; sortIdx < _vm->_globals._sortedDisplayCount; sortIdx++) { + if (_vm->_globals._sortedDisplay[arr[sortIdx]]._priority > _vm->_globals._sortedDisplay[arr[sortIdx + 1]]._priority) { + SWAP(arr[sortIdx], arr[sortIdx + 1]); + loopCondFl = true; + } + } + } while (loopCondFl); + + for (int sortIdx = 1; sortIdx < _vm->_globals._sortedDisplayCount + 1; sortIdx++) { + int idx = arr[sortIdx]; + switch (_vm->_globals._sortedDisplay[idx]._sortMode) { + case SORT_BOB: + setBobInfo(_vm->_globals._sortedDisplay[idx]._index); + break; + case SORT_SPRITE: + DEF_SPRITE(_vm->_globals._sortedDisplay[idx]._index); + break; + case SORT_HIDING: + displayHiding(_vm->_globals._sortedDisplay[idx]._index); + break; + default: + break; + } + _vm->_globals._sortedDisplay[idx]._sortMode = SORT_NONE; + } + } else { + for (int idx = 1; idx < _vm->_globals._sortedDisplayCount + 1; ++idx) { + switch (_vm->_globals._sortedDisplay[idx]._sortMode) { + case SORT_BOB: + setBobInfo(_vm->_globals._sortedDisplay[idx]._index); + break; + case SORT_SPRITE: + DEF_SPRITE(_vm->_globals._sortedDisplay[idx]._index); + break; + case SORT_HIDING: + displayHiding(_vm->_globals._sortedDisplay[idx]._index); + break; + default: + break; + } + _vm->_globals._sortedDisplay[idx]._sortMode = SORT_NONE; + } + } + + // Reset the Sort array + for (int idx = 0; idx < 50; ++idx) { + _vm->_globals._sortedDisplay[idx]._sortMode = SORT_NONE; + _vm->_globals._sortedDisplay[idx]._index = 0; + _vm->_globals._sortedDisplay[idx]._priority = 0; + } + + _vm->_globals._sortedDisplayCount = 0; + if (_vm->_dialogsManager._inventDisplayedFl) { + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, _vm->_dialogsManager._inventWin1, _vm->_dialogsManager._inventX, _vm->_dialogsManager._inventY, _vm->_dialogsManager._inventWidth, _vm->_dialogsManager._inventHeight); + if (_oldBorderPos.x && _oldBorderPos.y) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_dialogsManager._inventBuf2, _oldBorderPos.x + 300, _oldBorderPos.y + 300, _oldBorderSpriteIndex + 1); + if (_borderPos.x && _borderPos.y) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_dialogsManager._inventBuf2, _borderPos.x + 300, _borderPos.y + 300, _borderSpriteIndex); + _vm->_graphicsManager.addVesaSegment(_vm->_dialogsManager._inventX, _vm->_dialogsManager._inventY, _vm->_dialogsManager._inventX + _vm->_dialogsManager._inventWidth, _vm->_dialogsManager._inventY + _vm->_dialogsManager._inventHeight); + } + + if (_saveLoadFl) { + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, _saveLoadSprite, _vm->_eventsManager._startPos.x + 183, 60, 274, 353); + if (_saveLoadX && _saveLoadY) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _saveLoadSprite2, _saveLoadX + _vm->_eventsManager._startPos.x + 300, _saveLoadY + 300, 0); + + _vm->_graphicsManager.addVesaSegment(_vm->_eventsManager._startPos.x + 183, 60, _vm->_eventsManager._startPos.x + 457, 413); + } + + // If the Options dialog is activated, draw the elements + if (_vm->_globals._optionDialogFl) { + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 464, 407, 0); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 657, 556, _vm->_globals._menuSpeed); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 731, 495, _vm->_globals._menuTextOff); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 731, 468, _vm->_globals._menuVoiceOff); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 731, 441, _vm->_globals._menuSoundOff); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 731, 414, _vm->_globals._menuMusicOff); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 600, 522, _vm->_globals._menuDisplayType); + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._optionDialogSpr, + _vm->_eventsManager._startPos.x + 611, 502, _vm->_globals._menuScrollSpeed); + _vm->_graphicsManager.addVesaSegment(_vm->_eventsManager._startPos.x + 164, 107, _vm->_eventsManager._startPos.x + 498, 320); + } + + // Loop to draw any on-screen text + for (int idx = 0; idx <= 10; ++idx) { + if (_vm->_fontManager._text[idx]._textOnFl) { + if ((_vm->_fontManager._text[idx]._textType < 2) || (_vm->_fontManager._text[idx]._textType > 3)) + _vm->_fontManager.box(idx, + _vm->_fontManager._text[idx]._messageId, _vm->_fontManager._text[idx]._filename, + _vm->_eventsManager._startPos.x + _vm->_fontManager._text[idx]._pos.x, _vm->_fontManager._text[idx]._pos.y); + else + _vm->_fontManager.box(idx, + _vm->_fontManager._text[idx]._messageId, _vm->_fontManager._text[idx]._filename, + _vm->_fontManager._text[idx]._pos.x, _vm->_fontManager._text[idx]._pos.y); + _vm->_fontManager._textList[idx]._enabledFl = true; + + if ((_vm->_fontManager._text[idx]._textType < 2) || (_vm->_fontManager._text[idx]._textType > 3)) + _vm->_fontManager._textList[idx]._pos.x = _vm->_eventsManager._startPos.x + _vm->_fontManager._text[idx]._pos.x; + else + _vm->_fontManager._textList[idx]._pos.x = _vm->_fontManager._text[idx]._pos.x; + + _vm->_fontManager._textList[idx]._pos.y = _vm->_fontManager._text[idx]._pos.y; + _vm->_fontManager._textList[idx]._width = _vm->_fontManager._text[idx]._width; + _vm->_fontManager._textList[idx]._height = _vm->_fontManager._text[idx]._height; + + if (_vm->_fontManager._textList[idx]._pos.x < _vm->_graphicsManager._minX) + _vm->_fontManager._textList[idx]._pos.x = _vm->_graphicsManager._minX - 1; + if (_vm->_fontManager._textList[idx]._pos.y < _vm->_graphicsManager._minY) + _vm->_fontManager._textList[idx]._pos.y = _vm->_graphicsManager._minY - 1; + + int posX = _vm->_fontManager._textList[idx]._pos.x; + if (_vm->_fontManager._textList[idx]._width + posX > _vm->_graphicsManager._maxX) + _vm->_fontManager._textList[idx]._width = _vm->_graphicsManager._maxX - posX; + int posY = _vm->_fontManager._textList[idx]._pos.y; + if (_vm->_fontManager._textList[idx]._height + posY > _vm->_graphicsManager._maxY) + _vm->_fontManager._textList[idx]._height = _vm->_graphicsManager._maxY - posY; + if (_vm->_fontManager._textList[idx]._width <= 0 || _vm->_fontManager._textList[idx]._height <= 0) + _vm->_fontManager._textList[idx]._enabledFl = false; + } + } + + _vm->_dialogsManager.inventAnim(); +} + +void ObjectsManager::initBob() { + for (int idx = 0; idx < 35; ++idx) + resetBob(idx); +} + +void ObjectsManager::resetBob(int idx) { + BobItem &bob = _bob[idx]; + ListeItem &item = _vm->_globals.Liste2[idx]; + + bob.field0 = 0; + bob._spriteData = g_PTRNUL; + bob._xp = 0; + bob._yp = 0; + bob._frameIndex = 0; + bob._animDataIdx = 0; + bob.field12 = 0; + bob.field14 = 0; + bob._disabledAnimationFl = false; + bob._animData = g_PTRNUL; + bob.field1C = false; + bob.field1E = 0; + bob.field20 = 0; + bob.field22 = 0; + bob.field34 = 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) { + if (!_bob[idx]._activeFl) + return; + + int xp = _bob[idx]._oldX; + int yp = _bob[idx]._oldY; + + if (_bob[idx]._isSpriteFl) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _bob[idx]._spriteData, + xp + 300, yp + 300, _bob[idx]._frameIndex); + else + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, + _bob[idx]._spriteData, xp + 300, yp + 300, _bob[idx]._frameIndex, + _bob[idx]._zoomOutFactor, _bob[idx]._zooInmFactor, + _bob[idx]._flipFl); + + _vm->_globals.Liste2[idx]._visibleFl = true; + _vm->_globals.Liste2[idx]._posX = xp; + _vm->_globals.Liste2[idx]._posY = yp; + + _vm->_globals.Liste2[idx]._width = _bob[idx]._oldWidth; + _vm->_globals.Liste2[idx]._height = _bob[idx]._oldHeight; + + if (_vm->_globals.Liste2[idx]._posX < _vm->_graphicsManager._minX) { + _vm->_globals.Liste2[idx]._width -= _vm->_graphicsManager._minX - _vm->_globals.Liste2[idx]._posX; + _vm->_globals.Liste2[idx]._posX = _vm->_graphicsManager._minX; + } + + if (_vm->_globals.Liste2[idx]._posY < _vm->_graphicsManager._minY) { + _vm->_globals.Liste2[idx]._height -= _vm->_graphicsManager._minY - _vm->_globals.Liste2[idx]._posY; + _vm->_globals.Liste2[idx]._posY = _vm->_graphicsManager._minY; + } + + if (_vm->_globals.Liste2[idx]._width + _vm->_globals.Liste2[idx]._posX > _vm->_graphicsManager._maxX) + _vm->_globals.Liste2[idx]._width = _vm->_graphicsManager._maxX - _vm->_globals.Liste2[idx]._posX; + + if (_vm->_globals.Liste2[idx]._height + _vm->_globals.Liste2[idx]._posY > _vm->_graphicsManager._maxY) + _vm->_globals.Liste2[idx]._height = _vm->_graphicsManager._maxY - _vm->_globals.Liste2[idx]._posY; + + if (_vm->_globals.Liste2[idx]._width <= 0 || _vm->_globals.Liste2[idx]._height <= 0) + _vm->_globals.Liste2[idx]._visibleFl = false; + + if (_vm->_globals.Liste2[idx]._visibleFl) + _vm->_graphicsManager.addVesaSegment( + _vm->_globals.Liste2[idx]._posX, + _vm->_globals.Liste2[idx]._posY, + _vm->_globals.Liste2[idx]._posX + _vm->_globals.Liste2[idx]._width, + _vm->_globals.Liste2[idx]._posY + _vm->_globals.Liste2[idx]._height); +} + +void ObjectsManager::displayBob(int idx) { + _priorityFl = true; + + if (_bob[idx].field0) + return; + + resetBob(idx); + + const byte *data = _vm->_globals._animBqe[idx]._data; + int bankIdx = READ_LE_INT16(data); + if (!bankIdx) + return; + if ((!_vm->_globals.Bank[bankIdx]._loadedFl) || (!READ_LE_UINT16(data + 24))) + return; + + + int16 v9 = READ_LE_INT16(data + 2); + int16 v8 = READ_LE_INT16(data + 4); + // data[6] isn't used, read skipped + int16 v6 = READ_LE_INT16(data + 8); + + if (!v9) + v9 = 1; + if (!v6) + v6 = -1; + + _bob[idx]._isSpriteFl = false; + + if (_vm->_globals.Bank[bankIdx]._fileHeader == 1) { + _bob[idx]._isSpriteFl = true; + _bob[idx]._zoomFactor = 0; + _bob[idx]._flipFl = false; + } + + _bob[idx]._animData = _vm->_globals._animBqe[idx]._data; + _bob[idx].field0 = 10; + _bob[idx]._spriteData = _vm->_globals.Bank[bankIdx]._data; + + _bob[idx].field1E = v9; + _bob[idx].field20 = v6; + _bob[idx].field22 = v8; +} + +void ObjectsManager::hideBob(int idx) { + if ((_bob[idx].field0 == 3) || (_bob[idx].field0 == 10)) + _bob[idx].field0++; +} + +void ObjectsManager::BOB_OFFSET(int idx, int offset) { + _bob[idx]._oldX2 = offset; +} + +void ObjectsManager::SCBOB(int idx) { + HidingItem *hid = &_vm->_globals._hidingItem[idx]; + if (hid->_useCount == 0) + return; + + for (int i = 0; i <= 20; i++) { + if ((_bob[i].field0) && (!_bob[i]._disabledAnimationFl) && (!_bob[i].field34) && (_bob[i]._frameIndex != 250)) { + int oldRight = _bob[i]._oldX + _bob[i]._oldWidth; + int oldBottom = _bob[i]._oldY + _bob[i]._oldHeight; + int cachedRight = hid->_width + hid->_x; + + if ((oldBottom > hid->_y) && (oldBottom < hid->field14 +hid->_height + hid->_y)) { + if ((oldRight >= hid->_x && oldRight <= cachedRight) + || (cachedRight >= _bob[i]._oldWidth && _bob[i]._oldWidth >= hid->_x) + || (cachedRight >= _bob[i]._oldWidth && _bob[i]._oldWidth >= hid->_x) + || (_bob[i]._oldWidth >= hid->_x && oldRight <= cachedRight) + || (_bob[i]._oldWidth <= hid->_x && oldRight >= cachedRight)) + ++hid->_useCount; + } + } + } +} + +void ObjectsManager::CALCUL_BOB(int idx) { + _bob[idx]._activeFl = false; + if (_bob[idx]._isSpriteFl) { + _bob[idx]._flipFl = false; + _bob[idx]._zoomFactor = 0; + } + + int spriteIdx = _bob[idx]._frameIndex; + if (spriteIdx == 250) + return; + + int deltaY, deltaX; + if (_bob[idx]._flipFl) { + deltaX = getOffsetX(_bob[idx]._spriteData, spriteIdx, true); + deltaY = getOffsetY(_bob[idx]._spriteData, _bob[idx]._frameIndex, true); + } else { + deltaX = getOffsetX(_bob[idx]._spriteData, spriteIdx, false); + deltaY = getOffsetY(_bob[idx]._spriteData, _bob[idx]._frameIndex, false); + } + + int negZoom = 0; + int posZoom = 0; + if (_bob[idx]._zoomFactor < 0) { + negZoom = -_bob[idx]._zoomFactor; + if (negZoom > 95) + negZoom = 95; + } else + posZoom = _bob[idx]._zoomFactor; + + if (posZoom) { + if (deltaX >= 0) + deltaX = _vm->_graphicsManager.zoomIn(deltaX, posZoom); + else + deltaX = -_vm->_graphicsManager.zoomIn(-deltaX, posZoom); + + if (deltaY >= 0) + deltaY = _vm->_graphicsManager.zoomIn(deltaY, posZoom); + else + deltaY = -_vm->_graphicsManager.zoomIn(abs(deltaX), posZoom); + } + + if (negZoom) { + if (deltaX >= 0) + deltaX = _vm->_graphicsManager.zoomOut(deltaX, negZoom); + else + deltaX = -_vm->_graphicsManager.zoomOut(-deltaX, negZoom); + + if (deltaY >= 0) + deltaY = _vm->_graphicsManager.zoomOut(deltaY, negZoom); + else + deltaY = -_vm->_graphicsManager.zoomOut(abs(deltaX), negZoom); + } + + int newX = _bob[idx]._xp - deltaX; + int newY = _bob[idx]._yp - deltaY; + _bob[idx]._activeFl = true; + _bob[idx]._oldX = newX; + _bob[idx]._oldY = newY; + _bob[idx]._zooInmFactor = posZoom; + _bob[idx]._zoomOutFactor = negZoom; + + _vm->_globals.Liste2[idx]._visibleFl = true; + _vm->_globals.Liste2[idx]._posX = newX; + _vm->_globals.Liste2[idx]._posY = newY; + + int width = getWidth(_bob[idx]._spriteData, _bob[idx]._frameIndex); + int height = getHeight(_bob[idx]._spriteData, _bob[idx]._frameIndex); + + if (posZoom) { + width = _vm->_graphicsManager.zoomIn(width, posZoom); + height = _vm->_graphicsManager.zoomIn(height, posZoom); + } + if (negZoom) { + height = _vm->_graphicsManager.zoomOut(height, negZoom); + width = _vm->_graphicsManager.zoomOut(width, negZoom); + } + + _vm->_globals.Liste2[idx]._width = width; + _vm->_globals.Liste2[idx]._height = height; + _bob[idx]._oldWidth = width; + _bob[idx]._oldHeight = height; +} + +void ObjectsManager::checkHidingItem() { + for (int hidingItemIdx = 0; hidingItemIdx <= 19; hidingItemIdx++) { + HidingItem *hid = &_vm->_globals._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->field14 + hid->_height + hid->_y)) { + if ((right >= hid->_x && right <= hidingRight) + || (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; + } + } + } + + SCBOB(hidingItemIdx); + if (hid->_useCount != _oldUseCount) { + int priority = hid->field14 + hid->_height + hid->_y; + if (priority > 440) + priority = 500; + + beforeSort(SORT_HIDING, hidingItemIdx, priority); + hid->_useCount = 1; + hid->field10 = true; + } else if (hid->field10) { + hid->field10 = false; + hid->_useCount = 1; + } + + } +} + +void ObjectsManager::DEF_SPRITE(int idx) { + SpriteItem *spr = &_sprite[idx]; + if (!spr->_activeFl) + return; + + if (spr->_rleFl) + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, spr->_spriteData, + spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex); + else + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, spr->_spriteData, + spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex, spr->_reducePct, spr->_zoomPct, spr->_flipFl); + + ListeItem *list = &_vm->_globals.Liste[idx]; + list->_width = spr->_width; + list->_height = spr->_height; + + if (list->_posX < _vm->_graphicsManager._minX) { + list->_width -= _vm->_graphicsManager._minX - list->_posX; + list->_posX = _vm->_graphicsManager._minX; + } + + if (list->_posY < _vm->_graphicsManager._minY) { + list->_height -= _vm->_graphicsManager._minY - list->_posY; + list->_posY = _vm->_graphicsManager._minY; + } + + if (list->_width + list->_posX > _vm->_graphicsManager._maxX) + list->_width = _vm->_graphicsManager._maxX - list->_posX; + + if (list->_height + list->_posY > _vm->_graphicsManager._maxY) + list->_height = _vm->_graphicsManager._maxY - list->_posY; + + if (list->_width <= 0 || list->_height <= 0) + list->_visibleFl = false; + + if (list->_visibleFl) + _vm->_graphicsManager.addVesaSegment( list->_posX, list->_posY, list->_posX + list->_width, list->_posY + list->_height); +} + +void ObjectsManager::displayHiding(int idx) { + HidingItem *hid = &_vm->_globals._hidingItem[idx]; + + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, _vm->_globals._hidingItemData[1], + hid->_x + 300, hid->_y + 300, hid->_spriteIndex); + _vm->_graphicsManager.addVesaSegment(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->field12 + offX; + int deltaX = tmpX; + int tmpY = spr->field14 + 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->_graphicsManager.zoomIn(tmpX, zoomPercent); + else + deltaX = -_vm->_graphicsManager.zoomIn(-tmpX, zoomPercent); + + if (tmpY >= 0) { + deltaY = _vm->_graphicsManager.zoomIn(tmpY, zoomPercent); + } else { + tmpY = abs(tmpX); + deltaY = -_vm->_graphicsManager.zoomIn(tmpY, zoomPercent); + } + } else if (reducePercent) { + if (tmpX >= 0) + deltaX = _vm->_graphicsManager.zoomOut(tmpX, reducePercent); + else + deltaX = -_vm->_graphicsManager.zoomOut(-tmpX, reducePercent); + + if (tmpY >= 0) { + deltaY = _vm->_graphicsManager.zoomOut(tmpY, reducePercent); + } else { + tmpY = abs(tmpX); + deltaY = -_vm->_graphicsManager.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; + + _vm->_globals.Liste[idx]._visibleFl = true; + _vm->_globals.Liste[idx]._posX = newPosX; + _vm->_globals.Liste[idx]._posY = newPosY; + + int width = getWidth(spr->_spriteData, spr->_spriteIndex); + int height = getHeight(spr->_spriteData, spr->_spriteIndex); + + if (zoomPercent) { + width = _vm->_graphicsManager.zoomIn(width, zoomPercent); + height = _vm->_graphicsManager.zoomIn(height, zoomPercent); + } else if (reducePercent) { + height = _vm->_graphicsManager.zoomOut(height, reducePercent); + width = _vm->_graphicsManager.zoomOut(width, reducePercent); + } + + spr->_width = width; + spr->_height = height; +} + +// Before Sort +void ObjectsManager::beforeSort(SortMode sortMode, int index, int priority) { + ++_vm->_globals._sortedDisplayCount; + assert (_vm->_globals._sortedDisplayCount <= 48); + + _vm->_globals._sortedDisplay[_vm->_globals._sortedDisplayCount]._sortMode = sortMode; + _vm->_globals._sortedDisplay[_vm->_globals._sortedDisplayCount]._index = index; + _vm->_globals._sortedDisplay[_vm->_globals._sortedDisplayCount]._priority = priority; +} + +// Display BOB Anim +void ObjectsManager::displayBobAnim() { + for (int idx = 1; idx <= 35; idx++) { + if (idx <= 20 && PERSO_ON) { + _bob[idx].field1C = false; + continue; + } + + if (_bob[idx].field0 != 10) + continue; + + _bob[idx].field1C = false; + int v1 = _bob[idx].field20; + if (v1 == -1) + v1 = 50; + if (_bob[idx]._animData == g_PTRNUL || _bob[idx]._disabledAnimationFl || v1 <= 0) { + if (_bob[idx].field1E == 1 || _bob[idx].field1E == 2) + _bob[idx].field1C = true; + continue; + } + + if (_bob[idx].field12 == _bob[idx].field14) { + _bob[idx].field1C = true; + } else { + _bob[idx].field14++; + _bob[idx].field1C = false; + } + + if (!_bob[idx].field1C) { + if (_bob[idx].field1E == 1 || _bob[idx].field1E == 2) + _bob[idx].field1C = true; + continue; + } + + byte *dataPtr = _bob[idx]._animData + 20; + int dataIdx = _bob[idx]._animDataIdx; + _bob[idx]._xp = READ_LE_INT16(dataPtr + 2 * dataIdx); + if (_vm->_globals._lockedAnims[idx]._enableFl) + _bob[idx]._xp = _vm->_globals._lockedAnims[idx]._posX; + if ( PERSO_ON && idx > 20 ) + _bob[idx]._xp += _vm->_eventsManager._startPos.x; + + _bob[idx]._yp = READ_LE_INT16(dataPtr + 2 * dataIdx + 2); + _bob[idx].field12 = READ_LE_INT16(dataPtr + 2 * dataIdx + 4); + _bob[idx]._zoomFactor = READ_LE_INT16(dataPtr + 2 * dataIdx + 6); + _bob[idx]._frameIndex = dataPtr[2 * dataIdx + 8]; + _bob[idx]._flipFl = (dataPtr[2 * dataIdx + 9] != 0); + _bob[idx]._animDataIdx += 5; + + int v5 = _bob[idx].field12; + if (v5 > 0) { + int v6 = v5 / _vm->_globals._speed; + _bob[idx].field12 = v5 / _vm->_globals._speed; + if (v6 > 0) { + _bob[idx].field14 = 1; + if (_bob[idx].field1E == 1 || _bob[idx].field1E == 2) + _bob[idx].field1C = true; + continue; + } + + _bob[idx].field12 = 1; + } + if (!_bob[idx].field12) { + if (_bob[idx].field20 > 0) + _bob[idx].field20--; + if (_bob[idx].field20 != -1 && _bob[idx].field20 <= 0) { + _bob[idx].field0 = 11; + } else { + _bob[idx]._animDataIdx = 0; + byte *v21 = _bob[idx]._animData + 20; + _bob[idx]._xp = READ_LE_INT16(v21); + + if (_vm->_globals._lockedAnims[idx]._enableFl) + _bob[idx]._xp = _vm->_globals._lockedAnims[idx]._posX; + if (PERSO_ON && idx > 20) + _bob[idx]._xp += _vm->_eventsManager._startPos.x; + + _bob[idx]._yp = READ_LE_INT16(v21 + 2); + _bob[idx].field12 = READ_LE_INT16(v21 + 4); + _bob[idx]._zoomFactor = READ_LE_INT16(v21 + 6); + _bob[idx]._frameIndex = v21[8]; + _bob[idx]._flipFl = (v21[9] != 0); + _bob[idx]._animDataIdx += 5; + int v10 = _bob[idx].field12; + + if (v10 > 0) { + int v11 = v10 / _vm->_globals._speed; + _bob[idx].field12 = v11; + // Original code. It can't be negative, so the check is on == 0 + if (v11 <= 0) + _bob[idx].field12 = 1; + } + } + } + + _bob[idx].field14 = 1; + if (_bob[idx].field1E == 1 || _bob[idx].field1E == 2) + _bob[idx].field1C = true; + } + + if (!PERSO_ON && BOBTOUS) { + for (int i = 0; i < 35; i++) { + if (_bob[i].field0 == 10 && !_bob[i]._disabledAnimationFl) + _bob[i].field1C = true; + } + } + + BOBTOUS = false; + + for (int i = 1; i <= 35; i++) { + if (i > 20 || !PERSO_ON) { + if ((_bob[i].field0 == 10) && (_bob[i].field1C)) { + if ((_bob[i].field1E != 2) && (_bob[i].field1E != 4)) { + if (_vm->_globals.Liste2[i]._visibleFl) { + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, + _vm->_globals.Liste2[i]._posX, _vm->_globals.Liste2[i]._posY, + _vm->_globals.Liste2[i]._width, _vm->_globals.Liste2[i]._height, + _vm->_graphicsManager._vesaBuffer, _vm->_globals.Liste2[i]._posX, + _vm->_globals.Liste2[i]._posY); + _vm->_globals.Liste2[i]._visibleFl = false; + } + } + } + + if (_bob[i].field0 == 11) { + if (_vm->_globals.Liste2[i]._visibleFl) { + _vm->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, + _vm->_globals.Liste2[i]._posX, _vm->_globals.Liste2[i]._posY, + _vm->_globals.Liste2[i]._width, _vm->_globals.Liste2[i]._height, + _vm->_graphicsManager._vesaBuffer, + _vm->_globals.Liste2[i]._posX, _vm->_globals.Liste2[i]._posY); + _vm->_globals.Liste2[i]._visibleFl = false; + } + + _bob[i].field0 = 0; + } + } + } + + for (int i = 1; i <= 35; i++) { + _bob[i]._oldY = 0; + if (_bob[i].field0 == 10 && !_bob[i]._disabledAnimationFl && _bob[i].field1C) { + CALCUL_BOB(i); + int v19 = _bob[i]._oldX2 + _bob[i]._oldHeight + _bob[i]._oldY; + + if (v19 > 450) + v19 = 600; + + if (_bob[i]._activeFl) + beforeSort(SORT_BOB, i, v19); + } + } +} + +// Display VBOB +void ObjectsManager::displayVBob() { + int width, height; + + for (int idx = 0; idx <= 29; idx++) { + VBobItem *vbob = &_vm->_globals.VBob[idx]; + if (vbob->field4 == 4) { + width = getWidth(vbob->_spriteData, vbob->_frameIndex); + height = getHeight(vbob->_spriteData, vbob->_frameIndex); + + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaScreen, vbob->_surface, + vbob->_xp, vbob->_yp, width, height); + + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, vbob->_surface, + vbob->_xp, vbob->_yp, width, height); + + _vm->_graphicsManager.addVesaSegment(vbob->_xp, vbob->_yp, vbob->_xp + width, height + vbob->_yp); + vbob->_surface = _vm->_globals.freeMemory(vbob->_surface); + + vbob->field4 = 0; + vbob->_spriteData = g_PTRNUL; + vbob->_xp = 0; + vbob->_yp = 0; + vbob->_oldX = 0; + vbob->_oldY = 0; + vbob->_frameIndex = 0; + vbob->_oldFrameIndex = 0; + vbob->_oldSpriteData = g_PTRNUL; + } + + if (vbob->field4 == 3) { + width = getWidth(vbob->_oldSpriteData, vbob->_oldFrameIndex); + height = getHeight(vbob->_oldSpriteData, vbob->_oldFrameIndex); + + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaScreen, vbob->_surface, + vbob->_oldX, vbob->_oldY, width, height); + + _vm->_graphicsManager.restoreSurfaceRect(_vm->_graphicsManager._vesaBuffer, vbob->_surface, + vbob->_oldX, vbob->_oldY, width, height); + + _vm->_graphicsManager.addVesaSegment(vbob->_oldX, vbob->_oldY, vbob->_oldX + width, vbob->_oldY + height); + + vbob->field4 = 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->field4 == 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->_graphicsManager.copySurfaceRect(_vm->_graphicsManager._vesaScreen, surface, + vbob->_xp, vbob->_yp, width, height); + + byte *v10 = vbob->_spriteData; + if (*v10 == 78) { + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaScreen, v10, + vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false); + + _vm->_graphicsManager.Affiche_Perfect(_vm->_graphicsManager._vesaBuffer, vbob->_spriteData, + vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false); + } else { + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaBuffer, v10, + vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex); + + _vm->_graphicsManager.Sprite_Vesa(_vm->_graphicsManager._vesaScreen, vbob->_spriteData, + vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex); + } + + _vm->_graphicsManager.addVesaSegment(vbob->_xp, vbob->_yp , vbob->_xp + width, vbob->_yp + height); + vbob->field4 = 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 = g_PTRNUL; + _sprite[idx]._animationType = 0; + } + + for (int idx = 0; idx < MAX_SPRITE; idx++) { + ListeItem *list = &_vm->_globals.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 a8, int a9) { + assert (idx <= MAX_SPRITE); + + SpriteItem *spr = &_sprite[idx]; + spr->_spriteData = spriteData; + spr->_spritePos = pos; + spr->_spriteIndex = spriteIndex; + spr->_zoomFactor = zoomFactor; + spr->_flipFl = flipFl; + spr->field12 = a8; + spr->field14 = a9; + 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->_linesManager._route == (RouteItem *)g_PTRNUL) + return; + + if (_vm->_globals.Compteur > 1) { + --_vm->_globals.Compteur; + return; + } + + int newPosX; + int newPosY; + Directions newDirection; + + int oldPosX = 0; + int oldPosY = 0; + int oldFrameIdx = 0; + _vm->_globals.Compteur = 0; + if (_vm->_globals._oldDirection == DIR_NONE) { + computeAndSetSpriteSize(); + newPosX = _vm->_linesManager._route->_x; + newPosY = _vm->_linesManager._route->_y; + newDirection = _vm->_linesManager._route->_dir; + _vm->_linesManager._route++; + + if (newPosX != -1 || newPosY != -1) { + _vm->_globals._oldDirection = newDirection; + _vm->_globals._oldDirectionSpriteIdx = newDirection + 59; + _vm->_globals._oldFrameIndex = 0; + _oldCharacterPosX = newPosX; + _oldCharacterPosY = newPosY; + } else { + setSpriteIndex(0, _vm->_globals._oldDirection + 59); + _vm->_globals._actionDirection = DIR_NONE; + int zoneId; + if (_vm->_globals._actionMoveTo) + zoneId = _vm->_globals._saveData->_data[svField2]; + else + zoneId = _zoneNum; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + computeAndSetSpriteSize(); + setFlipSprite(0, false); + _vm->_globals.Compteur = 0; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_globals._oldDirection = DIR_NONE; + if (zoneId > 0) { + if (_vm->_linesManager.ZONEP[zoneId]._destX && _vm->_linesManager.ZONEP[zoneId]._destY && _vm->_linesManager.ZONEP[zoneId]._destY != 31) { + if (_vm->_linesManager.ZONEP[zoneId]._spriteIndex == -1) { + _vm->_linesManager.ZONEP[zoneId]._destX = 0; + _vm->_linesManager.ZONEP[zoneId]._destY = 0; + _vm->_linesManager.ZONEP[zoneId]._spriteIndex = 0; + } else { + setSpriteIndex(0, _vm->_linesManager.ZONEP[zoneId]._spriteIndex); + _vm->_globals._actionDirection = _vm->_linesManager.ZONEP[zoneId]._spriteIndex - 59; + } + } + } + } + _vm->_globals.Compteur = 0; + return; + } + if (_vm->_globals._oldDirection == DIR_RIGHT) { + if (_vm->_globals._oldFrameIndex < 24 || _vm->_globals._oldFrameIndex > 35) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 24; + } else { + int deltaX = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedX; + int deltaY = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY; + + if (_sprite[0]._zoomFactor < 0) { + deltaX = _vm->_graphicsManager.zoomOut(deltaX, -_sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } else if (_sprite[0]._zoomFactor > 0) { + deltaX = _vm->_graphicsManager.zoomIn(deltaX, _sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = _oldCharacterPosX + deltaX; + oldPosY = _oldCharacterPosY + deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 35) + oldFrameIdx = 24; + } + _vm->_globals.Compteur = 5 / _vm->_globals._speed; + } + if (_vm->_globals._oldDirection == DIR_LEFT) { + if (_vm->_globals._oldFrameIndex < 24 || _vm->_globals._oldFrameIndex > 35) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 24; + } else { + int deltaX = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedX; + int deltaY = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY; + if (_sprite[0]._zoomFactor < 0) { + deltaX = _vm->_graphicsManager.zoomOut(deltaX, -_sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } else if (_sprite[0]._zoomFactor > 0) { + deltaX = _vm->_graphicsManager.zoomIn(deltaX, _sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = _oldCharacterPosX - deltaX; + oldPosY = _oldCharacterPosY - deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 35) + oldFrameIdx = 24; + } + _vm->_globals.Compteur = 5 / _vm->_globals._speed; + } + if (_vm->_globals._oldDirection == DIR_UP) { + if (_vm->_globals._oldFrameIndex > 11) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 0; + } else { + int deltaY = abs(_vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY); + if (_sprite[0]._zoomFactor < 0) { + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } else if (_sprite[0]._zoomFactor > 0) { + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY - deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 11) + oldFrameIdx = 0; + } + _vm->_globals.Compteur = 4 / _vm->_globals._speed; + } + + if (_vm->_globals._oldDirection == DIR_DOWN) { + if (_vm->_globals._oldFrameIndex < 48 || _vm->_globals._oldFrameIndex > 59) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 48; + } else { + int deltaY = abs(_vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY); + if (_sprite[0]._zoomFactor < 0) { + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } else if (_sprite[0]._zoomFactor > 0) { + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = _oldCharacterPosX; + oldPosY = deltaY + _oldCharacterPosY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 59) + oldFrameIdx = 48; + } + _vm->_globals.Compteur = 4 / _vm->_globals._speed; + } + if (_vm->_globals._oldDirection == DIR_UP_RIGHT) { + if (_vm->_globals._oldFrameIndex < 12 || _vm->_globals._oldFrameIndex > 23) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 12; + } else { + int deltaX = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedX; + int deltaY = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY; + if (_sprite[0]._zoomFactor < 0) { + deltaX = _vm->_graphicsManager.zoomOut(deltaX, -_sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } + if (_sprite[0]._zoomFactor > 0) { + deltaX = _vm->_graphicsManager.zoomIn(deltaX, _sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = deltaX + _oldCharacterPosX; + oldPosY = _oldCharacterPosY + deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 23) + oldFrameIdx = 12; + } + _vm->_globals.Compteur = 5 / _vm->_globals._speed; + } + if (_vm->_globals._oldDirection == DIR_UP_LEFT) { + if (_vm->_globals._oldFrameIndex < 12 || _vm->_globals._oldFrameIndex > 23) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 12; + } else { + int deltaX = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedX; + int deltaY = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY; + if (_sprite[0]._zoomFactor < 0) { + deltaX = _vm->_graphicsManager.zoomOut(deltaX, -_sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } else if (_sprite[0]._zoomFactor > 0) { + deltaX = _vm->_graphicsManager.zoomIn(deltaX, _sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = _oldCharacterPosX - deltaX; + oldPosY = _oldCharacterPosY + deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 23) + oldFrameIdx = 12; + } + _vm->_globals.Compteur = 5 / _vm->_globals._speed; + } + if (_vm->_globals._oldDirection == DIR_DOWN_RIGHT) { + if (_vm->_globals._oldFrameIndex < 36 || _vm->_globals._oldFrameIndex > 47) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 36; + } else { + int deltaX = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedX; + int deltaY = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY; + if (_sprite[0]._zoomFactor < 0) { + deltaX = _vm->_graphicsManager.zoomOut(deltaX, -_sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } + if (_sprite[0]._zoomFactor > 0) { + deltaX = _vm->_graphicsManager.zoomIn(deltaX, _sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = deltaX + _oldCharacterPosX; + oldPosY = _oldCharacterPosY + deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 47) + oldFrameIdx = 36; + } + _vm->_globals.Compteur = 5 / _vm->_globals._speed; + } + if (_vm->_globals._oldDirection == DIR_DOWN_LEFT) { + if (_vm->_globals._oldFrameIndex < 36 || _vm->_globals._oldFrameIndex > 47) { + oldPosX = _oldCharacterPosX; + oldPosY = _oldCharacterPosY; + oldFrameIdx = 36; + } else { + int deltaX = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedX; + int deltaY = _vm->_globals._hopkinsItem[_vm->_globals._oldFrameIndex]._speedY; + if (_sprite[0]._zoomFactor < 0) { + deltaX = _vm->_graphicsManager.zoomOut(deltaX, -_sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomOut(deltaY, -_sprite[0]._zoomFactor); + } + if (_sprite[0]._zoomFactor > 0) { + deltaX = _vm->_graphicsManager.zoomIn(deltaX, _sprite[0]._zoomFactor); + deltaY = _vm->_graphicsManager.zoomIn(deltaY, _sprite[0]._zoomFactor); + } + oldPosX = _oldCharacterPosX - deltaX; + oldPosY = _oldCharacterPosY + deltaY; + oldFrameIdx = _vm->_globals._oldFrameIndex + 1; + if (oldFrameIdx > 47) + oldFrameIdx = 36; + } + _vm->_globals.Compteur = 5 / _vm->_globals._speed; + } + bool loopCond = false; + do { + newPosX = _vm->_linesManager._route->_x; + newPosY = _vm->_linesManager._route->_y; + newDirection = (Directions)_vm->_linesManager._route->_dir; + _vm->_linesManager._route++; + + if (newPosX == -1 && newPosY == -1) { + int zoneId; + if (_vm->_globals._actionMoveTo) + zoneId = _vm->_globals._saveData->_data[svField2]; + else + zoneId = _zoneNum; + setSpriteIndex(0, _vm->_globals._oldDirection + 59); + _vm->_globals._actionDirection = DIR_NONE; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + computeAndSetSpriteSize(); + setFlipSprite(0, false); + _vm->_globals.Compteur = 0; + _vm->_globals._oldDirection = DIR_NONE; + _oldCharacterPosX = getSpriteX(0); + _oldCharacterPosY = getSpriteY(0); + + if (zoneId > 0) { + if (_vm->_linesManager.ZONEP[zoneId]._destX && _vm->_linesManager.ZONEP[zoneId]._destY && _vm->_linesManager.ZONEP[zoneId]._destY != 31) { + if ( _vm->_linesManager.ZONEP[zoneId]._spriteIndex == -1) { + _vm->_linesManager.ZONEP[zoneId]._destX = 0; + _vm->_linesManager.ZONEP[zoneId]._destY = 0; + _vm->_linesManager.ZONEP[zoneId]._spriteIndex = 0; + } else { + setSpriteIndex(0, _vm->_linesManager.ZONEP[zoneId]._spriteIndex); + _vm->_globals._actionDirection = _vm->_linesManager.ZONEP[zoneId]._spriteIndex - 59; + } + } + } + _vm->_globals.Compteur = 0; + return; + } + if (_vm->_globals._oldDirection != newDirection) + break; + if ((newDirection == DIR_RIGHT && newPosX >= oldPosX) || (_vm->_globals._oldDirection == DIR_LEFT && newPosX <= oldPosX) || + (_vm->_globals._oldDirection == DIR_UP && newPosY <= oldPosY) || (_vm->_globals._oldDirection == DIR_DOWN && newPosY >= oldPosY) || + (_vm->_globals._oldDirection == DIR_UP_RIGHT && newPosX >= oldPosX) || (_vm->_globals._oldDirection == DIR_UP_LEFT && newPosX <= oldPosX) || + (_vm->_globals._oldDirection == DIR_DOWN_RIGHT && newPosX >= oldPosX) || (_vm->_globals._oldDirection == DIR_DOWN_LEFT && newPosX <= oldPosX)) + loopCond = true; + } while (!loopCond); + if (loopCond) { + computeAndSetSpriteSize(); + if ((_vm->_globals._oldDirection == DIR_DOWN_LEFT) || (_vm->_globals._oldDirection == DIR_LEFT) || (_vm->_globals._oldDirection == DIR_UP_LEFT)) + setFlipSprite(0, true); + + if ((_vm->_globals._oldDirection == DIR_UP) || (_vm->_globals._oldDirection == DIR_UP_RIGHT) || (_vm->_globals._oldDirection == DIR_RIGHT) || + (_vm->_globals._oldDirection == DIR_DOWN_RIGHT) || (_vm->_globals._oldDirection == DIR_DOWN)) + setFlipSprite(0, false); + + setSpriteX(0, newPosX); + setSpriteY(0, newPosY); + setSpriteIndex(0, oldFrameIdx); + } else { + if ((_vm->_globals._oldDirection == DIR_DOWN_LEFT) || (_vm->_globals._oldDirection == DIR_LEFT) || (_vm->_globals._oldDirection == DIR_UP_LEFT)) + setFlipSprite(0, true); + + if ((_vm->_globals._oldDirection == DIR_UP) || (_vm->_globals._oldDirection == DIR_UP_RIGHT) || (_vm->_globals._oldDirection == DIR_RIGHT) || + (_vm->_globals._oldDirection == DIR_DOWN_RIGHT) || (_vm->_globals._oldDirection == DIR_DOWN)) + setFlipSprite(0, false); + _vm->_globals.Compteur = 0; + } + _vm->_globals._oldDirection = newDirection; + _vm->_globals._oldDirectionSpriteIdx = newDirection + 59; + _vm->_globals._oldFrameIndex = oldFrameIdx; + _oldCharacterPosX = newPosX; + _oldCharacterPosY = newPosY; +} + +void ObjectsManager::GOHOME2() { + if (_vm->_linesManager._route == (RouteItem *)g_PTRNUL) + 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->_linesManager._route->_x; + int newPosY = _vm->_linesManager._route->_y; + Directions newDirection = (Directions)_vm->_linesManager._route->_dir; + _vm->_linesManager._route++; + + if ((nexPosX == -1) && (newPosY == -1)) + break; + + ++countColisionPixel; + if (countColisionPixel >= realSpeed) { + _vm->_globals._lastDirection = newDirection; + setSpriteX(0, nexPosX); + setSpriteY(0, newPosY); + switch (_vm->_globals._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 (_vm->_globals._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->_linesManager._route = (RouteItem *)g_PTRNUL; +} + +/** + * Load Zone + */ +void ObjectsManager::loadZone(const Common::String &file) { + for (int i = 1; i <= 100; i++) { + _vm->_linesManager.ZONEP[i]._destX = 0; + _vm->_linesManager.ZONEP[i]._destY = 0; + _vm->_linesManager.ZONEP[i]._spriteIndex = 0; + _vm->_linesManager.ZONEP[i]._verbFl1 = 0; + _vm->_linesManager.ZONEP[i]._verbFl2 = 0; + _vm->_linesManager.ZONEP[i]._verbFl3 = 0; + _vm->_linesManager.ZONEP[i]._verbFl4 = 0; + _vm->_linesManager.ZONEP[i]._verbFl5 = 0; + _vm->_linesManager.ZONEP[i]._verbFl6 = 0; + _vm->_linesManager.ZONEP[i]._verbFl7 = 0; + _vm->_linesManager.ZONEP[i]._verbFl8 = 0; + _vm->_linesManager.ZONEP[i]._verbFl9 = 0; + _vm->_linesManager.ZONEP[i]._verbFl10 = 0; + _vm->_linesManager.ZONEP[i]._messageId = 0; + _vm->_linesManager.ZONEP[i]._enabledFl = false; + } + + Common::File f; + if (!f.exists(file)) + error("File not found : %s", file.c_str()); + + byte *ptr = _vm->_fileManager.loadFile(file); + int bufId = 0; + int zoneLineIdx = 0; + int bobZoneIdx; + do { + bobZoneIdx = READ_LE_INT16((uint16 *)ptr + bufId); + if (bobZoneIdx != -1) { + _vm->_linesManager.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->_linesManager.ZONEP[bobZoneIdx]._enabledFl = true; + } + bufId += 5; + ++zoneLineIdx; + } while (bobZoneIdx != -1); + + for (int i = 1; i <= 100; i++) { + _vm->_linesManager.ZONEP[i]._destX = READ_LE_INT16((uint16 *)ptr + bufId); + _vm->_linesManager.ZONEP[i]._destY = READ_LE_INT16((uint16 *)ptr + bufId + 1); + _vm->_linesManager.ZONEP[i]._spriteIndex = READ_LE_INT16((uint16 *)ptr + bufId + 2); + bufId += 3; + } + + byte *v9 = (ptr + 10 * zoneLineIdx + 606); + bufId = 0; + for (int i = 1; i <= 100; i++) { + _vm->_linesManager.ZONEP[i]._verbFl1 = v9[bufId]; + _vm->_linesManager.ZONEP[i]._verbFl2 = v9[bufId + 1]; + _vm->_linesManager.ZONEP[i]._verbFl3 = v9[bufId + 2]; + _vm->_linesManager.ZONEP[i]._verbFl4 = v9[bufId + 3]; + _vm->_linesManager.ZONEP[i]._verbFl5 = v9[bufId + 4]; + _vm->_linesManager.ZONEP[i]._verbFl6 = v9[bufId + 5]; + _vm->_linesManager.ZONEP[i]._verbFl7 = v9[bufId + 6]; + _vm->_linesManager.ZONEP[i]._verbFl8 = v9[bufId + 7]; + _vm->_linesManager.ZONEP[i]._verbFl9 = v9[bufId + 8]; + _vm->_linesManager.ZONEP[i]._verbFl10 = v9[bufId + 9]; + + bufId += 10; + } + v9 += 1010; + for (int i = 0; i < 100; i++) + _vm->_linesManager.ZONEP[i + 1]._messageId = READ_LE_UINT16(v9 + 2 * i); + + _vm->_globals.freeMemory(ptr); + _vm->_linesManager.CARRE_ZONE(); +} + +void ObjectsManager::handleCityMap() { + _vm->_dialogsManager._inventFl = false; + _vm->_eventsManager._gameKey = KEY_NONE; + _vm->_linesManager.setMaxLineIdx(1); + _vm->_globals._characterMaxPosY = 440; + _vm->_globals._cityMapEnabledFl = true; + _vm->_graphicsManager._noFadingFl = false; + _vm->_globals._freezeCharacterFl = false; + _spritePtr = g_PTRNUL; + _vm->_globals._exitId = 0; + _vm->_globals._checkDistanceFl = true; + _vm->_soundManager.playSound(31); + _vm->_globals.iRegul = 1; + _vm->_graphicsManager.loadImage("PLAN"); + _vm->_linesManager.loadLines("PLAN.OB2"); + _vm->_globals.loadHidingItems("PLAN.CA2"); + loadZone("PLAN.ZO2"); + _spritePtr = _vm->_fileManager.loadFile("VOITURE.SPR"); + _vm->_animationManager.loadAnim("PLAN"); + _vm->_graphicsManager.displayAllBob(); + _vm->_graphicsManager.initScreen("PLAN", 2, false); + for (int i = 0; i <= 15; i++) + _vm->_globals.B_CACHE_OFF(i); + _vm->_globals.B_CACHE_OFF(19); + _vm->_globals.B_CACHE_OFF(20); + _vm->_globals.enableHiding(); + + if (!_mapCarPosX && !_mapCarPosY) { + _mapCarPosX = 900; + _mapCarPosY = 319; + } + addStaticSprite(_spritePtr, Common::Point(_mapCarPosX, _mapCarPosY), 0, 1, 0, false, 5, 5); + _vm->_eventsManager.setMouseXY(_mapCarPosX, _mapCarPosY); + _vm->_eventsManager.mouseOn(); + _vm->_graphicsManager.scrollScreen(getSpriteX(0) - 320); + _vm->_graphicsManager._scrollOffset = getSpriteX(0) - 320; + animateSprite(0); + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + + _vm->_globals.iRegul = 1; + _vm->_graphicsManager.fadeInLong(); + _vm->_eventsManager.changeMouseCursor(4); + _vm->_graphicsManager._noFadingFl = false; + + bool loopCond = false; + do { + int mouseButton = _vm->_eventsManager.getMouseButton(); + if (mouseButton) { + if (_vm->_globals._saveData->_data[svField170] == 1 && !_vm->_globals._saveData->_data[svField171]) { + _vm->_globals._saveData->_data[svField171] = 1; + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("APPEL1.pe2"); + _vm->_globals._introSpeechOffFl = false; + mouseButton = 0; + } + if (_vm->_globals._saveData->_data[svField80] == 1 && !_vm->_globals._saveData->_data[svField172]) { + _vm->_globals._saveData->_data[svField172] = 1; + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("APPEL2.pe2"); + _vm->_globals._introSpeechOffFl = false; + mouseButton = 0; + _vm->_eventsManager._curMouseButton = 0; + } + if (mouseButton == 1) + handleLeftButton(); + } + + _vm->_linesManager.checkZone(); + GOHOME2(); + + if (_vm->_linesManager._route == (RouteItem *)g_PTRNUL && _vm->_globals._actionMoveTo) + PARADISE(); + _vm->_eventsManager.VBL(); + + if (_vm->_globals._exitId) + loopCond = true; + } while (!_vm->shouldQuit() && !loopCond); + + if (!_vm->_graphicsManager._noFadingFl) + _vm->_graphicsManager.fadeOutLong(); + _vm->_globals.iRegul = 0; + _vm->_graphicsManager._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->_fontManager.hideText(9); + int destX = _vm->_eventsManager.getMouseX(); + int destY = _vm->_eventsManager.getMouseY(); + + if (!_vm->_dialogsManager._inventFl && !_vm->_globals._cityMapEnabledFl && + destX > _vm->_graphicsManager._scrollOffset - 30 && destX < _vm->_graphicsManager._scrollOffset + 50 && + destY > -30 && destY < 50) { + int oldMouseCursor = _vm->_eventsManager._mouseCursorId; + _vm->_dialogsManager._inventFl = true; + _vm->_dialogsManager.showInventory(); + _vm->_dialogsManager._inventFl = false; + _vm->_eventsManager._gameKey = KEY_NONE; + if (!_vm->_globals._exitId) { + _vm->_dialogsManager._inventFl = false; + _vm->_eventsManager._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->_linesManager.checkZone(); + if (_zoneNum <= 0) + return; + int routeIdx = 0; + do { + _vm->_linesManager.essai2[routeIdx] = _vm->_linesManager._route[routeIdx]; + ++routeIdx; + } while (_vm->_linesManager._route[routeIdx]._x != -1); + + _vm->_linesManager.essai2[routeIdx].invalidate();; + } + + if (_vm->_globals._actionMoveTo) { + _vm->_linesManager.checkZone(); + _vm->_globals._actionMoveTo = false; + _vm->_globals._saveData->_data[svField1] = 0; + _vm->_globals._saveData->_data[svField2] = 0; + } + + if (_vm->_globals._cityMapEnabledFl && (_vm->_eventsManager._mouseCursorId != 4 || _zoneNum <= 0)) + return; + if (_zoneNum != -1 && _zoneNum != 0) { + if (_vm->_linesManager.ZONEP[_zoneNum]._destX && _vm->_linesManager.ZONEP[_zoneNum]._destY && _vm->_linesManager.ZONEP[_zoneNum]._destY != 31) { + destX = _vm->_linesManager.ZONEP[_zoneNum]._destX; + destY = _vm->_linesManager.ZONEP[_zoneNum]._destY; + } + } + _vm->_globals._actionMoveTo = false; + RouteItem *oldRoute = _vm->_linesManager._route; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + if (_forestFl && _zoneNum >= 20 && _zoneNum <= 23) { + if (getSpriteY(0) > 374 && getSpriteY(0) <= 410) { + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + setSpriteIndex(0, _vm->_globals._oldDirectionSpriteIdx); + _vm->_globals._actionDirection = DIR_NONE; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + computeAndSetSpriteSize(); + setFlipSprite(0, false); + _vm->_globals.Compteur = 0; + _vm->_globals._oldDirection = DIR_NONE; + } else { + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(getSpriteX(0), getSpriteY(0), getSpriteX(0), 390); + if (_vm->_linesManager._route != (RouteItem *)g_PTRNUL) + _vm->_linesManager.PACOURS_PROPRE(_vm->_linesManager._route); + _oldCharacterPosX = getSpriteX(0); + _oldCharacterPosY = getSpriteY(0); + _vm->_globals.Compteur = 0; + if (_vm->_linesManager._route != (RouteItem *)g_PTRNUL || oldRoute == _vm->_linesManager._route) { + _vm->_globals._oldDirection = DIR_NONE; + } else { + _vm->_linesManager._route = oldRoute; + } + } + } else { + if (!_vm->_globals._freezeCharacterFl && !_vm->_globals._cityMapEnabledFl) { + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(getSpriteX(0), getSpriteY(0), destX, destY); + if (_vm->_linesManager._route != (RouteItem *)g_PTRNUL) + _vm->_linesManager.PACOURS_PROPRE(_vm->_linesManager._route); + _oldCharacterPosX = getSpriteX(0); + _oldCharacterPosY = getSpriteY(0); + _vm->_globals.Compteur = 0; + if (_vm->_linesManager._route != (RouteItem *)g_PTRNUL || oldRoute == _vm->_linesManager._route) + _vm->_globals._oldDirection = DIR_NONE; + else + _vm->_linesManager._route = oldRoute; + } + } + + if (!_vm->_globals._freezeCharacterFl && _vm->_globals._cityMapEnabledFl) + _vm->_linesManager._route = _vm->_linesManager.cityMapCarRoute(getSpriteX(0), getSpriteY(0), destX, destY); + + if (_zoneNum != -1 && _zoneNum != 0) { + if (_vm->_eventsManager._mouseCursorId == 23) + _vm->_globals._saveData->_data[svField1] = 5; + else + _vm->_globals._saveData->_data[svField1] = _vm->_eventsManager._mouseCursorId; + + if (_vm->_globals._cityMapEnabledFl) + _vm->_globals._saveData->_data[svField1] = 6; + _vm->_globals._saveData->_data[svField2] = _zoneNum; + _vm->_globals._saveData->_data[svField3] = _curObjectIndex; + _vm->_globals._actionMoveTo = true; + } + _vm->_fontManager.hideText(5); + _vm->_graphicsManager.SETCOLOR4(251, 100, 100, 100); + if (_vm->_globals._screenId == 20 && _vm->_globals._saveData->_data[svField132] == 1 + && _curObjectIndex == 20 && _zoneNum == 12 + && _vm->_eventsManager._mouseCursorId == 23) { + // Special case for throwing darts at the switch in Purgatory - the player shouldn't move + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + getSpriteX(0); + getSpriteY(0); + } +} + +void ObjectsManager::PARADISE() { + char result = _vm->_globals._saveData->_data[svField1]; + if (result && _vm->_globals._saveData->_data[svField2] && result != 4 && result > 3) { + _vm->_fontManager.hideText(5); + if (!_forestFl || _zoneNum < 20 || _zoneNum > 23) { + if (_vm->_graphicsManager._largeScreenFl) { + _vm->_graphicsManager._scrollStatus = 2; + if (_vm->_eventsManager._startPos.x + 320 - getSpriteX(0) > 160) { + bool loopCond = false; + do { + _vm->_graphicsManager._scrollPosX -= _vm->_graphicsManager._scrollSpeed; + if (_vm->_graphicsManager._scrollPosX < 0) { + _vm->_graphicsManager._scrollPosX = 0; + loopCond = true; + } + if (_vm->_graphicsManager._scrollPosX > SCREEN_WIDTH) { + _vm->_graphicsManager._scrollPosX = SCREEN_WIDTH; + loopCond = true; + } + if (_vm->_eventsManager.getMouseX() > _vm->_graphicsManager._scrollPosX + 620) + _vm->_eventsManager.setMouseXY(_vm->_eventsManager._mousePos.x - 4, _vm->_eventsManager.getMouseY()); + + _vm->_eventsManager.VBL(); + } while (!loopCond && _vm->_eventsManager._startPos.x > getSpriteX(0) - 320); + } else if (_vm->_eventsManager._startPos.x + 320 - getSpriteX(0) < -160) { + bool loopCond = false; + do { + _vm->_graphicsManager._scrollPosX += _vm->_graphicsManager._scrollSpeed; + if (_vm->_graphicsManager._scrollPosX < 0) { + _vm->_graphicsManager._scrollPosX = 0; + loopCond = true; + } + if (_vm->_graphicsManager._scrollPosX > SCREEN_WIDTH) { + _vm->_graphicsManager._scrollPosX = SCREEN_WIDTH; + loopCond = true; + } + if (_vm->_eventsManager.getMouseX() < _vm->_graphicsManager._scrollPosX + 10) + _vm->_eventsManager.setMouseXY(_vm->_eventsManager._mousePos.x + 4, _vm->_eventsManager.getMouseY()); + + _vm->_eventsManager.VBL(); + } while (!loopCond && _vm->_eventsManager._startPos.x < getSpriteX(0) - 320); + } + if (_vm->_eventsManager.getMouseX() > _vm->_graphicsManager._scrollPosX + 620) + _vm->_eventsManager.setMouseXY(_vm->_graphicsManager._scrollPosX + 610, 0); + if (_vm->_eventsManager.getMouseX() < _vm->_graphicsManager._scrollPosX + 10) + _vm->_eventsManager.setMouseXY(_vm->_graphicsManager._scrollPosX + 10, 0); + _vm->_eventsManager.VBL(); + _vm->_graphicsManager._scrollStatus = 0; + } + _vm->_talkManager.REPONSE(_vm->_globals._saveData->_data[svField2], _vm->_globals._saveData->_data[svField1]); + } else { + _vm->_talkManager.REPONSE2(_vm->_globals._saveData->_data[svField2], _vm->_globals._saveData->_data[svField1]); + } + _vm->_eventsManager.changeMouseCursor(4); + if (_zoneNum != -1 && _zoneNum != 0 && !_vm->_linesManager.ZONEP[_zoneNum]._enabledFl) { + _zoneNum = -1; + _forceZoneFl = true; + } + if (_zoneNum != _vm->_globals._saveData->_data[svField2] || _zoneNum == -1 || _zoneNum == 0) { + _vm->_eventsManager._mouseCursorId = 4; + _changeVerbFl = false; + } else { + _vm->_eventsManager._mouseCursorId = _vm->_globals._saveData->_data[svField1]; + if (_changeVerbFl) { + nextVerbIcon(); + _changeVerbFl = false; + } + if (_vm->_eventsManager._mouseCursorId == 5) + _vm->_eventsManager._mouseCursorId = 4; + } + if (_vm->_eventsManager._mouseCursorId != 23) + _vm->_eventsManager.changeMouseCursor(_vm->_eventsManager._mouseCursorId); + _zoneNum = 0; + _vm->_globals._saveData->_data[svField1] = 0; + _vm->_globals._saveData->_data[svField2] = 0; + } + if (_vm->_globals._cityMapEnabledFl) { + _vm->_eventsManager._mouseCursorId = 0; + _vm->_eventsManager.changeMouseCursor(0); + } + if (_vm->_globals._freezeCharacterFl && _vm->_eventsManager._mouseCursorId == 4) { + if (_zoneNum != -1 && _zoneNum != 0) + handleRightButton(); + } + _vm->_globals._actionMoveTo = false; +} + +/** + * Clear Screen + */ +void ObjectsManager::clearScreen() { + clearSprite(); + _vm->_graphicsManager.endDisplayBob(); + _vm->_fontManager.hideText(5); + _vm->_fontManager.hideText(9); + _vm->_globals.clearVBob(); + _vm->_animationManager.clearAnim(); + _vm->_linesManager.clearAllZones(); + _vm->_linesManager.resetLines(); + _vm->_globals.resetHidingItems(); + + for (int i = 0; i <= 48; i++) { + _vm->_linesManager.BOBZONE[i] = 0; + _vm->_linesManager.BOBZONE_FLAG[i] = false; + } + _vm->_eventsManager._mouseCursorId = 4; + _verb = 4; + _zoneNum = 0; + _forceZoneFl = true; + _vm->_linesManager.resetLinesNumb(); + _vm->_linesManager.resetLastLine(); + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_globals._answerBuffer = _vm->_globals.freeMemory(_vm->_globals._answerBuffer); + _vm->_globals.SPRITE_ECRAN = _vm->_globals.freeMemory(_vm->_globals.SPRITE_ECRAN); + _vm->_eventsManager._startPos.x = 0; + _vm->_eventsManager._mouseSpriteId = 0; + _vm->_globals._saveData->_data[svField1] = 0; + _vm->_globals._saveData->_data[svField2] = 0; + _vm->_globals._actionMoveTo = false; + _forceZoneFl = true; + _changeVerbFl = false; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_globals._oldDirection = DIR_NONE; + _vm->_graphicsManager.resetVesaSegment(); +} + +/** + * 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->_graphicsManager.copySurface(_vm->_graphicsManager._vesaScreen, 532, 25, 65, 40, _vm->_graphicsManager._vesaBuffer, 532, 25); + _vm->_graphicsManager.addVesaSegment(532, 25, 597, 65); + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + + 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.PERSO = _vm->_fileManager.loadFile("PERSO.SPR"); + _vm->_globals._characterType = 0; + addStaticSprite(_vm->_globals.PERSO, 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.PERSO = _vm->_fileManager.loadFile("PSAMAN.SPR"); + _vm->_globals._characterType = 2; + addStaticSprite(_vm->_globals.PERSO, 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[svField121] = 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[svField121] = 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[svField121] = 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->_eventsManager._mouseCursorId++; + + for(;;) { + if (_vm->_eventsManager._mouseCursorId == 4) { + if (!_vm->_globals._freezeCharacterFl || _zoneNum == -1 || _zoneNum == 0) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 5 || _vm->_eventsManager._mouseCursorId == 6) { + _vm->_eventsManager._mouseCursorId = 6; + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl1 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 7) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl2 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 8) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl3 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 9) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl4 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 10) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl5 == 1) + return; + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 11) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl6 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 12) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl7 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 13) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl8 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 14) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl9 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 15) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl10 == 1) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 16) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl1 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 17) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl4 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 18) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl5 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 19) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl6 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 20) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl7 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 21) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl10 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 22) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl8 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 23) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl3 == 2) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 24) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl4 == 3) + return; + + ++_vm->_eventsManager._mouseCursorId; + } + + if (_vm->_eventsManager._mouseCursorId == 25) { + if (_vm->_linesManager.ZONEP[_zoneNum]._verbFl9 == 2) + return; + } + _vm->_eventsManager._mouseCursorId = 4; + } +} + +/** + * Handle Right button + */ +void ObjectsManager::handleRightButton() { + if (_zoneNum != -1 && _zoneNum != 0) { + nextVerbIcon(); + if (_vm->_eventsManager._mouseCursorId != 23) + _vm->_eventsManager.changeMouseCursor(_vm->_eventsManager._mouseCursorId); + _verb = _vm->_eventsManager._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->_graphicsManager._scrollOffset + 158; + else if (zoneIdx == 2 || zoneIdx == 8 || zoneIdx == 14 || zoneIdx == 20 || zoneIdx == 26) + _borderPos.x = _vm->_graphicsManager._scrollOffset + 212; + else if (zoneIdx == 3 || zoneIdx == 9 || zoneIdx == 15 || zoneIdx == 21 || zoneIdx == 27) + _borderPos.x = _vm->_graphicsManager._scrollOffset + 266; + else if (zoneIdx == 4 || zoneIdx == 10 || zoneIdx == 16 || zoneIdx == 22 || zoneIdx == 28) + _borderPos.x = _vm->_graphicsManager._scrollOffset + 320; + else if (zoneIdx == 5 || zoneIdx == 11 || zoneIdx == 17 || zoneIdx == 23 || zoneIdx == 29) + _borderPos.x = _vm->_graphicsManager._scrollOffset + 374; + else if (zoneIdx == 6 || zoneIdx == 12 || zoneIdx == 18 || zoneIdx == 24 || zoneIdx == 30 || zoneIdx == 31) + _borderPos.x = _vm->_graphicsManager._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->_eventsManager._mouseCursorId = 0; + else if (zoneIdx >= 1 && zoneIdx <= 28) + _vm->_eventsManager._mouseCursorId = 8; + else if (zoneIdx == 29) + _vm->_eventsManager._mouseCursorId = 1; + else if (zoneIdx == 30) + _vm->_eventsManager._mouseCursorId = 2; + else if (zoneIdx == 31) + _vm->_eventsManager._mouseCursorId = 3; + else if (zoneIdx == 32) + _vm->_eventsManager._mouseCursorId = 16; + + if (zoneIdx >= 1 && zoneIdx <= 28 && !_vm->_globals._inventory[zoneIdx]) { + _vm->_eventsManager._mouseCursorId = 0; + _borderPos = Common::Point(0, 0); + _borderSpriteIndex = 0; + } + + if (_vm->_eventsManager._mouseCursorId != 23) + _vm->_eventsManager.changeMouseCursor(_vm->_eventsManager._mouseCursorId); + _vm->_eventsManager.getMouseX(); + _vm->_eventsManager.getMouseY(); +} + +/** + * Get next icon for an object in the inventory + */ +void ObjectsManager::nextObjectIcon(int idx) { + if (_vm->_eventsManager._mouseCursorId == 0 || _vm->_eventsManager._mouseCursorId == 2 || + _vm->_eventsManager._mouseCursorId == 3 || _vm->_eventsManager._mouseCursorId == 16) + return; + + int nextCursorId = _vm->_eventsManager._mouseCursorId + 1; + if (nextCursorId > 25) + nextCursorId = 6; + + do { + if (nextCursorId == 2 || nextCursorId == 5 || nextCursorId == 6) { + _vm->_eventsManager._mouseCursorId = 6; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag1 == 1) + return; + nextCursorId++; + } + if (nextCursorId == 7) { + _vm->_eventsManager._mouseCursorId = 7; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag2 == 1) + return; + nextCursorId++; + } + if (nextCursorId == 8) { + _vm->_eventsManager._mouseCursorId = 8; + return; + } + if (nextCursorId == 9 || nextCursorId == 10) { + _vm->_eventsManager._mouseCursorId = 10; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag6 == 1) + return; + nextCursorId = 11; + } + + if (nextCursorId == 11) { + _vm->_eventsManager._mouseCursorId = 11; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag3 == 1) + return; + nextCursorId++; + } + + if (nextCursorId == 12 || nextCursorId == 13) { + _vm->_eventsManager._mouseCursorId = 13; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag4 == 1) + return; + nextCursorId = 14; + } + + if (nextCursorId == 14 || nextCursorId == 15) { + _vm->_eventsManager._mouseCursorId = 15; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag5 == 1) + return; + nextCursorId = 23; + } + + if (nextCursorId >= 16 && nextCursorId <= 23) { + _vm->_eventsManager._mouseCursorId = 23; + if (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag5 == 2) + return; + nextCursorId = 24; + } + + if (nextCursorId == 24 || nextCursorId == 25) { + _vm->_eventsManager._mouseCursorId = 25; + } + + nextCursorId = 6; + } while (_vm->_globals._objectAuthIcons[_vm->_globals._inventory[idx]]._flag6 != 2); +} + +void ObjectsManager::takeInventoryObject(int idx) { + if (_vm->_eventsManager._mouseCursorId == 8) + changeObject(idx); +} + +void ObjectsManager::OPTI_OBJET() { + byte *data; + Common::String file; + int lastOpcodeResult = 1; + + file = "OBJET1.ini"; + data = _vm->_fileManager.searchCat(file, 1); + if (data == g_PTRNUL) { + data = _vm->_fileManager.loadFile(file); + if (data == g_PTRNUL) + 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->_scriptManager.handleOpcode(data + 20 * lastOpcodeResult); + if (_vm->shouldQuit()) + return; + + if (opcodeType == 2) + lastOpcodeResult = _vm->_scriptManager.handleGoto(data + 20 * lastOpcodeResult); + else if (opcodeType == 3) + lastOpcodeResult = _vm->_scriptManager.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->_talkManager.startAnimatedCharacterDialogue("flicspe1.pe2"); + _vm->_globals._introSpeechOffFl = false; + + if (_vm->_globals._censorshipFl) + break; + + oldPalette = _vm->_globals.allocMemory(1000); + memcpy(oldPalette, _vm->_graphicsManager._palette, 769); + + _vm->_saveLoadManager.saveFile("TEMP1.SCR", _vm->_graphicsManager._vesaScreen, 307200); + + if (!_vm->_graphicsManager._lineNbr) + _vm->_graphicsManager._scrollOffset = 0; + _vm->_graphicsManager.NB_SCREEN(true); + _vm->_soundManager._specialSoundNum = 198; + PERSO_ON = true; + _vm->_animationManager.NO_SEQ = true; + _vm->_animationManager._clearAnimationFl = false; + _vm->_animationManager.playAnim("otage.ANM", 1, 24, 500); + _vm->_animationManager.NO_SEQ = false; + _vm->_soundManager._specialSoundNum = 0; + _vm->_graphicsManager.NB_SCREEN(false); + + _vm->_saveLoadManager.load("TEMP1.SCR", _vm->_graphicsManager._vesaScreen); + g_system->getSavefileManager()->removeSavefile("TEMP1.SCR"); + + PERSO_ON = false; + memcpy(_vm->_graphicsManager._palette, oldPalette, 769); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + _vm->_globals.freeMemory(oldPalette); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaScreen, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + memcpy(_vm->_graphicsManager._vesaBuffer, _vm->_graphicsManager._vesaScreen, 614399); + + _vm->_graphicsManager._scrollStatus = 0; + _vm->_graphicsManager.DD_VBL(); + 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->_linesManager.disableZone(15); + _vm->_soundManager.playSoundFile("SOUND75.WAV"); + } + if (_vm->_globals._saveData->_data[svField261] == 2 && getBobAnimDataIdx(6) == 6) { + stopBobAnimation(6); + setBobAnimDataIdx(6, 0); + setBobAnimation(7); + _vm->_linesManager.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->_eventsManager.VBL(); + while (getBobAnimDataIdx(8) != 3); + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("GM3.PE2"); + stopBobAnimation(8); + _vm->_globals._saveData->_data[svField333] = 1; + _vm->_globals._disableInventFl = false; + break; + } +} + +void ObjectsManager::BOB_VIVANT(int idx) { + int startPos = 10 * idx; + if (!READ_LE_UINT16(_vm->_talkManager._characterAnim + startPos + 4)) + return; + + int xp = READ_LE_INT16(_vm->_talkManager._characterAnim + startPos); + int yp = READ_LE_INT16(_vm->_talkManager._characterAnim + startPos + 2); + int spriteIndex = _vm->_talkManager._characterAnim[startPos + 8]; + + _vm->_graphicsManager.fastDisplay(_vm->_talkManager._characterSprite, xp, yp, spriteIndex); +} + +void ObjectsManager::VBOB(byte *src, int idx, int xp, int yp, int frameIndex) { + if (idx > 29) + error("MAX_VBOB exceeded"); + + VBobItem *vbob = &_vm->_globals.VBob[idx]; + if (vbob->field4 <= 1) { + vbob->field4 = 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->field4 == 2 || vbob->field4 == 4) { + vbob->field4 = 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::VBOB_OFF(int idx) { + if (idx > 29) + error("MAX_VBOB exceeded"); + + VBobItem *vbob = &_vm->_globals.VBob[idx]; + if (vbob->field4 <= 1) + vbob->field4 = 0; + else + vbob->field4 = 4; +} + +void ObjectsManager::doActionBack(int idx) { + if (_curGestureFile != 1) { + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); + _curGestureFile = 1; + _gestureBuf = _vm->_fileManager.loadFile("DOS.SPR"); + } + + switch (idx) { + case 1: + ACTION(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 8, false); + break; + case 2: + SPACTION(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,13,-1,", 0, 0, 8, false); + break; + case 3: + SPACTION1(_gestureBuf, "12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 8); + break; + case 4: + ACTION(_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,", 0, 0, 8, false); + break; + case 5: + SPACTION(_gestureBuf, "15,16,17,18,19,20,21,-1,", 0, 0, 8, false); + break; + case 6: + SPACTION1(_gestureBuf, "20,19,18,17,16,15,-1,", 0, 0, 8); + break; + case 7: + SPACTION(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 0, 0, 8, false); + break; + case 8: + SPACTION1(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 0, 0, 8); + break; + case 9: + SPACTION(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 0, 0, 8, false); + break; + case 10: + SPACTION1(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 0, 0, 8); + break; + } +} + +void ObjectsManager::doActionRight(int idx) { + if (_curGestureFile != 3) { + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); + _curGestureFile = 3; + _gestureBuf = _vm->_fileManager.loadFile("PROFIL.SPR"); + } + + switch (idx) { + case 1: + ACTION(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 0, 0, 8, false); + break; + case 2: + SPACTION(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 0, 0, 8, false); + break; + case 3: + SPACTION1(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 0, 0, 8); + break; + case 4: + ACTION(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 0, 0, 8, false); + break; + case 5: + SPACTION(_gestureBuf, "23,24,25,-1,", 0, 0, 8, false); + break; + case 6: + SPACTION1(_gestureBuf, "24,,23,-1,", 0, 0, 8); + break; + case 7: + SPACTION(_gestureBuf, "23,24,25,26,27,-1,", 0, 0, 8, false); + break; + case 8: + SPACTION1(_gestureBuf, "26,25,24,23,-1,", 0, 0, 8); + break; + case 9: + SPACTION(_gestureBuf, "23,24,25,26,27,28,29,-1,", 0, 0, 8, false); + break; + case 10: + SPACTION1(_gestureBuf, "28,27,26,25,24,23,-1,", 0, 0, 8); + break; + } +} + +void ObjectsManager::doActionDiagRight(int idx) { + if (_curGestureFile != 4) { + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); + _curGestureFile = 4; + _gestureBuf = _vm->_fileManager.loadFile("3Q.SPR"); + } + + switch (idx) { + case 1: + ACTION(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 8, false); + break; + case 2: + SPACTION(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 0, 0, 8, false); + break; + case 3: + SPACTION1(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 8); + break; + case 4: + ACTION(_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,", 0, 0, 8, false); + break; + case 5: + SPACTION(_gestureBuf, "15,16,17,18,-1,", 0, 0, 8, false); + break; + case 6: + SPACTION1(_gestureBuf, "17,16,15,-1,", 0, 0, 8); + break; + case 7: + SPACTION(_gestureBuf, "15,16,17,18,19,20-1,", 0, 0, 8, false); + break; + case 8: + SPACTION1(_gestureBuf, "19,18,17,16,15,-1,", 0, 0, 8); + break; + case 9: + SPACTION(_gestureBuf, "15,16,17,18,19,20,21,-1,", 0, 0, 8, false); + break; + case 10: + SPACTION1(_gestureBuf, "20,19,18,17,15,-1,", 0, 0, 8); + break; + } +} + +void ObjectsManager::doActionFront(int idx) { + if (_curGestureFile != 2) { + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); + _curGestureFile = 2; + _gestureBuf = _vm->_fileManager.loadFile("FACE.SPR"); + } + + switch (idx) { + case 1: + ACTION(_gestureBuf, "0,1,2,3,4,5,6,7,9,9,9,9,9,9,7,6,5,4,3,2,1,0,-1,", 0, 0, 8, false); + break; + case 2: + SPACTION(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,15,-1,", 0, 0, 8, false); + break; + case 3: + SPACTION1(_gestureBuf, "14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 0, 0, 8); + break; + case 4: + ACTION(_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,", 0, 0, 8, false); + break; + } +} + +void ObjectsManager::doActionDiagLeft(int idx) { + if (_curGestureFile != 4) { + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); + _curGestureFile = 4; + _gestureBuf = _vm->_fileManager.loadFile("3Q.SPR"); + } + + switch (idx) { + case 1: + ACTION(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 8, true); + break; + case 2: + SPACTION(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 0, 0, 8, true); + break; + case 3: + SPACTION1(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 0, 0, 8); + break; + case 4: + ACTION(_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,", 0, 0, 8, true); + break; + case 5: + SPACTION(_gestureBuf, "15,16,17,18,-1,", 0, 0, 8, true); + break; + case 6: + SPACTION1(_gestureBuf, "17,16,15,-1,", 0, 0, 8); + break; + case 7: + SPACTION(_gestureBuf, "15,16,17,18,19,20,-1,", 0, 0, 8, true); + break; + case 8: + SPACTION1(_gestureBuf, "19,18,17,16,15,-1,", 0, 0, 8); + break; + case 9: + SPACTION(_gestureBuf, "15,16,17,18,19,20,21,-1,", 0, 0, 8, true); + break; + case 10: + SPACTION1(_gestureBuf, "20,19,18,17,15,-1,", 0, 0, 8); + break; + } +} + +void ObjectsManager::doActionLeft(int idx) { + if (_curGestureFile != 3) { + _gestureBuf = _vm->_globals.freeMemory(_gestureBuf); + _curGestureFile = 3; + _gestureBuf = _vm->_fileManager.loadFile("PROFIL.SPR"); + } + + switch (idx) { + case 1: + ACTION(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 0, 0, 8, true); + break; + case 2: + SPACTION(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 0, 0, 8, true); + break; + case 3: + SPACTION1(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 0, 0, 8); + break; + case 4: + ACTION(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 0, 0, 8, true); + break; + case 5: + SPACTION(_gestureBuf, "23,24,25,-1,", 0, 0, 8, true); + break; + case 6: + SPACTION1(_gestureBuf, "24,,23,-1,", 0, 0, 8); + break; + case 7: + SPACTION(_gestureBuf, "23,24,25,26,27,-1,", 0, 0, 8, true); + break; + case 8: + SPACTION1(_gestureBuf, "26,25,24,23,-1,", 0, 0, 8); + break; + case 9: + SPACTION(_gestureBuf, "23,24,25,26,27,28,29,-1,", 0, 0, 8, true); + break; + case 10: + SPACTION1(_gestureBuf, "28,27,26,25,24,23,-1,", 0, 0, 8); + break; + } +} + +void ObjectsManager::OPTI_ONE(int idx, int animIdx, int destPosi, int animAction) { + // Set Hopkins animation and position + if (animAction != 3) { + setBobAnimation(idx); + setBobAnimDataIdx(idx, animIdx); + } + + // Make Hopkins walk to the expected place + do { + _vm->_eventsManager.VBL(); + } while (destPosi != getBobAnimDataIdx(idx)); + + if (!animAction) + stopBobAnimation(idx); + else if (animAction == 4) { + _vm->_graphicsManager.fastDisplay(_bob[idx]._spriteData, + _bob[idx]._oldX, _bob[idx]._oldY, _bob[idx]._frameIndex); + stopBobAnimation(idx); + _vm->_eventsManager.VBL(); + } +} + +int ObjectsManager::getBobAnimDataIdx(int idx) { + return _bob[idx]._animDataIdx / 5; +} + +void ObjectsManager::setBobAnimDataIdx(int idx, int animIdx) { + _bob[idx]._animDataIdx = 5 * animIdx; + _bob[idx].field12 = 0; + _bob[idx].field14 = 0; +} + +/** + * Set Hopkins animation + */ +void ObjectsManager::setBobAnimation(int idx) { + if (!_bob[idx]._disabledAnimationFl) + return; + + _bob[idx]._disabledAnimationFl = false; + _bob[idx]._animDataIdx = 5; + _bob[idx]._frameIndex = 250; + _bob[idx].field12 = 0; + _bob[idx].field14 = 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; +} + +int ObjectsManager::getBobPosY(int idx) { + return _bob[idx]._yp; +} + +int ObjectsManager::getBobFrameIndex(int idx) { + return _bob[idx]._frameIndex; +} + +void ObjectsManager::loadLinkFile(const Common::String &file) { + Common::File f; + Common::String filename = file + ".LNK"; + byte *ptr = _vm->_fileManager.searchCat(filename, 3); + size_t nbytes = _vm->_globals._catalogSize; + if (ptr == g_PTRNUL) { + if (!f.open(filename)) + error("Error opening file - %s", filename.c_str()); + + nbytes = f.size(); + ptr = _vm->_globals.allocMemory(nbytes); + if (g_PTRNUL == ptr) + error("INILINK"); + _vm->_fileManager.readStream(f, ptr, nbytes); + f.close(); + } + if (!OBSSEUL) { + for (int idx = 0; idx < 500; ++idx) + _vm->_globals._spriteSize[idx] = READ_LE_INT16((uint16 *)ptr + idx); + + _vm->_globals.resetHidingItems(); + + Common::String filename2 = Common::String((const char *)ptr + 1000); + if (!filename2.empty()) { + _vm->_globals._hidingItemData[1] = _vm->_fileManager.searchCat(filename2, 8); + + if (_vm->_globals._hidingItemData[1] || _vm->_globals._hidingItemData[1] == g_PTRNUL) { + _vm->_globals._hidingItemData[1] = _vm->_fileManager.loadFile(filename2); + } else { + _vm->_globals._hidingItemData[1] = _vm->_fileManager.loadFile("RES_SLI.RES"); + } + + int curDataCacheId = 60; + byte *curDataPtr = ptr + 1000; + for (int hidingIdx = 0; hidingIdx <= 21; hidingIdx++) { + HidingItem *hid = &_vm->_globals._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->field14 = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 8); + + if (!_vm->_globals._hidingItemData[1]) { + hid->_useCount = 0; + } else { + hid->_spriteData = _vm->_globals._hidingItemData[1]; + hid->_width = getWidth(_vm->_globals._hidingItemData[1], curSpriteId); + hid->_height = getHeight(_vm->_globals._hidingItemData[1], curSpriteId); + hid->_useCount = 1; + } + if (!hid->_x && !hid->_y && !hid->_spriteIndex) + hid->_useCount = 0; + + curDataCacheId += 5; + } + _vm->_globals.enableHiding(); + } + } + + _vm->_linesManager.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->_linesManager.resetLinesNumb(); + Directions curDirection; + do { + curDirection = (Directions)READ_LE_INT16(curDataPtr + 2 * lineDataIdx); + if (curDirection != DIR_NONE) { + _vm->_linesManager.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->_linesManager.initRoute(); + } + } + + if (!OBSSEUL) { + 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++) { + _vm->_linesManager.ZONEP[i]._destX = 0; + _vm->_linesManager.ZONEP[i]._destY = 0; + _vm->_linesManager.ZONEP[i]._spriteIndex = 0; + _vm->_linesManager.ZONEP[i]._verbFl1 = 0; + _vm->_linesManager.ZONEP[i]._verbFl2 = 0; + _vm->_linesManager.ZONEP[i]._verbFl3 = 0; + _vm->_linesManager.ZONEP[i]._verbFl4 = 0; + _vm->_linesManager.ZONEP[i]._verbFl5 = 0; + _vm->_linesManager.ZONEP[i]._verbFl6 = 0; + _vm->_linesManager.ZONEP[i]._verbFl7 = 0; + _vm->_linesManager.ZONEP[i]._verbFl8 = 0; + _vm->_linesManager.ZONEP[i]._verbFl9 = 0; + _vm->_linesManager.ZONEP[i]._verbFl10 = 0; + _vm->_linesManager.ZONEP[i]._messageId = 0; + } + + int curLineIdx = 0; + int v28; + do { + v28 = READ_LE_INT16(curDataPtr + 2 * curDataIdx); + if (v28 != -1) { + _vm->_linesManager.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), + v28); + _vm->_linesManager.ZONEP[v28]._enabledFl = true; + } + curDataIdx += 5; + ++curLineIdx; + } while (v28 != -1); + for (int i = 1; i <= 100; i++) { + _vm->_linesManager.ZONEP[i]._destX = READ_LE_INT16(curDataPtr + 2 * curDataIdx); + _vm->_linesManager.ZONEP[i]._destY = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2); + _vm->_linesManager.ZONEP[i]._spriteIndex = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4); + curDataIdx += 3; + } + + byte *v22 = ptr + idx + (10 * curLineIdx + 606) + 4; + for (int i = 1; i <= 100; i++) { + int j = (i - 1) * 10; + _vm->_linesManager.ZONEP[i]._verbFl1 = v22[j]; + _vm->_linesManager.ZONEP[i]._verbFl2 = v22[j + 1]; + _vm->_linesManager.ZONEP[i]._verbFl3 = v22[j + 2]; + _vm->_linesManager.ZONEP[i]._verbFl4 = v22[j + 3]; + _vm->_linesManager.ZONEP[i]._verbFl5 = v22[j + 4]; + _vm->_linesManager.ZONEP[i]._verbFl6 = v22[j + 5]; + _vm->_linesManager.ZONEP[i]._verbFl7 = v22[j + 6]; + _vm->_linesManager.ZONEP[i]._verbFl8 = v22[j + 7]; + _vm->_linesManager.ZONEP[i]._verbFl9 = v22[j + 8]; + _vm->_linesManager.ZONEP[i]._verbFl10 = v22[j + 9]; + } + int dep = 1010; + for (int i = 1; i <= 100; i++) { + _vm->_linesManager.ZONEP[i]._messageId = READ_LE_INT16(v22 + dep); + dep += 2; + } + _vm->_linesManager.CARRE_ZONE(); + } + } + } + _vm->_globals.freeMemory(ptr); +} + +void ObjectsManager::SPECIAL_INI() { + switch (_vm->_globals._screenId) { + case 17: + if (_vm->_globals._prevScreenId == 20) { + _vm->_globals._disableInventFl = true; + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + _vm->_graphicsManager.fadeInLong(); + animateSprite(0); + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + VBOB(_vm->_globals.SPRITE_ECRAN, 5, 15, 28, 1); + _vm->_fontManager.hideText(9); + bool displayedTxtFl = false; + if (!_vm->_soundManager._textOffFl) { + _vm->_fontManager.initTextBuffers(9, 383, _vm->_globals._textFilename, 220, 72, 6, 36, 253); + _vm->_fontManager.showText(9); + displayedTxtFl = true; + } + if (!_vm->_soundManager._voiceOffFl) + _vm->_soundManager.mixVoice(383, 4, displayedTxtFl); + _vm->_globals._saveData->_data[svField270] = 1; + _vm->_globals._saveData->_data[svField300] = 1; + _vm->_globals._saveData->_data[svField320] = 1; + if (_vm->_soundManager._voiceOffFl) { + for (int i = 0; i <= 199; i++) + _vm->_eventsManager.VBL(); + } + _vm->_fontManager.hideText(9); + VBOB_OFF(5); + for (int i = 0; i <= 3; i++) + _vm->_eventsManager.VBL(); + _vm->_graphicsManager._noFadingFl = true; + _vm->_globals._disableInventFl = false; + } + break; + + case 18: + if (_vm->_globals._prevScreenId == 17) { + _vm->_eventsManager._mouseSpriteId = 4; + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + _vm->_graphicsManager.fadeInLong(); + _vm->_globals.iRegul = 1; + _vm->_globals._disableInventFl = false; + _vm->_graphicsManager._noFadingFl = true; + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("MAGE1.pe2"); + _vm->_graphicsManager._noFadingFl = true; + _vm->_globals._disableInventFl = false; + } + break; + + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + _vm->_linesManager.BOBZONE[20] = 1; + _vm->_linesManager.BOBZONE[21] = 2; + _vm->_linesManager.BOBZONE[22] = 3; + _vm->_linesManager.BOBZONE[23] = 4; + _vm->_linesManager.BOBZONE_FLAG[20] = true; + _vm->_linesManager.BOBZONE_FLAG[21] = true; + _vm->_linesManager.BOBZONE_FLAG[22] = true; + _vm->_linesManager.BOBZONE_FLAG[23] = true; + enableVerb(20, 5); + enableVerb(21, 5); + enableVerb(22, 5); + enableVerb(23, 5); + _vm->_linesManager.ZONEP[20]._messageId = 30; + _vm->_linesManager.ZONEP[21]._messageId = 30; + _vm->_linesManager.ZONEP[22]._messageId = 30; + _vm->_linesManager.ZONEP[23]._messageId = 30; + for (int i = 200; i <= 214; i++) { + if (_vm->_globals._saveData->_data[i] != 2) + _vm->_globals._saveData->_data[i] = 0; + } + break; + + case 73: + if (!_vm->_globals._saveData->_data[svField318]) { + _vm->_globals.resetHidingUseCount(0); + _vm->_globals.resetHidingUseCount(1); + } + break; + + case 93: + if (!_vm->_globals._saveData->_data[svField333]) + setBobAnimation(8); + break; + } +} + +void ObjectsManager::OPTI_BOBON(int idx1, int idx2, int idx3, int anim1Idx, int anim2Idx, int anim3Idx) { + if (idx1 != -1) + setBobAnimation(idx1); + if (idx2 != -1) + setBobAnimation(idx2); + if (idx3 != -1) + setBobAnimation(idx3); + if (idx1 != -1) + setBobAnimDataIdx(idx1, anim1Idx); + if (idx2 != -1) + setBobAnimDataIdx(idx2, anim2Idx); + if (idx3 != -1) + setBobAnimDataIdx(idx3, anim3Idx); +} + +void ObjectsManager::SCI_OPTI_ONE(int idx, int animIdx, int a3, int a4) { + _vm->_eventsManager._curMouseButton = 0; + _vm->_eventsManager._mouseButton = 0; + + if (a4 != 3) { + setBobAnimation(idx); + setBobAnimDataIdx(idx, animIdx); + } + + do { + _vm->_eventsManager.VBL(); + if (_vm->_eventsManager._curMouseButton) + break; + } while (a3 != getBobAnimDataIdx(idx)); + if (!a4) + stopBobAnimation(idx); +} + +void ObjectsManager::disableVerb(int idx, int a2) { + switch (a2) { + case 6: + case 16: + _vm->_linesManager.ZONEP[idx]._verbFl1 = 0; + break; + case 7: + _vm->_linesManager.ZONEP[idx]._verbFl2 = 0; + break; + case 5: + case 8: + _vm->_linesManager.ZONEP[idx]._verbFl3 = 0; + break; + case 9: + case 17: + case 24: + _vm->_linesManager.ZONEP[idx]._verbFl4 = 0; + break; + case 10: + case 18: + _vm->_linesManager.ZONEP[idx]._verbFl5 = 0; + break; + case 11: + case 19: + _vm->_linesManager.ZONEP[idx]._verbFl6 = 0; + break; + case 12: + case 20: + _vm->_linesManager.ZONEP[idx]._verbFl7 = 0; + break; + case 13: + case 22: + _vm->_linesManager.ZONEP[idx]._verbFl8 = 0; + case 14: + case 21: + case 25: + _vm->_linesManager.ZONEP[idx]._verbFl9 = 0; + break; + case 15: + _vm->_linesManager.ZONEP[idx]._verbFl10 = 0; + break; + } + _changeVerbFl = true; +} + +void ObjectsManager::enableVerb(int idx, int a2) { + switch (a2) { + case 5: + _vm->_linesManager.ZONEP[idx]._verbFl3 = 2; + break; + case 6: + _vm->_linesManager.ZONEP[idx]._verbFl1 = 1; + break; + case 7: + _vm->_linesManager.ZONEP[idx]._verbFl2 = 1; + break; + case 8: + _vm->_linesManager.ZONEP[idx]._verbFl3 = 1; + break; + case 9: + _vm->_linesManager.ZONEP[idx]._verbFl4 = 1; + break; + case 10: + _vm->_linesManager.ZONEP[idx]._verbFl5 = 1; + break; + case 11: + _vm->_linesManager.ZONEP[idx]._verbFl6 = 1; + break; + case 12: + _vm->_linesManager.ZONEP[idx]._verbFl7 = 1; + break; + case 13: + _vm->_linesManager.ZONEP[idx]._verbFl8 = 1; + break; + case 14: + _vm->_linesManager.ZONEP[idx]._verbFl8 = 1; + break; + case 15: + _vm->_linesManager.ZONEP[idx]._verbFl9 = 1; + break; + case 16: + _vm->_linesManager.ZONEP[idx]._verbFl1 = 2; + break; + case 17: + _vm->_linesManager.ZONEP[idx]._verbFl4 = 2; + break; + case 18: + _vm->_linesManager.ZONEP[idx]._verbFl5 = 2; + break; + case 19: + _vm->_linesManager.ZONEP[idx]._verbFl6 = 2; + break; + case 20: + _vm->_linesManager.ZONEP[idx]._verbFl7 = 2; + break; + case 21: + _vm->_linesManager.ZONEP[idx]._verbFl9 = 2; + break; + case 22: + _vm->_linesManager.ZONEP[idx]._verbFl8 = 2; + break; + case 24: + _vm->_linesManager.ZONEP[idx]._verbFl4 = 3; + break; + case 25: + _vm->_linesManager.ZONEP[idx]._verbFl9 = 2; + break; + } +} + +void ObjectsManager::ACTION(const byte *spriteData, const Common::String &actionStr, int a3, int a4, 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].field12 += a3; + _sprite[0].field14 += a4; + _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].field12 -= a3; + _sprite[0].field14 -= a4; + _sprite[0]._flipFl = oldFlipFl; + } else { + _sprite[0]._spriteData = spriteData; + _sprite[0]._spriteIndex = idx; + } + for (int i = 0; i < realSpeed; i++) + _vm->_eventsManager.VBL(); + if (idx == -1) + break; + } + } +} + +void ObjectsManager::SPACTION(byte *spriteData, const Common::String &animationSeq, int a3, int a4, 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].field12 += a3; + _sprite[0].field14 += a4; + _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->_eventsManager.VBL(); + } while (spriteIndex != -1); +} + +void ObjectsManager::SPACTION1(byte *spriteData, const Common::String &animString, int a3, int a4, 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].field12 -= a3; + _sprite[0].field14 -= a4; + _sprite[0]._flipFl = _oldFlipFl; + } else { + _sprite[0]._spriteData = spriteData; + _sprite[0]._spriteIndex = spriteIndex; + } + + for (int i = 0; i < realSpeed; i++) + _vm->_eventsManager.VBL(); + + 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->_dialogsManager._removeInventFl = true; + _vm->_soundManager.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->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playAnim("CREVE2.ANM", 100, 24, 500); + _vm->_globals._exitId = 150; + _vm->_graphicsManager._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) { + _vm->_globals._lockedAnims[idx]._enableFl = true; + _vm->_globals._lockedAnims[idx]._posX = x; +} + +/** + * Game scene control method + */ +void ObjectsManager::PERSONAGE(const Common::String &backgroundFile, const Common::String &linkFile, + const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) { + _vm->_dialogsManager._inventFl = false; + _vm->_eventsManager._gameKey = KEY_NONE; + _vm->_dialogsManager._removeInventFl = false; + _vm->_graphicsManager._scrollOffset = 0; + _vm->_globals._cityMapEnabledFl = false; + _vm->_globals.iRegul = 1; + _vm->_soundManager.playSound(soundNum); + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_globals._freezeCharacterFl = true; + _vm->_globals._exitId = 0; + if (!backgroundFile.empty()) + _vm->_graphicsManager.loadImage(backgroundFile); + if (!linkFile.empty()) + loadLinkFile(linkFile); + if (!animFile.empty()) + _vm->_animationManager.loadAnim(animFile); + _vm->_graphicsManager.displayAllBob(); + if (!s4.empty()) { + if (initializeScreen) + _vm->_graphicsManager.initScreen(s4, 0, initializeScreen); + else + _vm->_graphicsManager.initScreen(s4, 2, initializeScreen); + } + _vm->_eventsManager.mouseOn(); + if (_vm->_globals._screenId == 61) { + addStaticSprite(_vm->_globals.PERSO, Common::Point(330, 418), 0, 60, 0, false, 34, 190); + animateSprite(0); + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + computeAndSetSpriteSize(); + } + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + _vm->_eventsManager.changeMouseCursor(4); + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + _vm->_graphicsManager.fadeInLong(); + if (_vm->_globals._screenId == 61) { + _vm->_animationManager.playSequence("OUVRE.SEQ", 10, 4, 10); + stopBobAnimation(3); + _vm->_globals._checkDistanceFl = true; + _oldCharacterPosX = getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(getSpriteX(0), getSpriteY(0), 330, 345); + _vm->_globals._checkDistanceFl = true; + do { + GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + setSpriteIndex(0, 64); + } + do { + int mouseButton = _vm->_eventsManager.getMouseButton(); + if (mouseButton == 1) { + handleLeftButton(); + mouseButton = 1; + } else if (mouseButton == 2) + handleRightButton(); + _vm->_dialogsManager.testDialogOpening(); + _vm->_linesManager.checkZone(); + if (_vm->_globals._actionMoveTo) + PARADISE(); + if (!_vm->_globals._exitId) + _vm->_eventsManager.VBL(); + + if (_vm->_globals._exitId) + break; + } while (!_vm->shouldQuit()); + if (_vm->shouldQuit()) + return; + + _vm->_graphicsManager.fadeOutLong(); + if (!animFile.empty()) + _vm->_graphicsManager.endDisplayBob(); + if (_vm->_globals._screenId == 61) + removeSprite(0); + clearScreen(); + _vm->_globals.iRegul = 0; +} + +/** + * Game scene control method + */ +void ObjectsManager::PERSONAGE2(const Common::String &backgroundFile, const Common::String &linkFile, + const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) { + _vm->_dialogsManager._inventFl = false; + _vm->_eventsManager._gameKey = KEY_NONE; + _verb = 4; + _vm->_graphicsManager._scrollOffset = 0; + _vm->_dialogsManager._removeInventFl = false; + _vm->_globals._cityMapEnabledFl = false; + _vm->_graphicsManager._noFadingFl = false; + _vm->_globals._freezeCharacterFl = false; + _vm->_globals._exitId = 0; + _vm->_globals._checkDistanceFl = true; + _vm->_soundManager.playSound(soundNum); + _vm->_globals.iRegul = 1; + if (!backgroundFile.empty()) + _vm->_graphicsManager.loadImage(backgroundFile); + if (!linkFile.empty()) + loadLinkFile(linkFile); + if (!animFile.empty()) { + _vm->_animationManager.loadAnim(animFile); + _vm->_graphicsManager.displayAllBob(); + } + if (!s4.empty()) { + if (initializeScreen) + _vm->_graphicsManager.initScreen(s4, 0, initializeScreen); + else + _vm->_graphicsManager.initScreen(s4, 2, initializeScreen); + } + _vm->_eventsManager.mouseOn(); + _vm->_eventsManager._mouseCursorId = 4; + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + if (_vm->_globals._characterType) { + if (!_vm->_globals._saveData->_data[svField122] && !_vm->_globals._saveData->_data[svField356]) { + _vm->_globals.PERSO = _vm->_fileManager.loadFile("PERSO.SPR"); + _vm->_globals._characterType = 0; + } + } + if (!_vm->_globals._characterType) { + if (_vm->_globals._saveData->_data[svField122] == 1) { + _vm->_globals.PERSO = _vm->_fileManager.loadFile("HOPFEM.SPR"); + _vm->_globals._characterType = 1; + } + } + if (_vm->_globals._characterType != 2 && _vm->_globals._saveData->_data[svField356] == 1) { + _vm->_globals.PERSO = _vm->_fileManager.loadFile("PSAMAN.SPR"); + _vm->_globals._characterType = 2; + } + _vm->_globals.loadCharacterData(); + switch (_vm->_globals._characterType) { + case 0: + addStaticSprite(_vm->_globals.PERSO, _characterPos, 0, _startSpriteIndex, 0, false, 34, 190); + break; + case 1: + addStaticSprite(_vm->_globals.PERSO, _characterPos, 0, _startSpriteIndex, 0, false, 28, 155); + break; + case 2: + addStaticSprite(_vm->_globals.PERSO, _characterPos, 0, _startSpriteIndex, 0, false, 20, 127); + break; + } + _vm->_eventsManager.setMouseXY(_characterPos); + if (_vm->_graphicsManager._largeScreenFl) + _vm->_graphicsManager._scrollPosX = (int16)getSpriteX(0) - 320; + computeAndSetSpriteSize(); + animateSprite(0); + _vm->_globals.enableHiding(); + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + computeAndSetSpriteSize(); + SPECIAL_INI(); + _vm->_eventsManager._mouseSpriteId = 4; + _oldCharacterPosX = _characterPos.x; + _oldCharacterPosY = _characterPos.y; + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + + for (int idx = 0; idx < 5; ++idx) + _vm->_eventsManager.VBL(); + + _vm->_globals.iRegul = 1; + if (!_vm->_graphicsManager._noFadingFl) + _vm->_graphicsManager.fadeInLong(); + _vm->_graphicsManager._noFadingFl = false; + _vm->_eventsManager.changeMouseCursor(4); + + int xCheck = 0; + int yCheck = 0; + + bool breakFlag = false; + while (!_vm->shouldQuit() && !breakFlag) { + int mouseButtons = _vm->_eventsManager.getMouseButton(); + if (mouseButtons) { + if (mouseButtons == 1) { + if (_verb == 16 && _vm->_eventsManager._mouseCursorId == 16) { + int xp = _vm->_eventsManager.getMouseX(); + int yp = _vm->_eventsManager.getMouseY(); + + if ((xCheck == xp) && (yCheck == yp)) { + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + PARADISE(); + if (_vm->_globals._exitId) + breakFlag = true; + } + xCheck = xp; + yCheck = yp; + } + handleLeftButton(); + } else if (mouseButtons == 2) { + handleRightButton(); + } + } + if (!_vm->_globals._exitId) { + _vm->_dialogsManager.testDialogOpening(); + _vm->_linesManager.checkZone(); + if (_vm->_linesManager._route == (RouteItem *)g_PTRNUL + || (GOHOME(), _vm->_linesManager._route == (RouteItem *)g_PTRNUL)) { + if (_vm->_globals._actionMoveTo) + PARADISE(); + } + handleSpecialGames(); + _vm->_eventsManager.VBL(); + if (!_vm->_globals._exitId) + continue; + } + breakFlag = true; + } + + if (_vm->_globals._exitId != 8 || _vm->_globals._screenId != 5 || !_helicopterFl) { + if (!_vm->_graphicsManager._noFadingFl) + _vm->_graphicsManager.fadeOutLong(); + _vm->_graphicsManager._noFadingFl = false; + removeSprite(0); + if (_twoCharactersFl) { + removeSprite(1); + _twoCharactersFl = false; + } + if (!animFile.empty()) + _vm->_graphicsManager.endDisplayBob(); + clearScreen(); + } else { + _helicopterFl = false; + } + _vm->_globals.iRegul = 0; +} + +void ObjectsManager::setVerb(int id) { + _verb = id; +} +} // End of namespace Hopkins diff --git a/engines/hopkins/objects.h b/engines/hopkins/objects.h new file mode 100644 index 0000000000..1c82ab0662 --- /dev/null +++ b/engines/hopkins/objects.h @@ -0,0 +1,246 @@ +/* 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 SpriteItem { + int _animationType; + const byte *_spriteData; + Common::Point _spritePos; + int _zoomFactor; + bool _flipFl; + int _spriteIndex; + int field12; + int field14; + bool _rleFl; + bool _activeFl; + int _destX; + int _destY; + int _width; + int _height; + int _zoomPct; + int _reducePct; +}; + +struct BobItem { + int field0; + byte *_spriteData; + int _xp; + int _yp; + int _frameIndex; + int _animDataIdx; + int field12; + int field14; + bool _disabledAnimationFl; + byte *_animData; + bool field1C; + int field1E; + int field20; + int field22; + bool field34; // 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; +}; + +class HopkinsEngine; + +class ObjectsManager { +private: + HopkinsEngine *_vm; + + int _oldBorderSpriteIndex; + int _borderSpriteIndex; + byte *_spritePtr; + const byte *_oldSpriteData; + int _verb; + int _oldSpriteIndex; + bool _oldFlipFl; + int _curGestureFile; + byte *_gestureBuf; + + 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 initBob(); + void setBobInfo(int idx); + void SCBOB(int idx); + void CALCUL_BOB(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 DEF_SPRITE(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(); + int getBobFrameIndex(int idx); + void handleForest(int screenId, int minX, int maxX, int minY, int maxY, int idx); + + void SPECIAL_INI(); + void ACTION(const byte *spriteData, const Common::String &actionStr, int a3, int a4, 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 _oldInventoryPosX, _oldInventoryPosY; + 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]; + + bool PERSO_ON; + bool BOBTOUS; + bool OBSSEUL; + + ObjectsManager(); + ~ObjectsManager(); + + void setParent(HopkinsEngine *vm); + 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); + void addStaticSprite(const byte *spriteData, Common::Point pos, int idx, int spriteIndex, int zoomFactor, bool flipFl, int a8, int a9); + 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 setBobAnimDataIdx(int idx, int animIdx); + void setBobAnimation(int idx); + void stopBobAnimation(int idx); + int getBobPosX(int idx); + int getBobPosY(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 PERSONAGE(const Common::String &backgroundFile, const Common::String &linkFile, + const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen); + void PERSONAGE2(const Common::String &backgroundFile, const Common::String &linkFile, + const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen); + byte *loadObjectFromFile(int objIndex, bool mode); + void OPTI_OBJET(); + void hideBob(int idx); + void displayBob(int idx); + void SPACTION(byte *spriteData, const Common::String &animationSeq, int a3, int a4, int speed, bool flipFl); + void BOB_VIVANT(int idx); + void VBOB(byte *src, int idx, int xp, int yp, int frameIndex); + void VBOB_OFF(int idx); + void OPTI_ONE(int idx, int animIdx, int destPosi, int animAction); + void SCI_OPTI_ONE(int idx, int animIdx, int a3, int a4); + void GOHOME(); + void OPTI_BOBON(int idx1, int idx2, int idx3, int anim1Idx, int anim2Idx, int anim3Idx); + void BOB_OFFSET(int idx, int offset); + void SPACTION1(byte *spriteData, const Common::String &animString, int a3, int a4, int speed); + 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..f934c4c018 --- /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 + +void SaveLoadManager::setParent(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->_eventsManager._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[svField10] = 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->_objectsManager._mapCarPosX; + _vm->_globals._saveData->_mapCarPosY = _vm->_objectsManager._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[svField10] = slot; + _vm->_globals._exitId = _vm->_globals._saveData->_data[svField5]; + _vm->_globals._saveData->_data[svField6] = 0; + _vm->_globals._screenId = 0; + _vm->_objectsManager._mapCarPosX = _vm->_globals._saveData->_mapCarPosX; + _vm->_objectsManager._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->_graphicsManager.zoomOut(SCREEN_WIDTH, REDUCE_AMOUNT); + int h = _vm->_graphicsManager.zoomOut(SCREEN_HEIGHT - 40, REDUCE_AMOUNT); + + Graphics::Surface thumb8; + thumb8.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + + _vm->_graphicsManager.Reduc_Ecran(_vm->_graphicsManager._vesaBuffer, (byte *)thumb8.pixels, + _vm->_eventsManager._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->_graphicsManager.PAL_PIXELS[*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_LE_UINT16(&_vm->_graphicsManager.PAL_PIXELS[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..2a7806e759 --- /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: + void setParent(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..09555bd236 --- /dev/null +++ b/engines/hopkins/script.cpp @@ -0,0 +1,2565 @@ +/* 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() { + _tempObjectFl = false; +} + +void ScriptManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +int ScriptManager::handleOpcode(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->_soundManager._soundOffFl && _vm->_soundManager._soundFl) { + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + _vm->_eventsManager.VBL(); + } while (_vm->_soundManager._soundFl); + } + bool displayedTxtFl = false; + if (!_vm->_soundManager._textOffFl) { + int textPosX = READ_LE_INT16(dataP + 9); + int textPosY = READ_LE_INT16(dataP + 11); + _vm->_fontManager.initTextBuffers(9, mesgId, _vm->_globals._textFilename, 2 * textPosX, 2 * textPosY + 40, 6, dataP[7], 253); + _vm->_fontManager.showText(9); + displayedTxtFl = true; + } + if (!_vm->_soundManager._voiceOffFl) + _vm->_soundManager.mixVoice(mesgId, 4, displayedTxtFl); + } else { // if (_tempObjectFl) + if (_vm->_globals._saveData->_data[svField356]) { + _vm->_fontManager.initTextBuffers(9, 635, _vm->_globals._textFilename, 55, 20, dataP[8], 35, 253); + bool displayedTxtFl = false; + if (!_vm->_soundManager._textOffFl) { + _vm->_fontManager.showText(9); + displayedTxtFl = true; + } + + if (!_vm->_soundManager._voiceOffFl) + _vm->_soundManager.mixVoice(635, 4, displayedTxtFl); + } else { + int textPosX = READ_LE_INT16(dataP + 9); + if (_vm->_globals._language == LANG_FR && !_vm->_soundManager._textOffFl) + _vm->_fontManager.initTextBuffers(9, mesgId, "OBJET1.TXT", 2 * textPosX, 60, 6, dataP[7], 253); + else if (_vm->_globals._language == LANG_EN && !_vm->_soundManager._textOffFl) + _vm->_fontManager.initTextBuffers(9, mesgId, "OBJETAN.TXT", 2 * textPosX, 60, 6, dataP[7], 253); + else if (_vm->_globals._language == LANG_SP && !_vm->_soundManager._textOffFl) { + _vm->_fontManager.initTextBuffers(9, mesgId, "OBJETES.TXT", 2 * textPosX, 60, 6, dataP[7], 253); + } + + bool displayedTxtFl = false; + if (!_vm->_soundManager._textOffFl) { + _vm->_fontManager.showText(9); + displayedTxtFl = true; + } + + if (!_vm->_soundManager._voiceOffFl) + _vm->_soundManager.mixVoice(mesgId, 5, displayedTxtFl); + } + } + break; + } + case MKTAG24('B', 'O', 'B'): + if (!_vm->_objectsManager._disableFl) { + int vbobIdx = dataP[5]; + vbobFrameIndex = dataP[6]; + int v4 = dataP[7]; + int vbobPosX = READ_LE_INT16(dataP + 8); + int vbobPosY = READ_LE_INT16(dataP + 10); + if (vbobIdx == 52) { + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, vbobPosX, READ_LE_INT16(dataP + 10), vbobFrameIndex); + } else if (vbobIdx == 51) { + _vm->_objectsManager.BOB_VIVANT(vbobFrameIndex); + } else if (vbobIdx != 50) { + _vm->_objectsManager.VBOB(_vm->_globals.SPRITE_ECRAN, vbobIdx, vbobPosX, vbobPosY, vbobFrameIndex); + if (v4) + v4 /= _vm->_globals._speed; + if (v4 > 1) { + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + --v4; + _vm->_eventsManager.VBL(); + } while (v4); + } + } + } + opcodeType = 1; + break; + case MKTAG24('S', 'T', 'P'): + if (!_vm->_objectsManager._disableFl) { + _vm->_objectsManager._twoCharactersFl = false; + _vm->_objectsManager._characterPos.x = READ_LE_INT16(dataP + 6); + _vm->_objectsManager._characterPos.y = READ_LE_INT16(dataP + 8); + _vm->_objectsManager._startSpriteIndex = dataP[5]; + if (_vm->_objectsManager._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->_objectsManager._characterPos = _vm->_globals._saveData->_cloneHopkins._pos; + _vm->_objectsManager._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->_objectsManager._characterPos = _vm->_globals._saveData->_samantha._pos; + _vm->_objectsManager._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->_objectsManager._characterPos = _vm->_globals._saveData->_realHopkins._pos; + _vm->_objectsManager._startSpriteIndex = _vm->_globals._saveData->_realHopkins._startSpriteIndex; + } + } + if (_vm->_globals._saveData->_data[svField356] == 1 + && _vm->_globals._saveData->_realHopkins._location == _vm->_globals._screenId) { + _vm->_objectsManager.addStaticSprite( + _vm->_objectsManager._headSprites, + _vm->_globals._saveData->_realHopkins._pos, + 1, + 2, + _vm->_globals._saveData->_realHopkins._zoomFactor, + false, + 34, + 190); + _vm->_objectsManager.animateSprite(1); + _vm->_objectsManager._twoCharactersFl = true; + } + if (_vm->_globals._saveData->_data[svField357] == 1 + && _vm->_globals._saveData->_data[svField355] == 1 + && _vm->_globals._saveData->_samantha._location == _vm->_globals._screenId) { + _vm->_objectsManager.addStaticSprite( + _vm->_objectsManager._headSprites, + _vm->_globals._saveData->_samantha._pos, + 1, + 3, + _vm->_globals._saveData->_samantha._zoomFactor, + false, + 20, + 127); + _vm->_objectsManager.animateSprite(1); + _vm->_objectsManager._twoCharactersFl = true; + } + } + opcodeType = 1; + _vm->_objectsManager._changeHeadFl = false; + break; + case MKTAG24('S', 'T', 'E'): + if (!_vm->_objectsManager._disableFl) { + _vm->_globals._prevScreenId = _vm->_globals._screenId; + _vm->_globals._saveData->_data[svField6] = _vm->_globals._screenId; + _vm->_globals._screenId = _vm->_globals._saveData->_data[svField5] = dataP[5]; + vbobFrameIndex = dataP[6]; + } + opcodeType = 1; + break; + case MKTAG24('B', 'O', 'F'): + if (!_vm->_objectsManager._disableFl) + _vm->_objectsManager.VBOB_OFF(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[svField122] && !_vm->_globals._saveData->_data[svField356]) { + vbobFrameIndex = 0; + + switch (specialOpcode) { + case 1: + case 14: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(4); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(4); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(4); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(4); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(4); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(4); + break; + case 2: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(7); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(7); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(7); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(7); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(7); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(7); + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(8); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(8); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(8); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(8); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(8); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(8); + break; + case 19: + case 4: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(1); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(1); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(1); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(1); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(1); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(1); + break; + case 5: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(5); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(5); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(5); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(5); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(5); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(5); + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(6); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(6); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(6); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(6); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(6); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(6); + break; + case 17: + case 7: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(2); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(2); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(2); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(2); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(2); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(2); + break; + case 18: + case 8: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(3); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(3); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(3); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(3); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(3); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(3); + break; + case 9: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(5); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(5); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(5); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(5); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(5); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(5); + break; + case 10: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(6); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(6); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(6); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(6); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(6); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(6); + break; + case 15: + case 11: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(7); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(7); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(7); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(7); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(7); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.doActionLeft(7); + break; + case 16: + case 12: + if (_vm->_globals._actionDirection == DIR_UP) + _vm->_objectsManager.doActionBack(8); + if (_vm->_globals._actionDirection == DIR_RIGHT) + _vm->_objectsManager.doActionRight(8); + if (_vm->_globals._actionDirection == DIR_UP_RIGHT) + _vm->_objectsManager.doActionDiagRight(8); + if (_vm->_globals._actionDirection == DIR_DOWN) + _vm->_objectsManager.doActionFront(8); + if (_vm->_globals._actionDirection == DIR_UP_LEFT) + _vm->_objectsManager.doActionDiagLeft(8); + if (_vm->_globals._actionDirection == DIR_LEFT) + _vm->_objectsManager.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->_eventsManager.VBL(); + } + opcodeType = 1; + break; + } + case MKTAG24('O', 'B', 'P'): + opcodeType = 1; + _vm->_objectsManager.addObject(READ_LE_INT16(dataP + 5)); + break; + case MKTAG24('O', 'B', 'M'): + opcodeType = 1; + _vm->_objectsManager.removeObject(READ_LE_INT16(dataP + 5)); + break; + case MKTAG24('G', 'O', 'T'): + opcodeType = 2; + break; + case MKTAG24('Z', 'O', 'N'): + _vm->_linesManager.enableZone(READ_LE_INT16(dataP + 5)); + opcodeType = 1; + break; + case MKTAG24('Z', 'O', 'F'): + _vm->_linesManager.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->_globals.B_CACHE_OFF(READ_LE_INT16(dataP + 5)); + opcodeType = 1; + break; + case MKTAG24('A', 'N', 'I'): { + int animId = READ_LE_INT16(dataP + 5); + if (animId <= 100) + _vm->_objectsManager.setBobAnimation(animId); + else + _vm->_objectsManager.stopBobAnimation(animId - 100); + opcodeType = 1; + break; + } + case MKTAG24('S', 'P', 'E'): + switch (READ_LE_INT16(dataP + 5)) { + case 6: + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.OPTI_ONE(20, 0, 14, 4); + break; + + case 7: + _vm->_talkManager.startAnimatedCharacterDialogue("rueh1.pe2"); + break; + + case 8: + _vm->_talkManager.startAnimatedCharacterDialogue("ruef1.pe2"); + break; + + case 10: + _vm->_talkManager.startAnimatedCharacterDialogue("bqeflic1.pe2"); + break; + + case 11: + _vm->_talkManager.startAnimatedCharacterDialogue("bqeflic2.pe2"); + break; + + case 12: + _vm->_fontManager.hideText(9); + _vm->_eventsManager.VBL(); + _vm->_eventsManager.VBL(); + _vm->_talkManager.startAnimatedCharacterDialogue("bqetueur.pe2"); + break; + + case 13: + _vm->_eventsManager._mouseButton = _vm->_eventsManager._curMouseButton; + _vm->_globals._disableInventFl = true; + _vm->_graphicsManager.fadeOutLong(); + _vm->_globals.disableHiding(); + _vm->_objectsManager.removeSprite(0); + _vm->_fontManager.hideText(5); + _vm->_fontManager.hideText(9); + _vm->_graphicsManager.endDisplayBob(); + _vm->_objectsManager.clearScreen(); + + if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo()) { + _vm->_graphicsManager.fadeOutLong(); + } else { + _vm->_soundManager.playSoundFile("SOUND17.WAV"); + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playSequence2("HELICO.SEQ", 10, 4, 10); + } + + _vm->_animationManager.loadAnim("otage"); + _vm->_graphicsManager.loadImage("IM05"); + _vm->_graphicsManager.displayAllBob(); + + for (int i = 0; i <= 4; i++) { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } + + _vm->_eventsManager.mouseOff(); + _vm->_graphicsManager.fadeInDefaultLength(_vm->_graphicsManager._vesaBuffer); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(3) != 100); + _vm->_graphicsManager.fadeOutDefaultLength(_vm->_graphicsManager._vesaBuffer); + _vm->_graphicsManager.endDisplayBob(); + + // If uncensored, rip the throat of the hostage + if (!_vm->_globals._censorshipFl) { + _vm->_soundManager._specialSoundNum = 16; + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playAnim("EGORGE.ANM", 50, 28, 500); + _vm->_soundManager._specialSoundNum = 0; + } + _vm->_animationManager.loadAnim("ASCEN"); + _vm->_eventsManager.mouseOff(); + _vm->_graphicsManager.loadImage("ASCEN"); + _vm->_graphicsManager.displayAllBob(); + + for (int i = 0; i <= 4; i++) { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } + + _vm->_eventsManager.mouseOff(); + _vm->_graphicsManager.fadeInDefaultLength(_vm->_graphicsManager._vesaBuffer); + _vm->_objectsManager.SCI_OPTI_ONE(1, 0, 17, 3); + _vm->_graphicsManager.fadeOutDefaultLength(_vm->_graphicsManager._vesaBuffer); + _vm->_graphicsManager.endDisplayBob(); + + if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo()) + _vm->_soundManager.playSoundFile("SOUND17.WAV"); + + _vm->_soundManager._specialSoundNum = 14; + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playSequence2("ASSOM.SEQ", 10, 4, 500); + _vm->_soundManager._specialSoundNum = 0; + + if ((_vm->getPlatform() == Common::kPlatformWindows) && _vm->getIsDemo()) + _vm->_graphicsManager.fadeOutLong(); + + _vm->_globals._disableInventFl = false; + _vm->_objectsManager._helicopterFl = true; + break; + + case 16: + _vm->_talkManager.startAnimatedCharacterDialogue("ftoubib.pe2"); + break; + + case 17: + _vm->_talkManager.startAnimatedCharacterDialogue("flic2b.pe2"); + break; + + case 18: + _vm->_talkManager.startAnimatedCharacterDialogue("fjour.pe2"); + break; + + case 20: + _vm->_talkManager.startAnimatedCharacterDialogue("PUNK.pe2"); + break; + + case 21: + _vm->_talkManager.startAnimatedCharacterDialogue("MEDLEG.pe2"); + break; + + case 22: + _vm->_talkManager.animateObject("CADAVRE1.pe2"); + break; + + case 23: + _vm->_talkManager.startStaticCharacterDialogue("CHERCHE1.pe2"); + break; + + case 25: + _vm->_talkManager.startAnimatedCharacterDialogue("AGENT1.pe2"); + break; + + case 26: + _vm->_talkManager.startAnimatedCharacterDialogue("AGENT2.pe2"); + break; + + case 27: + if (_vm->_globals._saveData->_data[svField94] != 1 || _vm->_globals._saveData->_data[svField95] != 1) + _vm->_talkManager.startAnimatedCharacterDialogue("STANDAR.pe2"); + else + _vm->_talkManager.startAnimatedCharacterDialogue("STANDAR1.pe2"); + break; + + case 29: + _vm->_globals._disableInventFl = true; + _vm->_talkManager.animateObject("TELEP.pe2"); + _vm->_globals._disableInventFl = false; + break; + + case 32: + _vm->_talkManager.startAnimatedCharacterDialogue("SAMAN.pe2"); + break; + + case 35: + if (!_vm->_soundManager._soundOffFl) { + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_soundManager._soundFl); + } + _vm->_talkManager.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; + if (!_vm->_globals._saveData->_data[svField270]) + _vm->_talkManager.startStaticCharacterDialogue("PATRON0.pe2"); + if (_vm->_globals._saveData->_data[svField270] == 1) + _vm->_talkManager.startStaticCharacterDialogue("PATRON1.pe2"); + if (_vm->_globals._saveData->_data[svField270] == 2) + _vm->_talkManager.startStaticCharacterDialogue("PATRON2.pe2"); + if (_vm->_globals._saveData->_data[svField270] == 3) + _vm->_talkManager.startStaticCharacterDialogue("PATRON3.pe2"); + if (_vm->_globals._saveData->_data[svField270] > 3) { + _vm->_talkManager.startStaticCharacterDialogue("PATRON4.pe2"); + _vm->_globals._saveData->_data[svField270] = 5; + } + break; + + case 37: + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playSequence2("corde.SEQ", 32, 32, 100); + _vm->_graphicsManager._noFadingFl = true; + break; + + case 38: + _vm->_soundManager.loadSample(1, "SOUND44.WAV"); + _vm->_soundManager.loadSample(2, "SOUND42.WAV"); + _vm->_soundManager.loadSample(3, "SOUND41.WAV"); + _vm->_soundManager._specialSoundNum = 17; + _vm->_animationManager.playSequence("grenade.SEQ", 1, 32, 100); + _vm->_soundManager._specialSoundNum = 0; + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playAnim("CREVE17.ANM", 24, 24, 200); + _vm->_soundManager.removeSample(1); + _vm->_soundManager.removeSample(2); + _vm->_soundManager.removeSample(3); + _vm->_graphicsManager._noFadingFl = true; + break; + + case 40: + _vm->_talkManager.startAnimatedCharacterDialogue("MAGE.pe2"); + break; + + case 41: + _vm->_talkManager.startAnimatedCharacterDialogue("MORT3.pe2"); + break; + + case 42: + _vm->_talkManager.startAnimatedCharacterDialogue("MORT2.pe2"); + break; + + case 43: + _vm->_talkManager.startAnimatedCharacterDialogue("MORT1.pe2"); + break; + + case 44: + _vm->_talkManager.startAnimatedCharacterDialogue("MORT3A.pe2"); + break; + + case 45: + _vm->_talkManager.startAnimatedCharacterDialogue("FEM3.pe2"); + break; + + case 46: { + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 564, 420); + _vm->_objectsManager._zoneNum = -1; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.removeSprite(0); + _vm->_globals._checkDistanceFl = true; + _vm->_soundManager.loadSample(1, "SOUND44.WAV"); + _vm->_soundManager.loadSample(2, "SOUND45.WAV"); + _vm->_objectsManager.OPTI_BOBON(9, 10, -1, 0, 0, 0); + bool v15 = false; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 4 && !v15) { + _vm->_soundManager.playSample(1); + v15 = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 5) + v15 = false; + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 16 && !v15) { + _vm->_soundManager.playSample(1); + v15 = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 17) + v15 = false; + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 28 && !v15) { + _vm->_soundManager.playSample(1); + v15 = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 29) + v15 = false; + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 10 && !v15) { + _vm->_soundManager.playSample(2); + v15 = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 11) + v15 = false; + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 22 && !v15) { + _vm->_soundManager.playSample(2); + v15 = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 23) + v15 = false; + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 33 && !v15) { + _vm->_soundManager.playSample(2); + v15 = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 34) + v15 = false; + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 12) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 249, 1); + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 23) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 249, 2); + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 34) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 249, 3); + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(9) != 36); + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.stopBobAnimation(9); + _vm->_objectsManager.stopBobAnimation(10); + _vm->_soundManager.removeSample(1); + _vm->_soundManager.removeSample(2); + break; + } + + case 47: + _vm->_talkManager.startAnimatedCharacterDialogue("BARMAN.pe2"); + break; + + case 48: + _vm->_talkManager.startAnimatedCharacterDialogue("SAMAN2.pe2"); + break; + + case 49: { + _vm->_globals.disableHiding(); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.OPTI_BOBON(9, 10, -1, 0, 0, 0); + int v19 = 12; + if (_vm->_globals._saveData->_data[svField133] == 1) + v19 = 41; + int v20 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 4 && !v20) { + _vm->_soundManager.directPlayWav("SOUND44.WAV"); + v20 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 5) + v20 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 18 && !v20) { + _vm->_soundManager.directPlayWav("SOUND46.WAV"); + v20 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(9) == 19) + v20 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 11 && !v20) { + _vm->_soundManager.directPlayWav("SOUND45.WAV"); + v20 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(10) == 12) + v20 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(9) != v19); + if (v19 == 12) { + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.stopBobAnimation(9); + } + _vm->_globals.enableHiding(); + break; + } + + case 50: + _vm->_soundManager.playSoundFile("SOUND46.WAv"); + _vm->_objectsManager.OPTI_ONE(11, 0, 23, 0); + break; + + case 51: { + _vm->_graphicsManager.fadeOutLong(); + _vm->_globals.disableHiding(); + _vm->_objectsManager.removeSprite(0); + _vm->_fontManager.hideText(5); + _vm->_fontManager.hideText(9); + _vm->_graphicsManager.endDisplayBob(); + _vm->_graphicsManager.loadImage("IM20f"); + _vm->_animationManager.loadAnim("ANIM20f"); + _vm->_graphicsManager.displayAllBob(); + _vm->_eventsManager.mouseOff(); + _vm->_graphicsManager.fadeInLong(); + bool v52 = false; + _vm->_soundManager.loadWav("SOUND46.WAV", 1); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(12) == 5 && !v52) { + _vm->_soundManager.playWav(1); + v52 = true; + } + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(12) != 34); + _vm->_objectsManager.stopBobAnimation(2); + _vm->_graphicsManager.fadeOutLong(); + _vm->_graphicsManager._noFadingFl = true; + _vm->_globals._exitId = 20; + break; + } + + case 52: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("GARDE.PE2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 53: + _vm->_talkManager.startAnimatedCharacterDialogue("GARDE1.pe2"); + break; + + case 54: + _vm->_talkManager.startAnimatedCharacterDialogue("GARDE2.pe2"); + break; + + case 55: + _vm->_objectsManager.stopBobAnimation(1); + _vm->_objectsManager.OPTI_ONE(15, 0, 12, 0); + _vm->_objectsManager.stopBobAnimation(15); + _vm->_objectsManager.OBSSEUL = true; + _vm->_objectsManager.loadLinkFile("IM19a"); + _vm->_objectsManager.OBSSEUL = false; + break; + + case 56: + _vm->_globals.PERSO = _vm->_fileManager.loadFile("HOPFEM.SPR"); + _vm->_globals._characterType = 1; + _vm->_globals._saveData->_data[svField122] = 1; + _vm->_globals.loadCharacterData(); + _vm->_objectsManager._sprite[0].field12 = 28; + _vm->_objectsManager._sprite[0].field14 = 155; + _vm->_objectsManager.computeAndSetSpriteSize(); + break; + + case 57: + _vm->_globals.PERSO = _vm->_fileManager.loadFile("PERSO.SPR"); + _vm->_globals._characterType = 0; + _vm->_globals._saveData->_data[svField122] = 0; + _vm->_globals.loadCharacterData(); + _vm->_objectsManager._sprite[0].field12 = 34; + _vm->_objectsManager._sprite[0].field14 = 190; + _vm->_objectsManager.computeAndSetSpriteSize(); + break; + + case 58: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.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->_objectsManager._oldCharacterPosX = _vm->_objectsManager.getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 445, 332); + _vm->_globals._checkDistanceFl = true; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(7); + _vm->_objectsManager.setBobAnimDataIdx(7, 0); + int v18 = 0; + _vm->_soundManager.loadSample(1, "SOUND40.WAV"); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(7) == 10 && !v18) { + _vm->_soundManager.playSample(1); + v18 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(7) == 11) + v18 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(7) == 18 && !v18) { + _vm->_soundManager.playSample(1); + v18 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(7) == 19) + v18 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(7) == 19) + _vm->_objectsManager.setBobAnimation(3); + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(3) != 48); + _vm->_soundManager.removeSample(1); + _vm->_objectsManager.setSpriteIndex(0, 62); + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.setBobAnimation(6); + _vm->_objectsManager.stopBobAnimation(7); + _vm->_objectsManager.stopBobAnimation(3); + break; + } + + case 62: + _vm->_talkManager.animateObject("SBCADA.pe2"); + break; + + case 65: + _vm->_talkManager.animateObject("ScCADA.pe2"); + break; + + case 80: { + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(12); + _vm->_objectsManager.setBobAnimation(13); + _vm->_objectsManager.setBobAnimDataIdx(12, 0); + _vm->_objectsManager.setBobAnimDataIdx(13, 0); + int v21 = 0; + _vm->_soundManager.loadWav("SOUND44.WAV", 1); + _vm->_soundManager.loadWav("SOUND71.WAV", 2); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(12) == 4 && !v21) { + _vm->_soundManager.playWav(1); + v21 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(12) == 5) + v21 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 5 && !v21) { + _vm->_soundManager.playWav(2); + v21 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 6) + v21 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(13) == 8) { + _vm->_objectsManager.stopBobAnimation(13); + _vm->_objectsManager.stopBobAnimation(3); + _vm->_objectsManager.setBobAnimation(4); + _vm->_objectsManager.setBobAnimDataIdx(4, 0); + _vm->_objectsManager.setBobAnimDataIdx(13, 0); + } + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 16); + _vm->_objectsManager.stopBobAnimation(12); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.OBSSEUL = true; + _vm->_objectsManager.loadLinkFile("IM27a"); + _vm->_objectsManager.OBSSEUL = false; + break; + } + + case 81: { + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._oldCharacterPosX = _vm->_objectsManager.getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 119, 268); + _vm->_globals._checkDistanceFl = true; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(11); + _vm->_objectsManager.setBobAnimation(8); + _vm->_objectsManager.setBobAnimDataIdx(11, 0); + _vm->_objectsManager.setBobAnimDataIdx(8, 0); + _vm->_soundManager.loadWav("SOUND44.WAV", 1); + _vm->_soundManager.loadWav("SOUND48.WAV", 2); + _vm->_soundManager.loadWav("SOUND49.WAV", 3); + int v24 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(11) == 4 && !v24) { + _vm->_soundManager.playWav(1); + v24 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(11) == 5) + v24 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(8) == 11 && !v24) { + _vm->_soundManager.playWav(2); + v24 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(8) == 12) + v24 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(8) != 32); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 201, 14, 1); + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.stopBobAnimation(11); + _vm->_objectsManager.stopBobAnimation(8); + _vm->_objectsManager.setBobAnimation(5); + _vm->_objectsManager.setBobAnimation(6); + _vm->_objectsManager.setBobAnimDataIdx(5, 0); + _vm->_objectsManager.setBobAnimDataIdx(6, 0); + _vm->_soundManager.playWav(3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 74); + _vm->_objectsManager.stopBobAnimation(5); + _vm->_objectsManager.stopBobAnimation(6); + _vm->_objectsManager.setBobAnimation(9); + _vm->_objectsManager.setBobAnimation(7); + break; + } + + case 83: + _vm->_talkManager.startAnimatedCharacterDialogue("CVIGIL.pe2"); + break; + + case 84: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("CVIGIL1.PE2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 85: + _vm->_objectsManager.stopBobAnimation(3); + _vm->_objectsManager.setBobAnimation(5); + _vm->_objectsManager.setBobAnimDataIdx(5, 0); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 6); + _vm->_objectsManager.stopBobAnimation(5); + _vm->_objectsManager.setBobAnimation(6); + _vm->_objectsManager.OBSSEUL = true; + _vm->_objectsManager.loadLinkFile("IM24a"); + _vm->_objectsManager.OBSSEUL = false; + break; + + case 86: + if (_vm->_globals._saveData->_data[svField231] == 1) { + _vm->_talkManager.startAnimatedCharacterDialogue("chotess1.pe2"); + } else { + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("chotesse.pe2"); + _vm->_globals._introSpeechOffFl = false; + } + break; + + case 87: + if (_vm->_globals._saveData->_data[svField188]) + _vm->_talkManager.startAnimatedCharacterDialogue("stand2.pe2"); + else + _vm->_talkManager.startAnimatedCharacterDialogue("stand1.pe2"); + break; + + case 88: + if (_vm->_globals._saveData->_data[svField183] == 1) { + _vm->_objectsManager.setBobAnimDataIdx(1, 0); + _vm->_objectsManager.setBobAnimDataIdx(2, 0); + _vm->_objectsManager.setBobAnimation(1); + _vm->_objectsManager.setBobAnimation(2); + _vm->_soundManager.loadSample(1, "SOUND40.WAV"); + int v25 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 1 && !v25) { + _vm->_soundManager.playSample(1); + v25 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 2) + v25 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 3 && !v25) { + _vm->_soundManager.playSample(1); + v25 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 4) + v25 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 5 && !v25) { + _vm->_soundManager.playSample(1); + v25 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 6) + v25 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 7 && !v25) { + _vm->_soundManager.playSample(1); + v25 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 8) + v25 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(1) != 9); + _vm->_objectsManager.stopBobAnimation(1); + _vm->_objectsManager.stopBobAnimation(2); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 283, 160, 6); + _vm->_soundManager.removeSample(1); + } + if (_vm->_globals._saveData->_data[svField183] == 2) { + _vm->_objectsManager.setBobAnimDataIdx(1, 0); + _vm->_objectsManager.setBobAnimDataIdx(3, 0); + _vm->_objectsManager.setBobAnimation(1); + _vm->_objectsManager.setBobAnimation(3); + _vm->_soundManager.loadSample(1, "SOUND40.WAV"); + int v26 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 1 && !v26) { + _vm->_soundManager.playSample(1); + v26 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 2) + v26 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 3 && !v26) { + _vm->_soundManager.playSample(1); + v26 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 4) + v26 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 5 && !v26) { + _vm->_soundManager.playSample(1); + v26 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 6) + v26 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 7 && !v26) { + _vm->_soundManager.playSample(1); + v26 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 8) + v26 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(1) != 9); + _vm->_objectsManager.stopBobAnimation(1); + _vm->_objectsManager.stopBobAnimation(3); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 283, 161, 8); + _vm->_soundManager.removeSample(1); + } + break; + + case 90: + _vm->_soundManager.playSoundFile("SOUND52.WAV"); + if (!_vm->_globals._saveData->_data[svField186]) { + _vm->_animationManager.playSequence("CIB5A.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 0); + } + if (_vm->_globals._saveData->_data[svField186] == 1) { + _vm->_animationManager.playSequence("CIB5C.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 0); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 329, 87, 2); + } + break; + + case 91: + _vm->_soundManager.playSoundFile("SOUND52.WAV"); + if (!_vm->_globals._saveData->_data[svField186]) { + _vm->_animationManager.playSequence("CIB5B.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 5); + } + if (_vm->_globals._saveData->_data[svField186] == 1) { + _vm->_animationManager.playSequence("CIB5D.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 5); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 283, 160, 6); + } + break; + + case 92: + _vm->_soundManager.playSoundFile("SOUND52.WAV"); + if (!_vm->_globals._saveData->_data[svField184]) { + _vm->_animationManager.playSequence("CIB6A.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 0); + } + if (_vm->_globals._saveData->_data[svField184] == 1) { + _vm->_animationManager.playSequence("CIB6C.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 0); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 293, 139, 3); + } + break; + + case 93: + _vm->_soundManager.playSoundFile("SOUND52.WAV"); + if (!_vm->_globals._saveData->_data[svField184]) { + _vm->_animationManager.playSequence("CIB6B.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 5); + } + if (_vm->_globals._saveData->_data[svField184] == 1) { + _vm->_animationManager.playSequence("CIB6D.SEQ", 1, 12, 1); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 155, 29, 5); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 283, 161, 8); + } + break; + + case 94: + if (!_vm->_globals._saveData->_data[svField228]) + _vm->_talkManager.startAnimatedCharacterDialogue("flicn.pe2"); + if (_vm->_globals._saveData->_data[svField228] == 1) + _vm->_talkManager.startAnimatedCharacterDialogue("flicn1.pe2"); + break; + + case 95: + _vm->_objectsManager.setBobAnimation(9); + _vm->_objectsManager.setBobAnimation(10); + _vm->_objectsManager.setBobAnimation(12); + _vm->_objectsManager.setBobAnimDataIdx(9, 0); + _vm->_objectsManager.setBobAnimDataIdx(10, 0); + _vm->_objectsManager.setBobAnimDataIdx(12, 0); + _vm->_objectsManager.removeSprite(0); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(9) != 15); + _vm->_objectsManager.stopBobAnimation(9); + _vm->_objectsManager.animateSprite(0); + _vm->_soundManager.playSoundFile("SOUND50.WAV"); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(12) != 117); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 830, 122, 0); + _vm->_objectsManager.stopBobAnimation(12); + _vm->_objectsManager.stopBobAnimation(10); + _vm->_objectsManager.setBobAnimation(11); + break; + + case 98: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("CVIGIL2.PE2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 100: + _vm->_talkManager.startAnimatedCharacterDialogue("tourist.pe2"); + break; + + case 101: + _vm->_talkManager.startAnimatedCharacterDialogue("tahi1.pe2"); + break; + + case 103: + // Dice game + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("tourist1.pe2"); + _vm->_globals._introSpeechOffFl = false; + _vm->_animationManager.playAnim2("T421.ANM", 100, 14, 500); + _vm->_eventsManager.VBL(); + _vm->_eventsManager.VBL(); + _vm->_eventsManager.VBL(); + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("tourist2.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 104: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("tourist3.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 105: + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._oldCharacterPosX = _vm->_objectsManager.getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + if (_vm->_globals._saveData->_data[svField253] == 1) { + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 201, 294); + } + if (_vm->_globals._saveData->_data[svField253] == 2) { + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 158, 338); + } + if (_vm->_globals._saveData->_data[svField253] > 2) { + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 211, 393); + } + _vm->_globals._checkDistanceFl = true; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setSpriteIndex(0, 60); + _vm->_soundManager.loadSample(1, "SOUND63.WAV"); + if (_vm->_globals._saveData->_data[svField253] > 2) { + _vm->_objectsManager.setBobAnimation(4); + int v33 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 9 && !v33) { + _vm->_soundManager.playSample(1); + v33 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 10) + v33 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 32 && !v33) { + _vm->_soundManager.playSample(1); + v33 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 33) + v33 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 55 && !v33) { + _vm->_soundManager.playSample(1); + v33 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 56) + v33 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 72); + _vm->_objectsManager.stopBobAnimation(4); + } + if (_vm->_globals._saveData->_data[svField253] == 1) { + _vm->_objectsManager.setBobAnimation(6); + int v34 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(6) == 9 && !v34) { + _vm->_soundManager.playSample(1); + v34 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(6) == 10) + v34 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(6) == 32 && !v34) { + _vm->_soundManager.playSample(1); + v34 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(6) == 33) + v34 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(6) == 55 && !v34) { + _vm->_soundManager.playSample(1); + v34 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(6) == 56) + v34 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(6) != 72); + _vm->_objectsManager.stopBobAnimation(6); + } + if (_vm->_globals._saveData->_data[svField253] == 2) { + _vm->_objectsManager.setBobAnimation(5); + int v35 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(5) == 9 && !v35) { + _vm->_soundManager.playSample(1); + v35 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(5) == 10) + v35 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(5) == 32 && !v35) { + _vm->_soundManager.playSample(1); + v35 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(5) == 33) + v35 = 0; + if (_vm->_objectsManager.getBobAnimDataIdx(5) == 55 && !v35) { + _vm->_soundManager.playSample(1); + v35 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(5) == 56) + v35 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 72); + _vm->_objectsManager.stopBobAnimation(5); + } + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.doActionBack(1); + _vm->_soundManager.removeSample(1); + break; + + case 106: + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(4); + _vm->_objectsManager.setBobAnimDataIdx(4, 0); + _vm->_soundManager.loadWav("SOUND61.WAV", 1); + _vm->_soundManager.loadWav("SOUND62.WAV", 2); + _vm->_soundManager.loadWav("SOUND61.WAV", 3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 10); + _vm->_soundManager.playWav(1); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 18); + _vm->_soundManager.playWav(2); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 62); + _vm->_soundManager.playWav(3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 77); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.animateSprite(0); + break; + + case 107: + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(5); + _vm->_objectsManager.setBobAnimDataIdx(5, 0); + _vm->_soundManager.loadWav("SOUND61.WAV", 1); + _vm->_soundManager.loadWav("SOUND62.WAV", 2); + _vm->_soundManager.loadWav("SOUND61.WAV", 3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 10); + _vm->_soundManager.playWav(1); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 18); + _vm->_soundManager.playWav(2); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 38); + _vm->_soundManager.playWav(3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(5) != 53); + _vm->_objectsManager.stopBobAnimation(5); + _vm->_objectsManager.animateSprite(0); + break; + + case 108: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("peche1.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 109: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("peche2.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 110: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("peche3.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 111: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("peche4.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 112: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("teint1.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 113: + _vm->_talkManager.startAnimatedCharacterDialogue("teint.pe2"); + break; + + case 114: + _vm->_talkManager.startAnimatedCharacterDialogue("tahibar.pe2"); + break; + + case 115: + _vm->_talkManager.startAnimatedCharacterDialogue("ilebar.pe2"); + break; + + case 116: + _vm->_talkManager.startAnimatedCharacterDialogue("Profred.pe2"); + break; + + case 170: + _vm->_talkManager.startAnimatedCharacterDialogue("GRED.pe2"); + break; + + case 171: { + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("gred1.pe2"); + _vm->_globals._introSpeechOffFl = false; + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._oldCharacterPosX = _vm->_objectsManager.getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 361, 325); + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._zoneNum = -1; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_globals._exitId = 59; + break; + } + + case 172: + _vm->_talkManager.startAnimatedCharacterDialogue("GBLEU.pe2"); + break; + + case 173: { + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("gbleu1.pe2"); + _vm->_globals._introSpeechOffFl = false; + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._oldCharacterPosX = _vm->_objectsManager.getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 361, 325); + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._zoneNum = -1; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_globals._exitId = 59; + break; + } + + case 174: + _vm->_talkManager.startAnimatedCharacterDialogue("Profbl.pe2"); + break; + + case 175: + _vm->_objectsManager.setSpriteIndex(0, 55); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(9); + _vm->_objectsManager.setBobAnimation(10); + _vm->_objectsManager.BOB_OFFSET(10, 300); + _vm->_soundManager.playSoundFile("SOUND44.WAV"); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(10) != 7); + _vm->_objectsManager.setBobAnimation(6); + _vm->_objectsManager.stopBobAnimation(3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(6) != 10); + _vm->_soundManager.playSoundFile("SOUND71.WAV"); + _vm->_objectsManager.setBobAnimation(7); + _vm->_objectsManager.stopBobAnimation(4); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(7) != 15); + _vm->_objectsManager.stopBobAnimation(5); + _vm->_objectsManager.setBobAnimation(8); + _vm->_soundManager.playSoundFile("SOUND70.WAV"); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(8) != 76); + _vm->_objectsManager.stopBobAnimation(6); + _vm->_objectsManager.stopBobAnimation(7); + _vm->_objectsManager.stopBobAnimation(8); + _vm->_objectsManager.stopBobAnimation(9); + _vm->_objectsManager.stopBobAnimation(10); + _vm->_objectsManager.animateSprite(0); + break; + + case 176: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("gred2.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 177: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("gbleu2.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 200: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("Gm2.PE2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 201: + _vm->_objectsManager.setBobAnimation(3); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(3) != 18); + _vm->_objectsManager.stopBobAnimation(3); + _vm->_objectsManager.setBobAnimation(4); + break; + + case 202: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("SVGARD2.PE2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 203: + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(4); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 18) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 18, 334, 0, false); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 26); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.animateSprite(0); + break; + + case 204: { + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(3); + _vm->_soundManager.loadWav("SOUND67.WAV", 1); + int v41 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(3) == 10 && !v41) { + _vm->_soundManager.playWav(1); + v41 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(3) == 11) + v41 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(3) != 50); + _vm->_objectsManager.stopBobAnimation(3); + _vm->_objectsManager.animateSprite(0); + break; + } + + case 205: { + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(4); + _vm->_soundManager.loadWav("SOUND69.WAV", 1); + int v42 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 10 && !v42) { + _vm->_soundManager.playWav(1); + v42 = 1; + } + if (_vm->_objectsManager.getBobAnimDataIdx(4) == 11) + v42 = 0; + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(4) != 24); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.animateSprite(0); + break; + } + + case 207: + _vm->_talkManager.animateObject("PANNEAU.PE2"); + break; + + case 208: { + _vm->_globals._disableInventFl = true; + if (_vm->_globals._saveData->_data[svField6] != _vm->_globals._saveData->_data[svField401]) { + _vm->_soundManager._specialSoundNum = 208; + _vm->_animationManager.playSequence("SORT.SEQ", 10, 4, 10, true); + _vm->_soundManager._specialSoundNum = 0; + } + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 330, 418); + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._zoneNum = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.setSpriteIndex(0, 64); + _vm->_globals._exitId = _vm->_globals._saveData->_data[svField401]; + _vm->_globals._disableInventFl = false; + break; + } + + case 209: { + _vm->_objectsManager.setBobAnimDataIdx(1, 0); + _vm->_objectsManager.setBobAnimDataIdx(2, 0); + _vm->_objectsManager.setSpriteIndex(0, 60); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.setBobAnimation(1); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(1) != 9); + _vm->_objectsManager.stopBobAnimation(1); + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 330, 314); + _vm->_objectsManager._zoneNum = 0; + _vm->_globals._checkDistanceFl = true; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.setSpriteIndex(0, 64); + _vm->_objectsManager.setBobAnimation(2); + _vm->_soundManager.playSoundFile("SOUND66.WAV"); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(2) != 10); + _vm->_objectsManager.stopBobAnimation(2); + _vm->_objectsManager.setBobAnimation(4); + break; + } + + case 210: + _vm->_animationManager.NO_SEQ = true; + _vm->_soundManager._specialSoundNum = 210; + _vm->_animationManager.playSequence2("SECRET1.SEQ", 1, 12, 1); + _vm->_soundManager._specialSoundNum = 0; + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 192, 152, 0); + _vm->_objectsManager.setBobAnimation(9); + _vm->_objectsManager.OBSSEUL = true; + _vm->_objectsManager.loadLinkFile("IM73a"); + _vm->_objectsManager.OBSSEUL = false; + _vm->_globals.enableHiding(); + _vm->_animationManager.NO_SEQ = false; + _vm->_globals.setHidingUseCount(0); + _vm->_globals.setHidingUseCount(1); + _vm->_graphicsManager.SETCOLOR4(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR4(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR4(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR4(254, 0, 0, 0); + break; + + case 211: + _vm->_objectsManager.removeSprite(0); + _vm->_globals.disableHiding(); + _vm->_animationManager.NO_SEQ = true; + _vm->_soundManager._specialSoundNum = 211; + _vm->_animationManager.playSequence("SECRET2.SEQ", 1, 12, 100); + _vm->_soundManager._specialSoundNum = 0; + _vm->_animationManager.NO_SEQ = false; + _vm->_graphicsManager._noFadingFl = true; + _vm->_graphicsManager.fadeOutLong(); + + for (int i = 1; i <= 39; i++) { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } + + _vm->_graphicsManager.SETCOLOR4(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR4(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR4(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR4(254, 0, 0, 0); + break; + + case 215: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("aviat.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 216: + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("aviat1.pe2"); + _vm->_globals._introSpeechOffFl = false; + break; + + case 229: + _vm->_soundManager._specialSoundNum = 229; + _vm->_animationManager.playSequence("MUR.SEQ", 1, 12, 1); + _vm->_soundManager._specialSoundNum = 0; + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 340, 157, 2); + break; + + case 230: { + _vm->_objectsManager.OBSSEUL = true; + _vm->_objectsManager.loadLinkFile("IM93a"); + _vm->_objectsManager.OBSSEUL = false; + _vm->_globals.enableHiding(); + _vm->_globals._checkDistanceFl = true; + _vm->_objectsManager._oldCharacterPosX = _vm->_objectsManager.getSpriteX(0); + _vm->_globals._oldDirection = DIR_NONE; + _vm->_globals.Compteur = 0; + _vm->_globals._checkDistanceFl = true; + _vm->_linesManager._route = (RouteItem *)g_PTRNUL; + _vm->_linesManager._route = _vm->_linesManager.PARCOURS2(_vm->_objectsManager.getSpriteX(0), _vm->_objectsManager.getSpriteY(0), 488, 280); + _vm->_globals._checkDistanceFl = true; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_objectsManager.GOHOME(); + _vm->_eventsManager.VBL(); + } while (_vm->_linesManager._route != (RouteItem *)g_PTRNUL); + _vm->_objectsManager.removeSprite(0); + int v45 = 0; + _vm->_objectsManager.setBobAnimation(7); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + if (_vm->_objectsManager.getBobAnimDataIdx(7) == 9 && !v45) { + v45 = 1; + _vm->_soundManager.playSoundFile("SOUND81.WAV"); + } + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(7) != 15); + _vm->_objectsManager.stopBobAnimation(7); + _vm->_objectsManager.setSpriteX(0, 476); + _vm->_objectsManager.setSpriteY(0, 278); + _vm->_objectsManager.animateSprite(0); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 337, 154, 3); + _vm->_objectsManager.OBSSEUL = true; + _vm->_objectsManager.loadLinkFile("IM93c"); + _vm->_objectsManager.OBSSEUL = false; + _vm->_globals.enableHiding(); + break; + } + + case 231: + _vm->_globals.disableHiding(); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(12); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(12) != 6); + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("PRMORT.pe2"); + _vm->_globals._introSpeechOffFl = false; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(12) != 12); + _vm->_objectsManager.animateSprite(0); + _vm->_objectsManager.stopBobAnimation(12); + _vm->_globals.enableHiding(); + break; + + case 233: { + _vm->_globals.disableHiding(); + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.setBobAnimation(11); + int v46 = 0; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + if (_vm->_objectsManager.getBobAnimDataIdx(11) == 10 && !v46) + v46 = 1; + } while (_vm->_objectsManager.getBobAnimDataIdx(11) != 13); + _vm->_objectsManager.stopBobAnimation(11); + _vm->_globals.enableHiding(); + _vm->_objectsManager.setBobAnimation(13); + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } while (_vm->_objectsManager.getBobAnimDataIdx(13) != 48); + _vm->_globals._introSpeechOffFl = true; + _vm->_talkManager.startAnimatedCharacterDialogue("HRADIO.PE2"); + _vm->_globals._introSpeechOffFl = false; + _vm->_graphicsManager.fadeOutLong(); + _vm->_objectsManager.stopBobAnimation(13); + _vm->_graphicsManager._noFadingFl = true; + _vm->_globals._exitId = 94; + break; + } + + case 236: { + char v47 = _vm->_globals._saveData->_data[svField341]; + if (v47) { + if (v47 == 2) + vbobFrameIndex = 5; + else if (v47 == 3) + vbobFrameIndex = 4; + else if (v47 == 1) + vbobFrameIndex = 6; + _vm->_soundManager.playSoundFile("SOUND83.WAV"); + _vm->_objectsManager.OPTI_ONE(vbobFrameIndex, 26, 50, 0); + if (_vm->_globals._saveData->_data[svField341] == 1) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 27, 117, 0); + if (_vm->_globals._saveData->_data[svField341] == 2) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 145, 166, 2); + if (_vm->_globals._saveData->_data[svField341] == 3) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 296, 212, 4); + if (_vm->_globals._saveData->_data[svField341] == 1) + _vm->_globals._saveData->_data[svField338] = 0; + if (_vm->_globals._saveData->_data[svField341] == 2) + _vm->_globals._saveData->_data[svField339] = 0; + if (_vm->_globals._saveData->_data[svField341] == 3) + _vm->_globals._saveData->_data[svField340] = 0; + } + _vm->_soundManager.playSoundFile("SOUND83.WAV"); + _vm->_objectsManager.OPTI_ONE(6, 0, 23, 0); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 27, 117, 1); + break; + } + + case 237: { + char v48 = _vm->_globals._saveData->_data[svField341]; + if (v48) { + if (v48 == 2) + vbobFrameIndex = 5; + if (v48 == 3) + vbobFrameIndex = 4; + if (v48 == 1) + vbobFrameIndex = 6; + _vm->_soundManager.playSoundFile("SOUND83.WAV"); + _vm->_objectsManager.OPTI_ONE(vbobFrameIndex, 26, 50, 0); + if (_vm->_globals._saveData->_data[svField341] == 1) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 27, 117, 0); + if (_vm->_globals._saveData->_data[svField341] == 2) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 145, 166, 2); + if (_vm->_globals._saveData->_data[svField341] == 3) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 296, 212, 4); + if (_vm->_globals._saveData->_data[svField341] == 1) + _vm->_globals._saveData->_data[svField338] = 0; + if (_vm->_globals._saveData->_data[svField341] == 2) + _vm->_globals._saveData->_data[svField339] = 0; + if (_vm->_globals._saveData->_data[svField341] == 3) + _vm->_globals._saveData->_data[svField340] = 0; + } + _vm->_soundManager.playSoundFile("SOUND83.WAV"); + _vm->_objectsManager.OPTI_ONE(5, 0, 23, 0); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 145, 166, 3); + break; + } + + case 238: { + char v49 = _vm->_globals._saveData->_data[svField341]; + if (v49) { + if (v49 == 2) + vbobFrameIndex = 5; + else if (v49 == 3) + vbobFrameIndex = 4; + else if (v49 == 1) + vbobFrameIndex = 6; + _vm->_soundManager.playSoundFile("SOUND83.WAV"); + _vm->_objectsManager.OPTI_ONE(vbobFrameIndex, 26, 50, 0); + if (_vm->_globals._saveData->_data[svField341] == 1) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 27, 117, 0); + if (_vm->_globals._saveData->_data[svField341] == 2) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 145, 166, 2); + if (_vm->_globals._saveData->_data[svField341] == 3) + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 296, 212, 4); + if (_vm->_globals._saveData->_data[svField341] == 1) + _vm->_globals._saveData->_data[svField338] = 0; + if (_vm->_globals._saveData->_data[svField341] == 2) + _vm->_globals._saveData->_data[svField339] = 0; + if (_vm->_globals._saveData->_data[svField341] == 3) + _vm->_globals._saveData->_data[svField340] = 0; + } + _vm->_soundManager.playSoundFile("SOUND83.WAV"); + _vm->_objectsManager.OPTI_ONE(4, 0, 23, 0); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 296, 212, 5); + break; + } + + case 239: + _vm->_objectsManager.removeSprite(0); + _vm->_soundManager.playSoundFile("SOUND84.WAV"); + _vm->_objectsManager.OPTI_ONE(16, 0, 10, 0); + break; + + case 240: { + _vm->_objectsManager.setBobAnimation(1); + bool soundFlag = false; + do { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 12 && !soundFlag) { + _vm->_soundManager.playSoundFile("SOUND86.WAV"); + soundFlag = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 13) + soundFlag = false; + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 25 && !soundFlag) { + _vm->_soundManager.playSoundFile("SOUND85.WAV"); + soundFlag = true; + } + if (_vm->_objectsManager.getBobAnimDataIdx(1) == 25) + soundFlag = false; + } while (_vm->_objectsManager.getBobAnimDataIdx(1) != 32); + _vm->_objectsManager.stopBobAnimation(1); + _vm->_objectsManager.setBobAnimation(2); + _vm->_fontManager.hideText(9); + bool displayedTxtFl = false; + if (!_vm->_soundManager._textOffFl) { + _vm->_fontManager.initTextBuffers(9, 617, _vm->_globals._textFilename, 91, 41, 3, 30, 253); + _vm->_fontManager.showText(9); + displayedTxtFl = true; + } + if (!_vm->_soundManager._voiceOffFl) + _vm->_soundManager.mixVoice(617, 4, displayedTxtFl); + for (int i = 0; i <= 29; i++) { + if (_vm->shouldQuit()) + return -1; // Exiting game + + _vm->_eventsManager.VBL(); + } + CharacterLocation *v51 = &_vm->_globals._saveData->_realHopkins; + v51->_pos.x = _vm->_objectsManager.getSpriteX(0); + v51->_pos.y = _vm->_objectsManager.getSpriteY(0); + v51->_startSpriteIndex = 57; + v51->_location = 97; + _vm->_globals._saveData->_data[svField121] = 1; + _vm->_globals._saveData->_data[svField352] = 1; + _vm->_globals._saveData->_data[svField353] = 1; + _vm->_globals._saveData->_data[svField354] = 1; + break; + } + + case 241: + _vm->_talkManager.startAnimatedCharacterDialogue("RECEP.PE2"); + break; + + // Resurrect Samantha's clone + case 242: { + _vm->_soundManager.playSoundFile("SOUND87.WAV"); + _vm->_animationManager.NO_SEQ = true; + _vm->_animationManager.playSequence("RESUF.SEQ", 1, 24, 1); + _vm->_animationManager.NO_SEQ = false; + + 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->_objectsManager._twoCharactersFl = true; + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 373, 191, 3); + _vm->_objectsManager.addStaticSprite(_vm->_objectsManager._headSprites, samantha->_pos, 1, 3, samantha->_zoomFactor, false, 20, 127); + _vm->_objectsManager.animateSprite(1); + break; + } + + case 243: + _vm->_soundManager.playSoundFile("SOUND88.WAV"); + if (_vm->_globals._saveData->_data[svField341] == 2) { + _vm->_animationManager.NO_SEQ = true; + _vm->_animationManager.playSequence("RESU.SEQ", 2, 24, 2); + _vm->_animationManager.NO_SEQ = false; + } else { + _vm->_objectsManager.OPTI_ONE(7, 0, 14, 0); + } + break; + + case 245: + _vm->_soundManager.playSoundFile("SOUND89.WAV"); + _vm->_objectsManager.OPTI_ONE(5, 0, 6, 0); + _vm->_linesManager.ZONEP[4]._destX = 276; + _vm->_objectsManager.enableVerb(4, 19); + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 285, 379, 0); + _vm->_globals._saveData->_data[svField399] = 1; + break; + + case 246: + _vm->_objectsManager.removeSprite(0); + _vm->_objectsManager.OPTI_ONE(6, 0, 15, 0); + _vm->_objectsManager.PERSO_ON = true; + _vm->_graphicsManager.NB_SCREEN(true); + _vm->_animationManager.NO_SEQ = true; + _vm->_animationManager.playSequence2("TUNNEL.SEQ", 1, 18, 20); + _vm->_animationManager.NO_SEQ = false; + _vm->_graphicsManager._noFadingFl = true; + _vm->_graphicsManager.fadeOutLong(); + _vm->_objectsManager.PERSO_ON = false; + _vm->_globals._exitId = 100; + break; + + case 600: + if (!_vm->getIsDemo()) { + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_graphicsManager._fadeDefaultSpeed = 1; + _vm->_animationManager.playAnim("BOMBE1A.ANM", 100, 18, 100); + } + _vm->_graphicsManager.loadImage("BOMBEB"); + _vm->_graphicsManager.SETCOLOR3(252, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(251, 100, 100, 100); + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + _vm->_graphicsManager.initScreen("BOMBE", 2, true); + _vm->_graphicsManager.fadeInShort(); + break; + + case 601: + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 163, 7, false); + _vm->_objectsManager.OPTI_ONE(2, 0, 16, 4); + break; + + case 602: + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 163, 7, false); + _vm->_objectsManager.OPTI_ONE(4, 0, 16, 4); + break; + + case 603: + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 163, 7, false); + _vm->_objectsManager.OPTI_ONE(3, 0, 16, 4); + _vm->_soundManager._specialSoundNum = 199; + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playAnim("BOMBE2A.ANM", 50, 14, 500); + _vm->_soundManager._specialSoundNum = 0; + memset(_vm->_graphicsManager._vesaBuffer, 0, 614400); + _vm->_graphicsManager._noFadingFl = true; + _vm->_globals._exitId = 151; + break; + + case 604: + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 163, 7, false); + _vm->_objectsManager.OPTI_ONE(1, 0, 16, 4); + _vm->_soundManager._specialSoundNum = 199; + _vm->_animationManager.playAnim("BOMBE2A.ANM", 50, 14, 500); + _vm->_soundManager._specialSoundNum = 0; + _vm->_graphicsManager._noFadingFl = true; + memset(_vm->_graphicsManager._vesaBuffer, 0, 614400); + _vm->_globals._exitId = 151; + break; + + case 605: + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 163, 7, false); + _vm->_objectsManager.OPTI_ONE(5, 0, 16, 4); + _vm->_graphicsManager.fadeOutShort(); + _vm->_soundManager._specialSoundNum = 199; + _vm->_graphicsManager.FADE_LINUX = 2; + _vm->_animationManager.playAnim("BOMBE2A.ANM", 50, 14, 500); + _vm->_soundManager._specialSoundNum = 0; + _vm->_graphicsManager._noFadingFl = true; + memset(_vm->_graphicsManager._vesaBuffer, 0, 614400); + _vm->_globals._exitId = 151; + break; + + case 606: + _vm->_graphicsManager.fastDisplay(_vm->_globals.SPRITE_ECRAN, 513, 163, 7, false); + _vm->_objectsManager.OPTI_ONE(6, 0, 16, 4); + if ((_vm->getPlatform() != Common::kPlatformWindows) || !_vm->getIsDemo()) { + _vm->_animationManager.playAnim("BOMBE3A.ANM", 50, 14, 500); + memset(_vm->_graphicsManager._vesaBuffer, 0, 614400); + } + _vm->_globals._exitId = 6; + break; + + case 607: + // Display bomb plan + if (!_vm->getIsDemo()) { + memcpy(_vm->_graphicsManager._oldPalette, _vm->_graphicsManager._palette, 769); + _vm->_animationManager.playAnim2("PLAN.ANM", 50, 10, 800); + } + _vm->_graphicsManager.NBBLOC = 0; + break; + + case 608: + _vm->_objectsManager.stopBobAnimation(2); + _vm->_objectsManager.stopBobAnimation(3); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.stopBobAnimation(6); + _vm->_objectsManager.stopBobAnimation(11); + _vm->_objectsManager.stopBobAnimation(10); + break; + + case 609: + _vm->_objectsManager.setBobAnimation(2); + _vm->_objectsManager.setBobAnimation(3); + _vm->_objectsManager.setBobAnimation(4); + _vm->_objectsManager.setBobAnimation(6); + _vm->_objectsManager.setBobAnimation(11); + _vm->_objectsManager.setBobAnimation(10); + break; + + case 610: + _vm->_objectsManager.stopBobAnimation(5); + _vm->_objectsManager.stopBobAnimation(7); + _vm->_objectsManager.stopBobAnimation(8); + _vm->_objectsManager.stopBobAnimation(9); + _vm->_objectsManager.stopBobAnimation(12); + _vm->_objectsManager.stopBobAnimation(13); + break; + + case 611: + _vm->_objectsManager.setBobAnimation(5); + _vm->_objectsManager.setBobAnimation(7); + _vm->_objectsManager.setBobAnimation(8); + _vm->_objectsManager.setBobAnimation(9); + _vm->_objectsManager.setBobAnimation(12); + _vm->_objectsManager.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->_objectsManager.BOB_OFFSET(READ_LE_INT16(dataP + 5), READ_LE_INT16(dataP + 7)); + break; + case MKTAG24('V', 'O', 'N'): + _vm->_objectsManager.enableVerb(READ_LE_INT16(dataP + 5), READ_LE_INT16(dataP + 7)); + opcodeType = 1; + break; + case MKTAG24('Z', 'C', 'H'): + _vm->_linesManager.ZONEP[READ_LE_INT16(dataP + 5)]._messageId = READ_LE_INT16(dataP + 7); + opcodeType = 1; + break; + case MKTAG24('J', 'U', 'M'): + _vm->_objectsManager._jumpZone = READ_LE_INT16(dataP + 5); + _vm->_objectsManager._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->_soundManager.playSoundFile(file); + opcodeType = 1; + break; + } + case MKTAG24('V', 'O', 'F'): + _vm->_objectsManager.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 a2) { + int v20; + int v2 = a2; + bool loopFl; + do { + loopFl = false; + int v3 = v2; + int opcodeType; + do { + if (_vm->shouldQuit()) + return 0; // Exiting game + + ++v3; + opcodeType = checkOpcode(dataP + 20 * v3); + if (v3 > 400) + error("Control if failed"); + } while (opcodeType != 4); // EIF + v20 = v3; + int v6 = v2; + bool v7 = false; + do { + if (_vm->shouldQuit()) + return 0; // Exiting game + + ++v6; + if (checkOpcode(dataP + 20 * v6) == 3) // IIF + v7 = true; + if (v6 > 400) + error("Control if failed "); + if (v7) { + v2 = v20; + loopFl = true; + break; + } + } while (v20 != v6); + } while (loopFl); + + const byte *buf = dataP + 20 * a2; + 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 (a2 + 1); + } else if ((operType == 1) && check1Fl && check2Fl) { + return (a2 + 1); + } else if ((operType == 2) && (check1Fl || check2Fl)) { + return (a2 + 1); + } + + return (v20 + 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..cf719f52ce --- /dev/null +++ b/engines/hopkins/script.h @@ -0,0 +1,51 @@ +/* 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(); + void setParent(HopkinsEngine *vm); + + int handleOpcode(byte *dataP); + int handleIf(const byte *dataP, int a2); + 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..0ea33cd218 --- /dev/null +++ b/engines/hopkins/sound.cpp @@ -0,0 +1,918 @@ +/* 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 Audio { + +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 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 = Audio::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); +} + +} + +/*------------------------------------------------------------------------*/ + +namespace Hopkins { + +SoundManager::SoundManager() { + _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::setParent(HopkinsEngine *vm) { + _vm = vm; + _specialSoundNum = 0; +} + +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 = Audio::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); + + if (!_vm->_fileManager.searchCat(filename + ".WAV", 9)) { + 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->_globals._catalogPos; + catLen = _vm->_globals._catalogSize; + } else if (!_vm->_fileManager.searchCat(filename + ".APC", 9)) { + 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->_globals._catalogPos; + catLen = _vm->_globals._catalogSize; + } else if (!_vm->_fileManager.searchCat(filename + ".RAW", 9)) { + 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->_globals._catalogPos; + catLen = _vm->_globals._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 = (signed int)((long double)_musicVolume - (long double)_musicVolume / 100.0 * 45.0); + setMODMusicVolume(_musicVolume); + } + } + playVoice(); + + _vm->_eventsManager._escKeyFl = false; + + // Loop for playing voice + breakFlag = false; + do { + if (_specialSoundNum != 4 && !_skipRefreshFl) + _vm->_eventsManager.VBL(); + if (_vm->_eventsManager.getMouseButton()) + break; + _vm->_eventsManager.refreshEvents(); + if (_vm->_eventsManager._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->_eventsManager._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 != NULL && _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) { + if (_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) { + _soundFl = true; + _currentSoundIndex = wavIndex; + playWavSample(1, wavIndex); + } +} + +void SoundManager::delWav(int wavIndex) { + if (removeWavSample(wavIndex)) { + 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 Audio::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..1a3060264a --- /dev/null +++ b/engines/hopkins/sound.h @@ -0,0 +1,139 @@ +/* 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(); + ~SoundManager(); + void setParent(HopkinsEngine *vm); + + 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..d3c60a056e --- /dev/null +++ b/engines/hopkins/talk.cpp @@ -0,0 +1,1093 @@ +/* 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() { + _characterBuffer = NULL; + _characterPalette = NULL; + _characterSprite = NULL; + _characterAnim = NULL; + _characterSize = 0; + _dialogueMesgId1 = _dialogueMesgId2 = _dialogueMesgId3 = _dialogueMesgId4 = 0; + _paletteBufferIdx = 0; +} + +void TalkManager::setParent(HopkinsEngine *vm) { + _vm = vm; +} + +void TalkManager::startAnimatedCharacterDialogue(const Common::String &filename) { + Common::String spriteFilename; + + _vm->_fontManager.hideText(5); + _vm->_fontManager.hideText(9); + _vm->_eventsManager.VBL(); + _vm->_graphicsManager._scrollStatus = 1; + bool oldDisableInventFl = _vm->_globals._disableInventFl; + _vm->_globals._disableInventFl = true; + _characterBuffer = _vm->_fileManager.searchCat(filename, 5); + _characterSize = _vm->_globals._catalogSize; + if (_characterBuffer == g_PTRNUL) { + _characterBuffer = _vm->_fileManager.loadFile(filename); + _characterSize = _vm->_fileManager.fileSize(filename); + } + // CHECKME:_data[svField4] is useless? + _vm->_globals._saveData->_data[svField4] = 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; + _characterSprite = _vm->_fileManager.searchCat(spriteFilename, 7); + if (_characterSprite) { + _characterSprite = _vm->_objectsManager.loadSprite(spriteFilename); + } else { + _characterSprite = _vm->_objectsManager.loadSprite("RES_SAN.RES"); + } + + if (_vm->_graphicsManager._lineNbr == SCREEN_WIDTH) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 307200); + else if (_vm->_graphicsManager._lineNbr == (SCREEN_WIDTH * 2)) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 614400); + + if (!_vm->_graphicsManager._lineNbr) + _vm->_graphicsManager._scrollOffset = 0; + _vm->_graphicsManager.NB_SCREEN(true); + _vm->_objectsManager.PERSO_ON = true; + searchCharacterPalette(_paletteBufferIdx, false); + startCharacterAnim0(_paletteBufferIdx, false); + initCharacterAnim(); + _dialogueMesgId2 = _dialogueMesgId1 + 1; + _dialogueMesgId3 = _dialogueMesgId1 + 2; + _dialogueMesgId4 = _dialogueMesgId1 + 3; + int oldMouseCursorId = _vm->_eventsManager._mouseCursorId; + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.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->_eventsManager.VBL(); + } 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->_graphicsManager.NB_SCREEN(false); + + _vm->_saveLoadManager.load("TEMP.SCR", _vm->_graphicsManager._vesaScreen); + g_system->getSavefileManager()->removeSavefile("TEMP.SCR"); + + _vm->_objectsManager.PERSO_ON = false; + _vm->_eventsManager._mouseCursorId = oldMouseCursorId; + + _vm->_eventsManager.changeMouseCursor(oldMouseCursorId); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + + if (_vm->getIsDemo() == false) + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + + _vm->_graphicsManager.initColorTable(145, 150, _vm->_graphicsManager._palette); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaScreen, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + memcpy(_vm->_graphicsManager._vesaBuffer, _vm->_graphicsManager._vesaScreen, 614399); + _vm->_globals._disableInventFl = oldDisableInventFl; + _vm->_graphicsManager.DD_VBL(); + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + _vm->_graphicsManager._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; + _characterBuffer = _vm->_fileManager.searchCat(filename, 5); + _characterSize = _vm->_globals._catalogSize; + if (_characterBuffer == g_PTRNUL) { + _characterBuffer = _vm->_fileManager.loadFile(filename); + _characterSize = _vm->_fileManager.fileSize(filename); + } + + // CHECKME:_data[svField4] is useless? + _vm->_globals._saveData->_data[svField4] = 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->_eventsManager._mouseCursorId; + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.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->_eventsManager._mouseCursorId = oldMouseCursorId; + + _vm->_eventsManager.changeMouseCursor(oldMouseCursorId); + _vm->_graphicsManager.initColorTable(145, 150, _vm->_graphicsManager._palette); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._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->_objectsManager.setBobAnimation(curVal); + if (curVal != 1) + _vm->_objectsManager.setBobAnimation(READ_LE_INT16(bufPtr + 1)); + if (curVal != 2) + _vm->_objectsManager.setBobAnimation(READ_LE_INT16(bufPtr + 2)); + if (curVal != 3) + _vm->_objectsManager.setBobAnimation(READ_LE_INT16(bufPtr + 3)); + if (curVal != 4) + _vm->_objectsManager.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->_fontManager.initTextBuffers(5, _dialogueMesgId1, _questionsFilename, 5, sentence1PosY, 0, 65, 255); + _vm->_fontManager.initTextBuffers(6, _dialogueMesgId2, _questionsFilename, 5, sentence2PosY, 0, 65, 255); + _vm->_fontManager.initTextBuffers(7, _dialogueMesgId3, _questionsFilename, 5, sentence3PosY, 0, 65, 255); + _vm->_fontManager.initTextBuffers(8, _dialogueMesgId4, _questionsFilename, 5, sentence4PosY, 0, 65, 255); + _vm->_fontManager.showText(5); + _vm->_fontManager.showText(6); + _vm->_fontManager.showText(7); + _vm->_fontManager.showText(8); + + int retVal = -1; + bool loopCond = false; + do { + int mousePosY = _vm->_eventsManager.getMouseY(); + if (sentence1PosY < mousePosY && mousePosY < (sentence2PosY - 1)) { + _vm->_fontManager.setOptimalColor(6, 7, 8, 5); + retVal = _dialogueMesgId1; + } + if (sentence2PosY < mousePosY && mousePosY < (sentence3PosY - 1)) { + _vm->_fontManager.setOptimalColor(5, 7, 8, 6); + retVal = _dialogueMesgId2; + } + if (sentence3PosY < mousePosY && mousePosY < (sentence4PosY - 1)) { + _vm->_fontManager.setOptimalColor(5, 6, 8, 7); + retVal = _dialogueMesgId3; + } + if (sentence4PosY < mousePosY && mousePosY < 419) { + _vm->_fontManager.setOptimalColor(5, 6, 7, 8); + retVal = _dialogueMesgId4; + } + + _vm->_eventsManager.VBL(); + if (_vm->_eventsManager.getMouseButton()) + loopCond = true; + if (retVal == -1) + loopCond = false; + } while (!_vm->shouldQuit() && !loopCond); + + _vm->_soundManager.mixVoice(retVal, 1); + _vm->_fontManager.hideText(5); + _vm->_fontManager.hideText(6); + _vm->_fontManager.hideText(7); + _vm->_fontManager.hideText(8); + + if (animatedFl) { + uint16 *bufPtr = (uint16 *)_characterBuffer + 48; + + int curVal = READ_LE_INT16(bufPtr); + if (curVal != 0) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 1); + if (curVal != 1) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 2); + if (curVal != 2) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 3); + if (curVal != 3) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 4); + if (curVal != 4) + _vm->_objectsManager.stopBobAnimation(curVal); + } else { + dialogTalk(); + } + + _vm->_eventsManager.VBL(); + 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); + + // CHECKME:_data[svField4] is useless? + int v7 = READ_LE_INT16((uint16 *)charBuf + 9); + if (v7) + _vm->_globals._saveData->_data[svField4] = v7; + + if (!frameNumb) + frameNumb = 10; + if (animatedFl) { + uint16 *bufPtr = (uint16 *)_characterBuffer + 43; + int curVal = READ_LE_INT16(bufPtr); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 1); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 2); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 3); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 4); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + } else { + VISU_PARLE(); + } + + bool displayedTxtFl = false; + if (!_vm->_soundManager._textOffFl) { + _vm->_fontManager.initTextBuffers(9, mesgId, _answersFilename, mesgPosX, mesgPosY, 5, mesgLength, 252); + _vm->_fontManager.showText(9); + displayedTxtFl = true; + } + if (!_vm->_soundManager.mixVoice(mesgId, 1, displayedTxtFl)) { + _vm->_eventsManager._curMouseButton = 0; + _vm->_eventsManager._mouseButton = 0; + + if (_vm->getIsDemo()) { + for (int i = 0; i < frameNumb; i++) { + _vm->_eventsManager.VBL(); + } + } else { + for (int i = 0; i < frameNumb; i++) { + _vm->_eventsManager.VBL(); + if (_vm->_eventsManager._mouseButton || _vm->_eventsManager._curMouseButton) + break; + if (_vm->_eventsManager.getMouseButton() && i + 1 > abs(frameNumb / 5)) + break; + } + } + } + + if (!_vm->_soundManager._textOffFl) + _vm->_fontManager.hideText(9); + if (animatedFl) { + uint16 *bufPtr = (uint16 *)_characterBuffer + 43; + int curVal = READ_LE_INT16(bufPtr); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 1); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 2); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 3); + if (curVal) + _vm->_objectsManager.stopBobAnimation(curVal); + + curVal = READ_LE_INT16(bufPtr + 4); + if (curVal) + _vm->_objectsManager.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->_graphicsManager.setPaletteVGA256(_characterPalette); + _vm->_graphicsManager.initColorTable(145, 150, _characterPalette); +} + +void TalkManager::dialogWait() { + for (int idx = 26; idx <= 30; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + BOB_VISU_PARLE(idx); + } +} + +void TalkManager::dialogTalk() { + for (int idx = 26; idx <= 30; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.hideBob(idx); + } + + for (int idx = 26; idx <= 30; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.resetBob(idx); + } +} + +void TalkManager::dialogEndTalk() { + for (int idx = 21; idx <= 25; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.hideBob(idx); + } + + _vm->_eventsManager.VBL(); + _vm->_eventsManager.VBL(); + + for (int idx = 21; idx <= 25; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + _vm->_objectsManager.resetBob(idx); + } +} + +int TalkManager::countBoxLines(int idx, const Common::String &file) { + _vm->_fontManager._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 != g_PTRNUL); + + 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::VISU_PARLE() { + for (int idx = 21; idx <= 25; ++idx) { + if (_vm->_globals._animBqe[idx]._enabledFl) + BOB_VISU_PARLE(idx); + } +} + +void TalkManager::BOB_VISU_PARLE(int idx) { + _vm->_objectsManager._priorityFl = true; + if (!_vm->_objectsManager._bob[idx].field0) { + _vm->_objectsManager.resetBob(idx); + byte *v5 = _vm->_globals._animBqe[idx]._data; + int v4 = READ_LE_INT16(v5 + 2); + if (!v4) + v4 = 1; + if (READ_LE_INT16(v5 + 24)) { + _vm->_objectsManager._bob[idx]._isSpriteFl = true; + _vm->_objectsManager._bob[idx]._zoomFactor = 0; + _vm->_objectsManager._bob[idx]._flipFl = false; + _vm->_objectsManager._bob[idx]._animData = _vm->_globals._animBqe[idx]._data; + _vm->_objectsManager._bob[idx].field0 = 10; + v5 = _characterSprite; + _vm->_objectsManager._bob[idx]._spriteData = _characterSprite; + _vm->_objectsManager._bob[idx].field1E = v4; + _vm->_objectsManager._bob[idx].field20 = -1; + _vm->_objectsManager._bob[idx].field22 = 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; + int v7; + do { + v7 = READ_LE_INT16(&_characterAnim[2 * idx + 4]); + if (v7 && _vm->_globals._speed != 501) + _vm->_graphicsManager.fastDisplay(_characterSprite, _vm->_eventsManager._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 && v7); + } +} + +/** + * 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->_globals._animBqe[idx]._data = _vm->_globals.freeMemory(_vm->_globals._animBqe[idx]._data); + _vm->_globals._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->_globals._animBqe[idx]._enabledFl = false; + _vm->_globals._animBqe[idx]._data = g_PTRNUL; + return false; + } + ++bufIndx; + ++animLength; + ++curPtr; + } while (!loopCond); + _vm->_globals._animBqe[idx]._data = _vm->_globals.allocMemory(animLength + 50); + _vm->_globals._animBqe[idx]._enabledFl = true; + memcpy(_vm->_globals._animBqe[idx]._data, (const byte *)(bufPerso + bufPos + 5), 20); + int v23 = READ_LE_INT16(bufPos + bufPerso + 29); + WRITE_LE_UINT16(_vm->_globals._animBqe[idx]._data + 20, READ_LE_INT16(bufPos + bufPerso + 25)); + WRITE_LE_UINT16(_vm->_globals._animBqe[idx]._data + 22, READ_LE_INT16(bufPos + bufPerso + 27)); + WRITE_LE_UINT16(_vm->_globals._animBqe[idx]._data + 24, v23); + WRITE_LE_UINT16(_vm->_globals._animBqe[idx]._data + 26, READ_LE_INT16(bufPos + bufPerso + 31)); + _vm->_globals._animBqe[idx]._data[28] = bufPerso[bufPos + 33]; + _vm->_globals._animBqe[idx]._data[29] = bufPerso[bufPos + 34]; + byte *bqeCurData = _vm->_globals._animBqe[idx]._data + 20; + const byte *curBufPerso = bufPos + bufPerso + 25; + for (int i = 1; i < 5000; i++) { + bqeCurData += 10; + curBufPerso += 10; + if (!v23) + break; + v23 = 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, v23); + 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::REPONSE(int zone, int verb) { + byte zoneObj = zone; + byte verbObj = verb; + + bool outerLoopFl; + byte *ptr = g_PTRNUL; + do { + outerLoopFl = false; + bool tagFound = false; + if (_vm->_globals._answerBuffer == g_PTRNUL) + 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 != g_PTRNUL); + memset(ptr, 0, 620); + uint16 v7 = 0; + int v12 = 0; + bool innerLoopCond = false; + do { + tagFound = false; + if (READ_BE_UINT16(&curAnswerBuf[v7]) == MKTAG16('F', 'C')) { + ++v12; + assert(v12 < (620 / 20)); + + byte *v8 = (ptr + 20 * v12); + uint16 anwerIdx = 0; + do { + assert(anwerIdx < 20); + v8[anwerIdx++] = curAnswerBuf[v7++]; + if (READ_BE_UINT16(&curAnswerBuf[v7]) == MKTAG16('F', 'F')) { + tagFound = true; + v8[anwerIdx] = 'F'; + v8[anwerIdx + 1] = 'F'; + ++v7; + } + } while (!tagFound); + } + if (!tagFound) { + uint32 signature24 = READ_BE_UINT24(&curAnswerBuf[v7]); + if (signature24 == MKTAG24('C', 'O', 'D') || signature24 == MKTAG24('F', 'I', 'N')) + innerLoopCond = true; + } + curAnswerBuf += v7 + 1; + v7 = 0; + } while (!innerLoopCond); + innerLoopCond = false; + int lastOpcodeResult = 1; + do { + int opcodeType = _vm->_scriptManager.handleOpcode(ptr + 20 * lastOpcodeResult); + if (_vm->shouldQuit()) + return; + + if (opcodeType == 2) + // GOTO + lastOpcodeResult = _vm->_scriptManager.handleGoto(ptr + 20 * lastOpcodeResult); + else if (opcodeType == 3) + // IF + lastOpcodeResult = _vm->_scriptManager.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->_objectsManager._jumpZone; + verbObj = _vm->_objectsManager._jumpVerb; + outerLoopFl = true; + break; + } + } while (!innerLoopCond); + } while (outerLoopFl); + _vm->_globals.freeMemory(ptr); + _vm->_globals._saveData->_data[svField2] = 0; + return; +} + +void TalkManager::REPONSE2(int zone, int verb) { + int indx = 0; + if (verb != 5 || _vm->_globals._saveData->_data[svField3] != 4) + return; + + if (zone == 22 || zone == 23) { + _vm->_objectsManager.setFlipSprite(0, false); + _vm->_objectsManager.setSpriteIndex(0, 62); + _vm->_objectsManager.SPACTION(_vm->_objectsManager._forestSprite, "2,3,4,5,6,7,8,9,10,11,12,-1,", 0, 0, 4, false); + if (zone == 22) { + _vm->_objectsManager.lockAnimX(6, _vm->_objectsManager.getBobPosX(3)); + _vm->_objectsManager.lockAnimX(8, _vm->_objectsManager.getBobPosX(3)); + } else { // zone == 23 + _vm->_objectsManager.lockAnimX(6, _vm->_objectsManager.getBobPosX(4)); + _vm->_objectsManager.lockAnimX(8, _vm->_objectsManager.getBobPosX(4)); + } + _vm->_objectsManager.stopBobAnimation(3); + _vm->_objectsManager.stopBobAnimation(4); + _vm->_objectsManager.setBobAnimation(6); + _vm->_soundManager.playSample(1); + _vm->_objectsManager.SPACTION1(_vm->_objectsManager._forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 0, 0, 4); + do + _vm->_eventsManager.VBL(); + while (_vm->_objectsManager.getBobAnimDataIdx(6) < 12); + _vm->_objectsManager.stopBobAnimation(6); + _vm->_objectsManager.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->_linesManager.disableZone(22); + _vm->_linesManager.disableZone(23); + } else if (zone == 20 || zone == 21) { + _vm->_objectsManager.setFlipSprite(0, true); + _vm->_objectsManager.setSpriteIndex(0, 62); + _vm->_objectsManager.SPACTION(_vm->_objectsManager._forestSprite, "2,3,4,5,6,7,8,9,10,11,12,-1,", 0, 0, 4, true); + if (zone == 20) { + _vm->_objectsManager.lockAnimX(5, _vm->_objectsManager.getBobPosX(1)); + _vm->_objectsManager.lockAnimX(7, _vm->_objectsManager.getBobPosX(1)); + } else { // zone == 21 + _vm->_objectsManager.lockAnimX(5, _vm->_objectsManager.getBobPosX(2)); + _vm->_objectsManager.lockAnimX(7, _vm->_objectsManager.getBobPosX(2)); + } + _vm->_objectsManager.stopBobAnimation(1); + _vm->_objectsManager.stopBobAnimation(2); + _vm->_objectsManager.setBobAnimation(5); + _vm->_soundManager.playSample(1); + _vm->_objectsManager.SPACTION1(_vm->_objectsManager._forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 0, 0, 4); + do + _vm->_eventsManager.VBL(); + while (_vm->_objectsManager.getBobAnimDataIdx(5) < 12); + _vm->_objectsManager.stopBobAnimation(5); + _vm->_objectsManager.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->_linesManager.disableZone(21); + _vm->_linesManager.disableZone(20); + } +} + +void TalkManager::animateObject(const Common::String &a2) { + _vm->_fontManager.hideText(5); + _vm->_fontManager.hideText(9); + _vm->_eventsManager.VBL(); + _vm->_graphicsManager._scrollStatus = 1; + _vm->_linesManager.clearAllZones(); + _vm->_linesManager.resetLines(); + _vm->_globals.resetHidingItems(); + + for (int i = 0; i <= 44; i++) + _vm->_linesManager.BOBZONE[i] = 0; + + _vm->_objectsManager._zoneNum = -1; + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.changeMouseCursor(0); + _characterBuffer = _vm->_fileManager.searchCat(a2, 5); + _characterSize = _vm->_globals._catalogSize; + if (_characterBuffer == g_PTRNUL) { + _characterBuffer = _vm->_fileManager.loadFile(a2); + _characterSize = _vm->_fileManager.fileSize(a2); + } + 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); + + _characterSprite = _vm->_fileManager.searchCat(spriteFilename, 7); + if (_characterSprite) + _characterSprite = _vm->_objectsManager.loadSprite(spriteFilename); + else + _characterSprite = _vm->_objectsManager.loadSprite("RES_SAN.RES"); + + if (_vm->_graphicsManager._lineNbr == SCREEN_WIDTH) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 307200); + else if (_vm->_graphicsManager._lineNbr == (SCREEN_WIDTH * 2)) + _vm->_saveLoadManager.saveFile("TEMP.SCR", _vm->_graphicsManager._vesaScreen, 614400); + + if (!_vm->_graphicsManager._lineNbr) + _vm->_graphicsManager._scrollOffset = 0; + _vm->_graphicsManager.NB_SCREEN(true); + _paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110; + _vm->_graphicsManager.NB_SCREEN(true); + _vm->_objectsManager.PERSO_ON = true; + searchCharacterPalette(_paletteBufferIdx, true); + startCharacterAnim0(_paletteBufferIdx, false); + byte *oldAnswerBufferPtr = _vm->_globals._answerBuffer; + _vm->_globals._answerBuffer = g_PTRNUL; + _vm->_globals._freezeCharacterFl = true; + _vm->_objectsManager.loadLinkFile(screenFilename); + _vm->_objectsManager.PERSO_ON = true; + _vm->_globals._actionMoveTo = false; + _vm->_objectsManager._zoneNum = -1; + initCharacterAnim(); + VISU_PARLE(); + dialogWait(); + _vm->_graphicsManager.initScreen(screenFilename, 2, true); + _vm->_globals._freezeCharacterFl = true; + _vm->_objectsManager._forceZoneFl = true; + _vm->_objectsManager._zoneNum = -1; + do { + int mouseButton = _vm->_eventsManager.getMouseButton(); + if (mouseButton == 1) + _vm->_objectsManager.handleLeftButton(); + else if (mouseButton == 2) + _vm->_objectsManager.handleRightButton(); + + _vm->_linesManager.checkZone(); + if (_vm->_globals._actionMoveTo) + _vm->_objectsManager.PARADISE(); + _vm->_eventsManager.VBL(); + } while (!_vm->_globals._exitId); + dialogEndTalk(); + dialogTalk(); + clearCharacterAnim(); + clearCharacterAnim(); + _vm->_globals._introSpeechOffFl = false; + _characterBuffer = _vm->_globals.freeMemory(_characterBuffer); + _characterSprite = _vm->_globals.freeMemory(_characterSprite); + _vm->_graphicsManager.NB_SCREEN(false); + _vm->_linesManager.clearAllZones(); + _vm->_linesManager.resetLines(); + _vm->_globals.resetHidingItems(); + for (int i = 0; i <= 44; i++) + _vm->_linesManager.BOBZONE[i] = 0; + + _vm->_globals.freeMemory(_vm->_globals._answerBuffer); + _vm->_globals._answerBuffer = oldAnswerBufferPtr; + _vm->_objectsManager._disableFl = true; + _vm->_objectsManager.loadLinkFile(curScreenFilename); + _vm->_graphicsManager.initScreen(curScreenFilename, 2, true); + _vm->_objectsManager._disableFl = false; + _vm->_globals._freezeCharacterFl = false; + if (_vm->_globals._exitId == 101) + _vm->_globals._exitId = 0; + + _vm->_saveLoadManager.load("TEMP.SCR", _vm->_graphicsManager._vesaScreen); + g_system->getSavefileManager()->removeSavefile("TEMP.SCR"); + + _vm->_objectsManager.PERSO_ON = false; + _vm->_eventsManager._mouseCursorId = 4; + _vm->_eventsManager.changeMouseCursor(4); + _vm->_graphicsManager.SETCOLOR3(253, 100, 100, 100); + + if (!_vm->getIsDemo()) + _vm->_graphicsManager.SETCOLOR3(254, 0, 0, 0); + + _vm->_graphicsManager.initColorTable(145, 150, _vm->_graphicsManager._palette); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + _vm->_graphicsManager.lockScreen(); + _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaScreen, _vm->_eventsManager._startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0); + _vm->_graphicsManager.unlockScreen(); + _vm->_graphicsManager.setPaletteVGA256(_vm->_graphicsManager._palette); + memcpy(_vm->_graphicsManager._vesaBuffer, _vm->_graphicsManager._vesaScreen, 614399); + _vm->_globals._disableInventFl = false; + _vm->_graphicsManager.DD_VBL(); + for (int i = 0; i <= 4; i++) + _vm->_eventsManager.VBL(); + _vm->_graphicsManager._scrollStatus = 0; +} + +} // End of namespace Hopkins diff --git a/engines/hopkins/talk.h b/engines/hopkins/talk.h new file mode 100644 index 0000000000..e93c47fd38 --- /dev/null +++ b/engines/hopkins/talk.h @@ -0,0 +1,81 @@ +/* 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 VISU_PARLE(); + void BOB_VISU_PARLE(int idx); + +public: + byte *_characterAnim; + byte *_characterSprite; + + TalkManager(); + void setParent(HopkinsEngine *vm); + + void startStaticCharacterDialogue(const Common::String &filename); + void startAnimatedCharacterDialogue(const Common::String &filename); + void animateObject(const Common::String &a2); + + void REPONSE(int zone, int verb); + void REPONSE2(int zone, int verb); +}; + +} // End of namespace Hopkins + +#endif /* HOPKINS_TALK_H */ diff --git a/engines/plugins_table.h b/engines/plugins_table.h index 010de0d5e2..e5ac5efeb4 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -35,6 +35,9 @@ LINK_PLUGIN(GOB) #if PLUGIN_ENABLED_STATIC(GROOVIE) LINK_PLUGIN(GROOVIE) #endif +#if PLUGIN_ENABLED_STATIC(HOPKINS) +LINK_PLUGIN(HOPKINS) +#endif #if PLUGIN_ENABLED_STATIC(HUGO) LINK_PLUGIN(HUGO) #endif |