aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/mods/protracker.cpp16
-rw-r--r--audio/mods/protracker.h8
-rw-r--r--common/platform.cpp2
-rw-r--r--common/platform.h2
-rw-r--r--engines/configure.engines1
-rw-r--r--engines/engines.mk5
-rw-r--r--engines/hopkins/anim.cpp910
-rw-r--r--engines/hopkins/anim.h60
-rw-r--r--engines/hopkins/computer.cpp1221
-rw-r--r--engines/hopkins/computer.h109
-rw-r--r--engines/hopkins/debugger.cpp39
-rw-r--r--engines/hopkins/debugger.h45
-rw-r--r--engines/hopkins/detection.cpp191
-rw-r--r--engines/hopkins/detection_tables.h227
-rw-r--r--engines/hopkins/dialogs.cpp754
-rw-r--r--engines/hopkins/dialogs.h66
-rw-r--r--engines/hopkins/events.cpp542
-rw-r--r--engines/hopkins/events.h95
-rw-r--r--engines/hopkins/files.cpp261
-rw-r--r--engines/hopkins/files.h52
-rw-r--r--engines/hopkins/font.cpp480
-rw-r--r--engines/hopkins/font.h96
-rw-r--r--engines/hopkins/globals.cpp431
-rw-r--r--engines/hopkins/globals.h353
-rw-r--r--engines/hopkins/graphics.cpp1828
-rw-r--r--engines/hopkins/graphics.h178
-rw-r--r--engines/hopkins/hopkins.cpp2890
-rw-r--r--engines/hopkins/hopkins.h199
-rw-r--r--engines/hopkins/lines.cpp2966
-rw-r--r--engines/hopkins/lines.h183
-rw-r--r--engines/hopkins/menu.cpp168
-rw-r--r--engines/hopkins/menu.h46
-rw-r--r--engines/hopkins/module.mk29
-rw-r--r--engines/hopkins/objects.cpp3910
-rw-r--r--engines/hopkins/objects.h246
-rw-r--r--engines/hopkins/saveload.cpp333
-rw-r--r--engines/hopkins/saveload.h78
-rw-r--r--engines/hopkins/script.cpp2565
-rw-r--r--engines/hopkins/script.h51
-rw-r--r--engines/hopkins/sound.cpp918
-rw-r--r--engines/hopkins/sound.h139
-rw-r--r--engines/hopkins/talk.cpp1093
-rw-r--r--engines/hopkins/talk.h81
-rw-r--r--engines/plugins_table.h3
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