aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
diff options
context:
space:
mode:
Diffstat (limited to 'engines/gob')
-rw-r--r--engines/gob/anim.cpp37
-rw-r--r--engines/gob/anim.h41
-rw-r--r--engines/gob/cdrom.cpp240
-rw-r--r--engines/gob/cdrom.h53
-rw-r--r--engines/gob/dataio.cpp367
-rw-r--r--engines/gob/dataio.h70
-rw-r--r--engines/gob/draw.cpp874
-rw-r--r--engines/gob/draw.h139
-rw-r--r--engines/gob/driver_vga.cpp156
-rw-r--r--engines/gob/driver_vga.h44
-rw-r--r--engines/gob/game.cpp1952
-rw-r--r--engines/gob/game.h189
-rw-r--r--engines/gob/global.cpp152
-rw-r--r--engines/gob/global.h173
-rw-r--r--engines/gob/gob.cpp366
-rw-r--r--engines/gob/gob.h129
-rw-r--r--engines/gob/goblin.cpp2381
-rw-r--r--engines/gob/goblin.h231
-rw-r--r--engines/gob/init.cpp272
-rw-r--r--engines/gob/init.h47
-rw-r--r--engines/gob/inter.cpp443
-rw-r--r--engines/gob/inter.h313
-rw-r--r--engines/gob/inter_v1.cpp2624
-rw-r--r--engines/gob/inter_v2.cpp997
-rw-r--r--engines/gob/map.cpp785
-rw-r--r--engines/gob/map.h104
-rw-r--r--engines/gob/module.mk40
-rw-r--r--engines/gob/mult.cpp1214
-rw-r--r--engines/gob/mult.h208
-rw-r--r--engines/gob/music.cpp436
-rw-r--r--engines/gob/music.h96
-rw-r--r--engines/gob/pack.cpp108
-rw-r--r--engines/gob/pack.h36
-rw-r--r--engines/gob/palanim.cpp227
-rw-r--r--engines/gob/palanim.h47
-rw-r--r--engines/gob/parse.cpp420
-rw-r--r--engines/gob/parse.h75
-rw-r--r--engines/gob/parse_v1.cpp883
-rw-r--r--engines/gob/parse_v2.cpp942
-rw-r--r--engines/gob/scenery.cpp784
-rw-r--r--engines/gob/scenery.h148
-rw-r--r--engines/gob/sound.cpp145
-rw-r--r--engines/gob/sound.h104
-rw-r--r--engines/gob/timer.cpp37
-rw-r--r--engines/gob/timer.h43
-rw-r--r--engines/gob/util.cpp486
-rw-r--r--engines/gob/util.h106
-rw-r--r--engines/gob/video.cpp541
-rw-r--r--engines/gob/video.h141
49 files changed, 20446 insertions, 0 deletions
diff --git a/engines/gob/anim.cpp b/engines/gob/anim.cpp
new file mode 100644
index 0000000000..a51befe3c8
--- /dev/null
+++ b/engines/gob/anim.cpp
@@ -0,0 +1,37 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/video.h"
+#include "gob/anim.h"
+
+namespace Gob {
+
+Anim::Anim() {
+ _areaLeft = 0;
+ _areaTop = 0;
+ _areaWidth = 0;
+ _areaHeight = 0;
+ _animSurf = 0;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/anim.h b/engines/gob/anim.h
new file mode 100644
index 0000000000..f5252364b9
--- /dev/null
+++ b/engines/gob/anim.h
@@ -0,0 +1,41 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_ANIM_H
+#define GOB_ANIM_H
+
+namespace Gob {
+
+class Anim {
+public:
+ int16 _areaLeft;
+ int16 _areaTop;
+ int16 _areaWidth;
+ int16 _areaHeight;
+ Video::SurfaceDesc *_animSurf;
+
+ Anim();
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/cdrom.cpp b/engines/gob/cdrom.cpp
new file mode 100644
index 0000000000..bda2081404
--- /dev/null
+++ b/engines/gob/cdrom.cpp
@@ -0,0 +1,240 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2005-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/cdrom.h"
+#include "gob/dataio.h"
+#include "gob/game.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "sound/audiocd.h"
+
+namespace Gob {
+
+CDROM::CDROM(GobEngine *vm) : _vm(vm) {
+ _cdPlaying = false;
+ _LICbuffer = 0;
+ for (int i = 0; i < 16; i++)
+ _curTrack[i] = 0;
+ _numTracks = 0;
+ _trackStop = 0;
+ _startTime = 0;
+}
+
+void CDROM::readLIC(const char *fname) {
+ char tmp[80];
+ int handle;
+ uint16 version, startChunk, pos;
+
+ freeLICbuffer();
+
+ *_curTrack = 0;
+
+ strcpy(tmp, fname);
+
+ handle = _vm->_dataio->openData(tmp);
+
+ if (handle == -1)
+ return;
+
+ _vm->_dataio->closeData(handle);
+
+ _vm->_dataio->getUnpackedData(tmp);
+
+ handle = _vm->_dataio->openData(tmp);
+
+ _vm->_dataio->readData(handle, (char *)&version, 2);
+ version = READ_LE_UINT16(&version);
+
+ _vm->_dataio->readData(handle, (char *)&startChunk, 2);
+ startChunk = READ_LE_UINT16(&startChunk);
+
+ _vm->_dataio->readData(handle, (char *)&_numTracks, 2);
+ _numTracks = READ_LE_UINT16(&_numTracks);
+
+ if (version != 3) {
+ error("Wrong file %s (%d)", fname, version);
+ return;
+ }
+
+ _vm->_dataio->seekData(handle, 50, SEEK_SET);
+
+ for (int i = 0; i < startChunk; i++) {
+ _vm->_dataio->readData(handle, (char *)&pos, 2);
+ pos = READ_LE_UINT16(&pos);
+
+ if (!pos)
+ break;
+
+ _vm->_dataio->seekData(handle, pos, SEEK_CUR);
+ }
+
+ _LICbuffer = new byte[_numTracks * 22];
+ _vm->_dataio->readData(handle, (char *)_LICbuffer, _numTracks * 22);
+
+ _vm->_dataio->closeData(handle);
+}
+
+void CDROM::freeLICbuffer(void) {
+ delete[] _LICbuffer;
+ _LICbuffer = 0;
+}
+
+void CDROM::playBgMusic() {
+ static const char *tracks[][2] = {
+ {"avt00.tot", "mine"},
+ {"avt001.tot", "nuit"},
+ {"avt002.tot", "campagne"},
+ {"avt003.tot", "extsor1"},
+ {"avt004.tot", "interieure"},
+ {"avt005.tot", "zombie"},
+ {"avt006.tot", "zombie"},
+ {"avt007.tot", "campagne"},
+ {"avt008.tot", "campagne"},
+ {"avt009.tot", "extsor1"},
+ {"avt010.tot", "extsor1"},
+ {"avt011.tot", "interieure"},
+ {"avt012.tot", "zombie"},
+ {"avt014.tot", "nuit"},
+ {"avt015.tot", "interieure"},
+ {"avt016.tot", "statue"},
+ {"avt017.tot", "zombie"},
+ {"avt018.tot", "statue"},
+ {"avt019.tot", "mine"},
+ {"avt020.tot", "statue"},
+ {"avt021.tot", "mine"},
+ {"avt022.tot", "zombie"}
+ };
+
+ for (int i = 0; i < ARRAYSIZE(tracks); i++)
+ if (!scumm_stricmp(_vm->_game->_curTotFile, tracks[i][0])) {
+ startTrack(tracks[i][1]);
+ break;
+ }
+}
+
+void CDROM::playMultMusic() {
+ static const char *tracks[][6] = {
+ {"avt005.tot", "fra1", "all1", "ang1", "esp1", "ita1"},
+ {"avt006.tot", "fra2", "all2", "ang2", "esp2", "ita2"},
+ {"avt012.tot", "fra3", "all3", "ang3", "esp3", "ita3"},
+ {"avt016.tot", "fra4", "all4", "ang4", "esp4", "ita4"},
+ {"avt019.tot", "fra5", "all5", "ang5", "esp5", "ita5"},
+ {"avt022.tot", "fra6", "all6", "ang6", "esp6", "ita6"}
+ };
+
+ for (int i = 0; i < ARRAYSIZE(tracks); i++)
+ if (!scumm_stricmp(_vm->_game->_curTotFile, tracks[i][0])) {
+ _cdPlaying = true;
+ startTrack(tracks[i][_vm->_global->_language + 1]);
+ break;
+ }
+}
+
+void CDROM::startTrack(const char *trackname) {
+ byte *curPtr, *matchPtr;
+
+ if (!_LICbuffer)
+ return;
+
+ debug(3, "startTrack(%s)", trackname);
+
+ matchPtr = 0;
+ curPtr = _LICbuffer;
+
+ for (int i = 0; i < _numTracks; i++) {
+ if (!scumm_stricmp((char *)curPtr, trackname)) {
+ matchPtr = curPtr;
+ break;
+ }
+ curPtr += 22;
+ }
+
+ if (!matchPtr) {
+ error("Track %s not found", trackname);
+ return;
+ }
+
+ strcpy(_curTrack, trackname);
+
+ stopPlaying();
+
+ while (getTrackPos() != -1);
+
+ uint32 start, end;
+
+ start = READ_LE_UINT32(matchPtr + 12);
+ end = READ_LE_UINT32(matchPtr + 16);
+
+ play(start, end);
+
+ _startTime = _vm->_util->getTimeKey();
+ _trackStop = _startTime + (end - start + 1 + 150) * 40 / 3;
+}
+
+void CDROM::play(uint32 from, uint32 to) {
+ // play from sector [from] to sector [to]
+ //
+ // format is HSG:
+ // HSG encodes frame information into a double word:
+ // minute multiplied by 4500, plus second multiplied by 75,
+ // plus frame, minus 150
+ debug(3, "play(%d, %d)", from, to);
+
+ AudioCD.play(1, 0, from, to - from + 1);
+}
+
+int32 CDROM::getTrackPos(void) {
+ uint32 curPos = _vm->_util->getTimeKey() - _startTime;
+
+ if (AudioCD.isPlaying() && (_vm->_util->getTimeKey() < _trackStop))
+ return curPos * 3 / 40;
+ else
+ return -1;
+}
+
+void CDROM::stopPlaying(void) {
+ stop();
+
+ while (getTrackPos() != -1);
+}
+
+void CDROM::stop(void) {
+ debug(3, "stop()");
+
+ AudioCD.stop();
+}
+
+void CDROM::testCD(int trySubst, const char *label) {
+ if (!trySubst) {
+ error("CDROM track substitution is not supported");
+ return;
+ }
+
+ _LICbuffer = 0;
+ _cdPlaying = false;
+
+ // Original checked CD label here
+ // but will skip it as it will require OSystem extensions of direct
+ // CD secor reading
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/cdrom.h b/engines/gob/cdrom.h
new file mode 100644
index 0000000000..582a4a553a
--- /dev/null
+++ b/engines/gob/cdrom.h
@@ -0,0 +1,53 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2005-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+
+namespace Gob {
+
+class CDROM {
+public:
+ bool _cdPlaying;
+
+ void readLIC(const char *fname);
+ void freeLICbuffer(void);
+
+ void startTrack(const char *s);
+ void playBgMusic();
+ void playMultMusic();
+ void play(uint32 from, uint32 to);
+ int32 getTrackPos(void);
+ void stopPlaying(void);
+ void stop(void);
+ void testCD(int trySubst, const char *label);
+
+ CDROM(GobEngine *vm);
+
+protected:
+ byte *_LICbuffer;
+ char _curTrack[16];
+ uint16 _numTracks;
+ uint32 _trackStop;
+ uint32 _startTime;
+ GobEngine *_vm;
+};
+
+} // End of namespace Gob
diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp
new file mode 100644
index 0000000000..b66de4a497
--- /dev/null
+++ b/engines/gob/dataio.cpp
@@ -0,0 +1,367 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/dataio.h"
+#include "gob/pack.h"
+
+namespace Gob {
+
+DataIO::DataIO(GobEngine *vm) : _vm(vm) {
+}
+
+Common::File *DataIO::file_getHandle(int16 handle) {
+ return &_vm->_global->_filesHandles[handle];
+}
+
+int16 DataIO::file_open(const char *path, Common::File::AccessMode mode) {
+ int16 i;
+
+ for (i = 0; i < MAX_FILES; i++) {
+ if (!file_getHandle(i)->isOpen())
+ break;
+ }
+ if (i == MAX_FILES)
+ return -1;
+
+ file_getHandle(i)->open(path, mode);
+
+ if (file_getHandle(i)->isOpen())
+ return i;
+
+ return -1;
+}
+
+int16 DataIO::getChunk(const char *chunkName) {
+ int16 file;
+ int16 slot;
+ int16 chunk;
+ struct ChunkDesc *dataDesc;
+
+ for (file = 0; file < MAX_DATA_FILES; file++) {
+ if (_vm->_global->_dataFiles[file] == 0)
+ return -1;
+
+ for (slot = 0; slot < MAX_SLOT_COUNT; slot++)
+ if (_vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot] == -1)
+ break;
+
+ if (slot == MAX_SLOT_COUNT)
+ return -1;
+
+ dataDesc = _vm->_global->_dataFiles[file];
+ for (chunk = 0; chunk < _vm->_global->_numDataChunks[file];
+ chunk++, dataDesc++) {
+ if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0)
+ continue;
+
+ _vm->_global->_isCurrentSlot[file * MAX_SLOT_COUNT + slot] = 0;
+ _vm->_global->_chunkSize[file * MAX_SLOT_COUNT + slot] =
+ dataDesc->size;
+ _vm->_global->_chunkOffset[file * MAX_SLOT_COUNT + slot] =
+ dataDesc->offset;
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot] = 0;
+ return file * 10 + slot + 50;
+ }
+ }
+ return -1;
+}
+
+char DataIO::freeChunk(int16 handle) {
+ if (handle >= 50 && handle < 100) {
+ handle -= 50;
+ _vm->_global->_chunkPos[(handle / 10) * MAX_SLOT_COUNT + (handle % 10)] = -1;
+ return 0;
+ }
+ return 1;
+}
+
+int32 DataIO::readChunk(int16 handle, char *buf, int16 size) {
+ int16 file;
+ int16 slot;
+ int16 i;
+ int32 offset;
+
+ if (handle < 50 || handle >= 100)
+ return -2;
+
+ file = (handle - 50) / 10;
+ slot = (handle - 50) % 10;
+ if (_vm->_global->_isCurrentSlot[file * MAX_SLOT_COUNT + slot] == 0) {
+ for (i = 0; i < MAX_SLOT_COUNT; i++)
+ _vm->_global->_isCurrentSlot[file * MAX_SLOT_COUNT + i] = 0;
+
+ offset =
+ _vm->_global->_chunkOffset[file * MAX_SLOT_COUNT + slot] +
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot];
+ debug(7, "seek: %ld, %ld", _vm->_global->_chunkOffset[file * MAX_SLOT_COUNT + slot], _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot]);
+ file_getHandle(_vm->_global->_dataFileHandles[file])->seek(offset, SEEK_SET);
+ }
+
+ _vm->_global->_isCurrentSlot[file * MAX_SLOT_COUNT + slot] = 1;
+ if (_vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot] + size >
+ _vm->_global->_chunkSize[file * MAX_SLOT_COUNT + slot])
+ size =
+ _vm->_global->_chunkSize[file * MAX_SLOT_COUNT + slot] -
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot];
+
+ file_getHandle(_vm->_global->_dataFileHandles[file])->read(buf, size);
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot] += size;
+ return size;
+}
+
+int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) {
+ int16 file;
+ int16 slot;
+
+ if (handle < 50 || handle >= 100)
+ return -1;
+
+ file = (handle - 50) / 10;
+ slot = (handle - 50) % 10;
+ _vm->_global->_isCurrentSlot[file * MAX_SLOT_COUNT + slot] = 0;
+ if (from == SEEK_SET)
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot] = pos;
+ else
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot] += pos;
+
+ return _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + slot];
+}
+
+int32 DataIO::getChunkSize(const char *chunkName) {
+ int16 file;
+ int16 chunk;
+ struct ChunkDesc *dataDesc;
+ int16 slot;
+ int32 realSize;
+
+ for (file = 0; file < MAX_DATA_FILES; file++) {
+ if (_vm->_global->_dataFiles[file] == 0)
+ return -1;
+
+ dataDesc = _vm->_global->_dataFiles[file];
+ for (chunk = 0; chunk < _vm->_global->_numDataChunks[file];
+ chunk++, dataDesc++) {
+ if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0)
+ continue;
+
+ if (dataDesc->packed == 0) {
+ _vm->_global->_packedSize = -1;
+ return dataDesc->size;
+ }
+
+ for (slot = 0; slot < MAX_SLOT_COUNT; slot++)
+ _vm->_global->_isCurrentSlot[slot] = 0;
+
+ file_getHandle(_vm->_global->_dataFileHandles[file])->seek(dataDesc->offset, SEEK_SET);
+ realSize = file_getHandle(_vm->_global->_dataFileHandles[file])->readUint32LE();
+ _vm->_global->_packedSize = dataDesc->size;
+ return realSize;
+ }
+ }
+ return -1;
+}
+
+void DataIO::openDataFile(const char *src) {
+ char path[128];
+ int16 i;
+ int16 file;
+ ChunkDesc *dataDesc;
+
+ strcpy(path, src);
+ for (i = 0; path[i] != '.' && path[i] != 0; i++);
+ if (path[i] == 0)
+ strcat(path, ".stk");
+
+ for (file = 0; file < MAX_DATA_FILES; file++)
+ if (_vm->_global->_dataFiles[file] == 0)
+ break;
+
+ if (file == MAX_DATA_FILES)
+ error("dataFileOpen: Data file slots are full\n");
+ _vm->_global->_dataFileHandles[file] = file_open(path);
+
+ if (_vm->_global->_dataFileHandles[file] == -1)
+ error("dataFileOpen: Can't open %s data file\n", path);
+
+ _vm->_global->_numDataChunks[file] = file_getHandle(_vm->_global->_dataFileHandles[file])->readUint16LE();
+
+ debug(7, "DataChunks: %d [for %s]", _vm->_global->_numDataChunks[file], path);
+
+ dataDesc = new ChunkDesc[_vm->_global->_numDataChunks[file]];
+ _vm->_global->_dataFiles[file] = dataDesc;
+
+ for (i = 0; i < _vm->_global->_numDataChunks[file]; i++) {
+ file_getHandle(_vm->_global->_dataFileHandles[file])->read(dataDesc[i].chunkName, 13);
+ dataDesc[i].size = file_getHandle(_vm->_global->_dataFileHandles[file])->readUint32LE();
+ dataDesc[i].offset = file_getHandle(_vm->_global->_dataFileHandles[file])->readUint32LE();
+ dataDesc[i].packed = file_getHandle(_vm->_global->_dataFileHandles[file])->readByte();
+ }
+
+ for (i = 0; i < _vm->_global->_numDataChunks[file]; i++)
+ debug(7, "%d: %s %d", i, dataDesc[i].chunkName, dataDesc[i].size);
+
+ for (i = 0; i < MAX_SLOT_COUNT; i++)
+ _vm->_global->_chunkPos[file * MAX_SLOT_COUNT + i] = -1;
+
+}
+
+void DataIO::closeDataFile() {
+ int16 file;
+ for (file = MAX_DATA_FILES - 1; file >= 0; file--) {
+ if (_vm->_global->_dataFiles[file] != 0) {
+ delete[] _vm->_global->_dataFiles[file];
+ _vm->_global->_dataFiles[file] = 0;
+ file_getHandle(_vm->_global->_dataFileHandles[file])->close();
+ return;
+ }
+ }
+}
+
+char *DataIO::getUnpackedData(const char *name) {
+ int32 realSize;
+ int16 chunk;
+ char *unpackBuf;
+ char *packBuf;
+ char *ptr;
+ int32 sizeLeft;
+
+ realSize = getChunkSize(name);
+ if (_vm->_global->_packedSize == -1 || realSize == -1)
+ return 0;
+
+ chunk = getChunk(name);
+ if (chunk == -1)
+ return 0;
+
+ unpackBuf = new char[realSize];
+ if (unpackBuf == 0)
+ return 0;
+
+ packBuf = new char[_vm->_global->_packedSize];
+ if (packBuf == 0) {
+ delete[] unpackBuf;
+ return 0;
+ }
+
+ sizeLeft = _vm->_global->_packedSize;
+ ptr = packBuf;
+ while (sizeLeft > 0x4000) {
+ readChunk(chunk, ptr, 0x4000);
+ sizeLeft -= 0x4000;
+ ptr += 0x4000;
+ }
+ readChunk(chunk, ptr, sizeLeft);
+ freeChunk(chunk);
+ _vm->_pack->unpackData(packBuf, unpackBuf);
+
+ delete[] packBuf;
+ return unpackBuf;
+}
+
+void DataIO::closeData(int16 handle) {
+ if (freeChunk(handle) != 0)
+ file_getHandle(handle)->close();
+}
+
+int16 DataIO::openData(const char *path, Common::File::AccessMode mode) {
+ int16 handle;
+
+ if (mode != Common::File::kFileReadMode)
+ return file_open(path, mode);
+
+ handle = getChunk(path);
+ if (handle >= 0)
+ return handle;
+
+ return file_open(path, mode);
+}
+
+int32 DataIO::readData(int16 handle, char *buf, int16 size) {
+ int32 res;
+
+ res = readChunk(handle, buf, size);
+ if (res >= 0)
+ return res;
+
+ return file_getHandle(handle)->read(buf, size);
+}
+
+void DataIO::seekData(int16 handle, int32 pos, int16 from) {
+ int32 resPos;
+
+ resPos = seekChunk(handle, pos, from);
+ if (resPos != -1)
+ return;
+
+ file_getHandle(handle)->seek(pos, from);
+}
+
+int32 DataIO::getDataSize(const char *name) {
+ char buf[128];
+ int32 chunkSz;
+ Common::File file;
+
+ strcpy(buf, name);
+ chunkSz = getChunkSize(buf);
+ if (chunkSz >= 0)
+ return chunkSz;
+
+ if (!file.open(buf))
+ error("getDataSize: Can't find data(%s)", name);
+
+ chunkSz = file.size();
+ file.close();
+
+ return chunkSz;
+}
+
+char *DataIO::getData(const char *path) {
+ char *data;
+ char *ptr;
+ int32 size;
+ int16 handle;
+
+ data = getUnpackedData(path);
+ if (data != 0)
+ return data;
+
+ size = getDataSize(path);
+ data = new char[size];
+ if (data == 0)
+ return 0;
+
+ handle = openData(path);
+
+ ptr = data;
+ while (size > 0x4000) {
+ readData(handle, ptr, 0x4000);
+ size -= 0x4000;
+ ptr += 0x4000;
+ }
+ readData(handle, ptr, size);
+ closeData(handle);
+ return data;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h
new file mode 100644
index 0000000000..9b28adfd10
--- /dev/null
+++ b/engines/gob/dataio.h
@@ -0,0 +1,70 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_DATAIO_H
+#define GOB_DATAIO_H
+
+#include "common/file.h"
+#include "gob/gob.h"
+
+namespace Gob {
+
+#define MAX_DATA_FILES 3
+#define MAX_SLOT_COUNT 4
+
+class DataIO {
+public:
+ struct ChunkDesc {
+ char chunkName[13];
+ uint32 size;
+ uint32 offset;
+ byte packed;
+ ChunkDesc() : size(0), offset(0), packed(0) { chunkName[0] = 0; }
+ };
+
+ int16 file_open(const char *path, Common::File::AccessMode mode = Common::File::kFileReadMode);
+ Common::File *file_getHandle(int16 handle);
+ int16 getChunk(const char *chunkName);
+ char freeChunk(int16 handle);
+ int32 readChunk(int16 handle, char *buf, int16 size);
+ int16 seekChunk(int16 handle, int32 pos, int16 from);
+ int32 getChunkSize(const char *chunkName);
+ void openDataFile(const char *src);
+ void closeDataFile(void);
+ char *getUnpackedData(const char *name);
+ void closeData(int16 handle);
+ int16 openData(const char *path, Common::File::AccessMode mode = Common::File::kFileReadMode);
+ int32 readData(int16 handle, char *buf, int16 size);
+ void seekData(int16 handle, int32 pos, int16 from);
+ int32 getDataSize(const char *name);
+ char *getData(const char *path);
+ char *getSmallData(const char *path);
+
+ DataIO(class GobEngine *vm);
+
+protected:
+ class GobEngine *_vm;
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
new file mode 100644
index 0000000000..f0e09a96ae
--- /dev/null
+++ b/engines/gob/draw.cpp
@@ -0,0 +1,874 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/draw.h"
+#include "gob/global.h"
+#include "gob/video.h"
+#include "gob/game.h"
+#include "gob/util.h"
+#include "gob/scenery.h"
+#include "gob/inter.h"
+#include "gob/video.h"
+#include "gob/palanim.h"
+#include "gob/cdrom.h"
+
+namespace Gob {
+
+Draw::Draw(GobEngine *vm) : _vm(vm) {
+ _fontIndex = 0;
+ _spriteLeft = 0;
+ _spriteTop = 0;
+ _spriteRight = 0;
+ _spriteBottom = 0;
+ _destSpriteX = 0;
+ _destSpriteY = 0;
+ _backColor = 0;
+ _frontColor = 0;
+ _letterToPrint = 0;
+
+ _destSurface = 0;
+ _sourceSurface = 0;
+ _renderFlags = 0;
+ _backDeltaX = 0;
+ _backDeltaY = 0;
+
+ int i;
+
+ for (i = 0; i < 4; i++)
+ _fonts[i] = 0;
+
+ _textToPrint = 0;
+ _transparency = 0;
+
+ for (i = 0; i < 50; i++)
+ _spritesArray[i] = 0;
+
+ _invalidatedCount = 0;
+ for (i = 0; i < 30; i++) {
+ _invalidatedTops[i] = 0;
+ _invalidatedLefts[i] = 0;
+ _invalidatedRights[i] = 0;
+ _invalidatedBottoms[i] = 0;
+ }
+
+ _noInvalidated = 0;
+ _applyPal = 0;
+ _paletteCleared = 0;
+
+ _backSurface = 0;
+ _frontSurface = 0;
+
+ for (i = 0; i < 18; i++)
+ _unusedPalette1[i] = 0;
+ for (i = 0; i < 16; i++)
+ _unusedPalette2[i] = 0;
+ for (i = 0; i < 256; i++) {
+ _vgaPalette[i].red = 0;
+ _vgaPalette[i].blue = 0;
+ _vgaPalette[i].green = 0;
+ }
+ for (i = 0; i < 16; i++) {
+ _vgaSmallPalette[i].red = 0;
+ _vgaSmallPalette[i].blue = 0;
+ _vgaSmallPalette[i].green = 0;
+ }
+
+ _cursorX = 0;
+ _cursorY = 0;
+ _cursorWidth = 0;
+ _cursorHeight = 0;
+
+ _cursorXDeltaVar = -1;
+ _cursorYDeltaVar = -1;
+
+ for (i = 0; i < 40; i++) {
+ _cursorAnimLow[i] = 0;
+ _cursorAnimHigh[i] = 0;
+ _cursorAnimDelays[i] = 0;
+ }
+
+ _cursorIndex = 0;
+ _transparentCursor = 0;
+ _cursorSprites = 0;
+ _cursorBack = 0;
+ _cursorAnim = 0;
+
+ _palLoadData1[0] = 0;
+ _palLoadData1[1] = 17;
+ _palLoadData1[2] = 34;
+ _palLoadData1[3] = 51;
+ _palLoadData2[0] = 0;
+ _palLoadData2[1] = 68;
+ _palLoadData2[2] = 136;
+ _palLoadData2[3] = 204;
+
+ _cursorTimeKey = 0;
+}
+
+void Draw::invalidateRect(int16 left, int16 top, int16 right, int16 bottom) {
+ int16 temp;
+ int16 rect;
+ int16 i;
+
+ if (_renderFlags & RENDERFLAG_NOINVALIDATE)
+ return;
+
+ if (left > right) {
+ temp = left;
+ left = right;
+ right = temp;
+ }
+ if (top > bottom) {
+ temp = top;
+ top = bottom;
+ bottom = temp;
+ }
+
+ if (left > 319 || right < 0 || top > 199 || bottom < 0)
+ return;
+
+ _noInvalidated = 0;
+
+ if (_invalidatedCount >= 30) {
+ _invalidatedLefts[0] = 0;
+ _invalidatedTops[0] = 0;
+ _invalidatedRights[0] = 319;
+ _invalidatedBottoms[0] = 199;
+ _invalidatedCount = 1;
+ return;
+ }
+
+ if (left < 0)
+ left = 0;
+
+ if (right > 319)
+ right = 319;
+
+ if (top < 0)
+ top = 0;
+
+ if (bottom > 199)
+ bottom = 199;
+
+ left &= 0xfff0;
+ right |= 0x000f;
+
+ for (rect = 0; rect < _invalidatedCount; rect++) {
+
+ if (_invalidatedTops[rect] > top) {
+ if (_invalidatedTops[rect] > bottom) {
+ for (i = _invalidatedCount; i > rect; i--) {
+ _invalidatedLefts[i] =
+ _invalidatedLefts[i - 1];
+ _invalidatedTops[i] =
+ _invalidatedTops[i - 1];
+ _invalidatedRights[i] =
+ _invalidatedRights[i - 1];
+ _invalidatedBottoms[i] =
+ _invalidatedBottoms[i - 1];
+ }
+ _invalidatedLefts[rect] = left;
+ _invalidatedTops[rect] = top;
+ _invalidatedRights[rect] = right;
+ _invalidatedBottoms[rect] = bottom;
+ _invalidatedCount++;
+ return;
+ }
+ if (_invalidatedBottoms[rect] < bottom)
+ _invalidatedBottoms[rect] = bottom;
+
+ if (_invalidatedLefts[rect] > left)
+ _invalidatedLefts[rect] = left;
+
+ if (_invalidatedRights[rect] < right)
+ _invalidatedRights[rect] = right;
+
+ _invalidatedTops[rect] = top;
+ return;
+ }
+
+ if (_invalidatedBottoms[rect] < top)
+ continue;
+
+ if (_invalidatedBottoms[rect] < bottom)
+ _invalidatedBottoms[rect] = bottom;
+
+ if (_invalidatedLefts[rect] > left)
+ _invalidatedLefts[rect] = left;
+
+ if (_invalidatedRights[rect] < right)
+ _invalidatedRights[rect] = right;
+
+ return;
+ }
+
+ _invalidatedLefts[_invalidatedCount] = left;
+ _invalidatedTops[_invalidatedCount] = top;
+ _invalidatedRights[_invalidatedCount] = right;
+ _invalidatedBottoms[_invalidatedCount] = bottom;
+ _invalidatedCount++;
+ return;
+}
+
+void Draw::blitInvalidated(void) {
+ int16 i;
+
+ if (_cursorIndex == 4)
+ blitCursor();
+
+ if (_vm->_inter->_terminate)
+ return;
+
+ if (_noInvalidated && _applyPal == 0)
+ return;
+
+ if (_noInvalidated) {
+ setPalette();
+ _applyPal = 0;
+ return;
+ }
+
+ if (_applyPal) {
+ clearPalette();
+
+ _vm->_video->drawSprite(_backSurface, _frontSurface, 0, 0, 319,
+ 199, 0, 0, 0);
+ setPalette();
+ _invalidatedCount = 0;
+ _noInvalidated = 1;
+ _applyPal = 0;
+ return;
+ }
+
+ _vm->_global->_doRangeClamp = 0;
+ for (i = 0; i < _invalidatedCount; i++) {
+ _vm->_video->drawSprite(_backSurface, _frontSurface,
+ _invalidatedLefts[i], _invalidatedTops[i],
+ _invalidatedRights[i], _invalidatedBottoms[i],
+ _invalidatedLefts[i], _invalidatedTops[i], 0);
+ }
+ _vm->_global->_doRangeClamp = 1;
+
+ _invalidatedCount = 0;
+ _noInvalidated = 1;
+ _applyPal = 0;
+}
+
+void Draw::setPalette(void) {
+ if (_vm->_global->_videoMode != 0x13)
+ error("setPalette: Video mode 0x%x is not supported!\n",
+ _vm->_global->_videoMode);
+
+ _vm->_global->_pPaletteDesc->unused1 = _unusedPalette1;
+ _vm->_global->_pPaletteDesc->unused2 = _unusedPalette2;
+ _vm->_global->_pPaletteDesc->vgaPal = _vgaPalette;
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ _paletteCleared = 0;
+}
+
+void Draw::clearPalette(void) {
+ if (_paletteCleared == 0) {
+ _paletteCleared = 1;
+ _vm->_util->clearPalette();
+ }
+}
+
+void Draw::blitCursor(void) {
+ if (_cursorIndex == -1)
+ return;
+
+ _cursorIndex = -1;
+
+ if (_noInvalidated) {
+ _vm->_video->drawSprite(_backSurface, _frontSurface,
+ _cursorX, _cursorY,
+ _cursorX + _cursorWidth - 1,
+ _cursorY + _cursorHeight - 1, _cursorX,
+ _cursorY, 0);
+ } else {
+ invalidateRect(_cursorX, _cursorY,
+ _cursorX + _cursorWidth - 1,
+ _cursorY + _cursorHeight - 1);
+ }
+}
+
+void Draw::spriteOperation(int16 operation) {
+ uint16 id;
+ char *dataBuf;
+ Game::TotResItem *itemPtr;
+ int32 offset;
+ int16 len;
+ int16 i;
+ int16 x;
+ int16 y;
+ int16 perLine;
+
+ if (_sourceSurface >= 100)
+ _sourceSurface -= 80;
+
+ if (_destSurface >= 100)
+ _destSurface -= 80;
+
+ if (_renderFlags & RENDERFLAG_USEDELTAS) {
+ if (_sourceSurface == 21) {
+ _spriteLeft += _backDeltaX;
+ _spriteTop += _backDeltaY;
+ }
+
+ if (_destSurface == 21) {
+ _destSpriteX += _backDeltaX;
+ _destSpriteY += _backDeltaY;
+ if (operation == DRAW_DRAWLINE ||
+ (operation >= DRAW_DRAWBAR
+ && operation <= DRAW_FILLRECTABS)) {
+ _spriteRight += _backDeltaX;
+ _spriteBottom += _backDeltaY;
+ }
+ }
+ }
+
+ switch (operation) {
+ case DRAW_BLITSURF:
+ _vm->_video->drawSprite(_spritesArray[_sourceSurface],
+ _spritesArray[_destSurface],
+ _spriteLeft, _spriteTop,
+ _spriteLeft + _spriteRight - 1,
+ _spriteTop + _spriteBottom - 1,
+ _destSpriteX, _destSpriteY, _transparency);
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _destSpriteX + _spriteRight - 1,
+ _destSpriteY + _spriteBottom - 1);
+ }
+ break;
+
+ case DRAW_PUTPIXEL:
+ _vm->_video->putPixel(_destSpriteX, _destSpriteY,
+ _frontColor, _spritesArray[_destSurface]);
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _destSpriteX, _destSpriteY);
+ }
+ break;
+
+ case DRAW_FILLRECT:
+ _vm->_video->fillRect(_spritesArray[_destSurface],
+ _destSpriteX, _destSpriteY,
+ _destSpriteX + _spriteRight - 1,
+ _destSpriteY + _spriteBottom - 1, _backColor);
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _destSpriteX + _spriteRight - 1,
+ _destSpriteY + _spriteBottom - 1);
+ }
+ break;
+
+ case DRAW_DRAWLINE:
+ _vm->_video->drawLine(_spritesArray[_destSurface],
+ _destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom, _frontColor);
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom);
+ }
+ break;
+
+ case DRAW_INVALIDATE:
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX - _spriteRight, _destSpriteY - _spriteBottom, // !!
+ _destSpriteX + _spriteRight,
+ _destSpriteY + _spriteBottom);
+ }
+ break;
+
+ case DRAW_LOADSPRITE:
+ id = _spriteLeft;
+ if (id >= 30000) {
+ dataBuf =
+ _vm->_game->loadExtData(id, &_spriteRight,
+ &_spriteBottom);
+ _vm->_video->drawPackedSprite((byte *)dataBuf, _spriteRight,
+ _spriteBottom, _destSpriteX,
+ _destSpriteY, _transparency,
+ _spritesArray[_destSurface]);
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX,
+ _destSpriteY,
+ _destSpriteX + _spriteRight - 1,
+ _destSpriteY + _spriteBottom - 1);
+ }
+ delete[] dataBuf;
+ break;
+ }
+ // Load from .TOT resources
+ itemPtr = &_vm->_game->_totResourceTable->items[id];
+ offset = itemPtr->offset;
+ if (offset >= 0) {
+ dataBuf =
+ ((char *)_vm->_game->_totResourceTable) +
+ szGame_TotResTable + szGame_TotResItem *
+ _vm->_game->_totResourceTable->itemsCount + offset;
+ } else {
+ dataBuf =
+ _vm->_game->_imFileData +
+ (int32)READ_LE_UINT32(&((int32 *)_vm->_game->_imFileData)[-offset - 1]);
+ }
+
+ _spriteRight = itemPtr->width;
+ _spriteBottom = itemPtr->height;
+ _vm->_video->drawPackedSprite((byte *)dataBuf,
+ _spriteRight, _spriteBottom,
+ _destSpriteX, _destSpriteY,
+ _transparency, _spritesArray[_destSurface]);
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _destSpriteX + _spriteRight - 1,
+ _destSpriteY + _spriteBottom - 1);
+ }
+ break;
+
+ case DRAW_PRINTTEXT:
+ len = strlen(_textToPrint);
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _destSpriteX +
+ len * _fonts[_fontIndex]->itemWidth - 1,
+ _destSpriteY +
+ _fonts[_fontIndex]->itemHeight - 1);
+ }
+
+ for (i = 0; i < len; i++) {
+ _vm->_video->drawLetter(_textToPrint[i],
+ _destSpriteX, _destSpriteY,
+ _fonts[_fontIndex],
+ _transparency,
+ _frontColor, _backColor,
+ _spritesArray[_destSurface]);
+
+ _destSpriteX += _fonts[_fontIndex]->itemWidth;
+ }
+ break;
+
+ case DRAW_DRAWBAR:
+ _vm->_video->drawLine(_spritesArray[_destSurface],
+ _destSpriteX, _spriteBottom,
+ _spriteRight, _spriteBottom, _frontColor);
+
+ _vm->_video->drawLine(_spritesArray[_destSurface],
+ _destSpriteX, _destSpriteY,
+ _destSpriteX, _spriteBottom, _frontColor);
+
+ _vm->_video->drawLine(_spritesArray[_destSurface],
+ _spriteRight, _destSpriteY,
+ _spriteRight, _spriteBottom, _frontColor);
+
+ _vm->_video->drawLine(_spritesArray[_destSurface],
+ _destSpriteX, _destSpriteY,
+ _spriteRight, _destSpriteY, _frontColor);
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom);
+ }
+ break;
+
+ case DRAW_CLEARRECT:
+ if (_backColor < 16) {
+ _vm->_video->fillRect(_spritesArray[_destSurface],
+ _destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom,
+ _backColor);
+ }
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom);
+ }
+ break;
+
+ case DRAW_FILLRECTABS:
+ _vm->_video->fillRect(_spritesArray[_destSurface],
+ _destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom, _backColor);
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom);
+ }
+ break;
+
+ case DRAW_DRAWLETTER:
+ if (_fontToSprite[_fontIndex].sprite == -1) {
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX,
+ _destSpriteY,
+ _destSpriteX +
+ _fonts[_fontIndex]->itemWidth - 1,
+ _destSpriteY +
+ _fonts[_fontIndex]->itemHeight -
+ 1);
+ }
+ _vm->_video->drawLetter(_letterToPrint,
+ _destSpriteX, _destSpriteY,
+ _fonts[_fontIndex],
+ _transparency,
+ _frontColor, _backColor,
+ _spritesArray[_destSurface]);
+ break;
+ }
+
+ perLine =
+ _spritesArray[(int16)_fontToSprite[_fontIndex].
+ sprite]->width / _fontToSprite[_fontIndex].width;
+
+ y = (_letterToPrint -
+ _fontToSprite[_fontIndex].base) / perLine *
+ _fontToSprite[_fontIndex].height;
+
+ x = (_letterToPrint -
+ _fontToSprite[_fontIndex].base) % perLine *
+ _fontToSprite[_fontIndex].width;
+
+ if (_destSurface == 21) {
+ invalidateRect(_destSpriteX, _destSpriteY,
+ _destSpriteX +
+ _fontToSprite[_fontIndex].width,
+ _destSpriteY +
+ _fontToSprite[_fontIndex].height);
+ }
+
+ _vm->_video->drawSprite(_spritesArray[(int16)_fontToSprite
+ [_fontIndex].sprite],
+ _spritesArray[_destSurface], x, y,
+ x + _fontToSprite[_fontIndex].width,
+ y + _fontToSprite[_fontIndex].height,
+ _destSpriteX, _destSpriteY, _transparency);
+
+ break;
+ }
+
+ if (_renderFlags & RENDERFLAG_USEDELTAS) {
+ if (_sourceSurface == 21) {
+ _spriteLeft -= _backDeltaX;
+ _spriteTop -= _backDeltaY;
+ }
+
+ if (_destSurface == 21) {
+ _destSpriteX -= _backDeltaX;
+ _destSpriteY -= _backDeltaY;
+ }
+ }
+}
+
+void Draw::animateCursor(int16 cursor) {
+ int16 newX = 0;
+ int16 newY = 0;
+ Game::Collision *ptr;
+ int16 minX;
+ int16 minY;
+ int16 maxX;
+ int16 maxY;
+ int16 cursorIndex;
+
+ cursorIndex = cursor;
+
+ if (cursorIndex == -1) {
+ cursorIndex = 0;
+ for (ptr = _vm->_game->_collisionAreas; ptr->left != -1; ptr++) {
+ if (ptr->flags & 0xfff0)
+ continue;
+
+ if (ptr->left > _vm->_global->_inter_mouseX)
+ continue;
+
+ if (ptr->right < _vm->_global->_inter_mouseX)
+ continue;
+
+ if (ptr->top > _vm->_global->_inter_mouseY)
+ continue;
+
+ if (ptr->bottom < _vm->_global->_inter_mouseY)
+ continue;
+
+ if ((ptr->flags & 0xf) < 3)
+ cursorIndex = 1;
+ else
+ cursorIndex = 3;
+ break;
+ }
+ if (_cursorAnimLow[cursorIndex] == -1)
+ cursorIndex = 1;
+ }
+
+ if (_cursorAnimLow[cursorIndex] != -1) {
+ if (cursorIndex == _cursorIndex) {
+ if (_cursorAnimDelays[_cursorIndex] != 0 &&
+ _cursorAnimDelays[_cursorIndex] * 10 +
+ _cursorTimeKey <= _vm->_util->getTimeKey()) {
+ _cursorAnim++;
+ _cursorTimeKey = _vm->_util->getTimeKey();
+ } else {
+/* if (_noInvalidated &&
+ inter_mouseX == _cursorX && inter_mouseY == _cursorY)
+ return;*/
+ }
+ } else {
+ _cursorIndex = cursorIndex;
+ if (_cursorAnimDelays[_cursorIndex] != 0) {
+ _cursorAnim =
+ _cursorAnimLow[_cursorIndex];
+ _cursorTimeKey = _vm->_util->getTimeKey();
+ } else {
+ _cursorAnim = _cursorIndex;
+ }
+ }
+
+ if (_cursorAnimDelays[_cursorIndex] != 0 &&
+ (_cursorAnimHigh[_cursorIndex] < _cursorAnim ||
+ _cursorAnimLow[_cursorIndex] >
+ _cursorAnim)) {
+ _cursorAnim = _cursorAnimLow[_cursorIndex];
+ }
+
+ newX = _vm->_global->_inter_mouseX;
+ newY = _vm->_global->_inter_mouseY;
+ if (_cursorXDeltaVar != -1) {
+ newX -= (uint16)VAR_OFFSET(_cursorIndex * 4 + (_cursorXDeltaVar / 4) * 4);
+ newY -= (uint16)VAR_OFFSET(_cursorIndex * 4 + (_cursorYDeltaVar / 4) * 4);
+ }
+
+ minX = MIN(newX, _cursorX);
+ minY = MIN(newY, _cursorY);
+ maxX = MAX(_cursorX, newX) + _cursorWidth - 1;
+ maxY = MAX(_cursorY, newY) + _cursorHeight - 1;
+ _vm->_video->drawSprite(_backSurface, _cursorBack,
+ newX, newY, newX + _cursorWidth - 1,
+ newY + _cursorHeight - 1, 0, 0, 0);
+
+ _vm->_video->drawSprite(_cursorSprites, _backSurface,
+ _cursorWidth * _cursorAnim, 0,
+ _cursorWidth * (_cursorAnim + 1) - 1,
+ _cursorHeight - 1, newX, newY, _transparentCursor);
+
+ if (_noInvalidated == 0) {
+ cursorIndex = _cursorIndex;
+ _cursorIndex = -1;
+ blitInvalidated();
+ _cursorIndex = cursorIndex;
+ } else {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+ }
+
+ _vm->_video->drawSprite(_backSurface, _frontSurface,
+ minX, minY, maxX, maxY, minX, minY, 0);
+
+ _vm->_video->drawSprite(_cursorBack, _backSurface,
+ 0, 0, _cursorWidth - 1, _cursorHeight - 1,
+ newX, newY, 0);
+ } else {
+ blitCursor();
+ }
+
+ _cursorX = newX;
+ _cursorY = newY;
+}
+
+void Draw::printText(void) {
+ int16 savedFlags;
+ int16 ldestSpriteX;
+ char *dataPtr;
+ char *ptr;
+ char *ptr2;
+ int16 index;
+ int16 destX;
+ int16 destY;
+ char cmd;
+ int16 val;
+ char buf[20];
+
+ index = _vm->_inter->load16();
+
+ _vm->_cdrom->playMultMusic();
+
+ dataPtr = (char *)_vm->_game->_totTextData + _vm->_game->_totTextData->items[index].offset;
+ ptr = dataPtr;
+
+ if (_renderFlags & RENDERFLAG_CAPTUREPUSH) {
+ _destSpriteX = READ_LE_UINT16(ptr);
+ _destSpriteY = READ_LE_UINT16(ptr + 2);
+ _spriteRight = READ_LE_UINT16(ptr + 4) - _destSpriteX + 1;
+ _spriteBottom = READ_LE_UINT16(ptr + 6) - _destSpriteY + 1;
+ _vm->_game->capturePush(_destSpriteX, _destSpriteY,
+ _spriteRight, _spriteBottom);
+ (*_vm->_scenery->_pCaptureCounter)++;
+ }
+ _destSpriteX = READ_LE_UINT16(ptr);
+ destX = _destSpriteX;
+
+ _destSpriteY = READ_LE_UINT16(ptr + 2);
+ destY = _destSpriteY;
+
+ _spriteRight = READ_LE_UINT16(ptr + 4);
+ _spriteBottom = READ_LE_UINT16(ptr + 6);
+ _destSurface = 21;
+
+ ptr += 8;
+
+ _backColor = *ptr++;
+ _transparency = 1;
+ spriteOperation(DRAW_CLEARRECT);
+
+ _backColor = 0;
+ savedFlags = _renderFlags;
+
+ _renderFlags &= ~RENDERFLAG_NOINVALIDATE;
+ for (; (_destSpriteX = READ_LE_UINT16(ptr)) != -1; ptr++) {
+ _destSpriteX += destX;
+ _destSpriteY = READ_LE_UINT16(ptr + 2) + destY;
+ _spriteRight = READ_LE_UINT16(ptr + 4) + destX;
+ _spriteBottom = READ_LE_UINT16(ptr + 6) + destY;
+ ptr += 8;
+
+ cmd = (*ptr & 0xf0) >> 4;
+ if (cmd == 0) {
+ _frontColor = *ptr & 0xf;
+ spriteOperation(DRAW_DRAWLINE);
+ } else if (cmd == 1) {
+ _frontColor = *ptr & 0xf;
+ spriteOperation(DRAW_DRAWBAR);
+ } else if (cmd == 2) {
+ _backColor = *ptr & 0xf;
+ spriteOperation(DRAW_FILLRECTABS);
+ }
+ }
+ ptr += 2;
+
+ for (ptr2 = ptr; *ptr2 != 1; ptr2++) {
+ if (*ptr2 == 3)
+ ptr2++;
+
+ if (*ptr2 == 2)
+ ptr2 += 4;
+ }
+
+ ptr2++;
+
+ while (*ptr != 1) {
+ cmd = *ptr;
+ if (cmd == 3) {
+ ptr++;
+ _fontIndex = (*ptr & 0xf0) >> 4;
+ _frontColor = *ptr & 0xf;
+ ptr++;
+ continue;
+ } else if (cmd == 2) {
+ ptr++;
+ _destSpriteX = destX + READ_LE_UINT16(ptr);
+ _destSpriteY = destY + READ_LE_UINT16(ptr + 2);
+ ptr += 4;
+ continue;
+ }
+
+ if ((byte)*ptr != 0xba) {
+ _letterToPrint = *ptr;
+ spriteOperation(DRAW_DRAWLETTER);
+ _destSpriteX +=
+ _fonts[_fontIndex]->itemWidth;
+ ptr++;
+ } else {
+ cmd = ptr2[17] & 0x7f;
+ if (cmd == 0) {
+ val = READ_LE_UINT16(ptr2 + 18) * 4;
+ sprintf(buf, "%d", VAR_OFFSET(val));
+ } else if (cmd == 1) {
+ val = READ_LE_UINT16(ptr2 + 18) * 4;
+
+ strcpy(buf, _vm->_global->_inter_variables + val);
+ } else {
+ val = READ_LE_UINT16(ptr2 + 18) * 4;
+
+ sprintf(buf, "%d", VAR_OFFSET(val));
+ if (buf[0] == '-') {
+ while (strlen(buf) - 1 < (uint32)ptr2[17]) {
+ _vm->_util->insertStr("0", buf, 1);
+ }
+ } else {
+ while (strlen(buf) - 1 < (uint32)ptr2[17]) {
+ _vm->_util->insertStr("0", buf, 0);
+ }
+ }
+
+ _vm->_util->insertStr(",", buf, strlen(buf) + 1 - ptr2[17]);
+ }
+
+ _textToPrint = buf;
+ ldestSpriteX = _destSpriteX;
+ spriteOperation(DRAW_PRINTTEXT);
+ if (ptr2[17] & 0x80) {
+ if (ptr[1] == ' ') {
+ _destSpriteX += _fonts[_fontIndex]->itemWidth;
+ while (ptr[1] == ' ')
+ ptr++;
+ if (ptr[1] == 2) {
+ if (READ_LE_UINT16(ptr + 4) == _destSpriteY)
+ ptr += 5;
+ }
+ } else if (ptr[1] == 2 && READ_LE_UINT16(ptr + 4) == _destSpriteY) {
+ ptr += 5;
+ _destSpriteX += _fonts[_fontIndex]->itemWidth;
+ }
+ } else {
+ _destSpriteX = ldestSpriteX + _fonts[_fontIndex]->itemWidth;
+ }
+ ptr2 += 23;
+ ptr++;
+ }
+ }
+
+ _renderFlags = savedFlags;
+ if (_renderFlags & 4) {
+ warning("printText: Input not supported!");
+// xor ax, ax
+// loc_436_1391:
+// xor dx, dx
+// push ax
+// push dx
+// push ax
+// push dx
+// push ax
+// mov al, 0
+// push ax
+// call sub_9FF_1E71
+// add sp, 0Ch
+ }
+
+ if ((_renderFlags & RENDERFLAG_CAPTUREPOP) && *_vm->_scenery->_pCaptureCounter != 0) {
+ (*_vm->_scenery->_pCaptureCounter)--;
+ _vm->_game->capturePop(1);
+ }
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/draw.h b/engines/gob/draw.h
new file mode 100644
index 0000000000..77fcd3f349
--- /dev/null
+++ b/engines/gob/draw.h
@@ -0,0 +1,139 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_DRAW_H
+#define GOB_DRAW_H
+
+#include "gob/video.h"
+
+namespace Gob {
+
+#define RENDERFLAG_NOINVALIDATE 1
+#define RENDERFLAG_CAPTUREPUSH 2
+#define RENDERFLAG_CAPTUREPOP 8
+#define RENDERFLAG_USEDELTAS 0x10
+
+class Draw {
+public:
+ struct FontToSprite {
+ int8 sprite;
+ int8 base;
+ int8 width;
+ int8 height;
+ FontToSprite() : sprite(0), base(0), width(0), height() {}
+ };
+
+ int16 _fontIndex;
+ int16 _spriteLeft;
+ int16 _spriteTop;
+ int16 _spriteRight;
+ int16 _spriteBottom;
+ int16 _destSpriteX;
+ int16 _destSpriteY;
+ int16 _backColor;
+ int16 _frontColor;
+ char _letterToPrint;
+ FontToSprite _fontToSprite[4];
+ int16 _destSurface;
+ int16 _sourceSurface;
+ int16 _renderFlags;
+ int16 _backDeltaX;
+ int16 _backDeltaY;
+ Video::FontDesc *_fonts[4];
+ char *_textToPrint;
+ int16 _transparency;
+ Video::SurfaceDesc *_spritesArray[50];
+
+ int16 _invalidatedCount;
+ int16 _invalidatedTops[30];
+ int16 _invalidatedLefts[30];
+ int16 _invalidatedRights[30];
+ int16 _invalidatedBottoms[30];
+
+ int8 _noInvalidated;
+// int8 doFullFlip; // Never used?!?
+ int8 _paletteCleared;
+
+ int16 _cursorIndex;
+ int16 _transparentCursor;
+ uint32 _cursorTimeKey;
+
+ Video::SurfaceDesc *_backSurface;
+ Video::SurfaceDesc *_frontSurface;
+
+ int16 _unusedPalette1[18];
+ int16 _unusedPalette2[16];
+ Video::Color _vgaPalette[256];
+ Video::Color _vgaSmallPalette[16];
+
+ int16 _cursorX;
+ int16 _cursorY;
+ int16 _cursorWidth;
+ int16 _cursorHeight;
+
+ int16 _cursorXDeltaVar;
+ int16 _cursorYDeltaVar;
+
+ Video::SurfaceDesc *_cursorSprites;
+ Video::SurfaceDesc *_cursorBack;
+ int16 _cursorAnim;
+ int8 _cursorAnimLow[40];
+ int8 _cursorAnimHigh[40];
+ int8 _cursorAnimDelays[40];
+ int8 _applyPal;
+
+ int16 _palLoadData1[4];
+ int16 _palLoadData2[4];
+
+ void invalidateRect(int16 left, int16 top, int16 right, int16 bottom);
+ void blitInvalidated(void);
+ void setPalette(void);
+ void clearPalette(void);
+ void blitCursor(void);
+
+ void spriteOperation(int16 operation);
+ void animateCursor(int16 cursor);
+ void printText(void);
+
+ Draw(GobEngine *vm);
+
+protected:
+ GobEngine *_vm;
+};
+
+// Draw operations
+
+#define DRAW_BLITSURF 0
+#define DRAW_PUTPIXEL 1
+#define DRAW_FILLRECT 2
+#define DRAW_DRAWLINE 3
+#define DRAW_INVALIDATE 4
+#define DRAW_LOADSPRITE 5
+#define DRAW_PRINTTEXT 6
+#define DRAW_DRAWBAR 7
+#define DRAW_CLEARRECT 8
+#define DRAW_FILLRECTABS 9
+#define DRAW_DRAWLETTER 10
+
+} // End of namespace Gob
+
+#endif /* __DRAW_H */
diff --git a/engines/gob/driver_vga.cpp b/engines/gob/driver_vga.cpp
new file mode 100644
index 0000000000..3a2f44bc11
--- /dev/null
+++ b/engines/gob/driver_vga.cpp
@@ -0,0 +1,156 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/driver_vga.h"
+#include "graphics/primitives.h"
+
+#if defined (_MSC_VER) || defined (__WINS__)
+#define STUB_FUNC printf("STUB:")
+#else
+#define STUB_FUNC printf("STUB: %s\n", __PRETTY_FUNCTION__)
+#endif
+
+namespace Gob {
+
+void VGAVideoDriver::drawSprite(Video::SurfaceDesc *source, Video::SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp) {
+ if (x >= 0 && x < dest->width && y >= 0 && y < dest->height) {
+ int16 width = (right - left) + 1;
+ int16 height = (bottom - top) + 1;
+
+ byte *srcPos = source->vidPtr + (top * source->width) + left;
+ byte *destPos = dest->vidPtr + (y * dest->width) + x;
+ while (height--) {
+ if (transp) {
+ for (int16 i = 0; i < width; ++i) {
+ if (srcPos[i])
+ destPos[i] = srcPos[i];
+ }
+ } else {
+ for (int16 i = 0; i < width; ++i)
+ destPos[i] = srcPos[i];
+ }
+
+ srcPos += source->width; //width ?
+ destPos += dest->width;
+ }
+ }
+}
+
+void VGAVideoDriver::fillRect(Video::SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, byte color) {
+ if (left < dest->width && right < dest->width && top < dest->height && bottom < dest->height) {
+ byte *pos = dest->vidPtr + (top * dest->width) + left;
+ int16 width = (right - left) + 1;
+ int16 height = (bottom - top) + 1;
+ while (height--) {
+ for (int16 i = 0; i < width; ++i) {
+ pos[i] = color;
+ }
+
+ pos += dest->width;
+ }
+ }
+}
+
+void VGAVideoDriver::putPixel(int16 x, int16 y, byte color, Video::SurfaceDesc *dest) {
+ if (x >= 0 && x < dest->width && y >= 0 && y < dest->height)
+ dest->vidPtr[(y * dest->width) + x] = color;
+}
+
+void VGAVideoDriver::drawLetter(unsigned char item, int16 x, int16 y, Video::FontDesc *fontDesc, byte color1, byte color2, byte transp, Video::SurfaceDesc *dest) {
+ byte *src, *dst;
+ uint16 data;
+ int i, j;
+
+ src = (byte *)fontDesc->dataPtr + (item - fontDesc->startItem) * (fontDesc->itemSize & 0xff);
+ dst = dest->vidPtr + x + dest->width * y;
+
+ for (i = 0; i < fontDesc->itemHeight; i++) {
+ data = READ_BE_UINT16(src);
+ src += 2;
+ if (fontDesc->itemSize <= 8)
+ src--;
+
+ for (j = 0; j < fontDesc->itemWidth; j++) {
+ if (data & 0x8000) {
+ *dst = color2;
+ } else {
+ if (color1 == 0)
+ *dst = transp;
+ }
+ dst++;
+ data <<= 1;
+ }
+ dst += dest->width - fontDesc->itemWidth;
+ }
+}
+
+static void plotPixel(int x, int y, int color, void *data) {
+ Video::SurfaceDesc *dest = (Video::SurfaceDesc *)data;
+ if (x >= 0 && x < dest->width && y >= 0 && y < dest->height)
+ dest->vidPtr[(y * dest->width) + x] = color;
+}
+
+void VGAVideoDriver::drawLine(Video::SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, int16 y1, byte color) {
+ Graphics::drawLine(x0, y0, x1, y1, color, &plotPixel, dest);
+}
+
+void VGAVideoDriver::drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y, byte transp, Video::SurfaceDesc *dest) {
+ int destRight = x + width;
+ int destBottom = y + height;
+
+ byte* dst = dest->vidPtr + x + dest->width * y;
+
+ int curx = x;
+ int cury = y;
+
+ while (1) {
+ uint8 val = *sprBuf++;
+ unsigned int repeat = val & 7;
+ val &= 0xF8;
+ if (!(val & 8)) {
+ repeat <<= 8;
+ repeat |= *sprBuf++;
+ }
+ repeat++;
+ val >>= 4;
+
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (curx < dest->width && cury < dest->height)
+ if (!transp || val)
+ *dst = val;
+
+ dst++;
+ curx++;
+ if (curx == destRight) {
+ dst += dest->width + x - curx;
+ curx = x;
+ cury++;
+ if (cury == destBottom)
+ return;
+ }
+ }
+ }
+
+}
+
+}
+
diff --git a/engines/gob/driver_vga.h b/engines/gob/driver_vga.h
new file mode 100644
index 0000000000..de80b61c5f
--- /dev/null
+++ b/engines/gob/driver_vga.h
@@ -0,0 +1,44 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_DRIVER_VGA_H
+#define GOB_DRIVER_VGA_H
+
+#include "gob/video.h"
+
+namespace Gob {
+
+class VGAVideoDriver : public VideoDriver {
+public:
+ VGAVideoDriver() {}
+ virtual ~VGAVideoDriver() {}
+ void drawSprite(Video::SurfaceDesc *source, Video::SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp);
+ void fillRect(Video::SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, byte color);
+ void putPixel(int16 x, int16 y, byte color, Video::SurfaceDesc *dest);
+ void drawLetter(unsigned char item, int16 x, int16 y, Video::FontDesc *fontDesc, byte color1, byte color2, byte transp, Video::SurfaceDesc *dest);
+ void drawLine(Video::SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, int16 y1, byte color);
+ void drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y, byte transp, Video::SurfaceDesc *dest);
+};
+
+}
+
+#endif
diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp
new file mode 100644
index 0000000000..86544f0906
--- /dev/null
+++ b/engines/gob/game.cpp
@@ -0,0 +1,1952 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/game.h"
+#include "gob/video.h"
+#include "gob/dataio.h"
+#include "gob/pack.h"
+#include "gob/scenery.h"
+#include "gob/inter.h"
+#include "gob/parse.h"
+#include "gob/draw.h"
+#include "gob/mult.h"
+#include "gob/util.h"
+#include "gob/goblin.h"
+#include "gob/cdrom.h"
+#include "gob/music.h"
+
+namespace Gob {
+
+int16 Game::_captureCount = 0;
+Common::Rect Game::_captureStack[20];
+
+Game::Game(GobEngine *vm) : _vm(vm) {
+ _extTable = 0;
+ _totFileData = 0;
+ _totResourceTable = 0;
+ _imFileData = 0;
+ _extHandle = 0;
+ _collisionAreas = 0;
+ _shouldPushColls = 0;
+ _totTextData = 0;
+
+ // Collisions stack
+ _collStackSize = 0;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ _collStack[i] = 0;
+ _collStackElemSizes[i] = 0;
+ }
+
+ for (i = 0; i < 20; i++)
+ _soundSamples[i] = 0;
+
+ _curTotFile[0] = 0;
+ _curExtFile[0] = 0;
+ _totToLoad[0] = 0;
+
+ _startTimeKey = 0;
+ _mouseButtons = 0;
+
+ _lastCollKey = 0;
+ _lastCollAreaIndex = 0;
+ _lastCollId = 0;
+
+ _activeCollResId = 0;
+ _activeCollIndex = 0;
+ _handleMouse = 0;
+ _forceHandleMouse = 0;
+
+ _tempStr[0] = 0;
+ _curImaFile[0] = 0;
+ _soundFromExt[0] = 0;
+ _collStr[0] = 0;
+
+
+ // Capture
+}
+
+char *Game::loadExtData(int16 itemId, int16 *pResWidth, int16 *pResHeight) {
+ int16 commonHandle;
+ int16 itemsCount;
+ int32 offset;
+ uint32 size;
+ ExtItem *item;
+ char isPacked;
+ int16 handle;
+ int32 tableSize;
+ char path[20];
+ char *dataBuf;
+ char *packedBuf;
+ char *dataPtr;
+
+ itemId -= 30000;
+ if (_extTable == 0)
+ return 0;
+
+ commonHandle = -1;
+ itemsCount = _extTable->itemsCount;
+ item = &_extTable->items[itemId];
+ tableSize = szGame_ExtTable + szGame_ExtItem * itemsCount;
+
+ offset = item->offset;
+ size = item->size;
+ if (item->width & 0x8000)
+ isPacked = 1;
+ else
+ isPacked = 0;
+
+ if (pResWidth != 0) {
+ *pResWidth = item->width & 0x7fff;
+ *pResHeight = item->height;
+ debug(7, "loadExtData(%d, %d, %d)", itemId, *pResWidth, *pResHeight);
+ }
+
+ debug(7, "loadExtData(%d, 0, 0)", itemId);
+
+ if (item->height == 0)
+ size += (item->width & 0x7fff) << 16;
+
+ debug(7, "size: %d off: %d", size, offset);
+ if (offset >= 0) {
+ handle = _extHandle;
+ } else {
+ offset = -(offset + 1);
+ tableSize = 0;
+ _vm->_dataio->closeData(_extHandle);
+ strcpy(path, "commun.ex1");
+ path[strlen(path) - 1] = *(_totFileData + 0x3c) + '0';
+ commonHandle = _vm->_dataio->openData(path);
+ handle = commonHandle;
+ }
+
+ debug(7, "off: %ld size: %ld", offset, tableSize);
+ _vm->_dataio->seekData(handle, offset + tableSize, SEEK_SET);
+ // CHECKME: is the below correct?
+ if (isPacked)
+ dataBuf = new char[size];
+ else
+ dataBuf = new char[size];
+
+ dataPtr = dataBuf;
+ while (size > 32000) {
+ // BUG: huge->far conversion. Need normalization?
+ _vm->_dataio->readData(handle, (char *)dataPtr, 32000);
+ size -= 32000;
+ dataPtr += 32000;
+ }
+ _vm->_dataio->readData(handle, (char *)dataPtr, size);
+ if (commonHandle != -1) {
+ _vm->_dataio->closeData(commonHandle);
+ _extHandle = _vm->_dataio->openData(_curExtFile);
+ }
+
+ if (isPacked != 0) {
+ packedBuf = dataBuf;
+ dataBuf = new char[READ_LE_UINT32(packedBuf)];
+ _vm->_pack->unpackData(packedBuf, dataBuf);
+ delete[] packedBuf;
+ }
+
+ return dataBuf;
+
+}
+
+void Game::clearCollisions() {
+ int16 i;
+ for (i = 0; i < 250; i++) {
+ _collisionAreas[i].id = 0;
+ _collisionAreas[i].left = -1;
+ }
+}
+
+void Game::addNewCollision(int16 id, int16 left, int16 top, int16 right, int16 bottom,
+ int16 flags, int16 key, int16 funcEnter, int16 funcLeave) {
+ int16 i;
+ Collision *ptr;
+
+ debug(5, "addNewCollision");
+ debug(5, "id = %x", id);
+ debug(5, "left = %d, top = %d, right = %d, bottom = %d", left, top, right, bottom);
+ debug(5, "flags = %x, key = %x", flags, key);
+ debug(5, "funcEnter = %d, funcLeave = %d", funcEnter, funcLeave);
+
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left != -1)
+ continue;
+
+ ptr = &_collisionAreas[i];
+ ptr->id = id;
+ ptr->left = left;
+ ptr->top = top;
+ ptr->right = right;
+ ptr->bottom = bottom;
+ ptr->flags = flags;
+ ptr->key = key;
+ ptr->funcEnter = funcEnter;
+ ptr->funcLeave = funcLeave;
+ return;
+ }
+ error("addNewCollision: Collision array full!\n");
+}
+
+void Game::freeCollision(int16 id) {
+ int16 i;
+
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].id == id)
+ _collisionAreas[i].left = -1;
+ }
+}
+
+void Game::pushCollisions(char all) {
+ Collision *srcPtr;
+ Collision *destPtr;
+ int16 size;
+
+ debug(4, "pushCollisions");
+ for (size = 0, srcPtr = _collisionAreas; srcPtr->left != -1;
+ srcPtr++) {
+ if (all || (srcPtr->id & 0x8000))
+ size++;
+ }
+
+ destPtr = new Collision[size];
+ _collStack[_collStackSize] = destPtr;
+ _collStackElemSizes[_collStackSize] = size;
+ _collStackSize++;
+
+ for (srcPtr = _collisionAreas; srcPtr->left != -1; srcPtr++) {
+ if (all || (srcPtr->id & 0x8000)) {
+ memcpy(destPtr, srcPtr, sizeof(Collision));
+ srcPtr->left = -1;
+ destPtr++;
+ }
+ }
+}
+
+void Game::popCollisions(void) {
+ Collision *destPtr;
+ Collision *srcPtr;
+
+ debug(4, "popCollision");
+
+ _collStackSize--;
+ for (destPtr = _collisionAreas; destPtr->left != -1; destPtr++);
+
+ srcPtr = _collStack[_collStackSize];
+ memcpy(destPtr, srcPtr,
+ _collStackElemSizes[_collStackSize] *
+ sizeof(Collision));
+
+ free(_collStack[_collStackSize]);
+}
+
+int16 Game::checkMousePoint(int16 all, int16 *resId, int16 *resIndex) {
+ Collision *ptr;
+ int16 i;
+
+ if (resId != 0)
+ *resId = 0;
+
+ *resIndex = 0;
+
+ ptr = _collisionAreas;
+ for (i = 0; ptr->left != -1; ptr++, i++) {
+ if (all) {
+ if ((ptr->flags & 0xf) > 1)
+ continue;
+
+ if ((ptr->flags & 0xff00) != 0)
+ continue;
+
+ if (_vm->_global->_inter_mouseX < ptr->left
+ || _vm->_global->_inter_mouseX > ptr->right
+ || _vm->_global->_inter_mouseY < ptr->top
+ || _vm->_global->_inter_mouseY > ptr->bottom)
+ continue;
+
+ if (resId != 0)
+ *resId = ptr->id;
+
+ *resIndex = i;
+ return ptr->key;
+ } else {
+ if ((ptr->flags & 0xff00) != 0)
+ continue;
+
+ if ((ptr->flags & 0xf) != 1 && (ptr->flags & 0xf) != 2)
+ continue;
+
+ if ((ptr->flags & 0xf0) >> 4 != _mouseButtons - 1
+ && (ptr->flags & 0xf0) >> 4 != 2)
+ continue;
+
+ if (_vm->_global->_inter_mouseX < ptr->left
+ || _vm->_global->_inter_mouseX > ptr->right
+ || _vm->_global->_inter_mouseY < ptr->top
+ || _vm->_global->_inter_mouseY > ptr->bottom)
+ continue;
+
+ if (resId != 0)
+ *resId = ptr->id;
+ *resIndex = i;
+ return ptr->key;
+ }
+ }
+
+ if (_mouseButtons != 1 && all == 0)
+ return 0x11b;
+
+ return 0;
+}
+
+void Game::capturePush(int16 left, int16 top, int16 width, int16 height) {
+ int16 right;
+
+ if (_captureCount == 20)
+ error("capturePush: Capture stack overflow!");
+
+ _captureStack[_captureCount].left = left;
+ _captureStack[_captureCount].top = top;
+ _captureStack[_captureCount].right = left + width;
+ _captureStack[_captureCount].bottom = top + height;
+
+ _vm->_draw->_spriteTop = top;
+ _vm->_draw->_spriteBottom = height;
+
+ right = left + width - 1;
+ left &= 0xfff0;
+ right |= 0xf;
+
+ _vm->_draw->_spritesArray[30 + _captureCount] =
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, right - left + 1, height, 0);
+
+ _vm->_draw->_sourceSurface = 21;
+ _vm->_draw->_destSurface = 30 + _captureCount;
+
+ _vm->_draw->_spriteLeft = left;
+ _vm->_draw->_spriteRight = right - left + 1;
+ _vm->_draw->_destSpriteX = 0;
+ _vm->_draw->_destSpriteY = 0;
+ _vm->_draw->_transparency = 0;
+ _vm->_draw->spriteOperation(0);
+ _captureCount++;
+}
+
+void Game::capturePop(char doDraw) {
+ if (_captureCount <= 0)
+ return;
+
+ _captureCount--;
+ if (doDraw) {
+ _vm->_draw->_destSpriteX = _captureStack[_captureCount].left;
+ _vm->_draw->_destSpriteY = _captureStack[_captureCount].top;
+ _vm->_draw->_spriteRight =
+ _captureStack[_captureCount].width();
+ _vm->_draw->_spriteBottom =
+ _captureStack[_captureCount].height();
+
+ _vm->_draw->_transparency = 0;
+ _vm->_draw->_sourceSurface = 30 + _captureCount;
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_spriteLeft = _vm->_draw->_destSpriteX & 0xf;
+ _vm->_draw->_spriteTop = 0;
+ _vm->_draw->spriteOperation(0);
+ }
+ _vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[30 + _captureCount]);
+}
+
+char *Game::loadTotResource(int16 id) {
+ TotResItem *itemPtr;
+ int32 offset;
+
+ itemPtr = &_totResourceTable->items[id];
+ offset = itemPtr->offset;
+ if (offset >= 0) {
+ return ((char *)_totResourceTable) + szGame_TotResTable +
+ szGame_TotResItem * _totResourceTable->itemsCount + offset;
+ } else {
+ return (char *)(_imFileData + (int32)READ_LE_UINT32(&((int32 *)_imFileData)[-offset - 1]));
+ }
+}
+
+void Game::loadSound(int16 slot, char *dataPtr) {
+ Snd::SoundDesc *soundDesc;
+
+ soundDesc = new Snd::SoundDesc;
+
+ _soundSamples[slot] = soundDesc;
+
+ soundDesc->frequency = (dataPtr[4] << 8) + dataPtr[5];
+ soundDesc->size = (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3];
+ soundDesc->data = dataPtr + 6;
+ soundDesc->timerTicks = (int32)1193180 / (int32)soundDesc->frequency;
+
+ soundDesc->inClocks = (soundDesc->frequency * 10) / 182;
+ soundDesc->flag = 0;
+}
+
+void Game::interLoadSound(int16 slot) {
+ char *dataPtr;
+ int16 id;
+
+ if (slot == -1)
+ slot = _vm->_parse->parseValExpr();
+
+ id = _vm->_inter->load16();
+ if (id == -1) {
+ _vm->_global->_inter_execPtr += 9;
+ return;
+ }
+
+ if (id >= 30000) {
+ dataPtr = loadExtData(id, 0, 0);
+ _soundFromExt[slot] = 1;
+ } else {
+ dataPtr = loadTotResource(id);
+ _soundFromExt[slot] = 0;
+ }
+
+ loadSound(slot, dataPtr);
+}
+
+void Game::freeSoundSlot(int16 slot) {
+ if (slot == -1)
+ slot = _vm->_parse->parseValExpr();
+
+ if (_soundSamples[slot] == 0)
+ return;
+
+ if (_soundFromExt[slot] == 1) {
+ delete[] (_soundSamples[slot]->data - 6);
+ _soundFromExt[slot] = 0;
+ }
+
+ delete _soundSamples[slot];
+ _soundSamples[slot] = 0;
+}
+
+int16 Game::checkKeys(int16 *pMouseX, int16 *pMouseY, int16 *pButtons, char handleMouse) {
+ _vm->_util->processInput();
+
+ if (VAR(58) != 0) {
+ if (_vm->_mult->_frameStart != (int)VAR(58) - 1)
+ _vm->_mult->_frameStart++;
+ else
+ _vm->_mult->_frameStart = 0;
+
+ _vm->_mult->playMult(_vm->_mult->_frameStart + VAR(57), _vm->_mult->_frameStart + VAR(57), 1,
+ handleMouse);
+ }
+
+ if (_vm->_inter->_soundEndTimeKey != 0
+ && _vm->_util->getTimeKey() >= _vm->_inter->_soundEndTimeKey) {
+ _vm->_snd->stopSound(_vm->_inter->_soundStopVal);
+ _vm->_inter->_soundEndTimeKey = 0;
+ }
+
+ if (_vm->_global->_useMouse == 0)
+ error("checkKeys: Can't work without mouse!");
+
+ _vm->_util->getMouseState(pMouseX, pMouseY, pButtons);
+
+ if (*pButtons == 3)
+ *pButtons = 0;
+
+ return _vm->_util->checkKey();
+}
+
+int16 Game::checkCollisions(char handleMouse, int16 deltaTime, int16 *pResId,
+ int16 *pResIndex) {
+ char *savedIP;
+ int16 resIndex;
+ int16 key;
+ int16 oldIndex;
+ int16 oldId;
+ uint32 timeKey;
+
+ if (deltaTime >= -1) {
+ _lastCollKey = 0;
+ _lastCollAreaIndex = 0;
+ _lastCollId = 0;
+ }
+
+ if (pResId != 0)
+ *pResId = 0;
+
+ resIndex = 0;
+
+ if (_vm->_draw->_cursorIndex == -1 && handleMouse != 0
+ && _lastCollKey == 0) {
+ _lastCollKey =
+ checkMousePoint(1, &_lastCollId,
+ &_lastCollAreaIndex);
+
+ if (_lastCollKey != 0 && (_lastCollId & 0x8000) != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)_totFileData +
+ _collisionAreas[_lastCollAreaIndex].funcEnter;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+ }
+
+ if (handleMouse != 0)
+ _vm->_draw->animateCursor(-1);
+
+ timeKey = _vm->_util->getTimeKey();
+ while (1) {
+ if (_vm->_inter->_terminate) {
+ if (handleMouse)
+ _vm->_draw->blitCursor();
+ return 0;
+ }
+
+ if (_vm->_draw->_noInvalidated == 0) {
+ if (handleMouse)
+ _vm->_draw->animateCursor(-1);
+ else
+ _vm->_draw->blitInvalidated();
+ }
+
+ // NOTE: the original asm does the below checkKeys call
+ // _before_ this check. However, that can cause keypresses to get lost
+ // since there's a return statement in this check.
+ // Additionally, I added a 'deltaTime == -1' check there, since
+ // when this function is called with deltaTime == -1 in inputArea,
+ // and the return value is then discarded.
+ if (deltaTime < 0) {
+ uint32 curtime = _vm->_util->getTimeKey();
+ if (deltaTime == -1 || curtime + deltaTime > timeKey) {
+ if (pResId != 0)
+ *pResId = 0;
+
+ if (pResIndex != 0)
+ *pResIndex = 0;
+
+ return 0;
+ }
+ }
+
+ key = checkKeys(&_vm->_global->_inter_mouseX, &_vm->_global->_inter_mouseY,
+ &_mouseButtons, handleMouse);
+
+ if (handleMouse == 0 && _mouseButtons != 0) {
+ _vm->_util->waitMouseRelease(0);
+ key = 3;
+ }
+
+ if (key != 0) {
+
+ if (handleMouse == 1)
+ _vm->_draw->blitCursor();
+
+ if (pResId != 0)
+ *pResId = 0;
+
+ if (pResIndex != 0)
+ *pResIndex = 0;
+
+ if (_lastCollKey != 0 &&
+ _collisionAreas[_lastCollAreaIndex].funcLeave != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)_totFileData +
+ _collisionAreas[_lastCollAreaIndex].funcLeave;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+
+ _lastCollKey = 0;
+ if (key != 0)
+ return key;
+ }
+
+ if (handleMouse != 0) {
+ if (_mouseButtons != 0) {
+ oldIndex = 0;
+
+ _vm->_draw->animateCursor(2);
+ if (deltaTime <= 0) {
+ if (handleMouse == 1)
+ _vm->_util->waitMouseRelease(1);
+ } else if (deltaTime > 0) {
+ _vm->_util->delay(deltaTime);
+ }
+
+ _vm->_draw->animateCursor(-1);
+ if (pResId != 0)
+ *pResId = 0;
+
+ key = checkMousePoint(0, pResId, &resIndex);
+
+ if (pResIndex != 0)
+ *pResIndex = resIndex;
+
+ if (key != 0 || (pResId != 0 && *pResId != 0)) {
+ if (handleMouse == 1 && (deltaTime <= 0
+ || _mouseButtons == 0))
+ _vm->_draw->blitCursor();
+
+ if (_lastCollKey != 0 &&
+ _collisionAreas[_lastCollAreaIndex].funcLeave != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr =
+ (char *)_totFileData +
+ _collisionAreas[_lastCollAreaIndex].funcLeave;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+ _lastCollKey = 0;
+ return key;
+ }
+
+ if (_lastCollKey != 0 &&
+ _collisionAreas[_lastCollAreaIndex].funcLeave != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr =
+ (char *)_totFileData +
+ _collisionAreas[_lastCollAreaIndex].funcLeave;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+
+ _lastCollKey =
+ checkMousePoint(1, &_lastCollId,
+ &_lastCollAreaIndex);
+
+ if (_lastCollKey != 0
+ && (_lastCollId & 0x8000) != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr =
+ (char *)_totFileData +
+ _collisionAreas[_lastCollAreaIndex].funcEnter;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+ } else {
+
+ if (handleMouse != 0 &&
+ (_vm->_global->_inter_mouseX != _vm->_draw->_cursorX
+ || _vm->_global->_inter_mouseY != _vm->_draw->_cursorY)) {
+ oldIndex = _lastCollAreaIndex;
+ oldId = _lastCollId;
+
+ key =
+ checkMousePoint(1,
+ &_lastCollId,
+ &_lastCollAreaIndex);
+
+ if (key != _lastCollKey) {
+ if (_lastCollKey != 0
+ && (oldId & 0x8000) != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)_totFileData +
+ _collisionAreas[oldIndex].funcLeave;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+
+ _lastCollKey = key;
+ if (_lastCollKey != 0 && (_lastCollId & 0x8000) != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)_totFileData +
+ _collisionAreas[_lastCollAreaIndex].funcEnter;
+
+ _vm->_inter->funcBlock(0);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+ }
+ }
+ }
+ }
+
+ if (handleMouse != 0)
+ _vm->_draw->animateCursor(-1);
+
+ _vm->_util->delay(10);
+
+ _vm->_snd->loopSounds();
+ }
+}
+
+int16 Game::inputArea(int16 xPos, int16 yPos, int16 width, int16 height, int16 backColor,
+ int16 frontColor, char *str, int16 fontIndex, char inpType, int16 *pTotTime) {
+ int16 handleMouse;
+ uint32 editSize;
+ Video::FontDesc *pFont;
+ char curSym;
+ int16 key;
+ const char *str1;
+ const char *str2;
+ int16 i;
+ uint32 pos;
+ int16 flag;
+ int16 savedKey;
+
+ if (_handleMouse != 0 &&
+ (_vm->_global->_useMouse != 0 || _forceHandleMouse != 0))
+ handleMouse = 1;
+ else
+ handleMouse = 0;
+
+ pos = strlen(str);
+ pFont = _vm->_draw->_fonts[fontIndex];
+ editSize = width / pFont->itemWidth;
+
+ while (1) {
+ strcpy(_tempStr, str);
+ strcat(_tempStr, " ");
+ if (strlen(_tempStr) > editSize)
+ strcpy(_tempStr, str);
+
+ _vm->_draw->_destSpriteX = xPos;
+ _vm->_draw->_destSpriteY = yPos;
+ _vm->_draw->_spriteRight = editSize * pFont->itemWidth;
+ _vm->_draw->_spriteBottom = height;
+
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_backColor = backColor;
+ _vm->_draw->_frontColor = frontColor;
+ _vm->_draw->_textToPrint = _tempStr;
+ _vm->_draw->_transparency = 1;
+ _vm->_draw->_fontIndex = fontIndex;
+ _vm->_draw->spriteOperation(DRAW_FILLRECT);
+
+ _vm->_draw->_destSpriteY = yPos + (height - 8) / 2;
+
+ _vm->_draw->spriteOperation(DRAW_PRINTTEXT);
+ if (pos == editSize)
+ pos--;
+
+ curSym = _tempStr[pos];
+
+ flag = 1;
+
+ while (1) {
+ _tempStr[0] = curSym;
+ _tempStr[1] = 0;
+
+ _vm->_draw->_destSpriteX = xPos + pFont->itemWidth * pos;
+ _vm->_draw->_destSpriteY = yPos + height - 1;
+ _vm->_draw->_spriteRight = pFont->itemWidth;
+ _vm->_draw->_spriteBottom = 1;
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_backColor = frontColor;
+ _vm->_draw->spriteOperation(DRAW_FILLRECT);
+
+ if (flag != 0) {
+ key = checkCollisions(handleMouse, -1,
+ &_activeCollResId,
+ &_activeCollIndex);
+ }
+ flag = 0;
+
+ key = checkCollisions(handleMouse, -300,
+ &_activeCollResId, &_activeCollIndex);
+
+ if (*pTotTime > 0) {
+ *pTotTime -= 300;
+ if (*pTotTime <= 1) {
+ key = 0;
+ _activeCollResId = 0;
+ break;
+ }
+ }
+
+ _tempStr[0] = curSym;
+ _tempStr[1] = 0;
+ _vm->_draw->_destSpriteX = xPos + pFont->itemWidth * pos;
+ _vm->_draw->_destSpriteY = yPos + height - 1;
+ _vm->_draw->_spriteRight = pFont->itemWidth;
+ _vm->_draw->_spriteBottom = 1;
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_backColor = backColor;
+ _vm->_draw->_frontColor = frontColor;
+ _vm->_draw->_textToPrint = _tempStr;
+ _vm->_draw->_transparency = 1;
+ _vm->_draw->spriteOperation(DRAW_FILLRECT);
+
+ _vm->_draw->_destSpriteY = yPos + (height - 8) / 2;
+ _vm->_draw->spriteOperation(DRAW_PRINTTEXT);
+
+ if (key != 0 || _activeCollResId != 0)
+ break;
+
+ key = checkCollisions(handleMouse, -300,
+ &_activeCollResId, &_activeCollIndex);
+
+ if (*pTotTime > 0) {
+ *pTotTime -= 300;
+ if (*pTotTime <= 1) {
+ key = 0;
+ _activeCollResId = 0;
+ break;
+ }
+
+ }
+ if (key != 0 || _activeCollResId != 0)
+ break;
+
+ if (_vm->_inter->_terminate)
+ return 0;
+ }
+
+ if (key == 0 || _activeCollResId != 0 || _vm->_inter->_terminate)
+ return 0;
+
+ switch (key) {
+ case 0x4d00: // Right Arrow
+ if (pos < strlen(str) && pos < editSize - 1) {
+ pos++;
+ continue;
+ }
+ return 0x5000;
+
+ case 0x4b00: // Left Arrow
+ if (pos > 0) {
+ pos--;
+ continue;
+ }
+ return 0x4800;
+
+ case 0xe08: // Backspace
+ if (pos > 0) {
+ _vm->_util->cutFromStr(str, pos - 1, 1);
+ pos--;
+ continue;
+ }
+
+ case 0x5300: // Del
+
+ if (pos >= strlen(str))
+ continue;
+
+ _vm->_util->cutFromStr(str, pos, 1);
+ continue;
+
+ case 0x1c0d: // Enter
+ case 0x3b00: // F1
+ case 0x3c00: // F2
+ case 0x3d00: // F3
+ case 0x3e00: // F4
+ case 0x3f00: // F5
+ case 0x4000: // F6
+ case 0x4100: // F7
+ case 0x4200: // F8
+ case 0x4300: // F9
+ case 0x4400: // F10
+ case 0x4800: // Up arrow
+ case 0x5000: // Down arrow
+ return key;
+
+ case 0x11b: // Escape
+ if (_vm->_global->_useMouse != 0)
+ continue;
+
+ _forceHandleMouse = !_forceHandleMouse;
+
+ if (_handleMouse != 0 &&
+ (_vm->_global->_useMouse != 0 || _forceHandleMouse != 0))
+ handleMouse = 1;
+ else
+ handleMouse = 0;
+
+ if (_vm->_global->_pressedKeys[1] == 0)
+ continue;
+
+ while (_vm->_global->_pressedKeys[1] != 0);
+ continue;
+
+ default:
+
+ savedKey = key;
+ key &= 0xff;
+
+ if ((inpType == 9 || inpType == 10) && key >= ' '
+ && key <= 0xff) {
+ str1 = "0123456789-.,+ ";
+ str2 = "0123456789-,,+ ";
+
+ if ((savedKey >> 8) > 1
+ && (savedKey >> 8) < 12)
+ key = ((savedKey >> 8) - 1) % 10 + '0';
+
+ for (i = 0; str1[i] != 0; i++) {
+ if (key == str1[i]) {
+ key = str2[i];
+ break;
+ }
+ }
+
+ if (i == (int16)strlen(str1))
+ key = 0;
+ }
+
+ if (key >= ' ' && key <= 0xff) {
+ if (editSize == strlen(str))
+ _vm->_util->cutFromStr(str, strlen(str) - 1,
+ 1);
+
+ if (key >= 'a' && key <= 'z')
+ key += ('A' - 'a');
+
+ pos++;
+ _tempStr[0] = key;
+ _tempStr[1] = 0;
+
+ _vm->_util->insertStr(_tempStr, str, pos - 1);
+
+ //strupr(str);
+ }
+ }
+ }
+}
+
+int16 Game::multiEdit(int16 time, int16 index, int16 *pCurPos, InputDesc * inpDesc) {
+ Collision *collArea;
+ int16 descInd;
+ int16 key;
+ int16 found = -1;
+ int16 i;
+
+ descInd = 0;
+ for (i = 0; i < 250; i++) {
+ collArea = &_collisionAreas[i];
+
+ if (collArea->left == -1)
+ continue;
+
+ if ((collArea->id & 0x8000) == 0)
+ continue;
+
+ if ((collArea->flags & 0x0f) < 3)
+ continue;
+
+ if ((collArea->flags & 0x0f) > 10)
+ continue;
+
+ strcpy(_tempStr, _vm->_global->_inter_variables + collArea->key);
+
+ _vm->_draw->_destSpriteX = collArea->left;
+ _vm->_draw->_destSpriteY = collArea->top;
+ _vm->_draw->_spriteRight = collArea->right - collArea->left + 1;
+ _vm->_draw->_spriteBottom = collArea->bottom - collArea->top + 1;
+
+ _vm->_draw->_destSurface = 21;
+
+ _vm->_draw->_backColor = inpDesc[descInd].backColor;
+ _vm->_draw->_frontColor = inpDesc[descInd].frontColor;
+ _vm->_draw->_textToPrint = _tempStr;
+ _vm->_draw->_transparency = 1;
+ _vm->_draw->_fontIndex = inpDesc[descInd].fontIndex;
+ _vm->_draw->spriteOperation(DRAW_FILLRECT);
+ _vm->_draw->_destSpriteY +=
+ ((collArea->bottom - collArea->top + 1) - 8) / 2;
+
+ _vm->_draw->spriteOperation(DRAW_PRINTTEXT);
+ descInd++;
+ }
+
+ for (i = 0; i < 40; i++) {
+ WRITE_VAR_OFFSET(i * 4 + 0x44, 0);
+ }
+
+ while (1) {
+ descInd = 0;
+
+ for (i = 0; i < 250; i++) {
+ collArea = &_collisionAreas[i];
+
+ if (collArea->left == -1)
+ continue;
+
+ if ((collArea->id & 0x8000) == 0)
+ continue;
+
+ if ((collArea->flags & 0x0f) < 3)
+ continue;
+
+ if ((collArea->flags & 0x0f) > 10)
+ continue;
+
+ if (descInd == *pCurPos) {
+ found = i;
+ break;
+ }
+
+ descInd++;
+ }
+
+ assert(found != -1);
+
+ collArea = &_collisionAreas[found];
+
+ key = inputArea(collArea->left, collArea->top,
+ collArea->right - collArea->left + 1,
+ collArea->bottom - collArea->top + 1,
+ inpDesc[*pCurPos].backColor, inpDesc[*pCurPos].frontColor,
+ _vm->_global->_inter_variables + collArea->key,
+ inpDesc[*pCurPos].fontIndex, collArea->flags, &time);
+
+ if (_vm->_inter->_terminate)
+ return 0;
+
+ switch (key) {
+ case 0:
+ if (_activeCollResId == 0)
+ return 0;
+
+ if ((_collisionAreas[_activeCollIndex].
+ flags & 0x0f) < 3)
+ return 0;
+
+ if ((_collisionAreas[_activeCollIndex].
+ flags & 0x0f) > 10)
+ return 0;
+
+ *pCurPos = 0;
+ for (i = 0; i < 250; i++) {
+ collArea = &_collisionAreas[i];
+
+ if (collArea->left == -1)
+ continue;
+
+ if ((collArea->id & 0x8000) == 0)
+ continue;
+
+ if ((collArea->flags & 0x0f) < 3)
+ continue;
+
+ if ((collArea->flags & 0x0f) > 10)
+ continue;
+
+ if (i == _activeCollIndex)
+ break;
+
+ pCurPos[0]++;
+ }
+ break;
+
+ case 0x3b00:
+ case 0x3c00:
+ case 0x3d00:
+ case 0x3e00:
+ case 0x3f00:
+ case 0x4000:
+ case 0x4100:
+ case 0x4200:
+ case 0x4300:
+ case 0x4400:
+ return key;
+
+ case 0x1c0d:
+
+ if (index == 1)
+ return key;
+
+ if (*pCurPos == index - 1) {
+ *pCurPos = 0;
+ break;
+ }
+
+ pCurPos[0]++;
+ break;
+
+ case 0x5000:
+ if (index - 1 > *pCurPos)
+ pCurPos[0]++;
+ break;
+
+ case 0x4800:
+ if (*pCurPos > 0)
+ pCurPos[0]--;
+ break;
+ }
+ }
+}
+
+int16 Game::adjustKey(int16 key) {
+ if (key <= 0x60 || key >= 0x7b)
+ return key;
+
+ return key - 0x20;
+}
+
+void Game::collisionsBlock(void) {
+ InputDesc descArray[20];
+ int16 array[250];
+ char count;
+ int16 collResId;
+ char *startIP;
+ int16 curCmd;
+ int16 cmd;
+ int16 cmdHigh;
+ int16 key;
+ int16 flags;
+ int16 left;
+ int16 top;
+ int16 width;
+ int16 height;
+ int16 var_22;
+ int16 index;
+ int16 curEditIndex;
+ int16 deltaTime;
+ int16 descIndex2;
+ int16 stackPos2;
+ int16 descIndex;
+ int16 timeVal;
+ char *str;
+ int16 savedCollStackSize;
+ int16 i;
+ int16 counter;
+ int16 var_24;
+ int16 var_26;
+ int16 _collStackPos;
+ Collision *collPtr;
+ int16 timeKey;
+ char *savedIP;
+
+ if (_shouldPushColls)
+ pushCollisions(1);
+
+ collResId = -1;
+ _vm->_global->_inter_execPtr++;
+ count = *_vm->_global->_inter_execPtr++;
+ _handleMouse = _vm->_global->_inter_execPtr[0];
+ deltaTime = 1000 * (byte)_vm->_global->_inter_execPtr[1];
+ descIndex2 = (byte)_vm->_global->_inter_execPtr[2];
+ stackPos2 = (byte)_vm->_global->_inter_execPtr[3];
+ descIndex = (byte)_vm->_global->_inter_execPtr[4];
+
+ if (stackPos2 != 0 || descIndex != 0)
+ deltaTime /= 100;
+
+ timeVal = deltaTime;
+ _vm->_global->_inter_execPtr += 6;
+
+ startIP = _vm->_global->_inter_execPtr;
+ WRITE_VAR(16, 0);
+ var_22 = 0;
+ index = 0;
+ curEditIndex = 0;
+
+ for (curCmd = 0; curCmd < count; curCmd++) {
+ array[curCmd] = 0;
+ cmd = *_vm->_global->_inter_execPtr++;
+
+ if ((cmd & 0x40) != 0) {
+ cmd -= 0x40;
+ cmdHigh = (byte)*_vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr++;
+ cmdHigh <<= 8;
+ } else {
+ cmdHigh = 0;
+ }
+
+ if ((cmd & 0x80) != 0) {
+ left = _vm->_parse->parseValExpr();
+ top = _vm->_parse->parseValExpr();
+ width = _vm->_parse->parseValExpr();
+ height = _vm->_parse->parseValExpr();
+ } else {
+ left = _vm->_inter->load16();
+ top = _vm->_inter->load16();
+ width = _vm->_inter->load16();
+ height = _vm->_inter->load16();
+ }
+ cmd &= 0x7f;
+
+ debug(4, "collisionsBlock(%d)", cmd);
+
+ switch (cmd) {
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+
+ _vm->_util->waitKey();
+ var_22 = 1;
+ key = _vm->_parse->parseVarIndex();
+ descArray[index].fontIndex = _vm->_inter->load16();
+ descArray[index].backColor = *_vm->_global->_inter_execPtr++;
+ descArray[index].frontColor = *_vm->_global->_inter_execPtr++;
+
+ if (cmd < 5 || cmd > 8) {
+ descArray[index].ptr = 0;
+ } else {
+ descArray[index].ptr = _vm->_global->_inter_execPtr + 2;
+ _vm->_global->_inter_execPtr += _vm->_inter->load16();
+ }
+
+ if (left == -1)
+ break;
+
+ if ((cmd & 1) == 0) {
+ addNewCollision(curCmd + 0x8000, left,
+ top,
+ left +
+ width *
+ _vm->_draw->_fonts[descArray[index].fontIndex]->
+ itemWidth - 1, top + height - 1, cmd, key,
+ 0,
+ _vm->_global->_inter_execPtr - (char *)_totFileData);
+
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ } else {
+ addNewCollision(curCmd + 0x8000, left,
+ top,
+ left +
+ width *
+ _vm->_draw->_fonts[descArray[index].fontIndex]->
+ itemWidth - 1, top + height - 1, cmd, key,
+ 0, 0);
+ }
+ index++;
+ break;
+
+ case 21:
+ key = _vm->_inter->load16();
+ array[curCmd] = _vm->_inter->load16();
+ flags = _vm->_inter->load16() & 3;
+
+ addNewCollision(curCmd + 0x8000, left, top,
+ left + width - 1,
+ top + height - 1,
+ (flags << 4) + cmdHigh + 2, key,
+ _vm->_global->_inter_execPtr - (char *)_totFileData, 0);
+
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ break;
+
+ case 20:
+ collResId = curCmd;
+ // Fall through to case 2
+
+ case 2:
+ key = _vm->_inter->load16();
+ array[curCmd] = _vm->_inter->load16();
+ flags = _vm->_inter->load16() & 3;
+
+ addNewCollision(curCmd + 0x8000, left, top,
+ left + width - 1,
+ top + height - 1,
+ (flags << 4) + cmdHigh + 2, key, 0,
+ _vm->_global->_inter_execPtr - (char *)_totFileData);
+
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ break;
+
+ case 0:
+ _vm->_global->_inter_execPtr += 6;
+ startIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ key = curCmd + 0xA000;
+
+ addNewCollision(curCmd + 0x8000, left, top,
+ left + width - 1,
+ top + height - 1,
+ cmd + cmdHigh, key,
+ startIP - (char *)_totFileData,
+ _vm->_global->_inter_execPtr - (char *)_totFileData);
+
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ break;
+
+ case 1:
+ key = _vm->_inter->load16();
+ array[curCmd] = _vm->_inter->load16();
+ flags = _vm->_inter->load16() & 3;
+
+ startIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ if (key == 0)
+ key = curCmd + 0xa000;
+
+ addNewCollision(curCmd + 0x8000, left, top,
+ left + width - 1,
+ top + height - 1,
+ (flags << 4) + cmd + cmdHigh, key,
+ startIP - (char *)_totFileData,
+ _vm->_global->_inter_execPtr - (char *)_totFileData);
+
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ break;
+ }
+ }
+
+ _forceHandleMouse = 0;
+ _vm->_util->waitKey();
+
+ do {
+ if (var_22 != 0) {
+ key =
+ multiEdit(deltaTime, index, &curEditIndex,
+ descArray);
+
+ if (key == 0x1c0d) {
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].id & 0x8000) == 0)
+ continue;
+
+ if ((_collisionAreas[i].flags & 1) != 0)
+ continue;
+
+ if ((_collisionAreas[i].flags & 0x0f) <= 2)
+ continue;
+
+ collResId = _collisionAreas[i].id;
+ _activeCollResId = collResId;
+ collResId &= 0x7fff;
+ _activeCollIndex = i;
+ break;
+ }
+ break;
+ }
+ } else {
+ key =
+ checkCollisions(_handleMouse, -deltaTime,
+ &_activeCollResId, &_activeCollIndex);
+ }
+
+ if ((key & 0xff) >= ' ' && (key & 0xff) <= 0xff &&
+ (key >> 8) > 1 && (key >> 8) < 12) {
+ key = '0' + (((key >> 8) - 1) % 10) + (key & 0xff00);
+ }
+
+ if (_activeCollResId == 0) {
+ if (key != 0) {
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].
+ id & 0x8000) == 0)
+ continue;
+
+ if (_collisionAreas[i].key == key
+ || _collisionAreas[i].key ==
+ 0x7fff) {
+
+ _activeCollResId =
+ _collisionAreas[i].id;
+ _activeCollIndex = i;
+ break;
+ }
+ }
+
+ if (_activeCollResId == 0) {
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].id & 0x8000) == 0)
+ continue;
+
+ if ((_collisionAreas[i].key & 0xff00) != 0)
+ continue;
+
+ if (_collisionAreas[i].key == 0)
+ continue;
+
+ if (adjustKey(key & 0xff) == adjustKey(_collisionAreas[i].key) || _collisionAreas[i].key == 0x7fff) {
+ _activeCollResId = _collisionAreas[i].id;
+ _activeCollIndex = i;
+ break;
+ }
+ }
+ }
+ } else {
+
+ if (deltaTime != 0 && VAR(16) == 0) {
+ if (stackPos2 != 0) {
+ _collStackPos = 0;
+ collPtr = _collisionAreas;
+
+ for (i = 0, collPtr = _collisionAreas; collPtr->left != -1; i++, collPtr++) {
+ if ((collPtr->id & 0x8000) == 0)
+ continue;
+
+ _collStackPos++;
+ if (_collStackPos != stackPos2)
+ continue;
+
+ _activeCollResId = collPtr->id;
+ _activeCollIndex = i;
+ WRITE_VAR(2, _vm->_global->_inter_mouseX);
+ WRITE_VAR(3, _vm->_global->_inter_mouseY);
+ WRITE_VAR(4, _mouseButtons);
+ WRITE_VAR(16, array[(uint16)_activeCollResId & ~0x8000]);
+
+ if (collPtr->funcLeave != 0) {
+ timeKey = _vm->_util->getTimeKey();
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)_totFileData + collPtr->funcLeave;
+ _shouldPushColls = 1;
+ savedCollStackSize = _collStackSize;
+ _vm->_inter->funcBlock(0);
+
+ if (savedCollStackSize != _collStackSize)
+ popCollisions();
+
+ _shouldPushColls = 0;
+ _vm->_global->_inter_execPtr = savedIP;
+ deltaTime = timeVal - (_vm->_util->getTimeKey() - timeKey);
+
+ if (deltaTime < 2)
+ deltaTime = 2;
+ }
+
+ if (VAR(16) == 0)
+ _activeCollResId = 0;
+ break;
+ }
+ } else {
+ if (descIndex != 0) {
+ counter = 0;
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].id & 0x8000) == 0)
+ continue;
+
+ counter++;
+ if (counter != descIndex)
+ continue;
+
+ _activeCollResId = _collisionAreas[i].id;
+ _activeCollIndex = i;
+ break;
+ }
+ } else {
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].id & 0x8000) == 0)
+ continue;
+
+ _activeCollResId = _collisionAreas[i].id;
+ _activeCollIndex = i;
+ break;
+ }
+ }
+ }
+ } else {
+ if (descIndex2 != 0) {
+ counter = 0;
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].id & 0x8000) == 0)
+ continue;
+
+ counter++;
+ if (counter != descIndex2)
+ continue;
+
+ _activeCollResId = _collisionAreas[i].id;
+ _activeCollIndex = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (_activeCollResId == 0)
+ continue;
+
+ if (_collisionAreas[_activeCollIndex].funcLeave != 0)
+ continue;
+
+ WRITE_VAR(2, _vm->_global->_inter_mouseX);
+ WRITE_VAR(3, _vm->_global->_inter_mouseY);
+ WRITE_VAR(4, _mouseButtons);
+ WRITE_VAR(16, array[(uint16)_activeCollResId & ~0x8000]);
+
+ if (_collisionAreas[_activeCollIndex].funcEnter != 0) {
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)_totFileData +
+ _collisionAreas[_activeCollIndex].
+ funcEnter;
+
+ _shouldPushColls = 1;
+
+ _collStackPos = _collStackSize;
+ _vm->_inter->funcBlock(0);
+ if (_collStackPos != _collStackSize)
+ popCollisions();
+ _shouldPushColls = 0;
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+
+ WRITE_VAR(16, 0);
+ _activeCollResId = 0;
+ }
+ while (_activeCollResId == 0 && !_vm->_inter->_terminate);
+
+ if (((uint16)_activeCollResId & ~0x8000) == collResId) {
+ _collStackPos = 0;
+ var_24 = 0;
+ var_26 = 1;
+ for (i = 0; i < 250; i++) {
+ if (_collisionAreas[i].left == -1)
+ continue;
+
+ if ((_collisionAreas[i].id & 0x8000) == 0)
+ continue;
+
+ if ((_collisionAreas[i].flags & 0x0f) < 3)
+ continue;
+
+ if ((_collisionAreas[i].flags & 0x0f) > 10)
+ continue;
+
+ if ((_collisionAreas[i].flags & 0x0f) > 8) {
+ char *ptr;
+ strcpy(_tempStr,
+ _vm->_global->_inter_variables + _collisionAreas[i].key);
+ while ((ptr = strchr(_tempStr, ' ')) != 0) {
+ _vm->_util->cutFromStr(_tempStr, (ptr - _tempStr), 1);
+ ptr = strchr(_tempStr, ' ');
+ }
+ strcpy(_vm->_global->_inter_variables + _collisionAreas[i].key, _tempStr);
+ }
+
+ if ((_collisionAreas[i].flags & 0x0f) >= 5 &&
+ (_collisionAreas[i].flags & 0x0f) <= 8) {
+ str = descArray[var_24].ptr;
+
+ strcpy(_tempStr, _vm->_global->_inter_variables + _collisionAreas[i].key);
+
+ if ((_collisionAreas[i].flags & 0x0f) < 7)
+ _vm->_util->prepareStr(_tempStr);
+
+ int16 pos = 0;
+ do {
+ strcpy(_collStr, str);
+ pos += strlen(str) + 1;
+
+ str += strlen(str) + 1;
+
+ if ((_collisionAreas[i].flags & 0x0f) < 7)
+ _vm->_util->prepareStr(_collStr);
+
+ if (strcmp(_tempStr, _collStr) == 0) {
+ VAR(17)++;
+ WRITE_VAR(17 + var_26, 1);
+ break;
+ }
+ } while (READ_LE_UINT16(descArray[var_24].ptr - 2) > pos);
+ _collStackPos++;
+ } else {
+ VAR(17 + var_26) = 2;
+ }
+ var_24++;
+ var_26++;
+ }
+
+ if (_collStackPos != (int16)VAR(17))
+ WRITE_VAR(17, 0);
+ else
+ WRITE_VAR(17, 1);
+ }
+
+ savedIP = 0;
+ if (!_vm->_inter->_terminate) {
+ savedIP = (char *)_totFileData +
+ _collisionAreas[_activeCollIndex].funcLeave;
+
+ WRITE_VAR(2, _vm->_global->_inter_mouseX);
+ WRITE_VAR(3, _vm->_global->_inter_mouseY);
+ WRITE_VAR(4, _mouseButtons);
+
+ if (VAR(16) == 0) {
+ WRITE_VAR(16, array[(uint16)_activeCollResId & ~0x8000]);
+ }
+ }
+
+ for (curCmd = 0; curCmd < count; curCmd++) {
+ freeCollision(curCmd + 0x8000);
+ }
+ _vm->_global->_inter_execPtr = savedIP;
+}
+
+void Game::prepareStart(void) {
+ int16 i;
+
+ clearCollisions();
+
+ _vm->_global->_pPaletteDesc->unused2 = _vm->_draw->_unusedPalette2;
+ _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1;
+ _vm->_global->_pPaletteDesc->vgaPal = _vm->_draw->_vgaPalette;
+
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+
+ _vm->_draw->_backSurface = _vm->_video->initSurfDesc(_vm->_global->_videoMode, 320, 200, 0);
+
+ _vm->_video->fillRect(_vm->_draw->_backSurface, 0, 0, 319, 199, 1);
+ _vm->_draw->_frontSurface = _vm->_global->_pPrimarySurfDesc;
+ _vm->_video->fillRect(_vm->_draw->_frontSurface, 0, 0, 319, 199, 1);
+
+ _vm->_util->setMousePos(152, 92);
+
+ _vm->_draw->_cursorX = 152;
+ _vm->_global->_inter_mouseX = 152;
+
+ _vm->_draw->_cursorY = 92;
+ _vm->_global->_inter_mouseY = 92;
+ _vm->_draw->_invalidatedCount = 0;
+ _vm->_draw->_noInvalidated = 1;
+ _vm->_draw->_applyPal = 0;
+ _vm->_draw->_paletteCleared = 0;
+ _vm->_draw->_cursorWidth = 16;
+ _vm->_draw->_cursorHeight = 16;
+ _vm->_draw->_transparentCursor = 1;
+
+ for (i = 0; i < 40; i++) {
+ _vm->_draw->_cursorAnimLow[i] = -1;
+ _vm->_draw->_cursorAnimDelays[i] = 0;
+ _vm->_draw->_cursorAnimHigh[i] = 0;
+ }
+
+ _vm->_draw->_cursorAnimLow[1] = 0;
+ _vm->_draw->_cursorSprites = _vm->_video->initSurfDesc(_vm->_global->_videoMode, 32, 16, 2);
+ _vm->_draw->_cursorBack = _vm->_video->initSurfDesc(_vm->_global->_videoMode, 16, 16, 0);
+ _vm->_draw->_renderFlags = 0;
+ _vm->_draw->_backDeltaX = 0;
+ _vm->_draw->_backDeltaY = 0;
+
+ _startTimeKey = _vm->_util->getTimeKey();
+}
+
+void Game::loadTotFile(char *path) {
+ int16 handle;
+
+ handle = _vm->_dataio->openData(path);
+ if (handle >= 0) {
+ _vm->_dataio->closeData(handle);
+ _totFileData = _vm->_dataio->getData(path);
+ } else {
+ _totFileData = 0;
+ }
+}
+
+void Game::loadExtTable(void) {
+ int16 count, i;
+
+ // Function is correct. [sev]
+
+ _extHandle = _vm->_dataio->openData(_curExtFile);
+ if (_extHandle < 0)
+ return;
+
+ _vm->_dataio->readData(_extHandle, (char *)&count, 2);
+ count = FROM_LE_16(count);
+
+ _vm->_dataio->seekData(_extHandle, 0, 0);
+ _extTable = new ExtTable;
+ _extTable->items = 0;
+ if (count)
+ _extTable->items = new ExtItem[count];
+
+ _vm->_dataio->readData(_extHandle, (char *)&_extTable->itemsCount, 2);
+ _extTable->itemsCount = FROM_LE_16(_extTable->itemsCount);
+ _vm->_dataio->readData(_extHandle, (char *)&_extTable->unknown, 1);
+
+ for (i = 0; i < count; i++) {
+ _vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].offset, 4);
+ _extTable->items[i].offset = FROM_LE_32(_extTable->items[i].offset);
+ _vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].size, 2);
+ _extTable->items[i].size = FROM_LE_16(_extTable->items[i].size);
+ _vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].width, 2);
+ _extTable->items[i].width = FROM_LE_16(_extTable->items[i].width);
+ _vm->_dataio->readData(_extHandle, (char *)&_extTable->items[i].height, 2);
+ _extTable->items[i].height = FROM_LE_16(_extTable->items[i].height);
+ }
+}
+
+void Game::loadImFile(void) {
+ char path[20];
+ int16 handle;
+
+ if (_totFileData[0x3d] != 0 && _totFileData[0x3b] == 0)
+ return;
+
+ strcpy(path, "commun.im1");
+ if (_totFileData[0x3b] != 0)
+ path[strlen(path) - 1] = '0' + _totFileData[0x3b];
+
+ handle = _vm->_dataio->openData(path);
+ if (handle < 0)
+ return;
+
+ _vm->_dataio->closeData(handle);
+ _imFileData = _vm->_dataio->getData(path);
+}
+
+void Game::playTot(int16 skipPlay) {
+ char savedTotName[20];
+ int16 *oldCaptureCounter;
+ int16 *oldBreakFrom;
+ int16 *oldNestLevel;
+ int16 _captureCounter;
+ int16 breakFrom;
+ int16 nestLevel;
+ char needTextFree;
+ char needFreeResTable;
+ char *curPtr;
+ int32 variablesCount;
+ char *filePtr;
+ char *savedIP;
+ int16 i;
+
+ oldNestLevel = _vm->_inter->_nestLevel;
+ oldBreakFrom = _vm->_inter->_breakFromLevel;
+ oldCaptureCounter = _vm->_scenery->_pCaptureCounter;
+ savedIP = _vm->_global->_inter_execPtr;
+
+ _vm->_inter->_nestLevel = &nestLevel;
+ _vm->_inter->_breakFromLevel = &breakFrom;
+ _vm->_scenery->_pCaptureCounter = &_captureCounter;
+ strcpy(savedTotName, _curTotFile);
+
+ if (skipPlay == 0) {
+ while (1) {
+ for (i = 0; i < 4; i++) {
+ _vm->_draw->_fontToSprite[i].sprite = -1;
+ _vm->_draw->_fontToSprite[i].base = -1;
+ _vm->_draw->_fontToSprite[i].width = -1;
+ _vm->_draw->_fontToSprite[i].height = -1;
+ }
+
+ if(_vm->_features & GF_MAC)
+ _vm->_music->stopPlay();
+ else
+ _vm->_cdrom->stopPlaying();
+ _vm->_draw->animateCursor(4);
+ _vm->_inter->initControlVars();
+ _vm->_mult->initAll();
+ _vm->_mult->zeroMultData();
+
+ for (i = 0; i < 20; i++)
+ _vm->_draw->_spritesArray[i] = 0;
+
+ _vm->_draw->_spritesArray[20] = _vm->_draw->_frontSurface;
+ _vm->_draw->_spritesArray[21] = _vm->_draw->_backSurface;
+ _vm->_draw->_spritesArray[23] = _vm->_draw->_cursorSprites;
+
+ for (i = 0; i < 20; i++)
+ _soundSamples[i] = 0;
+
+ _totTextData = 0;
+ _totResourceTable = 0;
+ _imFileData = 0;
+ _extTable = 0;
+ _extHandle = -1;
+
+ needFreeResTable = 1;
+ needTextFree = 1;
+
+ _totToLoad[0] = 0;
+
+ if (_curTotFile[0] == 0 && _totFileData == 0)
+ break;
+
+ loadTotFile(_curTotFile);
+ if (_totFileData == 0) {
+ _vm->_draw->blitCursor();
+ break;
+ }
+
+ strcpy(_curImaFile, _curTotFile);
+ strcpy(_curExtFile, _curTotFile);
+
+ _curImaFile[strlen(_curImaFile) - 4] = 0;
+ strcat(_curImaFile, ".ima");
+
+ _curExtFile[strlen(_curExtFile) - 4] = 0;
+ strcat(_curExtFile, ".ext");
+
+ debug(4, "IMA: %s", _curImaFile);
+ debug(4, "EXT: %s", _curExtFile);
+
+ filePtr = (char *)_totFileData + 0x30;
+
+ if (READ_LE_UINT32(filePtr) != (uint32)-1) {
+ curPtr = _totFileData;
+ _totTextData =
+ (TotTextTable *) (curPtr +
+ READ_LE_UINT32((char *)_totFileData + 0x30));
+
+ _totTextData->itemsCount = (int16)READ_LE_UINT16(&_totTextData->itemsCount);
+
+ for (i = 0; i < _totTextData->itemsCount; ++i) {
+ _totTextData->items[i].offset = (int16)READ_LE_UINT16(&_totTextData->items[i].offset);
+ _totTextData->items[i].size = (int16)READ_LE_UINT16(&_totTextData->items[i].size);
+ }
+
+ needTextFree = 0;
+ }
+
+ filePtr = (char *)_totFileData + 0x34;
+ if (READ_LE_UINT32(filePtr) != (uint32)-1) {
+ curPtr = _totFileData;
+
+ _totResourceTable =
+ (TotResTable *)(curPtr +
+ READ_LE_UINT32((char *)_totFileData + 0x34));
+
+ _totResourceTable->itemsCount = (int16)READ_LE_UINT16(&_totResourceTable->itemsCount);
+
+ for (i = 0; i < _totResourceTable->itemsCount; ++i) {
+ _totResourceTable->items[i].offset = (int32)READ_LE_UINT32(&_totResourceTable->items[i].offset);
+ _totResourceTable->items[i].size = (int16)READ_LE_UINT16(&_totResourceTable->items[i].size);
+ _totResourceTable->items[i].width = (int16)READ_LE_UINT16(&_totResourceTable->items[i].width);
+ _totResourceTable->items[i].height = (int16)READ_LE_UINT16(&_totResourceTable->items[i].height);
+ }
+
+ needFreeResTable = 0;
+ }
+
+ loadImFile();
+ loadExtTable();
+
+ _vm->_global->_inter_animDataSize = READ_LE_UINT16((char *)_totFileData + 0x38);
+ if (_vm->_global->_inter_variables == 0) {
+ variablesCount = READ_LE_UINT32((char *)_totFileData + 0x2c);
+ _vm->_global->_inter_variables = new char[variablesCount * 4];
+ for (i = 0; i < variablesCount; i++)
+ WRITE_VAR(i, 0);
+ }
+
+ _vm->_global->_inter_execPtr = (char *)_totFileData;
+ _vm->_global->_inter_execPtr += READ_LE_UINT32((char *)_totFileData + 0x64);
+
+ _vm->_inter->renewTimeInVars();
+
+ WRITE_VAR(13, _vm->_global->_useMouse);
+ WRITE_VAR(14, _vm->_global->_soundFlags);
+ WRITE_VAR(15, _vm->_global->_videoMode);
+ WRITE_VAR(16, _vm->_global->_language);
+
+ _vm->_inter->callSub(2);
+
+ if (_totToLoad[0] != 0)
+ _vm->_inter->_terminate = false;
+
+ variablesCount = READ_LE_UINT32((char *)_totFileData + 0x2c);
+ _vm->_draw->blitInvalidated();
+ delete[] _totFileData;
+ _totFileData = 0;
+
+ if (needTextFree)
+ delete[] _totTextData;
+ _totTextData = 0;
+
+ if (needFreeResTable)
+ delete[] _totResourceTable;
+ _totResourceTable = 0;
+
+ delete[] _imFileData;
+ _imFileData = 0;
+
+ if (_extTable)
+ delete[] _extTable->items;
+ delete _extTable;
+ _extTable = 0;
+
+ if (_extHandle >= 0)
+ _vm->_dataio->closeData(_extHandle);
+
+ _extHandle = -1;
+
+ for (i = 0; i < *_vm->_scenery->_pCaptureCounter; i++)
+ capturePop(0);
+
+ _vm->_mult->checkFreeMult();
+ _vm->_mult->freeAll();
+
+ for (i = 0; i < 20; i++) {
+ if (_vm->_draw->_spritesArray[i] != 0)
+ _vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[i]);
+ _vm->_draw->_spritesArray[i] = 0;
+ }
+ _vm->_snd->stopSound(0);
+
+ for (i = 0; i < 20; i++)
+ freeSoundSlot(i);
+
+ if (_totToLoad[0] == 0)
+ break;
+
+ strcpy(_curTotFile, _totToLoad);
+ }
+ }
+
+ strcpy(_curTotFile, savedTotName);
+
+ _vm->_inter->_nestLevel = oldNestLevel;
+ _vm->_inter->_breakFromLevel = oldBreakFrom;
+ _vm->_scenery->_pCaptureCounter = oldCaptureCounter;
+ _vm->_global->_inter_execPtr = savedIP;
+}
+
+void Game::start(void) {
+ _collisionAreas = new Collision[250];
+ prepareStart();
+ playTot(0);
+
+ delete[] _collisionAreas;
+
+ _vm->_video->freeSurfDesc(_vm->_draw->_cursorSprites);
+ _vm->_video->freeSurfDesc(_vm->_draw->_cursorBack);
+ _vm->_video->freeSurfDesc(_vm->_draw->_backSurface);
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/game.h b/engines/gob/game.h
new file mode 100644
index 0000000000..f1548d4386
--- /dev/null
+++ b/engines/gob/game.h
@@ -0,0 +1,189 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_GAME_H
+#define GOB_GAME_H
+
+#include "gob/sound.h"
+
+namespace Gob {
+
+class Game {
+public:
+
+#pragma START_PACK_STRUCTS
+#define szGame_TotResItem (4 + 2 + 2 + 2)
+ struct Collision {
+ int16 id;
+ int16 left;
+ int16 top;
+ int16 right;
+ int16 bottom;
+ int16 flags;
+ int16 key;
+ int16 funcEnter;
+ int16 funcLeave;
+ } GCC_PACK;
+
+ struct TotResItem {
+ int32 offset; // if > 0, then offset from end of resource table.
+ // If < 0, then -offset-1 is index in .IM file table
+ int16 size;
+ int16 width;
+ int16 height;
+ } GCC_PACK;
+
+#define szGame_TotResTable (2 + 1)
+ struct TotResTable {
+ int16 itemsCount;
+ byte unknown;
+ TotResItem items[1];
+ } GCC_PACK;
+
+#define szGame_ExtItem (4 + 2 + 2 + 2)
+ struct ExtItem {
+ int32 offset; // offset from the table end
+ uint16 size;
+ int16 width; // width&0x7fff - width, width&0x8000 - pack flag
+ int16 height; // not zero
+ } GCC_PACK;
+
+#define szGame_ExtTable (2 + 1)
+ struct ExtTable {
+ int16 itemsCount;
+ byte unknown;
+ ExtItem* items;
+ } GCC_PACK;
+
+#define szGame_TotTextItem (2 + 2)
+ struct TotTextItem {
+ int16 offset;
+ int16 size;
+ } GCC_PACK;
+
+#define szGame_TotTextTable (2)
+ struct TotTextTable {
+ int16 itemsCount;
+ TotTextItem items[1];
+ } GCC_PACK;
+
+ struct InputDesc {
+ int16 fontIndex;
+ int16 backColor;
+ int16 frontColor;
+ char *ptr;
+ } GCC_PACK;
+#pragma END_PACK_STRUCTS
+
+ TotResTable *_totResourceTable;
+ Collision *_collisionAreas;
+ Collision *_collStack[3];
+
+ TotTextTable *_totTextData;
+
+ char _curTotFile[14];
+ char _curExtFile[14];
+
+ char *_imFileData;
+ char *_totFileData;
+
+ int16 _extHandle;
+
+ Snd::SoundDesc *_soundSamples[20];
+
+ char _totToLoad[20];
+
+ int32 _startTimeKey;
+ int16 _mouseButtons;
+
+ Game(GobEngine *vm);
+
+ char *loadExtData(int16 dataId, int16 *pResWidth, int16 *pResHeight);
+ char *loadTotResource(int16 id);
+
+ void capturePush(int16 left, int16 top, int16 width, int16 height);
+
+ void capturePop(char doDraw);
+ void interLoadSound(int16 slot);
+ void freeSoundSlot(int16 slot);
+ int16 checkKeys(int16 *pMousex, int16 *pMouseY, int16 *pButtons,
+ char handleMouse);
+ int16 checkCollisions(char handleMouse, int16 deltaTime, int16 *pResId,
+ int16 *pResIndex);
+ void clearCollisions(void);
+ void addNewCollision(int16 val_0, int16 left, int16 top, int16 right, int16 bottom,
+ int16 flags, int16 key, int16 val_E, int16 val_10);
+ void freeCollision(int16 id);
+
+ void loadSound(int16 slot, char *dataPtr);
+ int16 inputArea(int16 xPos, int16 yPos, int16 width, int16 height, int16 backColor,
+ int16 frontColor, char *str, int16 fontIndex, char inpType, int16 *pTotTime);
+ int16 multiEdit(int16 time, int16 index, int16 *pCurPos,
+ InputDesc * inpDesc);
+ int16 adjustKey(int16 key);
+ void collisionsBlock(void);
+ void prepareStart(void);
+ void loadTotFile(char *path);
+ void loadExtTable(void);
+ void loadImFile(void);
+ void playTot(int16 skipPlay);
+ void start(void);
+
+protected:
+
+ int16 _lastCollKey;
+ int16 _lastCollAreaIndex;
+ int16 _lastCollId;
+
+ int16 _activeCollResId;
+ int16 _activeCollIndex;
+ char _handleMouse;
+ char _forceHandleMouse;
+
+ char _tempStr[256];
+
+ ExtTable *_extTable;
+ char _curImaFile[18];
+
+ int16 _collStackSize;
+ int16 _collStackElemSizes[3];
+
+ char _soundFromExt[20];
+
+ char _shouldPushColls;
+
+ // Capture
+ static Common::Rect _captureStack[20];
+ static int16 _captureCount;
+
+ char _collStr[256];
+
+ GobEngine *_vm;
+
+ void pushCollisions(char all);
+ void popCollisions(void);
+ int16 checkMousePoint(int16 all, int16 *resId, int16 *resIndex);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp
new file mode 100644
index 0000000000..0d732e1f2a
--- /dev/null
+++ b/engines/gob/global.cpp
@@ -0,0 +1,152 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+
+namespace Gob {
+
+Global::Global(GobEngine *vm) : _vm(vm) {
+ _useMouse = UNDEF;
+ _mousePresent = UNDEF;
+
+ _presentCGA = UNDEF;
+ _presentEGA = UNDEF;
+ _presentVGA = UNDEF;
+ _presentHER = UNDEF;
+
+ _videoMode = 0;
+
+ /* Sound */
+ _presentSound = 0x8000; /* undefined values */
+ _soundFlags = 0x8000;
+ _blasterPort = 0;
+ _disableSoundCfg = 0;
+
+ //char _playingSound = 0;
+
+ /* Mouse */
+ _disableMouseCfg = 0;
+
+ _mouseXShift = 3;
+ _mouseYShift = 3;
+
+ _mouseMaxCol = 320;
+ _mouseMaxRow = 200;
+
+ /* Language */
+ _disableLangCfg = 0x8000;
+ _language = 0x8000;
+
+ /* Timer variables */
+ _startTime = 0;
+ _timer_delta = 1000;
+
+ _frameWaitTime = 0;
+ _startFrameTime = 0;
+
+ /* Timer and delays */
+ _delayTime = 0;
+
+ /* Joystick */
+ _useJoystick = 1;
+
+ /* Data files */
+ _packedSize = 0;
+ int i;
+
+ for (i = 0; i < MAX_DATA_FILES; i++) {
+ _dataFiles[i] = 0;
+ _numDataChunks[i] = 0;
+ _dataFileHandles[i] = -1;
+ }
+
+ _primaryWidth = 0;
+ _primaryHeight = 0;
+
+ _sprAllocated = 0;
+
+ _doRangeClamp = 0;
+
+ _setAllPalette = 0;
+
+ _oldMode = 3;
+ _dontSetPalette = 0;
+ _pPrimarySurfDesc = 0;
+
+ _pPaletteDesc = 0;
+
+ _unusedPalette1[0] = (int16)0;
+ _unusedPalette1[1] = (int16)0x0b;
+ _unusedPalette1[2] = (int16)0;
+ _unusedPalette1[3] = (int16)0x5555;
+ _unusedPalette1[4] = (int16)0xAAAA;
+ _unusedPalette1[5] = (int16)0xFFFF;
+ _unusedPalette1[6] = (int16)0;
+ _unusedPalette1[7] = (int16)0x5555;
+ _unusedPalette1[8] = (int16)0xAAAA;
+ _unusedPalette1[9] = (int16)0xFFFF;
+ _unusedPalette1[10] = (int16)0;
+ _unusedPalette1[11] = (int16)0x5555;
+ _unusedPalette1[12] = (int16)0xAAAA;
+ _unusedPalette1[13] = (int16)0xFFFF;
+ _unusedPalette1[14] = (int16)0;
+ _unusedPalette1[15] = (int16)0x5555;
+ _unusedPalette1[16] = (int16)0xAAAA;
+ _unusedPalette1[17] = (int16)0xFFFF;
+
+ for (i = 0; i < 16 ;i++)
+ _unusedPalette2[i] = i;
+
+ _vgaPalette[0].red = 0x00; _vgaPalette[0].green = 0x00; _vgaPalette[0].blue = 0x00;
+ _vgaPalette[1].red = 0x00; _vgaPalette[1].green = 0x00; _vgaPalette[1].blue = 0x2a;
+ _vgaPalette[2].red = 0x00; _vgaPalette[2].green = 0x2a; _vgaPalette[2].blue = 0x00;
+ _vgaPalette[3].red = 0x00; _vgaPalette[3].green = 0x2a; _vgaPalette[3].blue = 0x2a;
+ _vgaPalette[4].red = 0x2a; _vgaPalette[4].green = 0x00; _vgaPalette[4].blue = 0x00;
+ _vgaPalette[5].red = 0x2a; _vgaPalette[5].green = 0x00; _vgaPalette[5].blue = 0x2a;
+ _vgaPalette[6].red = 0x2a; _vgaPalette[6].green = 0x15; _vgaPalette[6].blue = 0x00;
+ _vgaPalette[7].red = 0x2a; _vgaPalette[7].green = 0x2a; _vgaPalette[7].blue = 0x2a;
+ _vgaPalette[8].red = 0x15; _vgaPalette[8].green = 0x15; _vgaPalette[8].blue = 0x15;
+ _vgaPalette[9].red = 0x15; _vgaPalette[9].green = 0x15; _vgaPalette[9].blue = 0x3f;
+ _vgaPalette[10].red = 0x15; _vgaPalette[10].green = 0x3f; _vgaPalette[10].blue = 0x15;
+ _vgaPalette[11].red = 0x15; _vgaPalette[11].green = 0x3f; _vgaPalette[11].blue = 0x3f;
+ _vgaPalette[12].red = 0x3f; _vgaPalette[12].green = 0x15; _vgaPalette[12].blue = 0x15;
+ _vgaPalette[13].red = 0x3f; _vgaPalette[13].green = 0x15; _vgaPalette[13].blue = 0x3f;
+ _vgaPalette[14].red = 0x3f; _vgaPalette[14].green = 0x3f; _vgaPalette[14].blue = 0x15;
+ _vgaPalette[15].red = 0x3f; _vgaPalette[15].green = 0x3f; _vgaPalette[15].blue = 0x3f;
+
+ _debugFlag = 0;
+ _inVM = 0;
+ _colorCount = 16;
+
+ _inter_resStr[0] = 0;
+ _inter_resVal = 0;
+
+ _inter_variables = 0;
+ _inter_execPtr = 0;
+ _inter_animDataSize = 10;
+
+ _inter_mouseX = 0;
+ _inter_mouseY = 0;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/global.h b/engines/gob/global.h
new file mode 100644
index 0000000000..1583e711c8
--- /dev/null
+++ b/engines/gob/global.h
@@ -0,0 +1,173 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_GLOBAL_H
+#define GOB_GLOBAL_H
+
+#include "gob/dataio.h"
+#include "gob/video.h"
+
+#include "common/file.h"
+
+namespace Gob {
+
+#define VIDMODE_CGA 0x05
+#define VIDMODE_EGA 0x0d
+#define VIDMODE_VGA 0x13
+#define VIDMODE_HER 7
+
+#define PROAUDIO_FLAG 0x10
+#define ADLIB_FLAG 0x08
+#define BLASTER_FLAG 0x04
+#define INTERSOUND_FLAG 0x02
+#define SPEAKER_FLAG 0x01
+#define MIDI_FLAG 0x4000
+
+#define NO 0
+#define YES 1
+#define UNDEF 2
+
+#define F1_KEY 0x3b00
+#define F2_KEY 0x3c00
+#define F3_KEY 0x3d00
+#define F4_KEY 0x3e00
+#define F5_KEY 0x3f00
+#define F6_KEY 0x4000
+#define ESCAPE 0x001b
+#define ENTER 0x000d
+
+#define MAX_FILES 30
+
+/* Video drivers */
+#define UNK_DRIVER 0
+#define VGA_DRIVER 1
+#define EGA_DRIVER 2
+#define CGA_DRIVER 3
+#define HER_DRIVER 4
+
+class Global {
+public:
+ char _pressedKeys[128];
+
+ char _useMouse;
+ int16 _mousePresent;
+
+ int16 _presentCGA;
+ int16 _presentEGA;
+ int16 _presentVGA;
+ int16 _presentHER;
+
+ int16 _videoMode;
+
+ int16 _disableVideoCfg;
+
+ uint16 _presentSound;
+ uint16 _soundFlags;
+ int16 _disableSoundCfg;
+ int16 _blasterPort;
+
+ uint16 _disableLangCfg;
+ uint16 _language;
+
+ // Timer variables
+ int32 _startTime;
+ int16 _timer_delta;
+
+ int16 _frameWaitTime;
+ int32 _startFrameTime;
+
+ // Mouse
+ int16 _disableMouseCfg;
+
+ int16 _mouseXShift;
+ int16 _mouseYShift;
+ int16 _mouseMaxCol;
+ int16 _mouseMaxRow;
+
+ // Timer and delays
+ int16 _delayTime;
+
+ // Joystick
+ char _useJoystick;
+
+ // Files
+ Common::File _filesHandles[MAX_FILES];
+
+ // Data files
+ struct DataIO::ChunkDesc *_dataFiles[MAX_DATA_FILES];
+ int16 _numDataChunks[MAX_DATA_FILES];
+ int16 _dataFileHandles[MAX_DATA_FILES];
+ int32 _chunkPos[MAX_SLOT_COUNT * MAX_DATA_FILES];
+ int32 _chunkOffset[MAX_SLOT_COUNT * MAX_DATA_FILES];
+ int32 _chunkSize[MAX_SLOT_COUNT * MAX_DATA_FILES];
+ char _isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES];
+ int32 _packedSize;
+
+ int16 _sprAllocated;
+
+ int16 _primaryWidth;
+ int16 _primaryHeight;
+
+ int16 _doRangeClamp;
+
+ char _redPalette[256];
+ char _greenPalette[256];
+ char _bluePalette[256];
+
+ int16 _setAllPalette;
+
+ Video::SurfaceDesc _primarySurfDesc;
+ Video::SurfaceDesc *_pPrimarySurfDesc;
+
+ int16 _oldMode;
+ char _dontSetPalette;
+
+ Video::PalDesc *_pPaletteDesc;
+
+ int16 _unusedPalette1[18];
+ int16 _unusedPalette2[16];
+ Video::Color _vgaPalette[16];
+ Video::PalDesc _paletteStruct;
+
+ int16 _debugFlag;
+ int16 _inVM;
+ int16 _colorCount;
+
+ char _inter_resStr[200];
+ int32 _inter_resVal;
+
+ char *_inter_variables;
+ char *_inter_execPtr;
+ int16 _inter_animDataSize;
+
+ int16 _inter_mouseX;
+ int16 _inter_mouseY;
+
+ Global(GobEngine *vm);
+
+protected:
+ GobEngine *_vm;
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
new file mode 100644
index 0000000000..a3285b219f
--- /dev/null
+++ b/engines/gob/gob.cpp
@@ -0,0 +1,366 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "common/stdafx.h"
+
+#include "base/plugins.h"
+#include "backends/fs/fs.h"
+#include "common/md5.h"
+
+#include "gob/gob.h"
+
+#include "gob/global.h"
+#include "gob/game.h"
+#include "gob/sound.h"
+#include "gob/init.h"
+#include "gob/inter.h"
+#include "gob/draw.h"
+#include "gob/anim.h"
+#include "gob/cdrom.h"
+#include "gob/goblin.h"
+#include "gob/map.h"
+#include "gob/mult.h"
+#include "gob/pack.h"
+#include "gob/palanim.h"
+#include "gob/parse.h"
+#include "gob/scenery.h"
+#include "gob/timer.h"
+#include "gob/util.h"
+#include "gob/music.h"
+
+enum {
+ // We only compute MD5 of the first megabyte of our data files.
+ kMD5FileSizeLimit = 1024 * 1024
+};
+
+static const Gob::GobGameSettings gob_games[] = {
+ // Supplied by Florian Zeitz on scummvm-devel
+ {"gob1", "Gobliiins (DOS EGA)", Gob::GF_GOB1, "82aea70ef26f41fa963dfae270993e49"},
+ {"gob1", "Gobliiins (DOS EGA)", Gob::GF_GOB1, "1f499458837008058b8ba6ae07057214"},
+ {"gob1", "Gobliiins (Windows)", Gob::GF_GOB1, "8a5e850c49d7cacdba5f5eb1fcc77b89"},
+
+ // Supplied by Theruler76 in bug report #1201233
+ {"gob1", "Gobliiins (DOS VGA)", Gob::GF_GOB1, "a5e232fcd02733c7dffff107d22d36eb"},
+
+ // CD 1.000 version. Multilingual
+ {"gob1", "Gobliiins (CD)", Gob::GF_GOB1 | Gob::GF_CD, "037db48ebce94bdfe42e2c9510da9211"},
+ // CD 1.02 version. Multilingual
+ {"gob1", "Gobliiins (CD)", Gob::GF_GOB1 | Gob::GF_CD, "45f9c1162dd7040fd05fd013ccc176e2"},
+
+ {"gob1", "Gobliiins (Amiga)", Gob::GF_GOB1, "d9f8736b7dc0ea891cd06592a72e8a72"},
+ {"gob1", "Gobliiins (Amiga)", Gob::GF_GOB1, "69f9ae85252271e7dfa62883e581e5e9"},
+ {"gob1", "Gobliiins (Amiga)", Gob::GF_GOB1, "26de406cb09228d902274446a6a2eceb"},
+ {"gob1", "Gobliiins (Amiga)", Gob::GF_GOB1, "baf88a95928edb3f51067983f2dffa93"},
+
+ {"gob1", "Gobliiins (Interactive Demo)", Gob::GF_GOB1, "4f5bf4b9e4c39ebb93579747fc678e97"},
+
+ {"gob1", "Gobliiins (Mac)", Gob::GF_GOB1 | Gob::GF_MAC, "4c0e8ce4a2f66ee8226952ad3c6c1155"},
+
+#if 0
+ {"gob2", "Gobliins 2 (DOS)", Gob::GF_GOB2, "abb5f762f9979d4253002de20f6e7b56"},
+ {"gob2", "Gobliins 2 (DOS)", Gob::GF_GOB2, "9b6de65d811c08eebf50391b84fcba92"},
+ {"gob2", "Gobliins 2 (DOS)", Gob::GF_GOB2, "54d59c200e3823ad0af11a605a6fd06a"},
+ {"gob2", "Gobliins 2 (DOS Ru)", Gob::GF_GOB2, "b6d47494bf88398ae59c1b5656cafce4"},
+ // CD 1.000.
+ {"gob2", "Gobliins 2 (CD)", Gob::GF_GOB2, "02bf538fd8003b8da23a3546299c3df4"},
+ // CD 1.01
+ {"gob2", "Gobliins 2 (CD)", Gob::GF_GOB2, "410e632682ab11969bc3b3b588066d95"},
+ {"gob2", "Gobliins 2 (Demo)", Gob::GF_GOB2, "be8b111191f965ac9b28fe530580d14e"},
+
+ {"gob3", "Goblins Quest 3", Gob::GF_GOB3, "36d9b4032b39a794c8640e500e98893a"},
+ {"gob3", "Goblins Quest 3", Gob::GF_GOB3, "d129f639f6ca8d6b5f0f4e15edb91058"},
+ {"gob3", "Goblins Quest 3", Gob::GF_GOB3, "8d17b0abc514b1512fdedc6072acd48b"},
+ // CD 1.000
+ {"gob3", "Goblins Quest 3 (CD)", Gob::GF_GOB3, "8d17b0abc514b1512fdedc6072acd48b"},
+ // CD 1.02. Spanish "Computer Gaming World"* distribution in Spain
+ {"gob3", "Goblins Quest 3 (CD)", Gob::GF_GOB3, "7d7ab9a987be7208b9b685846fbd3e82"},
+
+ {"gob3", "Goblins Quest 3 (Interactive Demo)", Gob::GF_GOB3, "4986b44cec309589508d7904f924c217"},
+ {"gob3", "Goblins Quest 3 (Demo)", Gob::GF_GOB3, "5024e7de8d6377fbbeabbaa92e0452bc"},
+ {"gob3", "Goblins Quest 3 (Interactive Demo)", Gob::GF_GOB3, "59ab69dab5fddbbf698c77a84297a5a2"},
+
+ // CD 1.0
+ {"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble", Gob::GF_WOODRUFF, "c27402cee260d2ff1c4cecb2006a630a"},
+
+ // CD 1.00, German release (INTRO.STRK seems to be multilingual, though?)
+ {"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble", Gob::GF_WOODRUFF, "751ba028d215e0db1e0254853de6a7e4"},
+#endif
+ {0, 0, 0, 0}
+};
+
+// Keep list of different supported games
+static const struct GobGameList {
+ const char *gameid;
+ const char *description;
+ uint32 features;
+ GameSettings toGameSettings() const {
+ GameSettings dummy = { gameid, description, features };
+ return dummy;
+ }
+} gob_list[] = {
+ {"gob1", "Gobliiins", Gob::GF_GOB1},
+ {"gob2", "Gobliins 2", Gob::GF_GOB2},
+ {0, 0, 0}
+};
+
+
+GameList Engine_GOB_gameList() {
+ GameList games;
+ const GobGameList *g = gob_list;
+
+ while (g->gameid) {
+ games.push_back(g->toGameSettings());
+ g++;
+ }
+
+ return games;
+}
+
+DetectedGameList Engine_GOB_detectGames(const FSList &fslist) {
+ DetectedGameList detectedGames;
+ const Gob::GobGameSettings *g;
+ FSList::const_iterator file;
+
+ // Iterate over all files in the given directory
+ for (file = fslist.begin(); file != fslist.end(); file++) {
+ if (file->isDirectory())
+ continue;
+
+ // All the supported games have an intro.stk file.
+ if (scumm_stricmp(file->displayName().c_str(), "intro.stk") == 0)
+ break;
+ }
+
+ if (file == fslist.end())
+ return detectedGames;
+
+ uint8 md5sum[16];
+ char md5str[32 + 1];
+
+ if (Common::md5_file(file->path().c_str(), md5sum, NULL, kMD5FileSizeLimit)) {
+ for (int i = 0; i < 16; i++) {
+ sprintf(md5str + i * 2, "%02x", (int)md5sum[i]);
+ }
+ for (g = gob_games; g->gameid; g++) {
+ if (strcmp(g->md5sum, (char *)md5str) == 0) {
+ detectedGames.push_back(g->toGameSettings());
+ }
+ }
+ if (detectedGames.isEmpty()) {
+ printf("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5str);
+
+ const GobGameList *g1 = gob_list;
+ while (g1->gameid) {
+ detectedGames.push_back(g1->toGameSettings());
+ g1++;
+ }
+ }
+ }
+ return detectedGames;
+}
+
+Engine *Engine_GOB_create(GameDetector * detector, OSystem *syst) {
+ // Detect game features based on MD5
+ uint8 md5sum[16];
+ char md5str[32 + 1];
+
+ if (Common::md5_file("intro.stk", md5sum, ConfMan.get("path").c_str(), kMD5FileSizeLimit)) {
+ for (int j = 0; j < 16; j++) {
+ sprintf(md5str + j*2, "%02x", (int)md5sum[j]);
+ }
+ } else {
+ error("Engine_GOB_create(): Cannot find intro.stk");
+ }
+
+ const Gob::GobGameSettings *g;
+ bool found = false;
+
+ // TODO
+ // Fallback. Maybe we will be able to determine game type from game
+ // data contents
+ Common::String realGame;
+ uint32 features;
+ if (ConfMan.hasKey("gameid"))
+ realGame = ConfMan.get("gameid");
+ else
+ realGame = detector->_targetName;
+ if (!strcmp(realGame.c_str(), "gob2"))
+ features = Gob::GF_GOB2;
+ else
+ features = Gob::GF_GOB1;
+
+ for (g = gob_games; g->gameid; g++) {
+ if (strcmp(g->md5sum, (char *)md5str) == 0) {
+ features = g->features;
+
+ if (g->description)
+ g_system->setWindowCaption(g->description);
+
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5str);
+ }
+
+ return new Gob::GobEngine(detector, syst, features);
+}
+
+REGISTER_PLUGIN(GOB, "Gob Engine")
+
+namespace Gob {
+
+#define MAX_TIME_DELTA 100
+
+GobEngine::GobEngine(GameDetector *detector, OSystem * syst, uint32 features)
+ : Engine(syst) {
+ // Setup mixer
+ if (!_mixer->isReady()) {
+ warning("Sound initialization failed.");
+ }
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+
+ _features = features;
+ _copyProtection = ConfMan.getBool("copy_protection");
+}
+
+GobEngine::~GobEngine() {
+ delete _game;
+ delete _snd;
+ delete _video;
+ delete _global;
+ delete _draw;
+ delete _anim;
+ delete _cdrom;
+ delete _dataio;
+ delete _goblin;
+ delete _init;
+ delete _inter;
+ delete _map;
+ delete _mult;
+ delete _pack;
+ delete _palanim;
+ delete _parse;
+ delete _scenery;
+ delete _gtimer;
+ delete _util;
+ delete _inter;
+ delete _music;
+}
+
+void GobEngine::errorString(const char *buf1, char *buf2) {
+ strcpy(buf2, buf1);
+}
+
+int GobEngine::go() {
+ _init->initGame(0);
+
+ return 0;
+}
+
+void GobEngine::shutdown() {
+ _system->quit();
+}
+
+int GobEngine::init(GameDetector &detector) {
+ _game = new Game(this);
+ _snd = new Snd(this);
+ _video = new Video(this);
+ _global = new Global(this);
+ _draw = new Draw(this);
+ _anim = new Anim();
+ _cdrom = new CDROM(this);
+ _dataio = new DataIO(this);
+ _goblin = new Goblin(this);
+ _init = new Init(this);
+ _map = new Map(this);
+ _mult = new Mult(this);
+ _pack = new Pack();
+ _palanim = new PalAnim(this);
+ _scenery = new Scenery(this);
+ _gtimer = new GTimer();
+ _util = new Util(this);
+ if (_features & Gob::GF_GOB1) {
+ _inter = new Inter_v1(this);
+ _parse = new Parse_v1(this);
+ }
+ else if (_features & Gob::GF_GOB2) {
+ _inter = new Inter_v2(this);
+ _parse = new Parse_v2(this);
+ }
+ else
+ error("GobEngine::init(): Unknown version of game engine");
+ if ((_features & Gob::GF_MAC) || (_features & Gob::GF_GOB1))
+ _music = new Music(this);
+
+ _system->beginGFXTransaction();
+ initCommonGFX(detector);
+ _system->initSize(320, 200);
+ _system->endGFXTransaction();
+
+ // On some systems it's not safe to run CD audio games from the CD.
+ if (_features & GF_CD)
+ checkCD();
+
+ int cd_num = ConfMan.getInt("cdrom");
+ if (cd_num >= 0)
+ _system->openCD(cd_num);
+
+ _global->_debugFlag = 1;
+ _global->_doRangeClamp = 1;
+
+ _global->_videoMode = 0x13;
+ _global->_useMouse = 1;
+ _global->_soundFlags = 0;
+
+ switch (Common::parseLanguage(ConfMan.get("language"))) {
+ case Common::FR_FRA:
+ _global->_language = 0;
+ break;
+ case Common::DE_DEU:
+ _global->_language = 1;
+ break;
+ case Common::ES_ESP:
+ _global->_language = 3;
+ break;
+ case Common::IT_ITA:
+ _global->_language = 4;
+ break;
+ default:
+ // Default to English
+ _global->_language = 2;
+ break;
+ }
+
+ // FIXME: This is the ugly way of reducing redraw overhead. It works
+ // well for 320x200 but it's unclear how well it will work for
+ // 640x480.
+
+ g_system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
+
+ return 0;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
new file mode 100644
index 0000000000..211ec124ad
--- /dev/null
+++ b/engines/gob/gob.h
@@ -0,0 +1,129 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GOB_GOB_H
+#define GOB_GOB_H
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "sound/mixer.h"
+#include "common/config-manager.h"
+
+#include "base/engine.h"
+#include "base/gameDetector.h"
+
+#include "gob/dataio.h"
+#include "gob/video.h"
+#include "common/file.h"
+
+namespace Gob {
+
+class Game;
+class Snd;
+class Video;
+class Global;
+class Draw;
+class Anim;
+class CDROM;
+class DataIO;
+class Goblin;
+class Init;
+class Inter;
+class Map;
+class Mult;
+class Pack;
+class PalAnim;
+class Parse;
+class Scenery;
+class GTimer;
+class Util;
+class Music;
+
+#define VAR_OFFSET(offs) (*(uint32 *)(_vm->_global->_inter_variables + (offs)))
+#define VAR(var) VAR_OFFSET((var) << 2)
+#define VAR_ADDRESS(var) (&VAR(var))
+
+#define WRITE_VAR_OFFSET(offs, val) (VAR_OFFSET(offs) = (val))
+#define WRITE_VAR(var, val) WRITE_VAR_OFFSET((var) << 2, (val))
+
+enum {
+ GF_GOB1 = 1 << 0,
+ GF_GOB2 = 1 << 1,
+ GF_GOB3 = 1 << 2,
+ GF_WOODRUFF = 1 << 3,
+ GF_CD = 1 << 4,
+ GF_MAC = 1 << 5
+};
+
+struct GobGameSettings {
+ const char *gameid;
+ const char *description;
+ uint32 features;
+ const char *md5sum;
+ GameSettings toGameSettings() const {
+ GameSettings dummy = { gameid, description, features };
+ return dummy;
+ }
+};
+
+class GobEngine : public Engine {
+ void errorString(const char *buf_input, char *buf_output);
+
+protected:
+ int go();
+ int init(GameDetector &detector);
+
+public:
+ GobEngine(GameDetector * detector, OSystem * syst, uint32 features);
+ virtual ~GobEngine();
+
+ void shutdown();
+
+ Common::RandomSource _rnd;
+
+ int32 _features;
+ bool _copyProtection;
+
+ Game *_game;
+ Snd *_snd;
+ Video *_video;
+ Global *_global;
+ Draw *_draw;
+ Anim *_anim;
+ CDROM *_cdrom;
+ DataIO *_dataio;
+ Goblin *_goblin;
+ Init *_init;
+ Map *_map;
+ Mult *_mult;
+ Pack *_pack;
+ PalAnim *_palanim;
+ Parse *_parse;
+ Scenery *_scenery;
+ GTimer *_gtimer;
+ Util *_util;
+ Inter *_inter;
+ Music *_music;
+};
+
+} // End of namespace Gob
+#endif
diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp
new file mode 100644
index 0000000000..f434c65a70
--- /dev/null
+++ b/engines/gob/goblin.cpp
@@ -0,0 +1,2381 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/goblin.h"
+#include "gob/inter.h"
+#include "gob/global.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+#include "gob/anim.h"
+#include "gob/scenery.h"
+#include "gob/map.h"
+#include "gob/sound.h"
+#include "gob/game.h"
+#include "gob/dataio.h"
+#include "gob/cdrom.h"
+#include "gob/music.h"
+
+namespace Gob {
+
+Goblin::Goblin(GobEngine *vm) : _vm(vm) {
+ _goesAtTarget = 0;
+ _readyToAct = 0;
+ _gobAction = 0;
+ _itemIndInPocket = 5;
+ _itemIdInPocket = 2;
+ _itemByteFlag = 0;
+ _destItemId = -1;
+ _destActionItem = 0;
+ _actDestItemDesc = 0;
+ _forceNextState[0] = -1;
+ _forceNextState[1] = -1;
+ _forceNextState[2] = -1;
+ _forceNextState[3] = -1;
+ _forceNextState[4] = -1;
+ _forceNextState[5] = -1;
+ _forceNextState[6] = -1;
+ _forceNextState[7] = 0;
+ _forceNextState[8] = 0;
+ _forceNextState[9] = 0;
+
+ _rotStates[0][0] = 0; _rotStates[0][1] = 22; _rotStates[0][2] = 23; _rotStates[0][3] = 24;
+ _rotStates[1][0] = 13; _rotStates[1][1] = 2; _rotStates[1][2] = 12; _rotStates[1][3] = 14;
+ _rotStates[2][0] = 16; _rotStates[2][1] = 15; _rotStates[2][2] = 4; _rotStates[2][3] = 17;
+ _rotStates[3][0] = 27; _rotStates[3][1] = 25; _rotStates[3][2] = 26; _rotStates[3][3] = 6;
+
+ _boreCounter = 0;
+ _positionedGob = 5;
+
+ _noPick = 0;
+ _objList = 0;
+ int i;
+ for (i = 0; i < 4; i++)
+ _goblins[i] = 0;
+ _currentGoblin = 0;
+ for (i = 0; i < 16; i++)
+ _soundData[i] = 0;
+ for (i = 0; i < 3; i++) {
+ _gobPositions[i].x = 0;
+ _gobPositions[i].y = 0;
+ }
+ _gobDestX = 0;
+ _gobDestY = 0;
+ _pressedMapX = 0;
+ _pressedMapY = 0;
+ _pathExistence = 0;
+
+ _some0ValPtr = 0;
+
+ _gobRetVarPtr = 0;
+ _curGobVarPtr = 0;
+ _curGobXPosVarPtr = 0;
+ _curGobYPosVarPtr = 0;
+ _itemInPocketVarPtr = 0;
+
+ _curGobStateVarPtr = 0;
+ _curGobFrameVarPtr = 0;
+ _curGobMultStateVarPtr = 0;
+ _curGobNextStateVarPtr = 0;
+ _curGobScrXVarPtr = 0;
+ _curGobScrYVarPtr = 0;
+ _curGobLeftVarPtr = 0;
+ _curGobTopVarPtr = 0;
+ _curGobRightVarPtr = 0;
+ _curGobBottomVarPtr = 0;
+ _curGobDoAnimVarPtr = 0;
+ _curGobOrderVarPtr = 0;
+ _curGobNoTickVarPtr = 0;
+ _curGobTypeVarPtr = 0;
+ _curGobMaxTickVarPtr = 0;
+ _curGobTickVarPtr = 0;
+ _curGobActStartStateVarPtr = 0;
+ _curGobLookDirVarPtr = 0;
+ _curGobPickableVarPtr = 0;
+ _curGobRelaxVarPtr = 0;
+ _curGobMaxFrameVarPtr = 0;
+
+ _destItemStateVarPtr = 0;
+ _destItemFrameVarPtr = 0;
+ _destItemMultStateVarPtr = 0;
+ _destItemNextStateVarPtr = 0;
+ _destItemScrXVarPtr = 0;
+ _destItemScrYVarPtr = 0;
+ _destItemLeftVarPtr = 0;
+ _destItemTopVarPtr = 0;
+ _destItemRightVarPtr = 0;
+ _destItemBottomVarPtr = 0;
+ _destItemDoAnimVarPtr = 0;
+ _destItemOrderVarPtr = 0;
+ _destItemNoTickVarPtr = 0;
+ _destItemTypeVarPtr = 0;
+ _destItemMaxTickVarPtr = 0;
+ _destItemTickVarPtr = 0;
+ _destItemActStartStVarPtr = 0;
+ _destItemLookDirVarPtr = 0;
+ _destItemPickableVarPtr = 0;
+ _destItemRelaxVarPtr = 0;
+ _destItemMaxFrameVarPtr = 0;
+
+ _destItemType = 0;
+ _destItemState = 0;
+ for (i = 0; i < 20; i++) {
+ _itemToObject[i] = 0;
+ _objects[i] = 0;
+ }
+ _objCount = 0;
+ _gobsCount = 0;
+}
+
+char Goblin::rotateState(int16 from, int16 to) {
+ return _rotStates[from / 2][to / 2];
+}
+
+int16 Goblin::peekGoblin(Gob_Object *_curGob) {
+ Util::ListNode *ptr;
+ Gob_Object *desc;
+ int16 index;
+ int16 i;
+
+ ptr = _objList->pHead;
+ index = 0;
+ while (ptr != 0) {
+ desc = (Gob_Object *) ptr->pData;
+ if (desc != _curGob) {
+ for (i = 0; i < 3; i++) {
+ if (desc != _goblins[i])
+ continue;
+
+ if (_vm->_global->_inter_mouseX < desc->right &&
+ _vm->_global->_inter_mouseX > desc->left &&
+ _vm->_global->_inter_mouseY < desc->bottom &&
+ _vm->_global->_inter_mouseY > desc->top) {
+ index = i + 1;
+ }
+ }
+ }
+ ptr = ptr->pNext;
+ }
+ return index;
+}
+
+void Goblin::initList(void) {
+ _objList = new Util::List;
+ _objList->pHead = 0;
+ _objList->pTail = 0;
+}
+
+void Goblin::sortByOrder(Util::List *list) {
+ Util::ListNode *ptr;
+ Util::ListNode *ptr2;
+
+ ptr = list->pHead;
+ while (ptr->pNext != 0) {
+ for (ptr2 = ptr->pNext; ptr2 != 0; ptr2 = ptr2->pNext) {
+ Gob_Object *objDesc = (Gob_Object *)ptr->pData;
+ Gob_Object *objDesc2 = (Gob_Object *)ptr2->pData;
+
+ if (objDesc->order <= objDesc2->order) {
+ if (objDesc->order != objDesc2->order)
+ continue;
+
+ if (objDesc->bottom <= objDesc2->bottom) {
+ if (objDesc->bottom != objDesc2->bottom)
+ continue;
+
+ if (objDesc != _goblins[_currentGoblin])
+ continue;
+ }
+ }
+
+ SWAP(ptr->pData, ptr2->pData);
+ }
+ ptr = ptr->pNext;
+ }
+}
+
+void Goblin::playSound(Snd::SoundDesc *snd, int16 repCount, int16 freq) {
+ if (snd != 0) {
+ _vm->_snd->stopSound(0);
+ _vm->_snd->playSample(snd, repCount, freq);
+ }
+}
+
+void Goblin::drawObjects(void) {
+ Util::ListNode *ptr;
+ Util::ListNode *ptr2;
+
+ Gob_Object *objDesc;
+ Gob_Object *gobDesc2;
+ int16 layer;
+
+ ptr = _objList->pHead;
+ for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) {
+ objDesc = (Gob_Object *) ptr->pData;
+
+ if (objDesc->type == 3)
+ objDesc->toRedraw = 1;
+ else if (objDesc->type == 1)
+ objDesc->toRedraw = 0;
+ }
+
+ for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) {
+ objDesc = (Gob_Object *) ptr->pData;
+ if (objDesc->toRedraw == 0)
+ continue;
+
+ _vm->_video->drawSprite(_vm->_anim->_animSurf, _vm->_draw->_backSurface,
+ objDesc->left, objDesc->top, objDesc->right,
+ objDesc->bottom, objDesc->left, objDesc->top, 0);
+
+ _vm->_draw->invalidateRect(objDesc->left, objDesc->top,
+ objDesc->right, objDesc->bottom);
+
+ if (objDesc->type != 0)
+ continue;
+
+ layer =
+ objDesc->stateMach[objDesc->state][objDesc->stateColumn]->
+ layer;
+ _vm->_scenery->updateAnim(layer, objDesc->curFrame, objDesc->animation,
+ 0, objDesc->xPos, objDesc->yPos, 0);
+
+ if (_vm->_scenery->_toRedrawLeft == -12345) {
+ objDesc->dirtyLeft = objDesc->left;
+ objDesc->dirtyRight = objDesc->right;
+ objDesc->dirtyTop = objDesc->top;
+ objDesc->dirtyBottom = objDesc->bottom;
+ } else {
+ objDesc->dirtyLeft =
+ MIN(objDesc->left, _vm->_scenery->_toRedrawLeft);
+ objDesc->dirtyRight =
+ MAX(objDesc->right, _vm->_scenery->_toRedrawRight);
+ objDesc->dirtyTop =
+ MIN(objDesc->top, _vm->_scenery->_toRedrawTop);
+ objDesc->dirtyBottom =
+ MAX(objDesc->bottom, _vm->_scenery->_toRedrawBottom);
+ }
+
+ objDesc->dirtyLeft = 0;
+ objDesc->dirtyRight = 319;
+ objDesc->dirtyTop = 0;
+ objDesc->dirtyBottom = 199;
+ }
+
+ sortByOrder(_objList);
+ for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) {
+ objDesc = (Gob_Object *) ptr->pData;
+ if (objDesc->toRedraw) {
+ layer =
+ objDesc->stateMach[objDesc->state][objDesc->
+ stateColumn]->layer;
+
+ if (objDesc->type == 0) {
+ if (objDesc->visible == 0) {
+ _vm->_scenery->updateAnim(layer,
+ objDesc->curFrame,
+ objDesc->animation, 0,
+ objDesc->xPos, objDesc->yPos, 0);
+
+ } else {
+ _vm->_scenery->updateAnim(layer,
+ objDesc->curFrame,
+ objDesc->animation, 2,
+ objDesc->xPos, objDesc->yPos, 1);
+ }
+ if (_vm->_scenery->_toRedrawLeft == -12345) {
+ objDesc->left = 0;
+ objDesc->top = 0;
+ objDesc->right = 0;
+ objDesc->bottom = 0;
+ } else {
+ _vm->_draw->invalidateRect(_vm->_scenery->_toRedrawLeft,
+ _vm->_scenery->_toRedrawTop,
+ _vm->_scenery->_toRedrawRight,
+ _vm->_scenery->_toRedrawBottom);
+
+ objDesc->left = _vm->_scenery->_toRedrawLeft;
+ objDesc->top = _vm->_scenery->_toRedrawTop;
+ objDesc->right = _vm->_scenery->_toRedrawRight;
+ objDesc->bottom = _vm->_scenery->_toRedrawBottom;
+ _vm->_scenery->updateStatic(objDesc->order);
+ }
+ } else {
+ objDesc->left = 0;
+ objDesc->top = 0;
+ objDesc->right = 0;
+ objDesc->bottom = 0;
+ objDesc->type = 1;
+ }
+ continue;
+ }
+
+ if (objDesc->type == 0 && objDesc->visible != 0) {
+ for (ptr2 = _objList->pHead; ptr2 != 0;
+ ptr2 = ptr2->pNext) {
+ gobDesc2 = (Gob_Object *) ptr2->pData;
+
+ if (gobDesc2->toRedraw == 0)
+ continue;
+
+ if (objDesc->right < gobDesc2->dirtyLeft)
+ continue;
+
+ if (gobDesc2->dirtyRight < objDesc->left)
+ continue;
+
+ if (objDesc->bottom < gobDesc2->dirtyTop)
+ continue;
+
+ if (gobDesc2->dirtyBottom < objDesc->top)
+ continue;
+
+ _vm->_scenery->_toRedrawLeft = gobDesc2->dirtyLeft;
+ _vm->_scenery->_toRedrawRight = gobDesc2->dirtyRight;
+ _vm->_scenery->_toRedrawTop = gobDesc2->dirtyTop;
+ _vm->_scenery->_toRedrawBottom = gobDesc2->dirtyBottom;
+
+ layer =
+ objDesc->stateMach[objDesc->
+ state][objDesc->stateColumn]->layer;
+
+ _vm->_scenery->updateAnim(layer, objDesc->curFrame,
+ objDesc->animation, 4, objDesc->xPos,
+ objDesc->yPos, 1);
+
+ _vm->_scenery->updateStatic(objDesc->order);
+ }
+ }
+ }
+
+ for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) {
+ objDesc = (Gob_Object *) ptr->pData;
+ if (objDesc->toRedraw == 0 || objDesc->type == 1)
+ continue;
+
+ Gob_State *state = objDesc->stateMach[objDesc->state][objDesc->stateColumn];
+ int16 sndFrame;
+ int16 sndItem;
+ int16 freq;
+ int16 repCount;
+
+ if (state->sndFrame & 0xff00) {
+ // There are two frames which trigger a sound effect,
+ // so everything has to be encoded in one byte each.
+ // Note that the frequency is multiplied by 100, not -
+ // as I would have thought, 0x100.
+
+ sndFrame = (state->sndFrame >> 8) & 0xff;
+ sndItem = (state->sndItem >> 8) & 0xff;
+ freq = 100 * ((state->freq >> 8) & 0xff);
+ repCount = (state->repCount >> 8) & 0xff;
+
+ if (objDesc->curFrame == sndFrame) {
+ if (sndItem != 0xff) {
+ playSound(_soundData[sndItem],
+ repCount, freq);
+ }
+ }
+
+ sndFrame = state->sndFrame & 0xff;
+ sndItem = state->sndItem & 0xff;
+ freq = 100 * (state->freq & 0xff);
+ repCount = state->repCount & 0xff;
+
+ if (objDesc->curFrame == sndFrame) {
+ if (sndItem != 0xff) {
+ playSound(_soundData[sndItem],
+ repCount, freq);
+ }
+ }
+ } else {
+ // There is only one, so frequency etc. are used as is.
+ sndFrame = state->sndFrame;
+ sndItem = state->sndItem;
+ freq = state->freq;
+ repCount = state->repCount;
+
+ if (objDesc->curFrame == sndFrame) {
+ if (sndItem != -1) {
+ playSound(_soundData[sndItem],
+ repCount, freq);
+ }
+ }
+ }
+ }
+
+// _vm->_scenery->updateAnim(27, 0, 9, 2, 10, 10, 1);
+}
+
+void Goblin::animateObjects(void) {
+ Util::ListNode *node;
+ Gob_Object *objDesc;
+ Scenery::AnimLayer *pLayer;
+ int16 layer;
+
+ for (node = _objList->pHead; node != 0; node = node->pNext) {
+ objDesc = (Gob_Object *) node->pData;
+ if (objDesc->doAnim != 1 || objDesc->type != 0)
+ continue;
+
+ if (objDesc->noTick != 0)
+ continue;
+
+ if (objDesc->tick < objDesc->maxTick)
+ objDesc->tick++;
+
+ if (objDesc->tick >= objDesc->maxTick) {
+ objDesc->tick = 1;
+ objDesc->curFrame++;
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+ pLayer =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer];
+
+ if (objDesc->curFrame < pLayer->framesCount)
+ continue;
+
+ objDesc->curFrame = 0;
+
+ objDesc->xPos += pLayer->animDeltaX;
+ objDesc->yPos += pLayer->animDeltaY;
+
+ if (objDesc->nextState == -1
+ && objDesc->multState == -1
+ && objDesc->unk14 == 0) {
+ objDesc->toRedraw = 0;
+ objDesc->curFrame = pLayer->framesCount - 1;
+ }
+
+ if (objDesc->multState != -1) {
+ if (objDesc->multState > 39) {
+ objDesc->stateMach = _goblins[(int)(objDesc->multObjIndex)]->stateMach;
+ objDesc->state = objDesc->multState - 40;
+ } else {
+ objDesc->stateMach = objDesc->realStateMach;
+ objDesc->state = objDesc->multState;
+ }
+ objDesc->animation =
+ objDesc->stateMach[objDesc->state][0]->
+ animation;
+ objDesc->multState = -1;
+ } else {
+ if (objDesc->nextState == -1)
+ continue;
+
+ objDesc->stateMach = objDesc->realStateMach;
+ objDesc->state = objDesc->nextState;
+ objDesc->animation =
+ objDesc->stateMach[objDesc->state][0]->
+ animation;
+ objDesc->nextState = -1;
+ }
+ objDesc->toRedraw = 1;
+ }
+ }
+}
+
+void Goblin::placeObject(Gob_Object *objDesc, char animated) {
+ int16 layer;
+
+ if (objDesc->stateMach[objDesc->state][0] != 0) {
+ objDesc->animation =
+ objDesc->stateMach[objDesc->state][0]->animation;
+
+ objDesc->noTick = 0;
+ objDesc->toRedraw = 1;
+ objDesc->doAnim = animated;
+
+ objDesc->maxTick = 1;
+ objDesc->tick = 1;
+ objDesc->curFrame = 0;
+ objDesc->type = 0;
+ objDesc->actionStartState = 0;
+ objDesc->nextState = -1;
+ objDesc->multState = -1;
+ objDesc->stateColumn = 0;
+ objDesc->curLookDir = 0;
+ objDesc->visible = 1;
+ objDesc->pickable = 0;
+ objDesc->unk14 = 0;
+
+ objDesc->relaxTime = _vm->_util->getRandom(30);
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+ _vm->_scenery->updateAnim(layer, 0, objDesc->animation, 0,
+ objDesc->xPos, objDesc->yPos, 0);
+
+ objDesc->order = _vm->_scenery->_toRedrawBottom / 24 + 3;
+
+ objDesc->left = objDesc->xPos;
+ objDesc->right = objDesc->xPos;
+ objDesc->dirtyLeft = objDesc->xPos;
+ objDesc->dirtyRight = objDesc->xPos;
+
+ objDesc->top = objDesc->yPos;
+ objDesc->bottom = objDesc->yPos;
+ objDesc->dirtyTop = objDesc->yPos;
+ objDesc->dirtyBottom = objDesc->yPos;
+
+ _vm->_util->listInsertBack(_objList, objDesc);
+ }
+}
+
+int16 Goblin::getObjMaxFrame(Gob_Object * objDesc) {
+ int16 layer;
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+ return _vm->_scenery->_animations[objDesc->animation].layers[layer]->framesCount -
+ 1;
+}
+
+int16 Goblin::objIntersected(Gob_Object *obj1, Gob_Object *obj2) {
+ if (obj1->type == 1 || obj2->type == 1)
+ return 0;
+
+ if (obj1->right < obj2->left)
+ return 0;
+
+ if (obj1->left > obj2->right)
+ return 0;
+
+ if (obj1->bottom < obj2->top)
+ return 0;
+
+ if (obj1->top > obj2->bottom)
+ return 0;
+
+ return 1;
+}
+
+void Goblin::setMultStates(Gob_Object * gobDesc) {
+ gobDesc->stateMach = _goblins[(int)gobDesc->multObjIndex]->stateMach;
+}
+
+int16 Goblin::nextLayer(Gob_Object *gobDesc) {
+ if (gobDesc->nextState == 10)
+ gobDesc->curLookDir = 0;
+
+ if (gobDesc->nextState == 11)
+ gobDesc->curLookDir = 4;
+
+ if (gobDesc->nextState > 39) {
+ setMultStates(gobDesc);
+ } else {
+ gobDesc->stateMach = gobDesc->realStateMach;
+ }
+
+ gobDesc->curFrame = 0;
+ if (gobDesc->nextState > 39)
+ gobDesc->state = gobDesc->nextState - 40;
+ else
+ gobDesc->state = gobDesc->nextState;
+
+ gobDesc->animation = gobDesc->stateMach[gobDesc->state][0]->animation;
+ return gobDesc->stateMach[gobDesc->state][0]->layer;
+}
+
+void Goblin::showBoredom(int16 gobIndex) {
+ Gob_Object *gobDesc;
+ int16 frame;
+ int16 frameCount;
+ int16 layer;
+ int16 state;
+ int16 boreFlag;
+
+ gobDesc = _goblins[gobIndex];
+ layer = gobDesc->stateMach[gobDesc->state][0]->layer;
+
+ frameCount =
+ _vm->_scenery->_animations[gobDesc->animation].layers[layer]->framesCount;
+ state = gobDesc->state;
+ frame = gobDesc->curFrame;
+
+ gobDesc->noTick = 0;
+ gobDesc->toRedraw = 1;
+
+ boreFlag = 1 << _vm->_util->getRandom(7);
+
+ if (gobIndex != _currentGoblin && _vm->_util->getRandom(3) != 0) {
+ if (state == 21) {
+ if ((boreFlag & 16) || (boreFlag & 32)) {
+ gobDesc->multState = 92 + gobIndex;
+ } else if (boreFlag & 1) {
+ gobDesc->multState = 86 + gobIndex;
+ } else if (boreFlag & 2) {
+ gobDesc->multState = 80 + gobIndex;
+ } else if (boreFlag & 4) {
+ gobDesc->multState = 89 + gobIndex;
+ } else if (boreFlag & 8) {
+ gobDesc->multState = 104 + gobIndex;
+ }
+ }
+ gobDesc->nextState = 21;
+ } else if (state >= 18 && state <= 21 && VAR(59) == 0) {
+ if (state == 30 || state == 31) // ???
+ return;
+
+ if (frame != frameCount)
+ return;
+
+ gobDesc->multState = 104 + gobIndex;
+ }
+}
+
+// index - goblin to select+1
+// index==0 - switch to next
+void Goblin::switchGoblin(int16 index) {
+ int16 next;
+ int16 tmp;
+
+ debug(4, "switchGoblin");
+ if (VAR(59) != 0)
+ return;
+
+ if (_goblins[_currentGoblin]->state <= 39 &&
+ _goblins[_currentGoblin]->curFrame != 0)
+ return;
+
+ if (index != 0 && _goblins[index - 1]->type != 0)
+ return;
+
+ if (index == 0)
+ next = (_currentGoblin + 1) % 3;
+ else
+ next = index - 1;
+
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3 ||
+ _vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6)
+ return;
+
+ if (_goblins[(_currentGoblin + 1) % 3]->type != 0 &&
+ _goblins[(_currentGoblin + 2) % 3]->type != 0)
+ return;
+
+ _gobPositions[_currentGoblin].x = _vm->_map->_curGoblinX;
+ _gobPositions[_currentGoblin].y = _vm->_map->_curGoblinY;
+
+ _goblins[_currentGoblin]->doAnim = 1;
+ _goblins[_currentGoblin]->nextState = 21;
+
+ nextLayer(_goblins[_currentGoblin]);
+
+ _currentGoblin = next;
+ if (_goblins[_currentGoblin]->type != 0)
+ _currentGoblin = (_currentGoblin + 1) % 3;
+
+ _goblins[_currentGoblin]->doAnim = 0;
+ if (_goblins[_currentGoblin]->curLookDir == 4)
+ _goblins[_currentGoblin]->nextState = 18;
+ else
+ _goblins[_currentGoblin]->nextState = 19;
+
+ _goblins[_currentGoblin]->toRedraw = 1;
+ nextLayer(_goblins[_currentGoblin]);
+
+ tmp = _gobPositions[_currentGoblin].x;
+ _pressedMapX = tmp;
+ _vm->_map->_destX = tmp;
+ _gobDestX = tmp;
+ _vm->_map->_curGoblinX = tmp;
+
+ tmp = _gobPositions[_currentGoblin].y;
+ _pressedMapY = tmp;
+ _vm->_map->_destY = tmp;
+ _gobDestY = tmp;
+ _vm->_map->_curGoblinY = tmp;
+
+ *_curGobVarPtr = _currentGoblin;
+ _pathExistence = 0;
+ _readyToAct = 0;
+}
+
+void Goblin::adjustDest(int16 posX, int16 posY) {
+ int16 resDelta;
+ int16 resDeltaDir;
+ int16 resDeltaPix;
+ int16 deltaPix;
+ int16 i;
+
+ if (_vm->_map->_passMap[_pressedMapY][_pressedMapX] == 0 &&
+ (_gobAction == 0
+ || _vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0)) {
+
+ resDelta = -1;
+ resDeltaDir = 0;
+ resDeltaPix = 0;
+
+ for (i = 1;
+ i <= _pressedMapX
+ && _vm->_map->_passMap[_pressedMapY][_pressedMapX - i] == 0;
+ i++);
+
+ if (i <= _pressedMapX) {
+ resDeltaPix = (i - 1) * 12 + (posX % 12) + 1;
+ resDelta = i;
+ }
+
+ for (i = 1;
+ (i + _pressedMapX) < Map::kMapWidth
+ && _vm->_map->_passMap[_pressedMapY][_pressedMapX + i] == 0;
+ i++);
+
+ if (_pressedMapX + i < Map::kMapWidth) {
+ deltaPix = (i * 12) - (posX % 12);
+ if (resDelta == -1 || deltaPix < resDeltaPix) {
+ resDeltaPix = deltaPix;
+ resDelta = i;
+ resDeltaDir = 1;
+ }
+ }
+
+ for (i = 1;
+ (i + _pressedMapY) < Map::kMapHeight
+ && _vm->_map->_passMap[_pressedMapY + i][_pressedMapX] == 0;
+ i++);
+
+ if (_pressedMapY + i < Map::kMapHeight) {
+ deltaPix = (i * 6) - (posY % 6);
+ if (resDelta == -1 || deltaPix < resDeltaPix) {
+ resDeltaPix = deltaPix;
+ resDelta = i;
+ resDeltaDir = 2;
+ }
+ }
+
+ for (i = 1;
+ i <= _pressedMapY
+ && _vm->_map->_passMap[_pressedMapY - i][_pressedMapX] == 0;
+ i++);
+
+ if (i <= _pressedMapY) {
+ deltaPix = (i * 6) + (posY % 6);
+ if (resDelta == -1 || deltaPix < resDeltaPix) {
+ resDeltaPix = deltaPix;
+ resDelta = i;
+ resDeltaDir = 3;
+ }
+ }
+
+ switch (resDeltaDir) {
+ case 0:
+ _pressedMapX -= resDelta;
+ break;
+
+ case 1:
+ _pressedMapX += resDelta;
+ break;
+
+ case 2:
+ _pressedMapY += resDelta;
+ break;
+
+ case 3:
+ _pressedMapY -= resDelta;
+ break;
+ }
+
+ }
+}
+
+void Goblin::adjustTarget(void) {
+ if (_gobAction == 4
+ && _vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0) {
+
+ if (_pressedMapY > 0
+ && _vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] !=
+ 0) {
+ _pressedMapY--;
+ } else if (_pressedMapX < Map::kMapWidth - 1
+ && _vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] !=
+ 0) {
+ _pressedMapX++;
+ } else if (_pressedMapX < Map::kMapWidth - 1 && _pressedMapY > 0
+ && _vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX +
+ 1] != 0) {
+ _pressedMapY--;
+ _pressedMapX++;
+ }
+ }
+}
+
+void Goblin::targetDummyItem(Gob_Object *gobDesc) {
+ if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 &&
+ _vm->_map->_passMap[_pressedMapY][_pressedMapX] == 1) {
+ if (gobDesc->curLookDir == 0) {
+ _vm->_map->_itemPoses[0].x = _pressedMapX;
+ _vm->_map->_itemPoses[0].y = _pressedMapY;
+ _vm->_map->_itemPoses[0].orient = -4;
+ } else {
+ _vm->_map->_itemPoses[0].x = _pressedMapX;
+ _vm->_map->_itemPoses[0].y = _pressedMapY;
+ _vm->_map->_itemPoses[0].orient = -1;
+ }
+ }
+}
+
+void Goblin::targetItem(void) {
+ int16 tmpX;
+ int16 tmpY;
+ int16 items;
+ int16 layer;
+ int16 tmpPosX;
+ int16 tmpPosY;
+ Gob_Object *itemDesc;
+
+ if (_gobAction == 3 || _gobAction == 4) {
+ items = _vm->_map->_itemsMap[_pressedMapY][_pressedMapX];
+ if (_gobAction == 4 && (items & 0xff00) != 0 &&
+ _objects[_itemToObject[(items & 0xff00) >> 8]]->
+ pickable == 1) {
+ _destItemId = (items & 0xff00) >> 8;
+ _destActionItem = (items & 0xff00) >> 8;
+ _itemByteFlag = 1;
+ } else if ((items & 0xff) == 0) {
+ _destItemId = (items & 0xff00) >> 8;
+ _destActionItem = (items & 0xff00) >> 8;
+ _itemByteFlag = 1;
+ } else if (_gobAction == 3 && _currentGoblin == 2 &&
+ (items & 0xff00) != 0) {
+ _destItemId = (items & 0xff00) >> 8;
+ _destActionItem = (items & 0xff00) >> 8;
+ _itemByteFlag = 1;
+ } else {
+ _destItemId = items & 0xff;
+ _destActionItem = items & 0xff;
+ _itemByteFlag = 0;
+ }
+
+ _pressedMapY = _vm->_map->_itemPoses[_destItemId].y;
+ _vm->_map->_destY = _vm->_map->_itemPoses[_destItemId].y;
+ _gobDestY = _vm->_map->_itemPoses[_destItemId].y;
+
+ if (_gobAction == 3 || _destActionItem == 0) {
+ _pressedMapX = _vm->_map->_itemPoses[_destItemId].x;
+ _vm->_map->_destX = _vm->_map->_itemPoses[_destItemId].x;
+ _gobDestX = _vm->_map->_itemPoses[_destItemId].x;
+ } else if ((items & 0xff00) != 0) {
+ if (_vm->_map->_itemPoses[_destItemId].orient == 4) {
+ if ((_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX - 1] & 0xff00) ==
+ (_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX] & 0xff00)) {
+ _pressedMapX--;
+ _vm->_map->_destX = _pressedMapX;
+ _gobDestX = _pressedMapX;
+ }
+ } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) {
+
+ if ((_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX + 1] & 0xff00) ==
+ (_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX] & 0xff00)) {
+ _pressedMapX++;
+ _vm->_map->_destX = _pressedMapX;
+ _gobDestX = _pressedMapX;
+ }
+ }
+
+ if ((_vm->_map->_itemsMap[_pressedMapY +
+ 1][_pressedMapX] & 0xff00) ==
+ (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] &
+ 0xff00)) {
+ _pressedMapY++;
+ _vm->_map->_destY = _pressedMapY;
+ _gobDestY = _pressedMapY;
+ }
+ } else {
+ if (_vm->_map->_itemPoses[_destItemId].orient == 4) {
+ if ((_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX - 1]) ==
+ (_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX])) {
+ _pressedMapX--;
+ _vm->_map->_destX = _pressedMapX;
+ _gobDestX = _pressedMapX;
+ }
+ } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) {
+
+ if ((_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX + 1]) ==
+ (_vm->_map->_itemsMap[_pressedMapY]
+ [_pressedMapX])) {
+ _pressedMapX++;
+ _vm->_map->_destX = _pressedMapX;
+ _gobDestX = _pressedMapX;
+ }
+ }
+
+ if ((_vm->_map->_itemsMap[_pressedMapY +
+ 1][_pressedMapX]) ==
+ (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) {
+ _pressedMapY++;
+ _vm->_map->_destY = _pressedMapY;
+ _gobDestY = _pressedMapY;
+ }
+
+ }
+
+ if (_gobAction == 4 && _destActionItem != 0 &&
+ _itemToObject[_destActionItem] != -1 &&
+ _objects[_itemToObject[_destActionItem]]->
+ pickable == 1) {
+
+ itemDesc =
+ _objects[_itemToObject[_destActionItem]];
+
+ itemDesc->animation =
+ itemDesc->stateMach[itemDesc->state][0]->animation;
+ layer =
+ itemDesc->stateMach[itemDesc->state][itemDesc->
+ stateColumn]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, itemDesc->animation, 0,
+ itemDesc->xPos, itemDesc->yPos, 0);
+
+ tmpX = (_vm->_scenery->_toRedrawRight + _vm->_scenery->_toRedrawLeft) / 2;
+ tmpY = _vm->_scenery->_toRedrawBottom;
+
+ tmpPosY = tmpY / 6;
+ if ((tmpY % 3) < 3 && tmpPosY > 0)
+ tmpPosY--;
+
+ tmpPosX = tmpX / 12;
+ if ((tmpX % 12) < 6 && tmpPosX > 0)
+ tmpPosX--;
+
+ if (_vm->_map->_itemPoses[_destActionItem].orient == 0 ||
+ _vm->_map->_itemPoses[_destActionItem].orient == -1) {
+ tmpPosX++;
+ }
+
+ if (_vm->_map->_passMap[tmpPosY][tmpPosX] == 1) {
+ _pressedMapX = tmpPosX;
+ _vm->_map->_destX = tmpPosX;
+ _gobDestX = tmpPosX;
+
+ _pressedMapY = tmpPosY;
+ _vm->_map->_destY = tmpPosY;
+ _gobDestY = tmpPosY;
+ }
+ }
+ }
+}
+
+void Goblin::initiateMove(void) {
+ _vm->_map->findNearestToDest();
+ _vm->_map->findNearestToGob();
+ _vm->_map->optimizePoints();
+
+ _pathExistence = _vm->_map->checkDirectPath(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
+ _pressedMapX, _pressedMapY);
+
+ if (_pathExistence == 3) {
+ if (_vm->_map->checkLongPath(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
+ _pressedMapX, _pressedMapY,
+ _vm->_map->_nearestWayPoint, _vm->_map->_nearestDest) == 0) {
+ _pathExistence = 0;
+ } else {
+ _vm->_map->_destX = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
+ _vm->_map->_destY = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
+ }
+ }
+}
+
+void Goblin::moveFindItem(int16 posX, int16 posY) {
+ int16 i;
+ if (_gobAction == 3 || _gobAction == 4) {
+ for (i = 0; i < 20; i++) {
+ if (_objects[i] == 0)
+ continue;
+
+ if (_objects[i]->type != 0)
+ continue;
+
+ if (_objects[i]->left > posX)
+ continue;
+
+ if (_objects[i]->right < posX)
+ continue;
+
+ if (_objects[i]->top > posY)
+ continue;
+
+ if (_objects[i]->bottom < posY)
+ continue;
+
+ if (_objects[i]->right - _objects[i]->left < 40)
+ posX =
+ (_objects[i]->left +
+ _objects[i]->right) / 2;
+
+ if (_objects[i]->bottom - _objects[i]->top < 40)
+ posY =
+ (_objects[i]->top +
+ _objects[i]->bottom) / 2;
+
+ break;
+ }
+
+ _pressedMapX = posX / 12;
+ _pressedMapY = posY / 6;
+
+ if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0
+ && i < 20) {
+
+ if (_vm->_map->_itemsMap[_pressedMapY +
+ 1][_pressedMapX] != 0) {
+ _pressedMapY++;
+ } else if (_vm->_map->_itemsMap[_pressedMapY +
+ 1][_pressedMapX + 1] != 0) {
+ _pressedMapX++;
+ _pressedMapY++;
+ } else
+ if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX +
+ 1] != 0) {
+ _pressedMapX++;
+ } else if (_vm->_map->_itemsMap[_pressedMapY -
+ 1][_pressedMapX + 1] != 0) {
+ _pressedMapX++;
+ _pressedMapY--;
+ } else if (_vm->_map->_itemsMap[_pressedMapY -
+ 1][_pressedMapX] != 0) {
+ _pressedMapY--;
+ } else if (_vm->_map->_itemsMap[_pressedMapY -
+ 1][_pressedMapX - 1] != 0) {
+ _pressedMapY--;
+ _pressedMapX--;
+ } else
+ if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX -
+ 1] != 0) {
+ _pressedMapX--;
+ } else if (_vm->_map->_itemsMap[_pressedMapY +
+ 1][_pressedMapX - 1] != 0) {
+ _pressedMapX--;
+ _pressedMapY++;
+ }
+ }
+ } else {
+ _pressedMapX = posX / 12;
+ _pressedMapY = posY / 6;
+ }
+}
+
+void Goblin::moveCheckSelect(int16 framesCount, Gob_Object * gobDesc, int16 *pGobIndex,
+ int16 *nextAct) {
+ if (gobDesc->right > _vm->_global->_inter_mouseX &&
+ gobDesc->left < _vm->_global->_inter_mouseX &&
+ gobDesc->bottom > _vm->_global->_inter_mouseY &&
+ gobDesc->bottom - 10 < _vm->_global->_inter_mouseY && _gobAction == 0) {
+ if (gobDesc->curLookDir & 4)
+ *nextAct = 16;
+ else
+ *nextAct = 23;
+
+ gobDesc->curFrame = framesCount - 1;
+ _pathExistence = 0;
+ } else {
+ *pGobIndex = peekGoblin(gobDesc);
+
+ if (*pGobIndex != 0) {
+ _pathExistence = 0;
+ } else if (_vm->_map->_curGoblinX == _pressedMapX &&
+ _vm->_map->_curGoblinY == _pressedMapY) {
+
+ if (_gobAction != 0)
+ _readyToAct = 1;
+
+ _pathExistence = 0;
+ }
+ }
+}
+
+void Goblin::moveInitStep(int16 framesCount, int16 action, int16 cont,
+ Gob_Object *gobDesc, int16 *pGobIndex, int16 *pNextAct) {
+ int16 posX;
+ int16 posY;
+
+ if (cont != 0 && _goesAtTarget == 0 &&
+ _readyToAct == 0 && VAR(59) == 0 &&
+ gobDesc->type != 1 &&
+ gobDesc->state != 10 && gobDesc->state != 11) {
+ if (gobDesc->state >= 40) {
+ gobDesc->curFrame = framesCount - 1;
+ }
+
+ _gobAction = action;
+ _forceNextState[0] = -1;
+ _forceNextState[1] = -1;
+ _forceNextState[2] = -1;
+
+ if (action == 3) {
+ posX = _vm->_global->_inter_mouseX + 6;
+ posY = _vm->_global->_inter_mouseY + 7;
+ } else if (action == 4) {
+ posX = _vm->_global->_inter_mouseX + 7;
+ posY = _vm->_global->_inter_mouseY + 12;
+ } else {
+ posX = _vm->_global->_inter_mouseX;
+ posY = _vm->_global->_inter_mouseY;
+ }
+
+ moveFindItem(posX, posY);
+ adjustDest(posX, posY);
+ adjustTarget();
+
+ _vm->_map->_destX = _pressedMapX;
+ _gobDestX = _pressedMapX;
+
+ _vm->_map->_destY = _pressedMapY;
+ _gobDestY = _pressedMapY;
+
+ targetDummyItem(gobDesc);
+
+ targetItem();
+ initiateMove();
+
+ moveCheckSelect(framesCount, gobDesc, pGobIndex, pNextAct);
+ } else {
+
+ if (_readyToAct != 0 &&
+ (_vm->_map->_curGoblinX != _pressedMapX ||
+ _vm->_map->_curGoblinY != _pressedMapY))
+ _readyToAct = 0;
+
+ if (gobDesc->type == 1) {
+ *pGobIndex = peekGoblin(gobDesc);
+ }
+ }
+}
+
+void Goblin::moveTreatRopeStairs(Gob_Object *gobDesc) {
+ if (_currentGoblin != 1)
+ return;
+
+ if (gobDesc->nextState == 28
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 6) {
+ _forceNextState[0] = 28;
+ _forceNextState[1] = -1;
+ }
+
+ if (gobDesc->nextState == 29
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 6) {
+ _forceNextState[0] = 29;
+ _forceNextState[1] = -1;
+ }
+
+ if ((gobDesc->nextState == 28 || gobDesc->nextState == 29
+ || gobDesc->nextState == 20)
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6) {
+ if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4
+ || gobDesc->curLookDir == 2)
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 6) {
+ _forceNextState[0] = 28;
+ _forceNextState[1] = -1;
+ } else if ((gobDesc->curLookDir == 0
+ || gobDesc->curLookDir == 4
+ || gobDesc->curLookDir == 6)
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 6) {
+ _forceNextState[0] = 29;
+ _forceNextState[1] = -1;
+ }
+ }
+
+ if (gobDesc->nextState == 8
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 3) {
+ _forceNextState[0] = 8;
+ _forceNextState[1] = -1;
+ }
+
+ if (gobDesc->nextState == 9
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 3) {
+ _forceNextState[0] = 9;
+ _forceNextState[1] = -1;
+ }
+
+ if (gobDesc->nextState == 20
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3) {
+ if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4
+ || gobDesc->curLookDir == 2)
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 3) {
+ _forceNextState[0] = 8;
+ _forceNextState[1] = -1;
+ } else if ((gobDesc->curLookDir == 0
+ || gobDesc->curLookDir == 4
+ || gobDesc->curLookDir == 6)
+ && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 3) {
+ _forceNextState[0] = 9;
+ _forceNextState[1] = -1;
+ }
+ }
+
+}
+
+void Goblin::movePathFind(Gob_Object *gobDesc, int16 nextAct) {
+ if (_pathExistence == 1) {
+ _vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
+ _vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
+
+ if (_vm->_map->_curGoblinX == _pressedMapX &&
+ _vm->_map->_curGoblinY == _pressedMapY && _gobAction != 0) {
+ _readyToAct = 1;
+ _pathExistence = 0;
+ }
+
+ nextAct = _vm->_map->getDirection(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
+ _vm->_map->_destX, _vm->_map->_destY);
+
+ if (nextAct == 0)
+ _pathExistence = 0;
+ } else if (_pathExistence == 3) {
+ _vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
+ _vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
+
+ if (_vm->_map->_curGoblinX == _gobDestX && _vm->_map->_curGoblinY == _gobDestY) {
+ _pathExistence = 1;
+ _vm->_map->_destX = _pressedMapX;
+ _vm->_map->_destY = _pressedMapY;
+ } else {
+
+ if (_vm->_map->checkDirectPath(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
+ _gobDestX, _gobDestY) == 1) {
+ _vm->_map->_destX = _gobDestX;
+ _vm->_map->_destY = _gobDestY;
+ } else if (_vm->_map->_curGoblinX == _vm->_map->_destX && _vm->_map->_curGoblinY == _vm->_map->_destY) {
+
+ if (_vm->_map->_nearestWayPoint > _vm->_map->_nearestDest) {
+ _vm->_map->optimizePoints();
+
+ _vm->_map->_destX =
+ _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
+ x;
+ _vm->_map->_destY =
+ _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
+ y;
+
+ if (_vm->_map->_nearestWayPoint > _vm->_map->_nearestDest)
+ _vm->_map->_nearestWayPoint--;
+ } else if (_vm->_map->_nearestWayPoint < _vm->_map->_nearestDest) {
+ _vm->_map->optimizePoints();
+
+ _vm->_map->_destX =
+ _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
+ x;
+ _vm->_map->_destY =
+ _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
+ y;
+
+ if (_vm->_map->_nearestWayPoint < _vm->_map->_nearestDest)
+ _vm->_map->_nearestWayPoint++;
+ } else {
+ if (_vm->_map->checkDirectPath(_vm->_map->_curGoblinX,
+ _vm->_map->_curGoblinY, _gobDestX,
+ _gobDestY) == 3 && _vm->_map->_passMap[_pressedMapY][_pressedMapX] != 0) {
+ _vm->_map->_destX = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
+ _vm->_map->_destY = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
+ } else {
+ _pathExistence = 1;
+ _vm->_map->_destX = _pressedMapX;
+ _vm->_map->_destY = _pressedMapY;
+ }
+ }
+ }
+ nextAct =
+ _vm->_map->getDirection(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
+ _vm->_map->_destX, _vm->_map->_destY);
+ }
+ }
+
+ if (_readyToAct != 0 && (_gobAction == 3 || _gobAction == 4))
+ nextAct = 0x4dc8;
+
+ switch (nextAct) {
+ case Map::kDirW:
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
+ break;
+
+ case Map::kDirE:
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
+ break;
+
+ case 16:
+ gobDesc->nextState = 16;
+ break;
+
+ case 23:
+ gobDesc->nextState = 23;
+ break;
+
+ case Map::kDirN:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 6 &&
+ _currentGoblin != 1) {
+ _pathExistence = 0;
+ break;
+ }
+
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3) {
+ gobDesc->nextState = 8;
+ break;
+ }
+
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6 &&
+ _currentGoblin == 1) {
+ gobDesc->nextState = 28;
+ break;
+ }
+
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 2);
+ break;
+
+ case Map::kDirS:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 6 &&
+ _currentGoblin != 1) {
+ _pathExistence = 0;
+ break;
+ }
+
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3) {
+ gobDesc->nextState = 9;
+ break;
+ }
+
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6 &&
+ _currentGoblin == 1) {
+ gobDesc->nextState = 29;
+ break;
+ }
+
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 6);
+ break;
+
+ case Map::kDirSE:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX + 1] == 6 &&
+ _currentGoblin != 1) {
+ _pathExistence = 0;
+ break;
+ }
+
+ gobDesc->nextState = 5;
+ if (gobDesc->curLookDir == 4)
+ break;
+
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
+ break;
+
+ case Map::kDirSW:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX - 1] == 6 &&
+ _currentGoblin != 1) {
+ _pathExistence = 0;
+ break;
+ }
+
+ gobDesc->nextState = 7;
+ if (gobDesc->curLookDir == 0)
+ break;
+
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
+ break;
+
+ case Map::kDirNW:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX - 1] == 6 &&
+ _currentGoblin != 1) {
+ _pathExistence = 0;
+ break;
+ }
+
+ gobDesc->nextState = 1;
+ if (gobDesc->curLookDir == 0)
+ break;
+
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
+ break;
+
+ case Map::kDirNE:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX + 1] == 6 &&
+ _currentGoblin != 1) {
+ _pathExistence = 0;
+ break;
+ }
+
+ gobDesc->nextState = 3;
+ if (gobDesc->curLookDir == 4)
+ break;
+
+ gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
+ break;
+
+ case 0x4dc8:
+
+ if (_currentGoblin == 0 && _gobAction == 3
+ && _itemIndInPocket == -1) {
+ _destItemId = -1;
+ _readyToAct = 0;
+ break;
+ }
+
+ if (_currentGoblin == 0 && _gobAction == 4 &&
+ _itemIndInPocket == -1 && _destActionItem == 0) {
+ gobDesc->multState = 104;
+ _destItemId = -1;
+ _readyToAct = 0;
+ break;
+ }
+
+ if (_currentGoblin == 0 && _gobAction == 4 &&
+ _itemIndInPocket == -1 && _destActionItem != 0 &&
+ _itemToObject[_destActionItem] != -1 &&
+ _objects[_itemToObject[_destActionItem]]->
+ pickable == 0) {
+ gobDesc->multState = 104;
+ _destItemId = -1;
+ _readyToAct = 0;
+ break;
+ }
+
+ switch (_vm->_map->_itemPoses[_destActionItem].orient) {
+ case 0:
+ case -4:
+ gobDesc->nextState = 10;
+ gobDesc->curLookDir = 0;
+ _destItemId = -1;
+ break;
+
+ case -1:
+ case 4:
+ gobDesc->nextState = 11;
+ gobDesc->curLookDir = 4;
+ _destItemId = -1;
+ break;
+ }
+ break;
+
+ default:
+ if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3 ||
+ (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6
+ && _currentGoblin == 1)) {
+ gobDesc->nextState = 20;
+ break;
+ }
+
+ switch (gobDesc->curLookDir) {
+ case 2:
+ case 4:
+ gobDesc->nextState = 18;
+ break;
+
+ case 6:
+ case 0:
+ gobDesc->nextState = 19;
+ break;
+ }
+ break;
+ }
+ return;
+}
+
+void Goblin::moveAdvance(Gob_Object *gobDesc, int16 nextAct, int16 framesCount) {
+ int16 i;
+ int16 newX;
+ int16 newY;
+ int16 flag;
+
+ movePathFind(gobDesc, nextAct);
+
+ gobDesc->curFrame++;
+ if (gobDesc->curFrame == 1)
+ gobDesc->actionStartState = gobDesc->state;
+
+ if (_goesAtTarget == 0
+ && gobDesc->stateMach == gobDesc->realStateMach) {
+ switch (gobDesc->state) {
+ case 0:
+ case 1:
+ case 7:
+ case 13:
+ case 16:
+ case 27:
+ gobDesc->curLookDir = 0;
+ break;
+
+ case 3:
+ case 4:
+ case 5:
+ case 12:
+ case 23:
+ case 26:
+ gobDesc->curLookDir = 4;
+ break;
+
+ case 28:
+ if (_currentGoblin != 1)
+ break;
+ gobDesc->curLookDir = 2;
+ break;
+
+ case 2:
+ case 8:
+ case 15:
+ case 22:
+ case 25:
+ gobDesc->curLookDir = 2;
+ break;
+
+ case 29:
+ if (_currentGoblin != 1)
+ break;
+
+ gobDesc->curLookDir = 6;
+ break;
+
+ case 6:
+ case 9:
+ case 14:
+ case 17:
+ case 24:
+ gobDesc->curLookDir = 6;
+ break;
+ }
+ }
+
+ if (gobDesc->state >= 0 && gobDesc->state < 10 &&
+ gobDesc->stateMach == gobDesc->realStateMach &&
+ (gobDesc->curFrame == 3 || gobDesc->curFrame == 6)) {
+ _vm->_snd->speakerOn(10 * _vm->_util->getRandom(3) + 50, 5);
+ }
+
+ if (_currentGoblin == 0
+ && gobDesc->stateMach == gobDesc->realStateMach
+ && (gobDesc->state == 10 || gobDesc->state == 11)
+ && gobDesc->curFrame == 9) {
+ _vm->_snd->stopSound(0);
+ if (_itemIndInPocket != -1) {
+ _vm->_snd->playSample(_soundData[14], 1, 9000);
+ }
+
+ if (_itemIndInPocket == -1) {
+ _vm->_snd->playSample(_soundData[14], 1, 5000);
+ }
+ }
+
+ if (_boreCounter++ == 120) {
+ _boreCounter = 0;
+ for (i = 0; i < 3; i++)
+ showBoredom(i);
+ }
+
+ if (gobDesc->multState != -1 && gobDesc->curFrame == framesCount &&
+ gobDesc->state != gobDesc->multState) {
+ gobDesc->nextState = gobDesc->multState;
+ gobDesc->multState = -1;
+
+ newX =
+ _vm->_scenery->_animations[gobDesc->animation].
+ layers[_gobStateLayer]->animDeltaX + gobDesc->xPos;
+
+ newY =
+ _vm->_scenery->_animations[gobDesc->animation].
+ layers[_gobStateLayer]->animDeltaY + gobDesc->yPos;
+
+ _gobStateLayer = nextLayer(gobDesc);
+
+ gobDesc->xPos = newX;
+ gobDesc->yPos = newY;
+ } else {
+ if (gobDesc->curFrame == 3 &&
+ gobDesc->stateMach == gobDesc->realStateMach &&
+ (gobDesc->state < 10 ||
+ (_currentGoblin == 1 && (gobDesc->state == 28
+ || gobDesc->state == 29))
+ )) {
+ flag = 0;
+ if (_forceNextState[0] != -1) {
+ gobDesc->nextState = _forceNextState[0];
+ for (i = 0; i < 9; i++)
+ _forceNextState[i] =
+ _forceNextState[i + 1];
+ }
+
+ _vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
+ _vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
+
+ if (gobDesc->nextState != gobDesc->state) {
+ _gobStateLayer = nextLayer(gobDesc);
+ flag = 1;
+ }
+
+ switch (gobDesc->state) {
+ case 0:
+ _gobPositions[_currentGoblin].x--;
+ break;
+
+ case 2:
+ case 8:
+ _gobPositions[_currentGoblin].y--;
+ break;
+
+ case 4:
+ _gobPositions[_currentGoblin].x++;
+ break;
+
+ case 6:
+ case 9:
+ _gobPositions[_currentGoblin].y++;
+ break;
+
+ case 1:
+ _gobPositions[_currentGoblin].x--;
+ _gobPositions[_currentGoblin].y--;
+ break;
+
+ case 3:
+ _gobPositions[_currentGoblin].x++;
+ _gobPositions[_currentGoblin].y--;
+ break;
+
+ case 5:
+ _gobPositions[_currentGoblin].x++;
+ _gobPositions[_currentGoblin].y++;
+ break;
+
+ case 7:
+ _gobPositions[_currentGoblin].x--;
+ _gobPositions[_currentGoblin].y++;
+ break;
+
+ case 38:
+ _gobPositions[_currentGoblin].y++;
+ break;
+ }
+
+ if (_currentGoblin == 1) {
+ if (gobDesc->state == 28)
+ _gobPositions[1].y--;
+
+ if (gobDesc->state == 29)
+ _gobPositions[1].y++;
+ }
+
+ if (flag != 0) {
+ _vm->_scenery->updateAnim(_gobStateLayer, 0,
+ gobDesc->animation, 0, gobDesc->xPos,
+ gobDesc->yPos, 0);
+
+ gobDesc->yPos =
+ (_vm->_map->_curGoblinY + 1) * 6 -
+ (_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop);
+ gobDesc->xPos =
+ _vm->_map->_curGoblinX * 12 - (_vm->_scenery->_toRedrawLeft -
+ _vm->_scenery->_animLeft);
+ }
+
+ if ((gobDesc->state == 10 || gobDesc->state == 11)
+ && _currentGoblin != 0)
+ _goesAtTarget = 1;
+ }
+
+ if (gobDesc->curFrame != framesCount)
+ return;
+
+ if (_forceNextState[0] != -1) {
+ gobDesc->nextState = _forceNextState[0];
+ for (i = 0; i < 10; i++)
+ _forceNextState[i] =
+ _forceNextState[i + 1];
+ }
+
+ _vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
+ _vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
+
+ _gobStateLayer = nextLayer(gobDesc);
+ if (gobDesc->stateMach == gobDesc->realStateMach) {
+
+ switch (gobDesc->nextState) {
+ case 0:
+ _gobPositions[_currentGoblin].x--;
+ break;
+
+ case 2:
+ case 8:
+ _gobPositions[_currentGoblin].y--;
+ break;
+
+ case 4:
+ _gobPositions[_currentGoblin].x++;
+ break;
+
+ case 6:
+ case 9:
+ _gobPositions[_currentGoblin].y++;
+ break;
+
+ case 1:
+ _gobPositions[_currentGoblin].x--;
+ _gobPositions[_currentGoblin].y--;
+ break;
+
+ case 3:
+ _gobPositions[_currentGoblin].x++;
+ _gobPositions[_currentGoblin].y--;
+ break;
+
+ case 5:
+ _gobPositions[_currentGoblin].x++;
+ _gobPositions[_currentGoblin].y++;
+ break;
+
+ case 7:
+ _gobPositions[_currentGoblin].x--;
+ _gobPositions[_currentGoblin].y++;
+ break;
+
+ case 38:
+ _gobPositions[_currentGoblin].y++;
+ break;
+ }
+ if (_currentGoblin == 1) {
+ if (gobDesc->nextState == 28)
+ _gobPositions[1].y--;
+
+ if (gobDesc->nextState == 29)
+ _gobPositions[1].y++;
+ }
+ }
+
+ _vm->_scenery->updateAnim(_gobStateLayer, 0, gobDesc->animation, 0,
+ gobDesc->xPos, gobDesc->yPos, 0);
+
+ gobDesc->yPos =
+ (_vm->_map->_curGoblinY + 1) * 6 - (_vm->_scenery->_toRedrawBottom -
+ _vm->_scenery->_animTop);
+ gobDesc->xPos =
+ _vm->_map->_curGoblinX * 12 - (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
+
+ if ((gobDesc->state == 10 || gobDesc->state == 11)
+ && _currentGoblin != 0)
+ _goesAtTarget = 1;
+ }
+ return;
+}
+
+int16 Goblin::doMove(Gob_Object *gobDesc, int16 cont, int16 action) {
+ int16 framesCount;
+ int16 nextAct;
+ int16 gobIndex;
+ int16 layer;
+
+ nextAct = 0;
+ gobIndex = 0;
+
+ layer = gobDesc->stateMach[gobDesc->state][0]->layer;
+ framesCount =
+ _vm->_scenery->_animations[gobDesc->animation].layers[layer]->framesCount;
+
+ if (VAR(59) == 0 &&
+ gobDesc->state != 30 && gobDesc->state != 31) {
+ gobDesc->order = (gobDesc->bottom) / 24 + 3;
+ }
+
+ if (_positionedGob != _currentGoblin) {
+ _vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
+ _vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
+ }
+
+ _positionedGob = _currentGoblin;
+
+ gobDesc->animation =
+ gobDesc->stateMach[gobDesc->state][gobDesc->stateColumn]->
+ animation;
+
+ _gobStateLayer =
+ gobDesc->stateMach[gobDesc->state][gobDesc->stateColumn]->layer;
+
+ moveInitStep(framesCount, action, cont, gobDesc, &gobIndex,
+ &nextAct);
+ moveTreatRopeStairs(gobDesc);
+ moveAdvance(gobDesc, nextAct, framesCount);
+
+ return gobIndex;
+}
+
+void Goblin::freeObjects(void) {
+ int16 i;
+ int16 state;
+ int16 col;
+
+ for (i = 0; i < 16; i++) {
+ if (_soundData[i] == 0)
+ continue;
+
+ _vm->_snd->freeSoundData(_soundData[i]);
+ _soundData[i] = 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (_goblins[i] == 0)
+ continue;
+
+ _goblins[i]->stateMach = _goblins[i]->realStateMach;
+
+ for (state = 0; state < 40; state++) {
+ for (col = 0; col < 6; col++) {
+ delete _goblins[i]->stateMach[state][col];
+ _goblins[i]->stateMach[state][col] = 0;
+ }
+ }
+
+ if (i == 3) {
+ for (state = 40; state < 70; state++) {
+ delete _goblins[3]->stateMach[state][0];
+ _goblins[3]->stateMach[state][0] = 0;
+ }
+ }
+
+ delete[] _goblins[i]->stateMach;
+ delete _goblins[i];
+ _goblins[i] = 0;
+ }
+
+ for (i = 0; i < 20; i++) {
+ if (_objects[i] == 0)
+ continue;
+
+ _objects[i]->stateMach = _objects[i]->realStateMach;
+
+ for (state = 0; state < 40; state++) {
+ for (col = 0; col < 6; col++) {
+ delete _objects[i]->stateMach[state][col];
+ _objects[i]->stateMach[state][col] = 0;
+ }
+ }
+
+ delete[] _objects[i]->stateMach;
+ delete _objects[i];
+ _objects[i] = 0;
+ }
+}
+
+void Goblin::zeroObjects(void) {
+ int16 i;
+
+ for (i = 0; i < 4; i++)
+ _goblins[i] = 0;
+
+ for (i = 0; i < 20; i++)
+ _objects[i] = 0;
+
+ for (i = 0; i < 16; i++)
+ _soundData[i] = 0;
+}
+
+void Goblin::freeAllObjects(void) {
+ _vm->_util->deleteList(_objList);
+ freeObjects();
+}
+
+void Goblin::loadObjects(char *source) {
+ int16 i;
+
+ zeroObjects();
+ for (i = 0; i < 20; i++)
+ _itemToObject[i] = 100;
+
+ freeObjects();
+ initList();
+ strcpy(_vm->_map->_sourceFile, source);
+
+ _vm->_map->_sourceFile[strlen(_vm->_map->_sourceFile) - 4] = 0;
+ _vm->_map->loadMapObjects(source);
+
+ for (i = 0; i < _gobsCount; i++)
+ placeObject(_goblins[i], 0);
+
+ for (i = 0; i < _objCount; i++) {
+ placeObject(_objects[i], 1);
+ }
+
+ initVarPointers();
+ _actDestItemDesc = 0;
+}
+
+void Goblin::saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal) {
+ Gob_Object *obj;
+ *_some0ValPtr = someVal;
+ *_curGobXPosVarPtr = xPos;
+ *_curGobYPosVarPtr = yPos;
+ *_itemInPocketVarPtr = _itemIndInPocket;
+
+ obj = _goblins[_currentGoblin];
+
+ *_curGobStateVarPtr = obj->state;
+ *_curGobFrameVarPtr = obj->curFrame;
+ *_curGobMultStateVarPtr = obj->multState;
+ *_curGobNextStateVarPtr = obj->nextState;
+ *_curGobScrXVarPtr = obj->xPos;
+ *_curGobScrYVarPtr = obj->yPos;
+ *_curGobLeftVarPtr = obj->left;
+ *_curGobTopVarPtr = obj->top;
+ *_curGobRightVarPtr = obj->right;
+ *_curGobBottomVarPtr = obj->bottom;
+ *_curGobDoAnimVarPtr = obj->doAnim;
+ *_curGobOrderVarPtr = obj->order;
+ *_curGobNoTickVarPtr = obj->noTick;
+ *_curGobTypeVarPtr = obj->type;
+ *_curGobMaxTickVarPtr = obj->maxTick;
+ *_curGobTickVarPtr = obj->tick;
+ *_curGobActStartStateVarPtr = obj->actionStartState;
+ *_curGobLookDirVarPtr = obj->curLookDir;
+ *_curGobPickableVarPtr = obj->pickable;
+ *_curGobRelaxVarPtr = obj->relaxTime;
+ *_curGobMaxFrameVarPtr = getObjMaxFrame(obj);
+
+ if (_actDestItemDesc == 0)
+ return;
+
+ obj = _actDestItemDesc;
+ *_destItemStateVarPtr = obj->state;
+ *_destItemFrameVarPtr = obj->curFrame;
+ *_destItemMultStateVarPtr = obj->multState;
+ *_destItemNextStateVarPtr = obj->nextState;
+ *_destItemScrXVarPtr = obj->xPos;
+ *_destItemScrYVarPtr = obj->yPos;
+ *_destItemLeftVarPtr = obj->left;
+ *_destItemTopVarPtr = obj->top;
+ *_destItemRightVarPtr = obj->right;
+ *_destItemBottomVarPtr = obj->bottom;
+ *_destItemDoAnimVarPtr = obj->doAnim;
+ *_destItemOrderVarPtr = obj->order;
+ *_destItemNoTickVarPtr = obj->noTick;
+ *_destItemTypeVarPtr = obj->type;
+ *_destItemMaxTickVarPtr = obj->maxTick;
+ *_destItemTickVarPtr = obj->tick;
+ *_destItemActStartStVarPtr = obj->actionStartState;
+ *_destItemLookDirVarPtr = obj->curLookDir;
+ *_destItemPickableVarPtr = obj->pickable;
+ *_destItemRelaxVarPtr = obj->relaxTime;
+ *_destItemMaxFrameVarPtr = getObjMaxFrame(obj);
+
+ _destItemState = obj->state;
+ _destItemType = obj->type;
+}
+
+void Goblin::initVarPointers(void) {
+ _gobRetVarPtr = (int32 *)VAR_ADDRESS(59);
+ _curGobStateVarPtr = (int32 *)VAR_ADDRESS(60);
+ _curGobFrameVarPtr = (int32 *)VAR_ADDRESS(61);
+ _curGobMultStateVarPtr = (int32 *)VAR_ADDRESS(62);
+ _curGobNextStateVarPtr = (int32 *)VAR_ADDRESS(63);
+ _curGobScrXVarPtr = (int32 *)VAR_ADDRESS(64);
+ _curGobScrYVarPtr = (int32 *)VAR_ADDRESS(65);
+ _curGobLeftVarPtr = (int32 *)VAR_ADDRESS(66);
+ _curGobTopVarPtr = (int32 *)VAR_ADDRESS(67);
+ _curGobRightVarPtr = (int32 *)VAR_ADDRESS(68);
+ _curGobBottomVarPtr = (int32 *)VAR_ADDRESS(69);
+ _curGobDoAnimVarPtr = (int32 *)VAR_ADDRESS(70);
+ _curGobOrderVarPtr = (int32 *)VAR_ADDRESS(71);
+ _curGobNoTickVarPtr = (int32 *)VAR_ADDRESS(72);
+ _curGobTypeVarPtr = (int32 *)VAR_ADDRESS(73);
+ _curGobMaxTickVarPtr = (int32 *)VAR_ADDRESS(74);
+ _curGobTickVarPtr = (int32 *)VAR_ADDRESS(75);
+ _curGobActStartStateVarPtr = (int32 *)VAR_ADDRESS(76);
+ _curGobLookDirVarPtr = (int32 *)VAR_ADDRESS(77);
+ _curGobPickableVarPtr = (int32 *)VAR_ADDRESS(80);
+ _curGobRelaxVarPtr = (int32 *)VAR_ADDRESS(81);
+ _destItemStateVarPtr = (int32 *)VAR_ADDRESS(82);
+ _destItemFrameVarPtr = (int32 *)VAR_ADDRESS(83);
+ _destItemMultStateVarPtr = (int32 *)VAR_ADDRESS(84);
+ _destItemNextStateVarPtr = (int32 *)VAR_ADDRESS(85);
+ _destItemScrXVarPtr = (int32 *)VAR_ADDRESS(86);
+ _destItemScrYVarPtr = (int32 *)VAR_ADDRESS(87);
+ _destItemLeftVarPtr = (int32 *)VAR_ADDRESS(88);
+ _destItemTopVarPtr = (int32 *)VAR_ADDRESS(89);
+ _destItemRightVarPtr = (int32 *)VAR_ADDRESS(90);
+ _destItemBottomVarPtr = (int32 *)VAR_ADDRESS(91);
+ _destItemDoAnimVarPtr = (int32 *)VAR_ADDRESS(92);
+ _destItemOrderVarPtr = (int32 *)VAR_ADDRESS(93);
+ _destItemNoTickVarPtr = (int32 *)VAR_ADDRESS(94);
+ _destItemTypeVarPtr = (int32 *)VAR_ADDRESS(95);
+ _destItemMaxTickVarPtr = (int32 *)VAR_ADDRESS(96);
+ _destItemTickVarPtr = (int32 *)VAR_ADDRESS(97);
+ _destItemActStartStVarPtr = (int32 *)VAR_ADDRESS(98);
+ _destItemLookDirVarPtr = (int32 *)VAR_ADDRESS(99);
+ _destItemPickableVarPtr = (int32 *)VAR_ADDRESS(102);
+ _destItemRelaxVarPtr = (int32 *)VAR_ADDRESS(103);
+ _destItemMaxFrameVarPtr = (int32 *)VAR_ADDRESS(105);
+ _curGobVarPtr = (int32 *)VAR_ADDRESS(106);
+ _some0ValPtr = (int32 *)VAR_ADDRESS(107);
+ _curGobXPosVarPtr = (int32 *)VAR_ADDRESS(108);
+ _curGobYPosVarPtr = (int32 *)VAR_ADDRESS(109);
+ _curGobMaxFrameVarPtr = (int32 *)VAR_ADDRESS(110);
+
+ _itemInPocketVarPtr = (int32 *)VAR_ADDRESS(114);
+
+ *_itemInPocketVarPtr = -2;
+}
+
+void Goblin::loadGobDataFromVars(void) {
+ Gob_Object *obj;
+
+ _itemIndInPocket = *_itemInPocketVarPtr;
+
+ obj = _goblins[_currentGoblin];
+
+ obj->state = *_curGobStateVarPtr;
+ obj->curFrame = *_curGobFrameVarPtr;
+ obj->multState = *_curGobMultStateVarPtr;
+ obj->nextState = *_curGobNextStateVarPtr;
+ obj->xPos = *_curGobScrXVarPtr;
+ obj->yPos = *_curGobScrYVarPtr;
+ obj->left = *_curGobLeftVarPtr;
+ obj->top = *_curGobTopVarPtr;
+ obj->right = *_curGobRightVarPtr;
+ obj->bottom = *_curGobBottomVarPtr;
+ obj->doAnim = *_curGobDoAnimVarPtr;
+ obj->order = *_curGobOrderVarPtr;
+ obj->noTick = *_curGobNoTickVarPtr;
+ obj->type = *_curGobTypeVarPtr;
+ obj->maxTick = *_curGobMaxTickVarPtr;
+ obj->tick = *_curGobTickVarPtr;
+ obj->actionStartState = *_curGobActStartStateVarPtr;
+ obj->curLookDir = *_curGobLookDirVarPtr;
+ obj->pickable = *_curGobPickableVarPtr;
+ obj->relaxTime = *_curGobRelaxVarPtr;
+
+ if (_actDestItemDesc == 0)
+ return;
+
+ obj = _actDestItemDesc;
+
+ obj->state = *_destItemStateVarPtr;
+ obj->curFrame = *_destItemFrameVarPtr;
+ obj->multState = *_destItemMultStateVarPtr;
+ obj->nextState = *_destItemNextStateVarPtr;
+ obj->xPos = *_destItemScrXVarPtr;
+ obj->yPos = *_destItemScrYVarPtr;
+ obj->left = *_destItemLeftVarPtr;
+ obj->top = *_destItemTopVarPtr;
+ obj->right = *_destItemRightVarPtr;
+ obj->bottom = *_destItemBottomVarPtr;
+ obj->doAnim = *_destItemDoAnimVarPtr;
+ obj->order = *_destItemOrderVarPtr;
+ obj->noTick = *_destItemNoTickVarPtr;
+ obj->type = *_destItemTypeVarPtr;
+ obj->maxTick = *_destItemMaxTickVarPtr;
+ obj->tick = *_destItemTickVarPtr;
+ obj->actionStartState = *_destItemActStartStVarPtr;
+ obj->curLookDir = *_destItemLookDirVarPtr;
+ obj->pickable = *_destItemPickableVarPtr;
+ obj->relaxTime = *_destItemRelaxVarPtr;
+
+ if (obj->type != _destItemType)
+ obj->toRedraw = 1;
+
+ if (obj->state != _destItemState && obj->type == 0)
+ obj->toRedraw = 1;
+}
+
+void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) {
+ int16 x;
+ int16 y;
+
+ if (_objects[indexToPocket]->pickable != 1)
+ return;
+
+ _objects[indexToPocket]->type = 3;
+
+ _itemIndInPocket = indexToPocket;
+ _itemIdInPocket = idToPocket;
+
+ for (y = 0; y < Map::kMapHeight; y++) {
+ for (x = 0; x < Map::kMapWidth; x++) {
+ if (_itemByteFlag == 1) {
+ if (((_vm->_map->_itemsMap[y][x] & 0xff00) >> 8) ==
+ idToPocket)
+ _vm->_map->_itemsMap[y][x] &= 0xff;
+ } else {
+ if ((_vm->_map->_itemsMap[y][x] & 0xff) == idToPocket)
+ _vm->_map->_itemsMap[y][x] &= 0xff00;
+ }
+ }
+ }
+
+ if (idToPocket >= 0 && idToPocket < 20) {
+ _vm->_map->_itemPoses[_itemIdInPocket].x = 0;
+ _vm->_map->_itemPoses[_itemIdInPocket].y = 0;
+ _vm->_map->_itemPoses[_itemIdInPocket].orient = 0;
+ }
+}
+
+void Goblin::placeItem(int16 indexInPocket, int16 idInPocket) {
+ Gob_Object *itemDesc;
+ int16 lookDir;
+ int16 xPos;
+ int16 yPos;
+ int16 layer;
+
+ itemDesc = _objects[indexInPocket];
+ lookDir = _goblins[0]->curLookDir & 4;
+
+ xPos = _gobPositions[0].x;
+ yPos = _gobPositions[0].y;
+
+ _itemIndInPocket = -1;
+ _itemIdInPocket = 0;
+
+ itemDesc->pickable = 1;
+ itemDesc->type = 0;
+ itemDesc->toRedraw = 1;
+ itemDesc->curFrame = 0;
+ itemDesc->order = _goblins[0]->order;
+ itemDesc->animation =
+ itemDesc->stateMach[itemDesc->state][0]->animation;
+ layer =
+ itemDesc->stateMach[itemDesc->state][itemDesc->stateColumn]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, itemDesc->animation, 0,
+ itemDesc->xPos, itemDesc->yPos, 0);
+
+ itemDesc->yPos +=
+ (_gobPositions[0].y * 6) + 5 - _vm->_scenery->_toRedrawBottom;
+
+ if (lookDir == 4) {
+ itemDesc->xPos += (_gobPositions[0].x * 12 + 14)
+ - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2;
+ } else {
+ itemDesc->xPos += (_gobPositions[0].x * 12)
+ - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2;
+ }
+
+ _vm->_map->placeItem(xPos, yPos, idInPocket);
+
+ if (yPos > 0) {
+ _vm->_map->placeItem(xPos, yPos - 1, idInPocket);
+ }
+
+ if (lookDir == 4) {
+ if (xPos < Map::kMapWidth - 1) {
+ _vm->_map->placeItem(xPos + 1, yPos, idInPocket);
+
+ if (yPos > 0) {
+ _vm->_map->placeItem(xPos + 1, yPos - 1, idInPocket);
+ }
+ }
+ } else {
+ if (xPos > 0) {
+ _vm->_map->placeItem(xPos - 1, yPos, idInPocket);
+
+ if (yPos > 0) {
+ _vm->_map->placeItem(xPos - 1, yPos - 1, idInPocket);
+ }
+ }
+ }
+
+ if (idInPocket >= 0 && idInPocket < 20) {
+ _vm->_map->_itemPoses[idInPocket].x = _gobPositions[0].x;
+ _vm->_map->_itemPoses[idInPocket].y = _gobPositions[0].y;
+ _vm->_map->_itemPoses[idInPocket].orient = lookDir;
+ if (_vm->_map->_itemPoses[idInPocket].orient == 0) {
+// _vm->_map->_itemPoses[idInPocket].x++;
+ if (_vm->_map->_passMap[(int)_vm->_map->_itemPoses[idInPocket].y][_vm->_map->_itemPoses[idInPocket].x + 1] == 1)
+ _vm->_map->_itemPoses[idInPocket].x++;
+ } else {
+ if (_vm->_map->_passMap[(int)_vm->_map->_itemPoses[idInPocket].y][_vm->_map->_itemPoses[idInPocket].x - 1] == 1)
+ _vm->_map->_itemPoses[idInPocket].x--;
+ }
+ }
+}
+
+void Goblin::swapItems(int16 indexToPick, int16 idToPick) {
+ int16 layer;
+ Gob_Object *pickObj;
+ Gob_Object *placeObj;
+ int16 idToPlace;
+ int16 x;
+ int16 y;
+
+ pickObj = _objects[indexToPick];
+ placeObj = _objects[_itemIndInPocket];
+
+ idToPlace = _itemIdInPocket;
+ pickObj->type = 3;
+ _itemIndInPocket = indexToPick;
+ _itemIdInPocket = idToPick;
+
+ if (_itemByteFlag == 0) {
+ for (y = 0; y < Map::kMapHeight; y++) {
+ for (x = 0; x < Map::kMapWidth; x++) {
+ if ((_vm->_map->_itemsMap[y][x] & 0xff) == idToPick)
+ _vm->_map->_itemsMap[y][x] =
+ (_vm->_map->_itemsMap[y][x] & 0xff00) +
+ idToPlace;
+ }
+ }
+ } else {
+
+ for (y = 0; y < Map::kMapHeight; y++) {
+ for (x = 0; x < Map::kMapWidth; x++) {
+ if (((_vm->_map->_itemsMap[y][x] & 0xff00) >> 8) ==
+ idToPick)
+ _vm->_map->_itemsMap[y][x] =
+ (_vm->_map->_itemsMap[y][x] & 0xff) +
+ (idToPlace << 8);
+ }
+ }
+ }
+
+ if (idToPick >= 0 && idToPick < 20) {
+ _vm->_map->_itemPoses[idToPlace].x =
+ _vm->_map->_itemPoses[_itemIdInPocket].x;
+ _vm->_map->_itemPoses[idToPlace].y =
+ _vm->_map->_itemPoses[_itemIdInPocket].y;
+ _vm->_map->_itemPoses[idToPlace].orient =
+ _vm->_map->_itemPoses[_itemIdInPocket].orient;
+
+ _vm->_map->_itemPoses[_itemIdInPocket].x = 0;
+ _vm->_map->_itemPoses[_itemIdInPocket].y = 0;
+ _vm->_map->_itemPoses[_itemIdInPocket].orient = 0;
+ }
+
+ _itemIndInPocket = -1;
+ _itemIdInPocket = 0;
+
+ placeObj->type = 0;
+ placeObj->nextState = -1;
+ placeObj->multState = -1;
+ placeObj->unk14 = 0;
+ placeObj->toRedraw = 1;
+ placeObj->curFrame = 0;
+ placeObj->order = _goblins[0]->order;
+
+ placeObj->animation =
+ placeObj->stateMach[placeObj->state][0]->animation;
+
+ layer =
+ placeObj->stateMach[placeObj->state][placeObj->stateColumn]->layer;
+ _vm->_scenery->updateAnim(layer, 0, placeObj->animation, 0, placeObj->xPos,
+ placeObj->yPos, 0);
+
+ placeObj->yPos +=
+ (_gobPositions[0].y * 6) + 5 - _vm->_scenery->_toRedrawBottom;
+
+ if (_vm->_map->_itemPoses[idToPlace].orient == 4) {
+ placeObj->xPos += (_gobPositions[0].x * 12 + 14)
+ - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2;
+ } else {
+ placeObj->xPos += (_gobPositions[0].x * 12)
+ - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2;
+ }
+}
+
+void Goblin::treatItemPick(int16 itemId) {
+ int16 itemIndex;
+ Gob_Object *gobDesc;
+
+ gobDesc = _goblins[_currentGoblin];
+
+ if (gobDesc->curFrame != 9)
+ return;
+
+ if (gobDesc->stateMach != gobDesc->realStateMach)
+ return;
+
+ _readyToAct = 0;
+ _goesAtTarget = 0;
+
+ itemIndex = _itemToObject[itemId];
+ if (itemId != 0 && itemIndex != -1
+ && _objects[itemIndex]->pickable != 1)
+ itemIndex = -1;
+
+ if (_itemIndInPocket != -1 && _itemIndInPocket == itemIndex)
+ itemIndex = -1;
+
+ if (_itemIndInPocket != -1 && itemIndex != -1
+ && _objects[itemIndex]->pickable == 1) {
+ swapItems(itemIndex, itemId);
+ _itemIndInPocket = itemIndex;
+ _itemIdInPocket = itemId;
+ return;
+ }
+
+ if (_itemIndInPocket != -1 && itemIndex == -1) {
+ placeItem(_itemIndInPocket, _itemIdInPocket);
+ return;
+ }
+
+ if (_itemIndInPocket == -1 && itemIndex != -1) {
+ pickItem(itemIndex, itemId);
+ return;
+ }
+}
+
+int16 Goblin::treatItem(int16 action) {
+ int16 state;
+
+ state = _goblins[_currentGoblin]->state;
+ if ((state == 10 || state == 11) &&
+ _goblins[_currentGoblin]->curFrame == 0) {
+ _readyToAct = 0;
+ }
+
+ if (action == 3 && _currentGoblin == 0 &&
+ (state == 10 || state == 11) && _goblins[0]->curFrame == 0) {
+ saveGobDataToVars(_gobPositions[_currentGoblin].x,
+ _gobPositions[_currentGoblin].y, 0);
+ _goesAtTarget = 1;
+ return -1;
+ }
+
+ if (_noPick == 0 && _currentGoblin == 0 &&
+ (state == 10 || state == 11)) {
+ treatItemPick(_destActionItem);
+
+ saveGobDataToVars(_gobPositions[_currentGoblin].x,
+ _gobPositions[_currentGoblin].y, 0);
+ return 0;
+ }
+
+ if (_goesAtTarget == 0) {
+ saveGobDataToVars(_gobPositions[_currentGoblin].x,
+ _gobPositions[_currentGoblin].y, 0);
+ return 0;
+ } else {
+
+ if (_itemToObject[_destActionItem] != 100 &&
+ _destActionItem != 0) {
+
+ if (_itemToObject[_destActionItem] == -1) {
+ _actDestItemDesc = 0;
+ } else {
+ _actDestItemDesc =
+ _objects[_itemToObject
+ [_destActionItem]];
+ }
+ }
+
+ _goesAtTarget = 0;
+ saveGobDataToVars(_gobPositions[_currentGoblin].x,
+ _gobPositions[_currentGoblin].y, 0);
+ return _destActionItem;
+ }
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h
new file mode 100644
index 0000000000..858bf247ae
--- /dev/null
+++ b/engines/gob/goblin.h
@@ -0,0 +1,231 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_GOBLIN_H
+#define GOB_GOBLIN_H
+
+#include "gob/util.h"
+#include "gob/sound.h"
+
+namespace Gob {
+
+#define TYPE_USUAL 0
+#define TYPE_AMORPHOUS 1
+#define TYPE_MOBILE 3
+
+class Goblin {
+public:
+#pragma START_PACK_STRUCTS
+ struct Gob_State {
+ int16 animation;// +0h
+ int16 layer; // +2h
+ int16 unk0; // +4h
+ int16 unk1; // +6h
+ int16 sndItem; // +8h, high/low byte - sound sample index
+ int16 freq; // +Ah, high/low byte * 100 - frequency
+ int16 repCount; // +Ch high/low byte - repeat count
+ int16 sndFrame; // +Eh
+ } GCC_PACK;
+
+ typedef Gob_State *Gob_PState;
+
+ typedef Gob_PState Gob_StateLine[6];
+
+ struct Gob_Object {
+ int16 animation; // +0h
+ int16 state; // +2h
+ int16 stateColumn; // +4h
+ int16 curFrame; // +6h
+ int16 xPos; // +8h
+ int16 yPos; // +Ah
+ int16 dirtyLeft; // +Ch
+ int16 dirtyTop; // +Eh
+ int16 dirtyRight; // +10h
+ int16 dirtyBottom; // +12h
+ int16 left; // +14h
+ int16 top; // +16h
+ int16 right; // +18h
+ int16 bottom; // +1ah
+ int16 nextState; // +1ch
+ int16 multState; // +1eh
+ int16 actionStartState; // +20h
+ int16 curLookDir; // +22h
+ int16 pickable; // +24h
+ int16 relaxTime; // +26h
+ Gob_StateLine *stateMach; // +28h
+ Gob_StateLine *realStateMach; // +2ch
+ char doAnim; // +30h
+ char order; // +31h
+ char noTick; // +32h
+ char toRedraw; // +33h
+ char type; // +34h
+ char maxTick; // +35h
+ char tick; // +36h
+ char multObjIndex; // +37h, from which play mult animations
+ char unk14; // +38h
+ char visible; // +39h
+ } GCC_PACK;
+
+ struct Gob_Pos {
+ char x;
+ char y;
+ } GCC_PACK;
+#pragma END_PACK_STRUCTS
+
+ Util::List *_objList;
+ Gob_Object *_goblins[4];
+ int16 _currentGoblin;
+ Snd::SoundDesc *_soundData[16];
+ int16 _gobStateLayer;
+ char _goesAtTarget;
+ char _readyToAct;
+ int16 _gobAction; // 0 - move, 3 - do action, 4 - pick
+ // goblins 0 - picker, 1 - fighter, 2 - mage
+ Gob_Pos _gobPositions[3];
+ int16 _gobDestX;
+ int16 _gobDestY;
+ int16 _pressedMapX;
+ int16 _pressedMapY;
+ char _pathExistence;
+
+ // Pointers to interpreter variables
+ int32 *_some0ValPtr;
+
+ int32 *_gobRetVarPtr;
+ int32 *_curGobVarPtr;
+ int32 *_curGobXPosVarPtr;
+ int32 *_curGobYPosVarPtr;
+ int32 *_itemInPocketVarPtr;
+
+ int32 *_curGobStateVarPtr;
+ int32 *_curGobFrameVarPtr;
+ int32 *_curGobMultStateVarPtr;
+ int32 *_curGobNextStateVarPtr;
+ int32 *_curGobScrXVarPtr;
+ int32 *_curGobScrYVarPtr;
+ int32 *_curGobLeftVarPtr;
+ int32 *_curGobTopVarPtr;
+ int32 *_curGobRightVarPtr;
+ int32 *_curGobBottomVarPtr;
+ int32 *_curGobDoAnimVarPtr;
+ int32 *_curGobOrderVarPtr;
+ int32 *_curGobNoTickVarPtr;
+ int32 *_curGobTypeVarPtr;
+ int32 *_curGobMaxTickVarPtr;
+ int32 *_curGobTickVarPtr;
+ int32 *_curGobActStartStateVarPtr;
+ int32 *_curGobLookDirVarPtr;
+ int32 *_curGobPickableVarPtr;
+ int32 *_curGobRelaxVarPtr;
+ int32 *_curGobMaxFrameVarPtr;
+
+ int32 *_destItemStateVarPtr;
+ int32 *_destItemFrameVarPtr;
+ int32 *_destItemMultStateVarPtr;
+ int32 *_destItemNextStateVarPtr;
+ int32 *_destItemScrXVarPtr;
+ int32 *_destItemScrYVarPtr;
+ int32 *_destItemLeftVarPtr;
+ int32 *_destItemTopVarPtr;
+ int32 *_destItemRightVarPtr;
+ int32 *_destItemBottomVarPtr;
+ int32 *_destItemDoAnimVarPtr;
+ int32 *_destItemOrderVarPtr;
+ int32 *_destItemNoTickVarPtr;
+ int32 *_destItemTypeVarPtr;
+ int32 *_destItemMaxTickVarPtr;
+ int32 *_destItemTickVarPtr;
+ int32 *_destItemActStartStVarPtr;
+ int32 *_destItemLookDirVarPtr;
+ int32 *_destItemPickableVarPtr;
+ int32 *_destItemRelaxVarPtr;
+ int32 *_destItemMaxFrameVarPtr;
+
+ int16 _destItemType;
+ int16 _destItemState;
+ int16 _itemToObject[20];
+ Gob_Object *_objects[20];
+ int16 _objCount;
+ int16 _gobsCount;
+ int16 _itemIndInPocket;
+ int16 _itemIdInPocket;
+ char _itemByteFlag;
+ int16 _destItemId;
+ int16 _destActionItem;
+ Gob_Object *_actDestItemDesc;
+ int16 _forceNextState[10];
+ char _boreCounter;
+ int16 _positionedGob;
+ char _noPick;
+
+ // Functions
+ char rotateState(int16 from, int16 to);
+ void playSound(Snd::SoundDesc * snd, int16 repCount, int16 freq);
+ void drawObjects(void);
+ void animateObjects(void);
+ void placeObject(Gob_Object * objDesc, char animated);
+ int16 getObjMaxFrame(Gob_Object * obj);
+ int16 objIntersected(Gob_Object * obj1, Gob_Object * obj2);
+ void setMultStates(Gob_Object * gobDesc);
+ int16 nextLayer(Gob_Object * gobDesc);
+ void showBoredom(int16 gobIndex);
+ void switchGoblin(int16 index);
+ void freeObjects(void);
+ void zeroObjects(void);
+ void freeAllObjects(void);
+ void loadObjects(char *source);
+ void initVarPointers(void);
+ void saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal);
+ void loadGobDataFromVars(void);
+ void pickItem(int16 indexToPocket, int16 idToPocket);
+ void placeItem(int16 indexInPocket, int16 idInPocket);
+ void swapItems(int16 indexToPick, int16 idToPick);
+ void treatItemPick(int16 itemId);
+ int16 treatItem(int16 action);
+ int16 doMove(Gob_Object *gobDesc, int16 cont, int16 action);
+
+ Goblin(GobEngine *vm);
+
+protected:
+ int16 _rotStates[4][4];
+ GobEngine *_vm;
+
+ int16 peekGoblin(Gob_Object *curGob);
+ void initList(void);
+ void sortByOrder(Util::List *list);
+ void adjustDest(int16 posX, int16 posY);
+ void adjustTarget(void);
+ void targetDummyItem(Gob_Object *gobDesc);
+ void targetItem(void);
+ void initiateMove(void);
+ void moveFindItem(int16 posX, int16 posY);
+ void moveCheckSelect(int16 framesCount, Gob_Object * gobDesc, int16 *pGobIndex, int16 *nextAct);
+ void moveInitStep(int16 framesCount, int16 action, int16 cont,
+ Gob_Object *gobDesc, int16 *pGobIndex, int16 *pNextAct);
+ void moveTreatRopeStairs(Gob_Object *gobDesc);
+ void movePathFind(Gob_Object *gobDesc, int16 nextAct);
+ void moveAdvance(Gob_Object *gobDesc, int16 nextAct, int16 framesCount);
+};
+
+} // End of namespace Gob
+
+#endif /* __GOBLIN_H */
diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp
new file mode 100644
index 0000000000..43b6344499
--- /dev/null
+++ b/engines/gob/init.cpp
@@ -0,0 +1,272 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/dataio.h"
+#include "gob/global.h"
+#include "gob/init.h"
+#include "gob/video.h"
+#include "gob/sound.h"
+#include "gob/timer.h"
+#include "gob/sound.h"
+#include "gob/game.h"
+#include "gob/draw.h"
+#include "gob/util.h"
+#include "gob/cdrom.h"
+
+namespace Gob {
+
+void game_start(void);
+
+const char *Init::_fontNames[] = { "jeulet1.let", "jeulet2.let", "jeucar1.let", "jeumath.let" };
+
+Init::Init(GobEngine *vm) : _vm(vm) {
+ _palDesc = 0;
+}
+
+void Init::findBestCfg(void) {
+ _vm->_global->_videoMode = VIDMODE_VGA;
+ _vm->_global->_useMouse = _vm->_global->_mousePresent;
+ if (_vm->_global->_presentSound & BLASTER_FLAG)
+ _vm->_global->_soundFlags = BLASTER_FLAG | SPEAKER_FLAG | MIDI_FLAG;
+ else if (_vm->_global->_presentSound & PROAUDIO_FLAG)
+ _vm->_global->_soundFlags = PROAUDIO_FLAG | SPEAKER_FLAG | MIDI_FLAG;
+ else if (_vm->_global->_presentSound & ADLIB_FLAG)
+ _vm->_global->_soundFlags = ADLIB_FLAG | SPEAKER_FLAG | MIDI_FLAG;
+ else if (_vm->_global->_presentSound & INTERSOUND_FLAG)
+ _vm->_global->_soundFlags = INTERSOUND_FLAG | SPEAKER_FLAG;
+ else if (_vm->_global->_presentSound & SPEAKER_FLAG)
+ _vm->_global->_soundFlags = SPEAKER_FLAG;
+ else
+ _vm->_global->_soundFlags = 0;
+}
+
+void Init::soundVideo(int32 smallHeap, int16 flag) {
+ if (_vm->_global->_videoMode != 0x13 && _vm->_global->_videoMode != 0)
+ error("soundVideo: Video mode 0x%x is not supported!",
+ _vm->_global->_videoMode);
+
+ //if ((flag & 4) == 0)
+ // _vm->_video->findVideo();
+
+ _vm->_global->_mousePresent = 1;
+
+ _vm->_global->_inVM = 0;
+
+ _vm->_global->_presentSound = 0; // FIXME: sound is not supported yet
+
+ _vm->_global->_sprAllocated = 0;
+ _vm->_gtimer->enableTimer();
+
+ // _vm->_snd->setResetTimerFlag(debugFlag); // TODO
+
+ if (_vm->_global->_videoMode == 0x13)
+ _vm->_global->_colorCount = 256;
+
+ _vm->_global->_pPaletteDesc = &_vm->_global->_paletteStruct;
+ _vm->_global->_pPaletteDesc->vgaPal = _vm->_draw->_vgaPalette;
+ _vm->_global->_pPaletteDesc->unused1 = _vm->_global->_unusedPalette1;
+ _vm->_global->_pPaletteDesc->unused2 = _vm->_global->_unusedPalette2;
+ _vm->_global->_pPrimarySurfDesc = &_vm->_global->_primarySurfDesc;
+
+ if (_vm->_global->_videoMode != 0)
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, 320, 200, PRIMARY_SURFACE);
+
+ if (_vm->_global->_soundFlags & MIDI_FLAG) {
+ _vm->_global->_soundFlags &= _vm->_global->_presentSound;
+ if (_vm->_global->_presentSound & ADLIB_FLAG)
+ _vm->_global->_soundFlags |= MIDI_FLAG;
+ } else {
+ _vm->_global->_soundFlags &= _vm->_global->_presentSound;
+ }
+}
+
+void Init::cleanup(void) {
+ if (_vm->_global->_debugFlag == 0)
+ _vm->_gtimer->disableTimer();
+
+ _vm->_video->freeDriver();
+ _vm->_video->freeSurfDesc(_vm->_global->_pPrimarySurfDesc);
+ _vm->_global->_pPrimarySurfDesc = 0;
+
+ if (_vm->_snd->_cleanupFunc != 0 && _vm->_snd->_playingSound != 0) {
+ (*_vm->_snd->_cleanupFunc) (0);
+ _vm->_snd->_cleanupFunc = 0;
+ }
+ _vm->_snd->speakerOff();
+
+ _vm->_dataio->closeDataFile();
+
+ if (_vm->_global->_sprAllocated != 0)
+ error("cleanup: Error! Allocated sprites left: %d",
+ _vm->_global->_sprAllocated);
+
+ _vm->_snd->stopSound(0);
+ _vm->_util->keyboard_release();
+ g_system->quit();
+}
+
+void Init::initGame(char *totName) {
+ int16 handle2;
+ int16 i;
+ int16 handle;
+ char *infBuf;
+ char *infPtr;
+ char *infEnd;
+ int16 j;
+ char buffer[20];
+ int32 varsCount;
+/*
+src = byte ptr -2Eh
+var_1A = word ptr -1Ah
+var_18 = word ptr -18h
+var_16 = dword ptr -16h
+var_12 = word ptr -12h
+var_10 = word ptr -10h
+handle2 = word ptr -0Eh
+fileHandle = word ptr -0Ch
+numFromTot = word ptr -0Ah
+memAvail = dword ptr -6
+memBlocks = word ptr -2*/
+
+ _vm->_global->_disableVideoCfg = 0x11;
+ _vm->_global->_disableMouseCfg = 0x15;
+ soundVideo(1000, 1);
+
+ handle2 = _vm->_dataio->openData("intro.stk");
+ if (handle2 >= 0) {
+ _vm->_dataio->closeData(handle2);
+ _vm->_dataio->openDataFile("intro.stk");
+ }
+
+ _vm->_util->initInput();
+
+ _vm->_video->setHandlers();
+ _vm->_video->initPrimary(_vm->_global->_videoMode);
+ _vm->_global->_mouseXShift = 1;
+ _vm->_global->_mouseYShift = 1;
+
+ _vm->_game->_totTextData = 0;
+ _vm->_game->_totFileData = 0;
+ _vm->_game->_totResourceTable = 0;
+ _vm->_global->_inter_variables = 0;
+ _palDesc = new Video::PalDesc;
+
+ if (_vm->_global->_videoMode != 0x13)
+ error("initGame: Only 0x13 video mode is supported!");
+
+ _palDesc->vgaPal = _vm->_draw->_vgaPalette;
+ _palDesc->unused1 = _vm->_draw->_unusedPalette1;
+ _palDesc->unused2 = _vm->_draw->_unusedPalette2;
+ _vm->_video->setFullPalette(_palDesc);
+
+ for (i = 0; i < 4; i++)
+ _vm->_draw->_fonts[i] = 0;
+
+ handle = _vm->_dataio->openData("intro.inf");
+
+ if (handle < 0) {
+ for (i = 0; i < 4; i++) {
+ handle2 = _vm->_dataio->openData(_fontNames[i]);
+ if (handle2 >= 0) {
+ _vm->_dataio->closeData(handle2);
+ _vm->_draw->_fonts[i] =
+ _vm->_util->loadFont(_fontNames[i]);
+ }
+ }
+ } else {
+ _vm->_dataio->closeData(handle);
+
+ infPtr = _vm->_dataio->getData("intro.inf");
+ infBuf = infPtr;
+
+ infEnd = infBuf + _vm->_dataio->getDataSize("intro.inf");
+
+ for (i = 0; i < 4; i++, infPtr++) {
+ for (j = 0; *infPtr >= ' ' && infPtr != infEnd;
+ j++, infPtr++)
+ buffer[j] = *infPtr;
+
+ buffer[j] = 0;
+ strcat(buffer, ".let");
+ handle2 = _vm->_dataio->openData(buffer);
+ if (handle2 >= 0) {
+ _vm->_dataio->closeData(handle2);
+ _vm->_draw->_fonts[i] = _vm->_util->loadFont(buffer);
+ }
+
+ if (infPtr == infEnd)
+ break;
+
+ infPtr++;
+ if (infPtr == infEnd)
+ break;
+ }
+ delete[] infBuf;
+ }
+
+ if (totName != 0) {
+ strcpy(buffer, totName);
+ strcat(buffer, ".tot");
+ } else {
+ strcpy(buffer, "intro.tot");
+ }
+
+ handle = _vm->_dataio->openData(buffer);
+
+ if (handle >= 0) {
+ // Get variables count
+ _vm->_dataio->seekData(handle, 0x2c, SEEK_SET);
+ _vm->_dataio->readData(handle, (char *)&varsCount, 4);
+ varsCount = FROM_LE_32(varsCount);
+ _vm->_dataio->closeData(handle);
+
+ _vm->_global->_inter_variables = new char[varsCount * 4];
+ memset(_vm->_global->_inter_variables, 0, varsCount * 4);
+
+ strcpy(_vm->_game->_curTotFile, buffer);
+
+ _vm->_cdrom->testCD(1, "GOB");
+ _vm->_cdrom->readLIC("gob.lic");
+ _vm->_game->start();
+
+ _vm->_cdrom->stopPlaying();
+ _vm->_cdrom->freeLICbuffer();
+
+ delete[] _vm->_global->_inter_variables;
+ delete[] _vm->_game->_totFileData;
+ delete[] _vm->_game->_totTextData;
+ delete[] _vm->_game->_totResourceTable;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (_vm->_draw->_fonts[i] != 0)
+ _vm->_util->freeFont(_vm->_draw->_fonts[i]);
+ }
+
+ delete _palDesc;
+ _vm->_dataio->closeDataFile();
+ _vm->_video->initPrimary(-1);
+ cleanup();
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/init.h b/engines/gob/init.h
new file mode 100644
index 0000000000..62cbb44f63
--- /dev/null
+++ b/engines/gob/init.h
@@ -0,0 +1,47 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_INIT_H
+#define GOB_INIT_H
+
+namespace Gob {
+
+class Init {
+public:
+ void findBestCfg(void);
+ void soundVideo(int32 smallHeapSize, int16 flag);
+
+ void initGame(char *totFile);
+
+ Init(GobEngine *vm);
+
+protected:
+ Video::PalDesc *_palDesc;
+ static const char *_fontNames[4];
+ GobEngine *_vm;
+
+ void cleanup(void);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp
new file mode 100644
index 0000000000..b17067411e
--- /dev/null
+++ b/engines/gob/inter.cpp
@@ -0,0 +1,443 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/inter.h"
+#include "gob/util.h"
+#include "gob/scenery.h"
+#include "gob/parse.h"
+#include "gob/game.h"
+#include "gob/draw.h"
+#include "gob/mult.h"
+#include "gob/goblin.h"
+#include "gob/cdrom.h"
+#include "gob/map.h"
+
+namespace Gob {
+
+Inter::Inter(GobEngine *vm) : _vm(vm) {
+ _terminate = false;
+ _breakFlag = false;
+ _animPalLowIndex = 0;
+ _animPalHighIndex = 0;
+ _animPalDir = 0;
+ _soundEndTimeKey = 0;
+ _soundStopVal = 0;
+ _breakFromLevel = 0;
+ _nestLevel = 0;
+}
+
+int16 Inter::load16(void) {
+ int16 tmp = (int16)READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ _vm->_global->_inter_execPtr += 2;
+ return tmp;
+}
+
+char Inter::evalExpr(int16 *pRes) {
+ byte token;
+
+//
+ _vm->_parse->printExpr(99);
+
+ _vm->_parse->parseExpr(99, &token);
+ if (pRes == 0)
+ return token;
+
+ switch (token) {
+ case 20:
+ *pRes = _vm->_global->_inter_resVal;
+ break;
+
+ case 22:
+ case 23:
+ *pRes = 0;
+ break;
+
+ case 24:
+ *pRes = 1;
+ break;
+ }
+ return token;
+}
+
+char Inter::evalBoolResult() {
+ byte token;
+
+ _vm->_parse->printExpr(99);
+
+ _vm->_parse->parseExpr(99, &token);
+ if (token == 24 || (token == 20 && _vm->_global->_inter_resVal != 0))
+ return 1;
+ else
+ return 0;
+}
+
+void Inter::animPalette(void) {
+ int16 i;
+ Video::Color col;
+
+ if (_animPalDir == 0)
+ return;
+
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+
+ if (_animPalDir == -1) {
+ col = _vm->_draw->_vgaSmallPalette[_animPalLowIndex];
+
+ for (i = _animPalLowIndex; i < _animPalHighIndex; i++)
+ _vm->_draw->_vgaSmallPalette[i] = _vm->_draw->_vgaSmallPalette[i + 1];
+
+ _vm->_draw->_vgaSmallPalette[_animPalHighIndex] = col;
+ } else {
+ col = _vm->_draw->_vgaSmallPalette[_animPalHighIndex];
+ for (i = _animPalHighIndex; i > _animPalLowIndex; i--)
+ _vm->_draw->_vgaSmallPalette[i] = _vm->_draw->_vgaSmallPalette[i - 1];
+
+ _vm->_draw->_vgaSmallPalette[_animPalLowIndex] = col;
+ }
+
+ _vm->_global->_pPaletteDesc->vgaPal = _vm->_draw->_vgaSmallPalette;
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+}
+
+void Inter::funcBlock(int16 retFlag) {
+ char cmdCount;
+ int16 counter;
+ byte cmd;
+ byte cmd2;
+
+ if (_vm->_global->_inter_execPtr == 0)
+ return;
+
+ _breakFlag = false;
+ _vm->_global->_inter_execPtr++;
+ cmdCount = *_vm->_global->_inter_execPtr++;
+ _vm->_global->_inter_execPtr += 2;
+
+ if (cmdCount == 0) {
+ _vm->_global->_inter_execPtr = 0;
+ return;
+ }
+
+ counter = 0;
+ do {
+ if (_terminate)
+ break;
+
+ cmd = (byte)*_vm->_global->_inter_execPtr;
+ if ((cmd >> 4) >= 12) {
+ cmd2 = 16 - (cmd >> 4);
+ cmd &= 0xf;
+ } else
+ cmd2 = 0;
+
+ _vm->_global->_inter_execPtr++;
+ counter++;
+
+// debug(4, "funcBlock(%d, %d)", cmd2, cmd);
+
+ if (cmd2 == 0)
+ cmd >>= 4;
+
+ if (executeFuncOpcode(cmd2, cmd, cmdCount, counter, retFlag))
+ return;
+
+ if (_breakFlag) {
+ if (retFlag != 2)
+ break;
+
+ if (*_breakFromLevel == -1)
+ _breakFlag = false;
+ break;
+ }
+ } while (counter != cmdCount);
+
+ _vm->_global->_inter_execPtr = 0;
+ return;
+}
+
+void Inter::storeKey(int16 key) {
+ WRITE_VAR(12, _vm->_util->getTimeKey() - _vm->_game->_startTimeKey);
+
+ WRITE_VAR(2, _vm->_global->_inter_mouseX);
+ WRITE_VAR(3, _vm->_global->_inter_mouseY);
+ WRITE_VAR(4, _vm->_game->_mouseButtons);
+ WRITE_VAR(1, _vm->_snd->_playingSound);
+
+ if (key == 0x4800)
+ key = 0x0b;
+ else if (key == 0x5000)
+ key = 0x0a;
+ else if (key == 0x4d00)
+ key = 0x09;
+ else if (key == 0x4b00)
+ key = 0x08;
+ else if (key == 0x011b)
+ key = 0x1b;
+ else if ((key & 0xff) != 0)
+ key &= 0xff;
+
+ WRITE_VAR(0, key);
+
+ if (key != 0)
+ _vm->_util->waitKey();
+}
+
+void Inter::checkSwitchTable(char **ppExec) {
+ int16 i;
+ int16 len;
+ char found;
+ int32 value;
+ char notFound;
+ char defFlag;
+
+ found = 0;
+ notFound = 1;
+ *ppExec = 0;
+ value = _vm->_parse->parseVarIndex();
+ value = VAR_OFFSET(value);
+
+ do {
+ len = *(int8*)_vm->_global->_inter_execPtr++; // must be a signed char typ and char is not default signed on all platforms.
+
+ if (len == -5)
+ break;
+
+ for (i = 0; i < len; i++) {
+ evalExpr(0);
+
+ if (_terminate)
+ return;
+
+ if (_vm->_global->_inter_resVal == value) {
+ found = 1;
+ notFound = 0;
+ }
+ }
+
+ if (found != 0)
+ *ppExec = _vm->_global->_inter_execPtr;
+
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+ found = 0;
+ } while (len != -5);
+
+ if (len != -5)
+ _vm->_global->_inter_execPtr++;
+
+ defFlag = *_vm->_global->_inter_execPtr;
+ defFlag >>= 4;
+ if (defFlag != 4)
+ return;
+ _vm->_global->_inter_execPtr++;
+
+ if (notFound)
+ *ppExec = _vm->_global->_inter_execPtr;
+
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+}
+
+void Inter::callSub(int16 retFlag) {
+ int16 block;
+ while (_vm->_global->_inter_execPtr != 0 && (char *)_vm->_global->_inter_execPtr != _vm->_game->_totFileData) {
+ block = *_vm->_global->_inter_execPtr;
+ if (block == 1) {
+ funcBlock(retFlag);
+ } else if (block == 2) {
+ _vm->_game->collisionsBlock();
+ }
+ }
+
+ if ((char *)_vm->_global->_inter_execPtr == _vm->_game->_totFileData)
+ _terminate = true;
+}
+
+void Inter::initControlVars(void) {
+ *_nestLevel = 0;
+ *_breakFromLevel = -1;
+
+ *_vm->_scenery->_pCaptureCounter = 0;
+
+ _breakFlag = false;
+ _terminate = false;
+ _animPalDir = 0;
+ _soundEndTimeKey = 0;
+}
+
+void Inter::renewTimeInVars(void) {
+ struct tm *t;
+ time_t now = time(NULL);
+
+ t = localtime(&now);
+
+ WRITE_VAR(5, 1900 + t->tm_year);
+ WRITE_VAR(6, t->tm_mon);
+ WRITE_VAR(7, 0);
+ WRITE_VAR(8, t->tm_mday);
+ WRITE_VAR(9, t->tm_hour);
+ WRITE_VAR(10, t->tm_min);
+ WRITE_VAR(11, t->tm_sec);
+}
+
+void Inter::manipulateMap(int16 xPos, int16 yPos, int16 item) {
+ for (int16 y = 0; y < Map::kMapHeight; y++) {
+ for (int16 x = 0; x < Map::kMapWidth; x++) {
+ if ((_vm->_map->_itemsMap[y][x] & 0xff) == item) {
+ _vm->_map->_itemsMap[y][x] &= 0xff00;
+ } else if (((_vm->_map->_itemsMap[y][x] & 0xff00) >> 8)
+ == item) {
+ _vm->_map->_itemsMap[y][x] &= 0xff;
+ }
+ }
+ }
+
+ if (xPos < Map::kMapWidth - 1) {
+ if (yPos > 0) {
+ if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0 ||
+ (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff00) !=
+ 0
+ || (_vm->_map->_itemsMap[yPos][xPos +
+ 1] & 0xff00) != 0
+ || (_vm->_map->_itemsMap[yPos - 1][xPos +
+ 1] & 0xff00) != 0) {
+
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff00)
+ + item;
+
+ _vm->_map->_itemsMap[yPos - 1][xPos] =
+ (_vm->_map->_itemsMap[yPos -
+ 1][xPos] & 0xff00) + item;
+
+ _vm->_map->_itemsMap[yPos][xPos + 1] =
+ (_vm->_map->_itemsMap[yPos][xPos +
+ 1] & 0xff00) + item;
+
+ _vm->_map->_itemsMap[yPos - 1][xPos + 1] =
+ (_vm->_map->_itemsMap[yPos - 1][xPos +
+ 1] & 0xff00) + item;
+ } else {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff) +
+ (item << 8);
+
+ _vm->_map->_itemsMap[yPos - 1][xPos] =
+ (_vm->_map->_itemsMap[yPos -
+ 1][xPos] & 0xff) + (item << 8);
+
+ _vm->_map->_itemsMap[yPos][xPos + 1] =
+ (_vm->_map->_itemsMap[yPos][xPos +
+ 1] & 0xff) + (item << 8);
+
+ _vm->_map->_itemsMap[yPos - 1][xPos + 1] =
+ (_vm->_map->_itemsMap[yPos - 1][xPos +
+ 1] & 0xff) + (item << 8);
+ }
+ } else {
+ if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0 ||
+ (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff00) !=
+ 0) {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff00)
+ + item;
+
+ _vm->_map->_itemsMap[yPos][xPos + 1] =
+ (_vm->_map->_itemsMap[yPos][xPos +
+ 1] & 0xff00) + item;
+ } else {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff) +
+ (item << 8);
+
+ _vm->_map->_itemsMap[yPos][xPos + 1] =
+ (_vm->_map->_itemsMap[yPos][xPos +
+ 1] & 0xff) + (item << 8);
+ }
+ }
+ } else {
+ if (yPos > 0) {
+ if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0 ||
+ (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff00) !=
+ 0) {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff00)
+ + item;
+
+ _vm->_map->_itemsMap[yPos - 1][xPos] =
+ (_vm->_map->_itemsMap[yPos -
+ 1][xPos] & 0xff00) + item;
+ } else {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff) +
+ (item << 8);
+
+ _vm->_map->_itemsMap[yPos - 1][xPos] =
+ (_vm->_map->_itemsMap[yPos -
+ 1][xPos] & 0xff) + (item << 8);
+ }
+ } else {
+ if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0) {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff00)
+ + item;
+ } else {
+ _vm->_map->_itemsMap[yPos][xPos] =
+ (_vm->_map->_itemsMap[yPos][xPos] & 0xff) +
+ (item << 8);
+ }
+ }
+ }
+
+ if (item < 0 || item >= 20)
+ return;
+
+ if (xPos > 1 && _vm->_map->_passMap[yPos][xPos - 2] == 1) {
+ _vm->_map->_itemPoses[item].x = xPos - 2;
+ _vm->_map->_itemPoses[item].y = yPos;
+ _vm->_map->_itemPoses[item].orient = 4;
+ return;
+ }
+
+ if (xPos < Map::kMapWidth - 2 && _vm->_map->_passMap[yPos][xPos + 2] == 1) {
+ _vm->_map->_itemPoses[item].x = xPos + 2;
+ _vm->_map->_itemPoses[item].y = yPos;
+ _vm->_map->_itemPoses[item].orient = 0;
+ return;
+ }
+
+ if (xPos < Map::kMapWidth - 1 && _vm->_map->_passMap[yPos][xPos + 1] == 1) {
+ _vm->_map->_itemPoses[item].x = xPos + 1;
+ _vm->_map->_itemPoses[item].y = yPos;
+ _vm->_map->_itemPoses[item].orient = 0;
+ return;
+ }
+
+ if (xPos > 0 && _vm->_map->_passMap[yPos][xPos - 1] == 1) {
+ _vm->_map->_itemPoses[item].x = xPos - 1;
+ _vm->_map->_itemPoses[item].y = yPos;
+ _vm->_map->_itemPoses[item].orient = 4;
+ return;
+ }
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
new file mode 100644
index 0000000000..ed55dfbcc3
--- /dev/null
+++ b/engines/gob/inter.h
@@ -0,0 +1,313 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_INTERPRET_H
+#define GOB_INTERPRET_H
+
+#include "gob/goblin.h"
+
+namespace Gob {
+
+// This is to help devices with small memory (PDA, smartphones, ...)
+// to save abit of memory used by opcode names in the Scumm engine.
+#ifndef REDUCE_MEMORY_USAGE
+# define _OPCODE(ver, x) { &ver::x, #x }
+#else
+# define _OPCODE(ver, x) { &ver::x, "" }
+#endif
+
+class Inter {
+public:
+ int16 _animPalLowIndex;
+ int16 _animPalHighIndex;
+ int16 _animPalDir;
+ uint32 _soundEndTimeKey;
+ int16 _soundStopVal;
+ char _terminate;
+ char _breakFlag;
+ int16 *_breakFromLevel;
+ int16 *_nestLevel;
+
+ int16 load16(void);
+ int16 peek16(char *ptr);
+ int32 peek32(char *ptr);
+
+ char evalExpr(int16 *pRes);
+ char evalBoolResult(void);
+ void animPalette(void);
+ void funcBlock(int16 retFlag);
+ void storeKey(int16 key);
+ void checkSwitchTable(char **ppExec);
+ void callSub(int16 retFlag);
+ void initControlVars(void);
+ void renewTimeInVars(void);
+ void manipulateMap(int16 xPos, int16 yPos, int16 item);
+
+ Inter(GobEngine *vm);
+ virtual ~Inter() {};
+
+protected:
+ GobEngine *_vm;
+
+ virtual void setupOpcodes(void) = 0;
+ virtual void executeDrawOpcode(byte i) = 0;
+ virtual bool executeFuncOpcode(byte i, byte j, char &cmdCount, int16 &counter, int16 &retFlag) = 0;
+ virtual void executeGoblinOpcode(int i, int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) = 0;
+ virtual const char *getOpcodeDrawDesc(byte i) = 0;
+ virtual const char *getOpcodeFuncDesc(byte i, byte j) = 0;
+ virtual const char *getOpcodeGoblinDesc(int i) = 0;
+};
+
+class Inter_v1 : public Inter {
+public:
+ Inter_v1(GobEngine *vm);
+ virtual ~Inter_v1() {};
+
+protected:
+ typedef void (Inter_v1::*OpcodeDrawProcV1)(void);
+ typedef bool (Inter_v1::*OpcodeFuncProcV1)(char &, int16 &, int16 &);
+ typedef void (Inter_v1::*OpcodeGoblinProcV1)(int16 &, int32 *, Goblin::Gob_Object *);
+ struct OpcodeDrawEntryV1 {
+ OpcodeDrawProcV1 proc;
+ const char *desc;
+ };
+ struct OpcodeFuncEntryV1 {
+ OpcodeFuncProcV1 proc;
+ const char *desc;
+ };
+ struct OpcodeGoblinEntryV1 {
+ OpcodeGoblinProcV1 proc;
+ const char *desc;
+ };
+ const OpcodeDrawEntryV1 *_opcodesDrawV1;
+ const OpcodeFuncEntryV1 *_opcodesFuncV1;
+ const OpcodeGoblinEntryV1 *_opcodesGoblinV1;
+ static const int _goblinFuncLookUp[][2];
+
+ virtual void setupOpcodes(void);
+ virtual void executeDrawOpcode(byte i);
+ virtual bool executeFuncOpcode(byte i, byte j, char &cmdCount, int16 &counter, int16 &retFlag);
+ virtual void executeGoblinOpcode(int i, int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ virtual const char *getOpcodeDrawDesc(byte i);
+ virtual const char *getOpcodeFuncDesc(byte i, byte j);
+ virtual const char *getOpcodeGoblinDesc(int i);
+
+ void o1_loadMult(void);
+ void o1_playMult(void);
+ void o1_freeMult(void);
+ void o1_initCursor(void);
+ void o1_initCursorAnim(void);
+ void o1_clearCursorAnim(void);
+ void o1_setRenderFlags(void);
+ void o1_loadAnim(void);
+ void o1_freeAnim(void);
+ void o1_updateAnim(void);
+ void o1_initMult(void);
+ void o1_multFreeMult(void);
+ void o1_animate(void);
+ void o1_multLoadMult(void);
+ void o1_storeParams(void);
+ void o1_getObjAnimSize(void);
+ void o1_loadStatic(void);
+ void o1_freeStatic(void);
+ void o1_renderStatic(void);
+ void o1_loadCurLayer(void);
+ void o1_playCDTrack(void);
+ void o1_getCDTrackPos(void);
+ void o1_stopCD(void);
+ void o1_loadFontToSprite(void);
+ void o1_freeFontToSprite(void);
+ bool o1_callSub(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_drawPrintText(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_call(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_callBool(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_loadCursor(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_repeatUntil(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_whileDo(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_evaluateStore(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_loadSpriteToPos(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_printText(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_loadTot(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_palLoad(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_keyFunc(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_capturePush(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_capturePop(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_animPalInit(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_drawOperations(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_renewTimeInVars(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_putPixel(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_createSprite(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_freeSprite(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_loadSpriteContent(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_copySprite(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_fillRect(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_drawLine(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_strToLong(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_invalidate(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_playSound(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_stopSound(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_playComposition(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_getFreeMem(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_checkData(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_prepareStr(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_insertStr(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_cutStr(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_strstr(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_istrlen(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_setMousePos(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_setFrameRate(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_loadFont(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_freeFont(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_readData(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_writeData(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_manageDataFile(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_setcmdCount(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_return(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_speakerOn(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_speakerOff(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_goblinFunc(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_returnTo(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_setBackDelta(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_loadSound(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_freeSoundSlot(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_waitEndPlay(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_animatePalette(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_animateCursor(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o1_blitCursor(char &cmdCount, int16 &counter, int16 &retFlag);
+ void o1_setState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setCurFrame(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setNextState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setMultState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setOrder(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setActionStartState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setCurLookDir(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setType(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setNoTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setPickable(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setXPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setYPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setDoAnim(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setRelaxTime(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setMaxTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getCurFrame(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getNextState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getMultState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getOrder(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getActionStartState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getCurLookDir(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getType(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getNoTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getPickable(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getObjMaxFrame(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getXPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getYPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getDoAnim(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getRelaxTime(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getMaxTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_manipulateMap(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getItem(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_manipulateMapIndirect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getItemIndirect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setPassMap(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinPosH(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getGoblinPosXH(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getGoblinPosYH(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinMultState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinStateRedraw(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinUnk14(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setItemIdInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setItemIndInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getItemIdInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getItemIndInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setItemPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_decRelaxTime(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getGoblinPosX(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getGoblinPosY(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_clearPathExistence(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinVisible(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinInvisible(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getObjectIntersect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_getGoblinIntersect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_loadObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_freeObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_animateObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_drawObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_loadMap(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_moveGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_switchGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_loadGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_writeTreatItem(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_moveGoblin0(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinTarget(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_setGoblinObjectsPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ void o1_initGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+};
+
+class Inter_v2 : public Inter_v1 {
+public:
+ Inter_v2(GobEngine *vm);
+ virtual ~Inter_v2() {};
+
+protected:
+ typedef void (Inter_v2::*OpcodeDrawProcV2)(void);
+ typedef bool (Inter_v2::*OpcodeFuncProcV2)(char &, int16 &, int16 &);
+ typedef void (Inter_v2::*OpcodeGoblinProcV2)(int16 &, int32 *, Goblin::Gob_Object *);
+ struct OpcodeDrawEntryV2 {
+ OpcodeDrawProcV2 proc;
+ const char *desc;
+ };
+ struct OpcodeFuncEntryV2 {
+ OpcodeFuncProcV2 proc;
+ const char *desc;
+ };
+ struct OpcodeGoblinEntryV2 {
+ OpcodeGoblinProcV2 proc;
+ const char *desc;
+ };
+ const OpcodeDrawEntryV2 *_opcodesDrawV2;
+ const OpcodeFuncEntryV2 *_opcodesFuncV2;
+ const OpcodeGoblinEntryV2 *_opcodesGoblinV2;
+ static const int _goblinFuncLookUp[][2];
+
+ virtual void setupOpcodes(void);
+ virtual void executeDrawOpcode(byte i);
+ virtual bool executeFuncOpcode(byte i, byte j, char &cmdCount, int16 &counter, int16 &retFlag);
+ virtual void executeGoblinOpcode(int i, int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc);
+ virtual const char *getOpcodeDrawDesc(byte i);
+ virtual const char *getOpcodeFuncDesc(byte i, byte j);
+ virtual const char *getOpcodeGoblinDesc(int i);
+
+ void o2_drawStub(void) { warning("Gob2 stub"); }
+ void o2_stub0x80(void);
+ void o2_stub0x23(void);
+ bool o2_evaluateStore(char &cmdCount, int16 &counter, int16 &retFlag);
+ bool o2_palLoad(char &cmdCount, int16 &counter, int16 &retFlag);
+ void o2_setRenderFlags(void);
+ bool o2_loadTot(char &cmdCount, int16 &counter, int16 &retFlag);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp
new file mode 100644
index 0000000000..747a852c19
--- /dev/null
+++ b/engines/gob/inter_v1.cpp
@@ -0,0 +1,2624 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/inter.h"
+#include "gob/util.h"
+#include "gob/scenery.h"
+#include "gob/parse.h"
+#include "gob/game.h"
+#include "gob/draw.h"
+#include "gob/mult.h"
+#include "gob/goblin.h"
+#include "gob/cdrom.h"
+#include "gob/music.h"
+#include "gob/map.h"
+#include "gob/palanim.h"
+
+namespace Gob {
+
+#define OPCODE(x) _OPCODE(Inter_v1, x)
+
+const int Inter_v1::_goblinFuncLookUp[][2] = {
+ {1, 0},
+ {2, 1},
+ {3, 2},
+ {4, 3},
+ {5, 4},
+ {6, 5},
+ {7, 6},
+ {8, 7},
+ {9, 8},
+ {10, 9},
+ {12, 10},
+ {13, 11},
+ {14, 12},
+ {15, 13},
+ {16, 14},
+ {21, 15},
+ {22, 16},
+ {23, 17},
+ {24, 18},
+ {25, 19},
+ {26, 20},
+ {27, 21},
+ {28, 22},
+ {29, 23},
+ {30, 24},
+ {32, 25},
+ {33, 26},
+ {34, 27},
+ {35, 28},
+ {36, 29},
+ {37, 30},
+ {40, 31},
+ {41, 32},
+ {42, 33},
+ {43, 34},
+ {44, 35},
+ {50, 36},
+ {52, 37},
+ {53, 38},
+ {150, 39},
+ {152, 40},
+ {200, 41},
+ {201, 42},
+ {202, 43},
+ {203, 44},
+ {204, 45},
+ {250, 46},
+ {251, 47},
+ {252, 48},
+ {500, 49},
+ {502, 50},
+ {503, 51},
+ {600, 52},
+ {601, 53},
+ {602, 54},
+ {603, 55},
+ {604, 56},
+ {605, 57},
+ {1000, 58},
+ {1001, 59},
+ {1002, 60},
+ {1003, 61},
+ {1004, 62},
+ {1005, 63},
+ {1006, 64},
+ {1008, 65},
+ {1009, 66},
+ {1010, 67},
+ {1011, 68},
+ {1015, 69},
+ {2005, 70}
+};
+
+Inter_v1::Inter_v1(GobEngine *vm) : Inter(vm) {
+ setupOpcodes();
+}
+
+void Inter_v1::setupOpcodes(void) {
+ static const OpcodeDrawEntryV1 opcodesDraw[256] = {
+ /* 00 */
+ OPCODE(o1_loadMult),
+ OPCODE(o1_playMult),
+ OPCODE(o1_freeMult),
+ {NULL, ""},
+ /* 04 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_initCursor),
+ /* 08 */
+ OPCODE(o1_initCursorAnim),
+ OPCODE(o1_clearCursorAnim),
+ OPCODE(o1_setRenderFlags),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ OPCODE(o1_loadAnim),
+ OPCODE(o1_freeAnim),
+ OPCODE(o1_updateAnim),
+ {NULL, ""},
+ /* 14 */
+ OPCODE(o1_initMult),
+ OPCODE(o1_multFreeMult),
+ OPCODE(o1_animate),
+ OPCODE(o1_multLoadMult),
+ /* 18 */
+ OPCODE(o1_storeParams),
+ OPCODE(o1_getObjAnimSize),
+ OPCODE(o1_loadStatic),
+ OPCODE(o1_freeStatic),
+ /* 1C */
+ OPCODE(o1_renderStatic),
+ OPCODE(o1_loadCurLayer),
+ {NULL, ""},
+ {NULL, ""},
+ /* 20 */
+ OPCODE(o1_playCDTrack),
+ OPCODE(o1_getCDTrackPos),
+ OPCODE(o1_stopCD),
+ {NULL, ""},
+ /* 24 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o1_loadFontToSprite),
+ OPCODE(o1_freeFontToSprite),
+ {NULL, ""},
+ {NULL, ""},
+ /* 34 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 38 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 3C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 40 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 44 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 48 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 4C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 50 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 54 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 58 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 5C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 60 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 64 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 68 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 6C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 70 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 74 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 78 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 7C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 80 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 84 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 88 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 8C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 90 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 94 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 98 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 9C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* AC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* BC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* CC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* DC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* EC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* FC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""}
+ };
+
+ static const OpcodeFuncEntryV1 opcodesFunc[80] = {
+ /* 00 */
+ OPCODE(o1_callSub),
+ OPCODE(o1_callSub),
+ OPCODE(o1_drawPrintText),
+ OPCODE(o1_loadCursor),
+ /* 04 */
+ {NULL, ""},
+ OPCODE(o1_call),
+ OPCODE(o1_repeatUntil),
+ OPCODE(o1_whileDo),
+ /* 08 */
+ OPCODE(o1_callBool),
+ OPCODE(o1_evaluateStore),
+ OPCODE(o1_loadSpriteToPos),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ {NULL, ""},
+ OPCODE(o1_printText),
+ OPCODE(o1_loadTot),
+ OPCODE(o1_palLoad),
+ /* 14 */
+ OPCODE(o1_keyFunc),
+ OPCODE(o1_capturePush),
+ OPCODE(o1_capturePop),
+ OPCODE(o1_animPalInit),
+ /* 18 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 1C */
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_drawOperations),
+ OPCODE(o1_setcmdCount),
+ /* 20 */
+ OPCODE(o1_return),
+ OPCODE(o1_renewTimeInVars),
+ OPCODE(o1_speakerOn),
+ OPCODE(o1_speakerOff),
+ /* 24 */
+ OPCODE(o1_putPixel),
+ OPCODE(o1_goblinFunc),
+ OPCODE(o1_createSprite),
+ OPCODE(o1_freeSprite),
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o1_returnTo),
+ OPCODE(o1_loadSpriteContent),
+ OPCODE(o1_copySprite),
+ OPCODE(o1_fillRect),
+ /* 34 */
+ OPCODE(o1_drawLine),
+ OPCODE(o1_strToLong),
+ OPCODE(o1_invalidate),
+ OPCODE(o1_setBackDelta),
+ /* 38 */
+ OPCODE(o1_playSound),
+ OPCODE(o1_stopSound),
+ OPCODE(o1_loadSound),
+ OPCODE(o1_freeSoundSlot),
+ /* 3C */
+ OPCODE(o1_waitEndPlay),
+ OPCODE(o1_playComposition),
+ OPCODE(o1_getFreeMem),
+ OPCODE(o1_checkData),
+ /* 40 */
+ {NULL, ""},
+ OPCODE(o1_prepareStr),
+ OPCODE(o1_insertStr),
+ OPCODE(o1_cutStr),
+ /* 44 */
+ OPCODE(o1_strstr),
+ OPCODE(o1_istrlen),
+ OPCODE(o1_setMousePos),
+ OPCODE(o1_setFrameRate),
+ /* 48 */
+ OPCODE(o1_animatePalette),
+ OPCODE(o1_animateCursor),
+ OPCODE(o1_blitCursor),
+ OPCODE(o1_loadFont),
+ /* 4C */
+ OPCODE(o1_freeFont),
+ OPCODE(o1_readData),
+ OPCODE(o1_writeData),
+ OPCODE(o1_manageDataFile),
+ };
+
+ static const OpcodeGoblinEntryV1 opcodesGoblin[71] = {
+ /* 00 */
+ OPCODE(o1_setState),
+ OPCODE(o1_setCurFrame),
+ OPCODE(o1_setNextState),
+ OPCODE(o1_setMultState),
+ /* 04 */
+ OPCODE(o1_setOrder),
+ OPCODE(o1_setActionStartState),
+ OPCODE(o1_setCurLookDir),
+ OPCODE(o1_setType),
+ /* 08 */
+ OPCODE(o1_setNoTick),
+ OPCODE(o1_setPickable),
+ OPCODE(o1_setXPos),
+ OPCODE(o1_setYPos),
+ /* 0C */
+ OPCODE(o1_setDoAnim),
+ OPCODE(o1_setRelaxTime),
+ OPCODE(o1_setMaxTick),
+ OPCODE(o1_getState),
+ /* 10 */
+ OPCODE(o1_getCurFrame),
+ OPCODE(o1_getNextState),
+ OPCODE(o1_getMultState),
+ OPCODE(o1_getOrder),
+ /* 14 */
+ OPCODE(o1_getActionStartState),
+ OPCODE(o1_getCurLookDir),
+ OPCODE(o1_getType),
+ OPCODE(o1_getNoTick),
+ /* 18 */
+ OPCODE(o1_getPickable),
+ OPCODE(o1_getObjMaxFrame),
+ OPCODE(o1_getXPos),
+ OPCODE(o1_getYPos),
+ /* 1C */
+ OPCODE(o1_getDoAnim),
+ OPCODE(o1_getRelaxTime),
+ OPCODE(o1_getMaxTick),
+ OPCODE(o1_manipulateMap),
+ /* 20 */
+ OPCODE(o1_getItem),
+ OPCODE(o1_manipulateMapIndirect),
+ OPCODE(o1_getItemIndirect),
+ OPCODE(o1_setPassMap),
+ /* 24 */
+ OPCODE(o1_setGoblinPosH),
+ OPCODE(o1_getGoblinPosXH),
+ OPCODE(o1_getGoblinPosYH),
+ OPCODE(o1_setGoblinMultState),
+ /* 28 */
+ OPCODE(o1_setGoblinUnk14),
+ OPCODE(o1_setItemIdInPocket),
+ OPCODE(o1_setItemIndInPocket),
+ OPCODE(o1_getItemIdInPocket),
+ /* 2C */
+ OPCODE(o1_getItemIndInPocket),
+ OPCODE(o1_setItemPos),
+ OPCODE(o1_setGoblinPos),
+ OPCODE(o1_setGoblinState),
+ /* 30 */
+ OPCODE(o1_setGoblinStateRedraw),
+ OPCODE(o1_decRelaxTime),
+ OPCODE(o1_getGoblinPosX),
+ OPCODE(o1_getGoblinPosY),
+ /* 34 */
+ OPCODE(o1_clearPathExistence),
+ OPCODE(o1_setGoblinVisible),
+ OPCODE(o1_setGoblinInvisible),
+ OPCODE(o1_getObjectIntersect),
+ /* 38 */
+ OPCODE(o1_getGoblinIntersect),
+ OPCODE(o1_setItemPos),
+ OPCODE(o1_loadObjects),
+ OPCODE(o1_freeObjects),
+ /* 3C */
+ OPCODE(o1_animateObjects),
+ OPCODE(o1_drawObjects),
+ OPCODE(o1_loadMap),
+ OPCODE(o1_moveGoblin),
+ /* 40 */
+ OPCODE(o1_switchGoblin),
+ OPCODE(o1_loadGoblin),
+ OPCODE(o1_writeTreatItem),
+ OPCODE(o1_moveGoblin0),
+ /* 44 */
+ OPCODE(o1_setGoblinTarget),
+ OPCODE(o1_setGoblinObjectsPos),
+ OPCODE(o1_initGoblin)
+ };
+
+ _opcodesDrawV1 = opcodesDraw;
+ _opcodesFuncV1 = opcodesFunc; // EGroupe
+ _opcodesGoblinV1 = opcodesGoblin;
+}
+
+bool Inter_v1::o1_setMousePos(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_global->_inter_mouseX = _vm->_parse->parseValExpr();
+ _vm->_global->_inter_mouseY = _vm->_parse->parseValExpr();
+ if (_vm->_global->_useMouse != 0)
+ _vm->_util->setMousePos(_vm->_global->_inter_mouseX, _vm->_global->_inter_mouseY);
+ return false;
+}
+
+bool Inter_v1::o1_evaluateStore(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char *savedPos;
+ int16 token;
+ int16 result;
+ int16 varOff;
+
+ savedPos = _vm->_global->_inter_execPtr;
+ varOff = _vm->_parse->parseVarIndex();
+ token = evalExpr(&result);
+ switch (savedPos[0]) {
+ case 23:
+ case 26:
+ WRITE_VAR_OFFSET(varOff, _vm->_global->_inter_resVal);
+ break;
+
+ case 25:
+ case 28:
+ if (token == 20)
+ *(_vm->_global->_inter_variables + varOff) = result;
+ else
+ strcpy(_vm->_global->_inter_variables + varOff, _vm->_global->_inter_resStr);
+ break;
+
+ }
+ return false;
+}
+
+bool Inter_v1::o1_capturePush(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 left;
+ int16 top;
+ int16 width;
+ int16 height;
+
+ left = _vm->_parse->parseValExpr();
+ top = _vm->_parse->parseValExpr();
+ width = _vm->_parse->parseValExpr();
+ height = _vm->_parse->parseValExpr();
+ _vm->_game->capturePush(left, top, width, height);
+ (*_vm->_scenery->_pCaptureCounter)++;
+ return false;
+}
+
+bool Inter_v1::o1_capturePop(char &cmdCount, int16 &counter, int16 &retFlag) {
+ if (*_vm->_scenery->_pCaptureCounter != 0) {
+ (*_vm->_scenery->_pCaptureCounter)--;
+ _vm->_game->capturePop(1);
+ }
+ return false;
+}
+
+bool Inter_v1::o1_printText(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char buf[60];
+ int16 i;
+
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+
+ _vm->_draw->_backColor = _vm->_parse->parseValExpr();
+ _vm->_draw->_frontColor = _vm->_parse->parseValExpr();
+ _vm->_draw->_fontIndex = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_textToPrint = buf;
+ _vm->_draw->_transparency = 0;
+
+ if (_vm->_draw->_backColor >= 16) {
+ _vm->_draw->_backColor = 0;
+ _vm->_draw->_transparency = 1;
+ }
+
+ do {
+ for (i = 0; *_vm->_global->_inter_execPtr != '.' && (byte)*_vm->_global->_inter_execPtr != 200;
+ i++, _vm->_global->_inter_execPtr++) {
+ buf[i] = *_vm->_global->_inter_execPtr;
+ }
+
+ if ((byte)*_vm->_global->_inter_execPtr != 200) {
+ _vm->_global->_inter_execPtr++;
+ switch (*_vm->_global->_inter_execPtr) {
+ case 23:
+ case 26:
+ sprintf(buf + i, "%d", VAR_OFFSET(_vm->_parse->parseVarIndex()));
+ break;
+
+ case 25:
+ case 28:
+ sprintf(buf + i, "%s", _vm->_global->_inter_variables + _vm->_parse->parseVarIndex());
+ break;
+ }
+ _vm->_global->_inter_execPtr++;
+ } else {
+ buf[i] = 0;
+ }
+ _vm->_draw->spriteOperation(DRAW_PRINTTEXT);
+ } while ((byte)*_vm->_global->_inter_execPtr != 200);
+ _vm->_global->_inter_execPtr++;
+
+ return false;
+}
+
+bool Inter_v1::o1_animPalInit(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _animPalDir = load16();
+ _animPalLowIndex = _vm->_parse->parseValExpr();
+ _animPalHighIndex = _vm->_parse->parseValExpr();
+ return false;
+}
+
+void Inter_v1::o1_loadMult(void) {
+ int16 resId;
+
+ resId = load16();
+ _vm->_mult->loadMult(resId);
+}
+
+void Inter_v1::o1_playMult(void) {
+ int16 checkEscape;
+
+ checkEscape = load16();
+ _vm->_mult->playMult(VAR(57), -1, checkEscape, 0);
+}
+
+void Inter_v1::o1_freeMult(void) {
+ load16(); // unused
+ _vm->_mult->freeMultKeys();
+}
+
+void Inter_v1::o1_initCursor(void) {
+ int16 width;
+ int16 height;
+ int16 count;
+ int16 i;
+
+ _vm->_draw->_cursorXDeltaVar = _vm->_parse->parseVarIndex();
+ _vm->_draw->_cursorYDeltaVar = _vm->_parse->parseVarIndex();
+
+ width = load16();
+ if (width < 16)
+ width = 16;
+
+ height = load16();
+ if (height < 16)
+ height = 16;
+
+ count = load16();
+ if (count < 2)
+ count = 2;
+
+ if (width != _vm->_draw->_cursorWidth || height != _vm->_draw->_cursorHeight ||
+ _vm->_draw->_cursorSprites->width != width * count) {
+
+ _vm->_video->freeSurfDesc(_vm->_draw->_cursorSprites);
+ _vm->_video->freeSurfDesc(_vm->_draw->_cursorBack);
+
+ _vm->_draw->_cursorWidth = width;
+ _vm->_draw->_cursorHeight = height;
+
+ if (count < 0x80)
+ _vm->_draw->_transparentCursor = 1;
+ else
+ _vm->_draw->_transparentCursor = 0;
+
+ if (count > 0x80)
+ count -= 0x80;
+
+ _vm->_draw->_cursorSprites =
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, _vm->_draw->_cursorWidth * count,
+ _vm->_draw->_cursorHeight, 2);
+ _vm->_draw->_spritesArray[23] = _vm->_draw->_cursorSprites;
+
+ _vm->_draw->_cursorBack =
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, _vm->_draw->_cursorWidth,
+ _vm->_draw->_cursorHeight, 0);
+ for (i = 0; i < 40; i++) {
+ _vm->_draw->_cursorAnimLow[i] = -1;
+ _vm->_draw->_cursorAnimDelays[i] = 0;
+ _vm->_draw->_cursorAnimHigh[i] = 0;
+ }
+ _vm->_draw->_cursorAnimLow[1] = 0;
+ }
+}
+
+void Inter_v1::o1_initCursorAnim(void) {
+ int16 ind;
+
+ ind = _vm->_parse->parseValExpr();
+ _vm->_draw->_cursorAnimLow[ind] = load16();
+ _vm->_draw->_cursorAnimHigh[ind] = load16();
+ _vm->_draw->_cursorAnimDelays[ind] = load16();
+}
+
+void Inter_v1::o1_clearCursorAnim(void) {
+ int16 ind;
+
+ ind = _vm->_parse->parseValExpr();
+ _vm->_draw->_cursorAnimLow[ind] = -1;
+ _vm->_draw->_cursorAnimHigh[ind] = 0;
+ _vm->_draw->_cursorAnimDelays[ind] = 0;
+}
+
+bool Inter_v1::o1_drawOperations(char &cmdCount, int16 &counter, int16 &retFlag) {
+ byte cmd;
+
+ cmd = *_vm->_global->_inter_execPtr++;
+
+ executeDrawOpcode(cmd);
+
+ return false;
+}
+
+bool Inter_v1::o1_getFreeMem(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 freeVar;
+ int16 maxFreeVar;
+
+ freeVar = _vm->_parse->parseVarIndex();
+ maxFreeVar = _vm->_parse->parseVarIndex();
+
+ // HACK
+ WRITE_VAR_OFFSET(freeVar, 1000000);
+ WRITE_VAR_OFFSET(maxFreeVar, 1000000);
+ return false;
+}
+
+bool Inter_v1::o1_manageDataFile(char &cmdCount, int16 &counter, int16 &retFlag) {
+ evalExpr(0);
+
+ if (_vm->_global->_inter_resStr[0] != 0)
+ _vm->_dataio->openDataFile(_vm->_global->_inter_resStr);
+ else
+ _vm->_dataio->closeDataFile();
+ return false;
+}
+
+bool Inter_v1::o1_writeData(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 offset;
+ int16 handle;
+ int16 size;
+ int16 dataVar;
+ int16 retSize;
+
+ evalExpr(0);
+ dataVar = _vm->_parse->parseVarIndex();
+ size = _vm->_parse->parseValExpr();
+ offset = _vm->_parse->parseValExpr();
+
+ WRITE_VAR(1, 1);
+ handle = _vm->_dataio->openData(_vm->_global->_inter_resStr, Common::File::kFileWriteMode);
+
+ if (handle < 0)
+ return false;
+
+ if (offset < 0) {
+ _vm->_dataio->seekData(handle, -offset - 1, 2);
+ } else {
+ _vm->_dataio->seekData(handle, offset, 0);
+ }
+
+ retSize = _vm->_dataio->file_getHandle(handle)->write(_vm->_global->_inter_variables + dataVar, size);
+
+ if (retSize == size)
+ WRITE_VAR(1, 0);
+
+ _vm->_dataio->closeData(handle);
+ return false;
+}
+
+bool Inter_v1::o1_checkData(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 handle;
+ int16 varOff;
+
+ evalExpr(0);
+ varOff = _vm->_parse->parseVarIndex();
+ handle = _vm->_dataio->openData(_vm->_global->_inter_resStr);
+
+ WRITE_VAR_OFFSET(varOff, handle);
+ if (handle >= 0)
+ _vm->_dataio->closeData(handle);
+ return false;
+}
+
+bool Inter_v1::o1_readData(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 retSize;
+ int16 size;
+ int16 dataVar;
+ int16 offset;
+ int16 handle;
+
+ evalExpr(0);
+ dataVar = _vm->_parse->parseVarIndex();
+ size = _vm->_parse->parseValExpr();
+ offset = _vm->_parse->parseValExpr();
+
+ if (_vm->_game->_extHandle >= 0)
+ _vm->_dataio->closeData(_vm->_game->_extHandle);
+
+ WRITE_VAR(1, 1);
+ handle = _vm->_dataio->openData(_vm->_global->_inter_resStr);
+ if (handle >= 0) {
+ _vm->_draw->animateCursor(4);
+ if (offset < 0)
+ _vm->_dataio->seekData(handle, -offset - 1, 2);
+ else
+ _vm->_dataio->seekData(handle, offset, 0);
+
+ retSize = _vm->_dataio->readData(handle, _vm->_global->_inter_variables + dataVar, size);
+ _vm->_dataio->closeData(handle);
+
+ if (retSize == size)
+ WRITE_VAR(1, 0);
+ }
+
+ if (_vm->_game->_extHandle >= 0)
+ _vm->_game->_extHandle = _vm->_dataio->openData(_vm->_game->_curExtFile);
+ return false;
+}
+
+bool Inter_v1::o1_loadFont(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 index;
+
+ evalExpr(0);
+ index = load16();
+
+ if (_vm->_draw->_fonts[index] != 0)
+ _vm->_util->freeFont(_vm->_draw->_fonts[index]);
+
+ _vm->_draw->animateCursor(4);
+ if (_vm->_game->_extHandle >= 0)
+ _vm->_dataio->closeData(_vm->_game->_extHandle);
+
+ _vm->_draw->_fonts[index] = _vm->_util->loadFont(_vm->_global->_inter_resStr);
+
+ if (_vm->_game->_extHandle >= 0)
+ _vm->_game->_extHandle = _vm->_dataio->openData(_vm->_game->_curExtFile);
+ return false;
+}
+
+bool Inter_v1::o1_freeFont(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 index;
+
+ index = load16();
+ if (_vm->_draw->_fonts[index] != 0)
+ _vm->_util->freeFont(_vm->_draw->_fonts[index]);
+
+ _vm->_draw->_fonts[index] = 0;
+ return false;
+}
+
+bool Inter_v1::o1_prepareStr(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 var;
+
+ var = _vm->_parse->parseVarIndex();
+ _vm->_util->prepareStr(_vm->_global->_inter_variables + var);
+ return false;
+}
+
+bool Inter_v1::o1_insertStr(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 pos;
+ int16 strVar;
+
+ strVar = _vm->_parse->parseVarIndex();
+ evalExpr(0);
+ pos = _vm->_parse->parseValExpr();
+ _vm->_util->insertStr(_vm->_global->_inter_resStr, _vm->_global->_inter_variables + strVar, pos);
+ return false;
+}
+
+bool Inter_v1::o1_cutStr(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 var;
+ int16 pos;
+ int16 size;
+
+ var = _vm->_parse->parseVarIndex();
+ pos = _vm->_parse->parseValExpr();
+ size = _vm->_parse->parseValExpr();
+ _vm->_util->cutFromStr(_vm->_global->_inter_variables + var, pos, size);
+ return false;
+}
+
+bool Inter_v1::o1_strstr(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 strVar;
+ int16 resVar;
+ int16 pos;
+
+ strVar = _vm->_parse->parseVarIndex();
+ evalExpr(0);
+ resVar = _vm->_parse->parseVarIndex();
+
+ char *res = strstr(_vm->_global->_inter_variables + strVar, _vm->_global->_inter_resStr);
+ pos = res ? (res - (_vm->_global->_inter_variables + strVar)) : -1;
+ WRITE_VAR_OFFSET(resVar, pos);
+ return false;
+}
+
+bool Inter_v1::o1_setFrameRate(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_util->setFrameRate(_vm->_parse->parseValExpr());
+ return false;
+}
+
+bool Inter_v1::o1_istrlen(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 len;
+ int16 var;
+
+ var = _vm->_parse->parseVarIndex();
+ len = strlen(_vm->_global->_inter_variables + var);
+ var = _vm->_parse->parseVarIndex();
+
+ WRITE_VAR_OFFSET(var, len);
+ return false;
+}
+
+bool Inter_v1::o1_strToLong(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char str[20];
+ int16 strVar;
+ int16 destVar;
+ int32 res;
+
+ strVar = _vm->_parse->parseVarIndex();
+ strcpy(str, _vm->_global->_inter_variables + strVar);
+ res = atol(str);
+
+ destVar = _vm->_parse->parseVarIndex();
+ WRITE_VAR_OFFSET(destVar, res);
+ return false;
+}
+
+bool Inter_v1::o1_invalidate(char &cmdCount, int16 &counter, int16 &retFlag) {
+ warning("invalidate: 'bugged' function!");
+ _vm->_draw->_destSurface = load16();
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteRight = _vm->_parse->parseValExpr();
+ _vm->_draw->_frontColor = _vm->_parse->parseValExpr();
+ _vm->_draw->spriteOperation(DRAW_INVALIDATE);
+ return false;
+}
+
+bool Inter_v1::o1_loadSpriteContent(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_spriteLeft = load16();
+ _vm->_draw->_destSurface = load16();
+ _vm->_draw->_transparency = load16();
+ _vm->_draw->_destSpriteX = 0;
+ _vm->_draw->_destSpriteY = 0;
+ _vm->_draw->spriteOperation(DRAW_LOADSPRITE);
+ return false;
+}
+
+bool Inter_v1::o1_copySprite(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_sourceSurface = load16();
+ _vm->_draw->_destSurface = load16();
+
+ _vm->_draw->_spriteLeft = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteTop = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteRight = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr();
+
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+
+ _vm->_draw->_transparency = load16();
+ _vm->_draw->spriteOperation(DRAW_BLITSURF);
+ return false;
+}
+
+bool Inter_v1::o1_putPixel(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_destSurface = load16();
+
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+ _vm->_draw->_frontColor = _vm->_parse->parseValExpr();
+ _vm->_draw->spriteOperation(DRAW_PUTPIXEL);
+ return false;
+}
+
+bool Inter_v1::o1_fillRect(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_destSurface = load16();
+
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteRight = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr();
+
+ _vm->_draw->_backColor = _vm->_parse->parseValExpr();
+ _vm->_draw->spriteOperation(DRAW_FILLRECT);
+ return false;
+}
+
+bool Inter_v1::o1_drawLine(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_destSurface = load16();
+
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteRight = _vm->_parse->parseValExpr();
+ _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr();
+
+ _vm->_draw->_frontColor = _vm->_parse->parseValExpr();
+ _vm->_draw->spriteOperation(DRAW_DRAWLINE);
+ return false;
+}
+
+bool Inter_v1::o1_createSprite(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 index;
+ int16 height;
+ int16 width;
+ int16 flag;
+
+ index = load16();
+ width = load16();
+ height = load16();
+
+ flag = load16();
+ if (flag == 1)
+ _vm->_draw->_spritesArray[index] = _vm->_video->initSurfDesc(_vm->_global->_videoMode, width, height, 2);
+ else
+ _vm->_draw->_spritesArray[index] = _vm->_video->initSurfDesc(_vm->_global->_videoMode, width, height, 0);
+
+ _vm->_video->clearSurf(_vm->_draw->_spritesArray[index]);
+ return false;
+}
+
+bool Inter_v1::o1_freeSprite(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 index;
+
+ index = load16();
+ if (_vm->_draw->_spritesArray[index] == 0)
+ return false;
+
+ _vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[index]);
+ _vm->_draw->_spritesArray[index] = 0;
+ return false;
+}
+
+bool Inter_v1::o1_playComposition(char &cmdCount, int16 &counter, int16 &retFlag) {
+ static int16 composition[50];
+ int16 i;
+ int16 dataVar;
+ int16 freqVal;
+
+ dataVar = _vm->_parse->parseVarIndex();
+ freqVal = _vm->_parse->parseValExpr();
+ for (i = 0; i < 50; i++)
+ composition[i] = (int16)VAR_OFFSET(dataVar + i * 4);
+
+ _vm->_snd->playComposition(_vm->_game->_soundSamples, composition, freqVal);
+ return false;
+}
+
+bool Inter_v1::o1_stopSound(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_snd->stopSound(_vm->_parse->parseValExpr());
+ _soundEndTimeKey = 0;
+ return false;
+}
+
+bool Inter_v1::o1_playSound(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 frequency;
+ int16 freq2;
+ int16 repCount;
+ int16 index;
+
+ index = _vm->_parse->parseValExpr();
+ repCount = _vm->_parse->parseValExpr();
+ frequency = _vm->_parse->parseValExpr();
+
+ _vm->_snd->stopSound(0);
+ _soundEndTimeKey = 0;
+ if (_vm->_game->_soundSamples[index] == 0)
+ return false;
+
+ if (repCount < 0) {
+ if (_vm->_global->_soundFlags < 2)
+ return false;
+
+ repCount = -repCount;
+ _soundEndTimeKey = _vm->_util->getTimeKey();
+
+ if (frequency == 0) {
+ freq2 = _vm->_game->_soundSamples[index]->frequency;
+ } else {
+ freq2 = frequency;
+ }
+ _soundStopVal =
+ (10 * (_vm->_game->_soundSamples[index]->size / 2)) / freq2;
+ _soundEndTimeKey +=
+ ((_vm->_game->_soundSamples[index]->size * repCount -
+ _vm->_game->_soundSamples[index]->size / 2) * 1000) / freq2;
+ }
+ _vm->_snd->playSample(_vm->_game->_soundSamples[index], repCount, frequency);
+ return false;
+}
+
+bool Inter_v1::o1_loadCursor(char &cmdCount, int16 &counter, int16 &retFlag) {
+ Game::TotResItem *itemPtr;
+ int16 width;
+ int16 height;
+ int32 offset;
+ char *dataBuf;
+ int16 id;
+ int8 index;
+
+ id = load16();
+ index = *_vm->_global->_inter_execPtr++;
+ itemPtr = &_vm->_game->_totResourceTable->items[id];
+ offset = itemPtr->offset;
+
+ if (offset >= 0) {
+ dataBuf =
+ ((char *)_vm->_game->_totResourceTable) + szGame_TotResTable +
+ szGame_TotResItem * _vm->_game->_totResourceTable->itemsCount + offset;
+ } else {
+ dataBuf = _vm->_game->_imFileData + (int32)READ_LE_UINT32(&((int32 *)_vm->_game->_imFileData)[-offset - 1]);
+ }
+
+ width = itemPtr->width;
+ height = itemPtr->height;
+
+ _vm->_video->fillRect(_vm->_draw->_cursorSprites, index * _vm->_draw->_cursorWidth, 0,
+ index * _vm->_draw->_cursorWidth + _vm->_draw->_cursorWidth - 1,
+ _vm->_draw->_cursorHeight - 1, 0);
+
+ _vm->_video->drawPackedSprite((byte*)dataBuf, width, height,
+ index * _vm->_draw->_cursorWidth, 0, 0, _vm->_draw->_cursorSprites);
+ _vm->_draw->_cursorAnimLow[index] = 0;
+
+ return false;
+}
+
+bool Inter_v1::o1_loadSpriteToPos(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_spriteLeft = load16();
+
+ _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
+ _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
+
+ _vm->_draw->_transparency = _vm->_global->_inter_execPtr[0];
+ _vm->_draw->_destSurface = (_vm->_global->_inter_execPtr[0] / 2) - 1;
+
+ if (_vm->_draw->_destSurface < 0)
+ _vm->_draw->_destSurface = 101;
+ _vm->_draw->_transparency &= 1;
+ _vm->_global->_inter_execPtr += 2;
+ _vm->_draw->spriteOperation(DRAW_LOADSPRITE);
+
+ return false;
+}
+
+bool Inter_v1::o1_loadTot(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char buf[20];
+ int8 size;
+ int16 i;
+
+ if ((*_vm->_global->_inter_execPtr & 0x80) != 0) {
+ _vm->_global->_inter_execPtr++;
+ evalExpr(0);
+ strcpy(buf, _vm->_global->_inter_resStr);
+ } else {
+ size = *_vm->_global->_inter_execPtr++;
+ for (i = 0; i < size; i++)
+ buf[i] = *_vm->_global->_inter_execPtr++;
+
+ buf[size] = 0;
+ }
+
+ strcat(buf, ".tot");
+ _terminate = true;
+ strcpy(_vm->_game->_totToLoad, buf);
+
+ return false;
+}
+
+bool Inter_v1::o1_keyFunc(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 flag;
+ int16 key;
+
+ flag = load16();
+ animPalette();
+ _vm->_draw->blitInvalidated();
+
+ if (flag != 0) {
+
+ if (flag != 1) {
+ if (flag != 2) {
+ _vm->_util->longDelay(flag);
+ return false;
+ }
+
+ key = 0;
+
+ if (_vm->_global->_pressedKeys[0x48])
+ key |= 1;
+
+ if (_vm->_global->_pressedKeys[0x50])
+ key |= 2;
+
+ if (_vm->_global->_pressedKeys[0x4d])
+ key |= 4;
+
+ if (_vm->_global->_pressedKeys[0x4b])
+ key |= 8;
+
+ if (_vm->_global->_pressedKeys[0x1c])
+ key |= 0x10;
+
+ if (_vm->_global->_pressedKeys[0x39])
+ key |= 0x20;
+
+ if (_vm->_global->_pressedKeys[1])
+ key |= 0x40;
+
+ if (_vm->_global->_pressedKeys[0x1d])
+ key |= 0x80;
+
+ if (_vm->_global->_pressedKeys[0x2a])
+ key |= 0x100;
+
+ if (_vm->_global->_pressedKeys[0x36])
+ key |= 0x200;
+
+ if (_vm->_global->_pressedKeys[0x38])
+ key |= 0x400;
+
+ if (_vm->_global->_pressedKeys[0x3b])
+ key |= 0x800;
+
+ if (_vm->_global->_pressedKeys[0x3c])
+ key |= 0x1000;
+
+ if (_vm->_global->_pressedKeys[0x3d])
+ key |= 0x2000;
+
+ if (_vm->_global->_pressedKeys[0x3e])
+ key |= 0x4000;
+
+ WRITE_VAR(0, key);
+ _vm->_util->waitKey();
+ return false;
+ }
+ key = _vm->_game->checkKeys(&_vm->_global->_inter_mouseX, &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons, 0);
+
+ storeKey(key);
+ return false;
+ } else {
+ key = _vm->_game->checkCollisions(0, 0, 0, 0);
+ storeKey(key);
+
+ if (flag == 1)
+ return false;
+
+ _vm->_util->waitKey();
+ }
+ return false;
+}
+
+bool Inter_v1::o1_repeatUntil(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char *blockPtr;
+ int16 size;
+ char flag;
+
+ _nestLevel[0]++;
+ blockPtr = _vm->_global->_inter_execPtr;
+
+ do {
+ _vm->_global->_inter_execPtr = blockPtr;
+ size = READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+
+ funcBlock(1);
+ _vm->_global->_inter_execPtr = blockPtr + size + 1;
+ flag = evalBoolResult();
+ } while (flag == 0 && !_breakFlag && !_terminate);
+
+ _nestLevel[0]--;
+
+ if (*_breakFromLevel > -1) {
+ _breakFlag = false;
+ *_breakFromLevel = -1;
+ }
+ return false;
+}
+
+bool Inter_v1::o1_whileDo(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char *blockPtr;
+ char *savedIP;
+ char flag;
+ int16 size;
+
+ _nestLevel[0]++;
+ do {
+ savedIP = _vm->_global->_inter_execPtr;
+ flag = evalBoolResult();
+
+ if (_terminate)
+ return false;
+
+ blockPtr = _vm->_global->_inter_execPtr;
+
+ size = READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+
+ if (flag != 0) {
+ funcBlock(1);
+ _vm->_global->_inter_execPtr = savedIP;
+ } else {
+ _vm->_global->_inter_execPtr += size;
+ }
+
+ if (_breakFlag || _terminate) {
+ _vm->_global->_inter_execPtr = blockPtr;
+ _vm->_global->_inter_execPtr += size;
+ break;
+ }
+ } while (flag != 0);
+
+ _nestLevel[0]--;
+ if (*_breakFromLevel > -1) {
+ _breakFlag = false;
+ *_breakFromLevel = -1;
+ }
+ return false;
+}
+
+void Inter_v1::o1_setRenderFlags(void) {
+ _vm->_draw->_renderFlags = _vm->_parse->parseValExpr();
+}
+
+void Inter_v1::o1_loadAnim(void) {
+ _vm->_scenery->loadAnim(0);
+}
+
+void Inter_v1::o1_freeAnim(void) {
+ _vm->_scenery->freeAnim(-1);
+}
+
+void Inter_v1::o1_updateAnim(void) {
+ _vm->_scenery->interUpdateAnim();
+}
+
+void Inter_v1::o1_initMult(void) {
+ _vm->_mult->interInitMult();
+}
+
+void Inter_v1::o1_multFreeMult(void) {
+ _vm->_mult->freeMult();
+}
+
+void Inter_v1::o1_animate(void) {
+ _vm->_mult->animate();
+}
+
+void Inter_v1::o1_multLoadMult(void) {
+ _vm->_mult->interLoadMult();
+}
+
+void Inter_v1::o1_storeParams(void) {
+ _vm->_scenery->interStoreParams();
+}
+
+void Inter_v1::o1_getObjAnimSize(void) {
+ _vm->_mult->interGetObjAnimSize();
+}
+
+void Inter_v1::o1_loadStatic(void) {
+ _vm->_scenery->loadStatic(0);
+}
+
+void Inter_v1::o1_freeStatic(void) {
+ _vm->_scenery->freeStatic(-1);
+}
+
+void Inter_v1::o1_renderStatic(void) {
+ _vm->_scenery->interRenderStatic();
+}
+
+void Inter_v1::o1_loadCurLayer(void) {
+ _vm->_scenery->interLoadCurLayer();
+}
+
+void Inter_v1::o1_playCDTrack(void) {
+ evalExpr(0);
+ if (_vm->_features & GF_MAC)
+ _vm->_music->playTrack(_vm->_global->_inter_resStr);
+ else
+ // Used in gob1 CD
+ _vm->_cdrom->startTrack(_vm->_global->_inter_resStr);
+}
+
+void Inter_v1::o1_getCDTrackPos(void) {
+ // Used in gob1 CD
+
+ // Some scripts busy-wait while calling this opcode.
+ // This is a very nasty thing to do, so let's add a
+ // short delay here. It's probably a safe thing to do.
+
+ _vm->_util->longDelay(1);
+
+ int pos = _vm->_cdrom->getTrackPos();
+ if (pos == -1)
+ pos = 32767;
+ WRITE_VAR(5, pos);
+}
+
+void Inter_v1::o1_stopCD(void) {
+ if (_vm->_features & GF_MAC)
+ _vm->_music->stopPlay();
+ else
+ // Used in gob1 CD
+ _vm->_cdrom->stopPlaying();
+}
+
+void Inter_v1::o1_loadFontToSprite(void) {
+ int16 i = load16();
+ _vm->_draw->_fontToSprite[i].sprite = load16();
+ _vm->_draw->_fontToSprite[i].base = load16();
+ _vm->_draw->_fontToSprite[i].width = load16();
+ _vm->_draw->_fontToSprite[i].height = load16();
+}
+
+void Inter_v1::o1_freeFontToSprite(void) {
+ int16 i = load16();
+ _vm->_draw->_fontToSprite[i].sprite = -1;
+ _vm->_draw->_fontToSprite[i].base = -1;
+ _vm->_draw->_fontToSprite[i].width = -1;
+ _vm->_draw->_fontToSprite[i].height = -1;
+}
+
+void Inter_v1::executeDrawOpcode(byte i) {
+ debug(4, "opcodeDraw %d (%s)", i, getOpcodeDrawDesc(i));
+
+ OpcodeDrawProcV1 op = _opcodesDrawV1[i].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeDraw: %d", i);
+ else
+ (this->*op) ();
+}
+
+bool Inter_v1::executeFuncOpcode(byte i, byte j, char &cmdCount, int16 &counter, int16 &retFlag) {
+ debug(4, "opcodeFunc %d (%s)", i, getOpcodeFuncDesc(i, j));
+
+ if ((i > 4) || (j > 15)) {
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ return false;
+ }
+
+ OpcodeFuncProcV1 op = _opcodesFuncV1[i*16 + j].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ else
+ return (this->*op) (cmdCount, counter, retFlag);
+ return false;
+}
+
+void Inter_v1::executeGoblinOpcode(int i, int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ debug(4, "opcodeGoblin %d (%s)", i, getOpcodeGoblinDesc(i));
+
+ OpcodeGoblinProcV1 op = NULL;
+
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i) {
+ op = _opcodesGoblinV1[_goblinFuncLookUp[j][1]].proc;
+ break;
+ }
+
+ if (op == NULL) {
+ warning("unimplemented opcodeGoblin: %d", i);
+ _vm->_global->_inter_execPtr -= 2;
+ int16 cmd = load16();
+ _vm->_global->_inter_execPtr += cmd * 2;
+ }
+ else
+ (this->*op) (extraData, retVarPtr, objDesc);
+}
+
+const char *Inter_v1::getOpcodeDrawDesc(byte i) {
+ return _opcodesDrawV1[i].desc;
+}
+
+const char *Inter_v1::getOpcodeFuncDesc(byte i, byte j) {
+ if ((i > 4) || (j > 15))
+ return "";
+
+ return _opcodesFuncV1[i*16 + j].desc;
+}
+
+const char *Inter_v1::getOpcodeGoblinDesc(int i) {
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i)
+ return _opcodesGoblinV1[_goblinFuncLookUp[j][1]].desc;
+ return "";
+}
+
+bool Inter_v1::o1_callSub(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char *storedIP = _vm->_global->_inter_execPtr;
+
+// _vm->_global->_inter_execPtr = (char *)_vm->_game->_totFileData + READ_LE_UINT16(_vm->_global->_inter_execPtr);
+
+ uint16 offset = READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ debug(5, "tot = \"%s\", offset = %d", _vm->_game->_curTotFile, offset);
+
+ // Skipping the copy protection screen in Gobliiins
+ if (!_vm->_copyProtection && (_vm->_features & GF_GOB1) && (offset == 3905)
+ && !scumm_stricmp(_vm->_game->_curTotFile, "intro.tot")) {
+ debug(2, "Skipping copy protection screen");
+ _vm->_global->_inter_execPtr += 2;
+ return false;
+ }
+
+ _vm->_global->_inter_execPtr = (char *)_vm->_game->_totFileData + offset;
+
+ if (counter == cmdCount && retFlag == 2)
+ return true;
+
+ callSub(2);
+ _vm->_global->_inter_execPtr = storedIP + 2;
+
+ return false;
+}
+
+bool Inter_v1::o1_drawPrintText(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->printText();
+ return false;
+}
+
+bool Inter_v1::o1_call(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char *callAddr;
+
+ checkSwitchTable(&callAddr);
+ char *storedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = callAddr;
+
+ if (counter == cmdCount && retFlag == 2)
+ return true;
+
+ funcBlock(0);
+ _vm->_global->_inter_execPtr = storedIP;
+
+ return false;
+}
+
+bool Inter_v1::o1_callBool(char &cmdCount, int16 &counter, int16 &retFlag) {
+ byte cmd;
+ bool boolRes = evalBoolResult() != 0;
+ if (boolRes != 0) {
+ if (counter == cmdCount
+ && retFlag == 2)
+ return true;
+
+ char *storedIP = _vm->_global->_inter_execPtr;
+ funcBlock(0);
+ _vm->_global->_inter_execPtr = storedIP;
+
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+
+ debug(5, "cmd = %d", (int16)*_vm->_global->_inter_execPtr);
+ cmd = (byte)(*_vm->_global->_inter_execPtr) >> 4;
+ _vm->_global->_inter_execPtr++;
+ if (cmd != 12)
+ return false;
+
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+ } else {
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+
+ debug(5, "cmd = %d", (int16)*_vm->_global->_inter_execPtr);
+ cmd = (byte)(*_vm->_global->_inter_execPtr) >> 4;
+ _vm->_global->_inter_execPtr++;
+ if (cmd != 12)
+ return false;
+
+ if (counter == cmdCount && retFlag == 2)
+ return true;
+
+ char *storedIP = _vm->_global->_inter_execPtr;
+ funcBlock(0);
+ _vm->_global->_inter_execPtr = storedIP;
+ _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
+ }
+ return false;
+}
+
+bool Inter_v1::o1_palLoad(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 i;
+ int16 ind1;
+ int16 ind2;
+ byte cmd;
+ char *palPtr;
+
+ cmd = *_vm->_global->_inter_execPtr++;
+ _vm->_draw->_applyPal = 0;
+ if (cmd & 0x80)
+ cmd &= 0x7f;
+ else
+ _vm->_draw->_applyPal = 1;
+
+ if (cmd == 49) {
+ warning("o1_palLoad: cmd == 49 is not supported");
+ //var_B = 1;
+ for (i = 0; i < 18; i++, _vm->_global->_inter_execPtr++) {
+ if (i < 2) {
+ if (_vm->_draw->_applyPal == 0)
+ continue;
+
+ _vm->_draw->_unusedPalette1[i] = *_vm->_global->_inter_execPtr;
+ continue;
+ }
+ //if (*inter_execPtr != 0)
+ // var_B = 0;
+
+ ind1 = *_vm->_global->_inter_execPtr >> 4;
+ ind2 = (*_vm->_global->_inter_execPtr & 0xf);
+
+ _vm->_draw->_unusedPalette1[i] =
+ ((_vm->_draw->_palLoadData1[ind1] + _vm->_draw->_palLoadData2[ind2]) << 8) +
+ (_vm->_draw->_palLoadData2[ind1] + _vm->_draw->_palLoadData1[ind2]);
+ }
+
+ _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1;
+ }
+
+ switch (cmd) {
+ case 52:
+ for (i = 0; i < 16; i++, _vm->_global->_inter_execPtr += 3) {
+ _vm->_draw->_vgaSmallPalette[i].red = _vm->_global->_inter_execPtr[0];
+ _vm->_draw->_vgaSmallPalette[i].green = _vm->_global->_inter_execPtr[1];
+ _vm->_draw->_vgaSmallPalette[i].blue = _vm->_global->_inter_execPtr[2];
+ }
+ break;
+
+ case 50:
+ for (i = 0; i < 16; i++, _vm->_global->_inter_execPtr++)
+ _vm->_draw->_unusedPalette2[i] = *_vm->_global->_inter_execPtr;
+ break;
+
+ case 53:
+ palPtr = _vm->_game->loadTotResource(_vm->_inter->load16());
+ memcpy((char *)_vm->_draw->_vgaPalette, palPtr, 768);
+ break;
+
+ case 54:
+ memset((char *)_vm->_draw->_vgaPalette, 0, 768);
+ break;
+ }
+ if (!_vm->_draw->_applyPal) {
+ _vm->_global->_pPaletteDesc->unused2 = _vm->_draw->_unusedPalette2;
+ _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1;
+
+ if (_vm->_global->_videoMode != 0x13)
+ _vm->_global->_pPaletteDesc->vgaPal = (Video::Color *)_vm->_draw->_vgaSmallPalette;
+ else
+ _vm->_global->_pPaletteDesc->vgaPal = (Video::Color *)_vm->_draw->_vgaPalette;
+
+ _vm->_palanim->fade((Video::PalDesc *) _vm->_global->_pPaletteDesc, 0, 0);
+ }
+ return false;
+}
+
+bool Inter_v1::o1_setcmdCount(char &cmdCount, int16 &counter, int16 &retFlag) {
+ cmdCount = *_vm->_global->_inter_execPtr++;
+ counter = 0;
+ return false;
+}
+
+bool Inter_v1::o1_return(char &cmdCount, int16 &counter, int16 &retFlag) {
+ if (retFlag != 2)
+ _breakFlag = true;
+
+ _vm->_global->_inter_execPtr = 0;
+ return false;
+}
+
+bool Inter_v1::o1_renewTimeInVars(char &cmdCount, int16 &counter, int16 &retFlag) {
+ renewTimeInVars();
+ return false;
+}
+
+bool Inter_v1::o1_speakerOn(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_snd->speakerOn(_vm->_parse->parseValExpr(), -1);
+ return false;
+}
+
+bool Inter_v1::o1_speakerOff(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_snd->speakerOff();
+ return false;
+}
+
+bool Inter_v1::o1_goblinFunc(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 cmd;
+ int16 extraData = 0;
+ Goblin::Gob_Object *objDesc = NULL;
+ int32 *retVarPtr;
+ bool objDescSet = false;
+
+ retVarPtr = (int32 *)VAR_ADDRESS(59);
+
+ cmd = load16();
+ _vm->_global->_inter_execPtr += 2;
+ if (cmd > 0 && cmd < 17) {
+ extraData = load16();
+ objDesc = _vm->_goblin->_objects[extraData];
+ objDescSet = true;
+ extraData = load16();
+ }
+
+ if (cmd > 90 && cmd < 107) {
+ extraData = load16();
+ objDesc = _vm->_goblin->_goblins[extraData];
+ objDescSet = true;
+ extraData = load16();
+ cmd -= 90;
+ }
+
+ if (cmd > 110 && cmd < 128) {
+ extraData = load16();
+ objDesc = _vm->_goblin->_goblins[extraData];
+ objDescSet = true;
+ cmd -= 90;
+ } else if (cmd > 20 && cmd < 38) {
+ extraData = load16();
+ objDesc = _vm->_goblin->_objects[extraData];
+ objDescSet = true;
+ }
+
+/*
+ NB: The original gobliiins engine did not initialize the objDesc
+ variable, so we manually check if objDesc is properly set before
+ checking if it is zero. If it was not set, we do not return. This
+ fixes a crash in the EGA version if the life bar is depleted, because
+ interFunc is called multiple times with cmd == 39.
+ Bug #1324814
+*/
+
+ if (cmd < 40 && objDescSet && objDesc == 0)
+ return false;
+
+ executeGoblinOpcode(cmd, extraData, retVarPtr, objDesc);
+
+ return false;
+}
+
+bool Inter_v1::o1_returnTo(char &cmdCount, int16 &counter, int16 &retFlag) {
+ if (retFlag == 1) {
+ _breakFlag = true;
+ _vm->_global->_inter_execPtr = 0;
+ return true;
+ }
+
+ if (*_nestLevel == 0)
+ return false;
+
+ *_breakFromLevel = *_nestLevel;
+ _breakFlag = true;
+ _vm->_global->_inter_execPtr = 0;
+ return true;
+}
+
+bool Inter_v1::o1_setBackDelta(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->_backDeltaX = _vm->_parse->parseValExpr();
+ _vm->_draw->_backDeltaY = _vm->_parse->parseValExpr();
+ return false;
+}
+
+bool Inter_v1::o1_loadSound(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_game->interLoadSound(-1);
+ return false;
+}
+
+bool Inter_v1::o1_freeSoundSlot(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_game->freeSoundSlot(-1);
+ return false;
+}
+
+bool Inter_v1::o1_waitEndPlay(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_snd->waitEndPlay();
+ return false;
+}
+
+bool Inter_v1::o1_animatePalette(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->blitInvalidated();
+ _vm->_util->waitEndFrame();
+ animPalette();
+ storeKey(_vm->_game->checkKeys(&_vm->_global->_inter_mouseX,
+ &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons, 0));
+ return false;
+}
+
+bool Inter_v1::o1_animateCursor(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->animateCursor(1);
+ return false;
+}
+
+bool Inter_v1::o1_blitCursor(char &cmdCount, int16 &counter, int16 &retFlag) {
+ _vm->_draw->blitCursor();
+ return false;
+}
+
+void Inter_v1::o1_setState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->state = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemStateVarPtr = extraData;
+}
+
+void Inter_v1::o1_setCurFrame(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->curFrame = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemFrameVarPtr = extraData;
+}
+
+void Inter_v1::o1_setNextState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->nextState = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemNextStateVarPtr = extraData;
+}
+
+void Inter_v1::o1_setMultState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->multState = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemMultStateVarPtr = extraData;
+}
+
+void Inter_v1::o1_setOrder(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->order = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemOrderVarPtr = extraData;
+}
+
+void Inter_v1::o1_setActionStartState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->actionStartState = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemActStartStVarPtr = extraData;
+}
+
+void Inter_v1::o1_setCurLookDir(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->curLookDir = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemLookDirVarPtr = extraData;
+}
+
+void Inter_v1::o1_setType(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->type = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemTypeVarPtr = extraData;
+
+ if (extraData == 0)
+ objDesc->toRedraw = 1;
+}
+
+void Inter_v1::o1_setNoTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->noTick = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemNoTickVarPtr = extraData;
+}
+
+void Inter_v1::o1_setPickable(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->pickable = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemPickableVarPtr = extraData;
+}
+
+void Inter_v1::o1_setXPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->xPos = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemScrXVarPtr = extraData;
+}
+
+void Inter_v1::o1_setYPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->yPos = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemScrYVarPtr = extraData;
+}
+
+void Inter_v1::o1_setDoAnim(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->doAnim = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemDoAnimVarPtr = extraData;
+}
+
+void Inter_v1::o1_setRelaxTime(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->relaxTime = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemRelaxVarPtr = extraData;
+}
+
+void Inter_v1::o1_setMaxTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ objDesc->maxTick = extraData;
+ if (objDesc == _vm->_goblin->_actDestItemDesc)
+ *_vm->_goblin->_destItemMaxTickVarPtr = extraData;
+}
+
+void Inter_v1::o1_getState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->state;
+}
+
+void Inter_v1::o1_getCurFrame(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->curFrame;
+}
+
+void Inter_v1::o1_getNextState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->nextState;
+}
+
+void Inter_v1::o1_getMultState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->multState;
+}
+
+void Inter_v1::o1_getOrder(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->order;
+}
+
+void Inter_v1::o1_getActionStartState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->actionStartState;
+}
+
+void Inter_v1::o1_getCurLookDir(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->curLookDir;
+}
+
+void Inter_v1::o1_getType(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->type;
+}
+
+void Inter_v1::o1_getNoTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->noTick;
+}
+
+void Inter_v1::o1_getPickable(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->pickable;
+}
+
+void Inter_v1::o1_getObjMaxFrame(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = _vm->_goblin->getObjMaxFrame(objDesc);
+}
+
+void Inter_v1::o1_getXPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->xPos;
+}
+
+void Inter_v1::o1_getYPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->yPos;
+}
+
+void Inter_v1::o1_getDoAnim(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->doAnim;
+}
+
+void Inter_v1::o1_getRelaxTime(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->relaxTime;
+}
+
+void Inter_v1::o1_getMaxTick(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = objDesc->maxTick;
+}
+
+void Inter_v1::o1_manipulateMap(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 xPos = load16();
+ int16 yPos = load16();
+ int16 item = load16();
+
+ manipulateMap(xPos, yPos, item);
+}
+
+void Inter_v1::o1_getItem(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 xPos = load16();
+ int16 yPos = load16();
+
+ if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0)
+ *retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xff00) >> 8;
+ else
+ *retVarPtr = _vm->_map->_itemsMap[yPos][xPos];
+}
+
+void Inter_v1::o1_manipulateMapIndirect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 xPos = load16();
+ int16 yPos = load16();
+ int16 item = load16();
+
+ xPos = VAR(xPos);
+ yPos = VAR(yPos);
+ item = VAR(item);
+
+ manipulateMap(xPos, yPos, item);
+}
+
+void Inter_v1::o1_getItemIndirect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 xPos = load16();
+ int16 yPos = load16();
+
+ xPos = VAR(xPos);
+ yPos = VAR(yPos);
+
+ if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0)
+ *retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xff00) >> 8;
+ else
+ *retVarPtr = _vm->_map->_itemsMap[yPos][xPos];
+}
+
+void Inter_v1::o1_setPassMap(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 xPos = load16();
+ int16 yPos = load16();
+ int16 val = load16();
+ _vm->_map->_passMap[yPos][xPos] = val;
+}
+
+void Inter_v1::o1_setGoblinPosH(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 layer;
+ int16 item = load16();
+ int16 xPos = load16();
+ int16 yPos = load16();
+
+ _vm->_goblin->_gobPositions[item].x = xPos * 2;
+ _vm->_goblin->_gobPositions[item].y = yPos * 2;
+
+ objDesc = _vm->_goblin->_goblins[item];
+ objDesc->nextState = 21;
+
+ _vm->_goblin->nextLayer(objDesc);
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, objDesc->animation, 0,
+ objDesc->xPos, objDesc->yPos, 0);
+
+ objDesc->yPos =
+ (_vm->_goblin->_gobPositions[item].y * 6 + 6) - (_vm->_scenery->_toRedrawBottom -
+ _vm->_scenery->_animTop);
+ objDesc->xPos =
+ _vm->_goblin->_gobPositions[item].x * 12 - (_vm->_scenery->_toRedrawLeft -
+ _vm->_scenery->_animLeft);
+
+ objDesc->curFrame = 0;
+ objDesc->state = 21;
+ if (_vm->_goblin->_currentGoblin == item) {
+ *_vm->_goblin->_curGobScrXVarPtr = objDesc->xPos;
+ *_vm->_goblin->_curGobScrYVarPtr = objDesc->yPos;
+
+ *_vm->_goblin->_curGobFrameVarPtr = 0;
+ *_vm->_goblin->_curGobStateVarPtr = 18;
+ _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x;
+ _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y;
+ }
+}
+
+void Inter_v1::o1_getGoblinPosXH(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item = load16();
+ *retVarPtr = _vm->_goblin->_gobPositions[item].x >> 1;
+}
+
+void Inter_v1::o1_getGoblinPosYH(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item = load16();
+ *retVarPtr = _vm->_goblin->_gobPositions[item].y >> 1;
+}
+
+void Inter_v1::o1_setGoblinMultState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 layer;
+ int16 item = load16();
+ int16 xPos = load16();
+ int16 yPos = load16();
+
+ objDesc = _vm->_goblin->_goblins[item];
+ if (yPos == 0) {
+ objDesc->multState = xPos;
+ objDesc->nextState = xPos;
+ _vm->_goblin->nextLayer(objDesc);
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+
+ objDesc->xPos =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer]->
+ posX;
+ objDesc->yPos =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer]->
+ posY;
+
+ *_vm->_goblin->_curGobScrXVarPtr = objDesc->xPos;
+ *_vm->_goblin->_curGobScrYVarPtr = objDesc->yPos;
+ *_vm->_goblin->_curGobFrameVarPtr = 0;
+ *_vm->_goblin->_curGobStateVarPtr = objDesc->state;
+ *_vm->_goblin->_curGobNextStateVarPtr = objDesc->nextState;
+ *_vm->_goblin->_curGobMultStateVarPtr = objDesc->multState;
+ *_vm->_goblin->_curGobMaxFrameVarPtr =
+ _vm->_goblin->getObjMaxFrame(objDesc);
+ _vm->_goblin->_noPick = 1;
+ return;
+ }
+
+ objDesc->multState = 21;
+ objDesc->nextState = 21;
+ objDesc->state = 21;
+ _vm->_goblin->nextLayer(objDesc);
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, objDesc->animation, 0,
+ objDesc->xPos, objDesc->yPos, 0);
+
+ objDesc->yPos =
+ (yPos * 6 + 6) - (_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop);
+ objDesc->xPos =
+ xPos * 12 - (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
+
+ _vm->_goblin->_gobPositions[item].x = xPos;
+ _vm->_goblin->_pressedMapX = xPos;
+ _vm->_map->_curGoblinX = xPos;
+
+ _vm->_goblin->_gobPositions[item].y = yPos;
+ _vm->_goblin->_pressedMapY = yPos;
+ _vm->_map->_curGoblinY = yPos;
+
+ *_vm->_goblin->_curGobScrXVarPtr = objDesc->xPos;
+ *_vm->_goblin->_curGobScrYVarPtr = objDesc->yPos;
+ *_vm->_goblin->_curGobFrameVarPtr = 0;
+ *_vm->_goblin->_curGobStateVarPtr = 21;
+ *_vm->_goblin->_curGobNextStateVarPtr = 21;
+ *_vm->_goblin->_curGobMultStateVarPtr = -1;
+ _vm->_goblin->_noPick = 0;
+}
+
+void Inter_v1::o1_setGoblinPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 layer;
+ int16 item = load16();
+ int16 xPos = load16();
+ int16 yPos = load16();
+
+ _vm->_goblin->_gobPositions[item].x = xPos;
+ _vm->_goblin->_gobPositions[item].y = yPos;
+
+ objDesc = _vm->_goblin->_goblins[item];
+ objDesc->nextState = 21;
+ _vm->_goblin->nextLayer(objDesc);
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, objDesc->animation, 0,
+ objDesc->xPos, objDesc->yPos, 0);
+
+ objDesc->yPos =
+ (yPos * 6 + 6) - (_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop);
+ objDesc->xPos =
+ xPos * 12 - (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
+
+ objDesc->curFrame = 0;
+ objDesc->state = 21;
+
+ if (_vm->_goblin->_currentGoblin == item) {
+ *_vm->_goblin->_curGobScrXVarPtr = objDesc->xPos;
+ *_vm->_goblin->_curGobScrYVarPtr = objDesc->yPos;
+ *_vm->_goblin->_curGobFrameVarPtr = 0;
+ *_vm->_goblin->_curGobStateVarPtr = 18;
+
+ _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x;
+ _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y;
+ }
+}
+
+void Inter_v1::o1_setGoblinState(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 layer;
+ int16 item = load16();
+ int16 state = load16();
+
+ objDesc = _vm->_goblin->_goblins[item];
+ objDesc->nextState = state;
+
+ _vm->_goblin->nextLayer(objDesc);
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+
+ objDesc->xPos =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer]->posX;
+ objDesc->yPos =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer]->posY;
+
+ if (item == _vm->_goblin->_currentGoblin) {
+ *_vm->_goblin->_curGobScrXVarPtr = objDesc->xPos;
+ *_vm->_goblin->_curGobScrYVarPtr = objDesc->yPos;
+ *_vm->_goblin->_curGobFrameVarPtr = 0;
+ *_vm->_goblin->_curGobStateVarPtr = objDesc->state;
+ *_vm->_goblin->_curGobMultStateVarPtr = objDesc->multState;
+ }
+}
+
+void Inter_v1::o1_setGoblinStateRedraw(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 layer;
+ int16 item = load16();
+ int16 state = load16();
+ objDesc = _vm->_goblin->_objects[item];
+
+ objDesc->nextState = state;
+
+ _vm->_goblin->nextLayer(objDesc);
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+ objDesc->xPos =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer]->posX;
+ objDesc->yPos =
+ _vm->_scenery->_animations[objDesc->animation].layers[layer]->posY;
+
+ objDesc->toRedraw = 1;
+ objDesc->type = 0;
+ if (objDesc == _vm->_goblin->_actDestItemDesc) {
+ *_vm->_goblin->_destItemScrXVarPtr = objDesc->xPos;
+ *_vm->_goblin->_destItemScrYVarPtr = objDesc->yPos;
+
+ *_vm->_goblin->_destItemStateVarPtr = objDesc->state;
+ *_vm->_goblin->_destItemNextStateVarPtr = -1;
+ *_vm->_goblin->_destItemMultStateVarPtr = -1;
+ *_vm->_goblin->_destItemFrameVarPtr = 0;
+ }
+}
+
+void Inter_v1::o1_setGoblinUnk14(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item = load16();
+ int16 val = load16();
+ objDesc = _vm->_goblin->_objects[item];
+ objDesc->unk14 = val;
+}
+
+void Inter_v1::o1_setItemIdInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->_itemIdInPocket = load16();
+}
+
+void Inter_v1::o1_setItemIndInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->_itemIndInPocket = load16();
+}
+
+void Inter_v1::o1_getItemIdInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = _vm->_goblin->_itemIdInPocket;
+}
+
+void Inter_v1::o1_getItemIndInPocket(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ *retVarPtr = _vm->_goblin->_itemIndInPocket;
+}
+
+void Inter_v1::o1_setItemPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item = load16();
+ int16 xPos = load16();
+ int16 yPos = load16();
+ int16 val = load16();
+
+ _vm->_map->_itemPoses[item].x = xPos;
+ _vm->_map->_itemPoses[item].y = yPos;
+ _vm->_map->_itemPoses[item].orient = val;
+}
+
+void Inter_v1::o1_decRelaxTime(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ objDesc = _vm->_goblin->_objects[extraData];
+
+ objDesc->relaxTime--;
+ if (objDesc->relaxTime < 0 &&
+ _vm->_goblin->getObjMaxFrame(objDesc) == objDesc->curFrame) {
+ objDesc->relaxTime = _vm->_util->getRandom(100) + 50;
+ objDesc->curFrame = 0;
+ objDesc->toRedraw = 1;
+ }
+}
+
+void Inter_v1::o1_getGoblinPosX(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item = load16();
+ *retVarPtr = _vm->_goblin->_gobPositions[item].x;
+}
+
+void Inter_v1::o1_getGoblinPosY(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item = load16();
+ *retVarPtr = _vm->_goblin->_gobPositions[item].y;
+}
+
+void Inter_v1::o1_clearPathExistence(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->_pathExistence = 0;
+}
+
+void Inter_v1::o1_setGoblinVisible(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ _vm->_goblin->_goblins[extraData]->visible = 1;
+}
+
+void Inter_v1::o1_setGoblinInvisible(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ _vm->_goblin->_goblins[extraData]->visible = 0;
+}
+
+void Inter_v1::o1_getObjectIntersect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ int16 item = load16();
+
+ objDesc = _vm->_goblin->_objects[extraData];
+ if (_vm->_goblin->objIntersected(objDesc, _vm->_goblin->_goblins[item]) != 0)
+ *retVarPtr = 1;
+ else
+ *retVarPtr = 0;
+}
+
+void Inter_v1::o1_getGoblinIntersect(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ int16 item = load16();
+
+ objDesc = _vm->_goblin->_goblins[extraData];
+ if (_vm->_goblin->objIntersected(objDesc, _vm->_goblin->_goblins[item]) != 0)
+ *retVarPtr = 1;
+ else
+ *retVarPtr = 0;
+}
+
+void Inter_v1::o1_loadObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ if (_vm->_game->_extHandle >= 0)
+ _vm->_dataio->closeData(_vm->_game->_extHandle);
+
+ _vm->_goblin->loadObjects((char *)VAR_ADDRESS(extraData));
+ _vm->_game->_extHandle = _vm->_dataio->openData(_vm->_game->_curExtFile);
+}
+
+void Inter_v1::o1_freeObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->freeAllObjects();
+}
+
+void Inter_v1::o1_animateObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->animateObjects();
+}
+
+void Inter_v1::o1_drawObjects(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->drawObjects();
+
+ if (_vm->_features & GF_MAC)
+ _vm->_music->playBgMusic();
+ else if (_vm->_cdrom->getTrackPos() == -1)
+ _vm->_cdrom->playBgMusic();
+}
+
+void Inter_v1::o1_loadMap(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_map->loadMapsInitGobs();
+}
+
+void Inter_v1::o1_moveGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ int16 item;
+ extraData = load16();
+ int16 xPos = load16();
+
+ if ((uint16)VAR(xPos) == 0) {
+ item =
+ _vm->_goblin->doMove(_vm->_goblin->_goblins[_vm->_goblin->_currentGoblin], 1,
+ (uint16)VAR(extraData));
+ } else {
+ item =
+ _vm->_goblin->doMove(_vm->_goblin->_goblins[_vm->_goblin->_currentGoblin], 1, 3);
+ }
+
+ if (item != 0)
+ _vm->_goblin->switchGoblin(item);
+}
+
+void Inter_v1::o1_switchGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->switchGoblin(0);
+}
+
+void Inter_v1::o1_loadGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->loadGobDataFromVars();
+}
+
+void Inter_v1::o1_writeTreatItem(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ int16 cmd = load16();
+ int16 xPos = load16();
+
+ if ((uint16)VAR(xPos) == 0) {
+ WRITE_VAR(cmd, _vm->_goblin->treatItem((uint16)VAR(extraData)));
+ return;
+ }
+
+ WRITE_VAR(cmd, _vm->_goblin->treatItem(3));
+}
+
+void Inter_v1::o1_moveGoblin0(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ _vm->_goblin->doMove(_vm->_goblin->_goblins[_vm->_goblin->_currentGoblin], 0, 0);
+}
+
+void Inter_v1::o1_setGoblinTarget(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ if (VAR(extraData) != 0)
+ _vm->_goblin->_goesAtTarget = 1;
+ else
+ _vm->_goblin->_goesAtTarget = 0;
+}
+
+void Inter_v1::o1_setGoblinObjectsPos(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ extraData = load16();
+ extraData = VAR(extraData);
+ _vm->_goblin->_objects[10]->xPos = extraData;
+
+ extraData = load16();
+ extraData = VAR(extraData);
+ _vm->_goblin->_objects[10]->yPos = extraData;
+}
+
+void Inter_v1::o1_initGoblin(int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ Goblin::Gob_Object *gobDesc = _vm->_goblin->_goblins[0];
+ int16 xPos;
+ int16 yPos;
+ int16 layer;
+
+ if (_vm->_goblin->_currentGoblin != 0) {
+ _vm->_goblin->_goblins[_vm->_goblin->_currentGoblin]->doAnim = 1;
+ _vm->_goblin->_goblins[_vm->_goblin->_currentGoblin]->nextState = 21;
+
+ _vm->_goblin->nextLayer(_vm->_goblin->_goblins[_vm->_goblin->_currentGoblin]);
+ _vm->_goblin->_currentGoblin = 0;
+
+ gobDesc->doAnim = 0;
+ gobDesc->type = 0;
+ gobDesc->toRedraw = 1;
+
+ _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[0].x;
+ _vm->_map->_destX = _vm->_goblin->_gobPositions[0].x;
+ _vm->_goblin->_gobDestX = _vm->_goblin->_gobPositions[0].x;
+
+ _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[0].y;
+ _vm->_map->_destY = _vm->_goblin->_gobPositions[0].y;
+ _vm->_goblin->_gobDestY = _vm->_goblin->_gobPositions[0].y;
+
+ *_vm->_goblin->_curGobVarPtr = 0;
+ _vm->_goblin->_pathExistence = 0;
+ _vm->_goblin->_readyToAct = 0;
+ }
+
+ if (gobDesc->state != 10 && _vm->_goblin->_itemIndInPocket != -1 &&
+ _vm->_goblin->getObjMaxFrame(gobDesc) == gobDesc->curFrame) {
+
+ gobDesc->stateMach = gobDesc->realStateMach;
+ xPos = _vm->_goblin->_gobPositions[0].x;
+ yPos = _vm->_goblin->_gobPositions[0].y;
+
+ gobDesc->nextState = 10;
+ layer = _vm->_goblin->nextLayer(gobDesc);
+
+ _vm->_scenery->updateAnim(layer, 0, gobDesc->animation, 0,
+ gobDesc->xPos, gobDesc->yPos, 0);
+
+ gobDesc->yPos =
+ (yPos * 6 + 6) - (_vm->_scenery->_toRedrawBottom -
+ _vm->_scenery->_animTop);
+ gobDesc->xPos =
+ xPos * 12 - (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
+ }
+
+ if (gobDesc->state != 10)
+ return;
+
+ if (_vm->_goblin->_itemIndInPocket == -1)
+ return;
+
+ if (gobDesc->curFrame != 10)
+ return;
+
+ objDesc = _vm->_goblin->_objects[_vm->_goblin->_itemIndInPocket];
+ objDesc->type = 0;
+ objDesc->toRedraw = 1;
+ objDesc->curFrame = 0;
+
+ objDesc->order = gobDesc->order;
+ objDesc->animation =
+ objDesc->stateMach[objDesc->state][0]->animation;
+
+ layer = objDesc->stateMach[objDesc->state][0]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, objDesc->animation, 0,
+ objDesc->xPos, objDesc->yPos, 0);
+
+ objDesc->yPos +=
+ (_vm->_goblin->_gobPositions[0].y * 6 + 5) - _vm->_scenery->_toRedrawBottom;
+
+ if (gobDesc->curLookDir == 4) {
+ objDesc->xPos += _vm->_goblin->_gobPositions[0].x * 12 + 14
+ - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2;
+ } else {
+ objDesc->xPos += _vm->_goblin->_gobPositions[0].x * 12
+ - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2;
+ }
+
+ _vm->_goblin->_itemIndInPocket = -1;
+ _vm->_goblin->_itemIdInPocket = -1;
+ _vm->_util->beep(50);
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
new file mode 100644
index 0000000000..672a662670
--- /dev/null
+++ b/engines/gob/inter_v2.cpp
@@ -0,0 +1,997 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/inter.h"
+#include "gob/util.h"
+#include "gob/scenery.h"
+#include "gob/parse.h"
+#include "gob/game.h"
+#include "gob/draw.h"
+#include "gob/mult.h"
+#include "gob/goblin.h"
+#include "gob/cdrom.h"
+#include "gob/palanim.h"
+
+namespace Gob {
+
+#define OPCODE(x) _OPCODE(Inter_v2, x)
+
+const int Inter_v2::_goblinFuncLookUp[][2] = {
+ {1, 0},
+ {2, 1},
+ {3, 2},
+ {4, 3},
+ {5, 4},
+ {6, 5},
+ {7, 6},
+ {8, 7},
+ {9, 8},
+ {10, 9},
+ {12, 10},
+ {13, 11},
+ {14, 12},
+ {15, 13},
+ {16, 14},
+ {21, 15},
+ {22, 16},
+ {23, 17},
+ {24, 18},
+ {25, 19},
+ {26, 20},
+ {27, 21},
+ {28, 22},
+ {29, 23},
+ {30, 24},
+ {32, 25},
+ {33, 26},
+ {34, 27},
+ {35, 28},
+ {36, 29},
+ {37, 30},
+ {40, 31},
+ {41, 32},
+ {42, 33},
+ {43, 34},
+ {44, 35},
+ {50, 36},
+ {52, 37},
+ {53, 38},
+ {150, 39},
+ {152, 40},
+ {200, 41},
+ {201, 42},
+ {202, 43},
+ {203, 44},
+ {204, 45},
+ {250, 46},
+ {251, 47},
+ {252, 48},
+ {500, 49},
+ {502, 50},
+ {503, 51},
+ {600, 52},
+ {601, 53},
+ {602, 54},
+ {603, 55},
+ {604, 56},
+ {605, 57},
+ {1000, 58},
+ {1001, 59},
+ {1002, 60},
+ {1003, 61},
+ {1004, 62},
+ {1005, 63},
+ {1006, 64},
+ {1008, 65},
+ {1009, 66},
+ {1010, 67},
+ {1011, 68},
+ {1015, 69},
+ {2005, 70}
+};
+
+Inter_v2::Inter_v2(GobEngine *vm) : Inter_v1(vm) {
+ setupOpcodes();
+}
+
+void Inter_v2::setupOpcodes(void) {
+ static const OpcodeDrawEntryV2 opcodesDraw[256] = {
+ /* 00 */
+ OPCODE(o1_loadMult),
+ OPCODE(o1_playMult),
+ OPCODE(o1_freeMult),
+ {NULL, ""},
+ /* 04 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_initCursor),
+ /* 08 */
+ OPCODE(o1_initCursorAnim),
+ OPCODE(o1_clearCursorAnim),
+ OPCODE(o2_setRenderFlags),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ OPCODE(o1_loadAnim),
+ OPCODE(o1_freeAnim),
+ OPCODE(o1_updateAnim),
+ OPCODE(o2_drawStub),
+ /* 14 */
+ OPCODE(o1_initMult),
+ OPCODE(o1_multFreeMult),
+ OPCODE(o1_animate),
+ OPCODE(o1_multLoadMult),
+ /* 18 */
+ OPCODE(o1_storeParams),
+ OPCODE(o1_getObjAnimSize),
+ OPCODE(o1_loadStatic),
+ OPCODE(o1_freeStatic),
+ /* 1C */
+ OPCODE(o1_renderStatic),
+ OPCODE(o1_loadCurLayer),
+ {NULL, ""},
+ {NULL, ""},
+ /* 20 */
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_stub0x23),
+ /* 24 */
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ {NULL, ""},
+ {NULL, ""},
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o1_loadFontToSprite),
+ OPCODE(o1_freeFontToSprite),
+ {NULL, ""},
+ {NULL, ""},
+ /* 34 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 38 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 3C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 40 */
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ /* 44 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 48 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 4C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 50 */
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ /* 54 */
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ {NULL, ""},
+ /* 58 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 5C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 60 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 64 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 68 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 6C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 70 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 74 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 78 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 7C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 80 */
+ OPCODE(o2_stub0x80),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ /* 84 */
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ OPCODE(o2_drawStub),
+ /* 88 */
+ OPCODE(o2_drawStub),
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 8C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 90 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 94 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 98 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 9C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* AC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* BC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* CC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* DC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* EC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* FC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""}
+ };
+
+ static const OpcodeFuncEntryV2 opcodesFunc[80] = {
+ /* 00 */
+ OPCODE(o1_callSub),
+ OPCODE(o1_callSub),
+ OPCODE(o1_drawPrintText),
+ OPCODE(o1_loadCursor),
+ /* 04 */
+ {NULL, ""},
+ OPCODE(o1_call),
+ OPCODE(o1_repeatUntil),
+ OPCODE(o1_whileDo),
+ /* 08 */
+ OPCODE(o1_callBool),
+ OPCODE(o2_evaluateStore),
+ OPCODE(o1_loadSpriteToPos),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ {NULL, ""},
+ OPCODE(o1_printText),
+ OPCODE(o2_loadTot),
+ OPCODE(o2_palLoad),
+ /* 14 */
+ OPCODE(o1_keyFunc),
+ OPCODE(o1_capturePush),
+ OPCODE(o1_capturePop),
+ OPCODE(o1_animPalInit),
+ /* 18 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 1C */
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_drawOperations),
+ OPCODE(o1_setcmdCount),
+ /* 20 */
+ OPCODE(o1_return),
+ OPCODE(o1_renewTimeInVars),
+ OPCODE(o1_speakerOn),
+ OPCODE(o1_speakerOff),
+ /* 24 */
+ OPCODE(o1_putPixel),
+ OPCODE(o1_goblinFunc),
+ OPCODE(o1_createSprite),
+ OPCODE(o1_freeSprite),
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o1_returnTo),
+ OPCODE(o1_loadSpriteContent),
+ OPCODE(o1_copySprite),
+ OPCODE(o1_fillRect),
+ /* 34 */
+ OPCODE(o1_drawLine),
+ OPCODE(o1_strToLong),
+ OPCODE(o1_invalidate),
+ OPCODE(o1_setBackDelta),
+ /* 38 */
+ OPCODE(o1_playSound),
+ OPCODE(o1_stopSound),
+ OPCODE(o1_loadSound),
+ OPCODE(o1_freeSoundSlot),
+ /* 3C */
+ OPCODE(o1_waitEndPlay),
+ OPCODE(o1_playComposition),
+ OPCODE(o1_getFreeMem),
+ OPCODE(o1_checkData),
+ /* 40 */
+ {NULL, ""},
+ OPCODE(o1_prepareStr),
+ OPCODE(o1_insertStr),
+ OPCODE(o1_cutStr),
+ /* 44 */
+ OPCODE(o1_strstr),
+ OPCODE(o1_istrlen),
+ OPCODE(o1_setMousePos),
+ OPCODE(o1_setFrameRate),
+ /* 48 */
+ OPCODE(o1_animatePalette),
+ OPCODE(o1_animateCursor),
+ OPCODE(o1_blitCursor),
+ OPCODE(o1_loadFont),
+ /* 4C */
+ OPCODE(o1_freeFont),
+ OPCODE(o1_readData),
+ OPCODE(o1_writeData),
+ OPCODE(o1_manageDataFile),
+ };
+
+ static const OpcodeGoblinEntryV2 opcodesGoblin[71] = {
+ /* 00 */
+ OPCODE(o1_setState),
+ OPCODE(o1_setCurFrame),
+ OPCODE(o1_setNextState),
+ OPCODE(o1_setMultState),
+ /* 04 */
+ OPCODE(o1_setOrder),
+ OPCODE(o1_setActionStartState),
+ OPCODE(o1_setCurLookDir),
+ OPCODE(o1_setType),
+ /* 08 */
+ OPCODE(o1_setNoTick),
+ OPCODE(o1_setPickable),
+ OPCODE(o1_setXPos),
+ OPCODE(o1_setYPos),
+ /* 0C */
+ OPCODE(o1_setDoAnim),
+ OPCODE(o1_setRelaxTime),
+ OPCODE(o1_setMaxTick),
+ OPCODE(o1_getState),
+ /* 10 */
+ OPCODE(o1_getCurFrame),
+ OPCODE(o1_getNextState),
+ OPCODE(o1_getMultState),
+ OPCODE(o1_getOrder),
+ /* 14 */
+ OPCODE(o1_getActionStartState),
+ OPCODE(o1_getCurLookDir),
+ OPCODE(o1_getType),
+ OPCODE(o1_getNoTick),
+ /* 18 */
+ OPCODE(o1_getPickable),
+ OPCODE(o1_getObjMaxFrame),
+ OPCODE(o1_getXPos),
+ OPCODE(o1_getYPos),
+ /* 1C */
+ OPCODE(o1_getDoAnim),
+ OPCODE(o1_getRelaxTime),
+ OPCODE(o1_getMaxTick),
+ OPCODE(o1_manipulateMap),
+ /* 20 */
+ OPCODE(o1_getItem),
+ OPCODE(o1_manipulateMapIndirect),
+ OPCODE(o1_getItemIndirect),
+ OPCODE(o1_setPassMap),
+ /* 24 */
+ OPCODE(o1_setGoblinPosH),
+ OPCODE(o1_getGoblinPosXH),
+ OPCODE(o1_getGoblinPosYH),
+ OPCODE(o1_setGoblinMultState),
+ /* 28 */
+ OPCODE(o1_setGoblinUnk14),
+ OPCODE(o1_setItemIdInPocket),
+ OPCODE(o1_setItemIndInPocket),
+ OPCODE(o1_getItemIdInPocket),
+ /* 2C */
+ OPCODE(o1_getItemIndInPocket),
+ OPCODE(o1_setItemPos),
+ OPCODE(o1_setGoblinPos),
+ OPCODE(o1_setGoblinState),
+ /* 30 */
+ OPCODE(o1_setGoblinStateRedraw),
+ OPCODE(o1_decRelaxTime),
+ OPCODE(o1_getGoblinPosX),
+ OPCODE(o1_getGoblinPosY),
+ /* 34 */
+ OPCODE(o1_clearPathExistence),
+ OPCODE(o1_setGoblinVisible),
+ OPCODE(o1_setGoblinInvisible),
+ OPCODE(o1_getObjectIntersect),
+ /* 38 */
+ OPCODE(o1_getGoblinIntersect),
+ OPCODE(o1_setItemPos),
+ OPCODE(o1_loadObjects),
+ OPCODE(o1_freeObjects),
+ /* 3C */
+ OPCODE(o1_animateObjects),
+ OPCODE(o1_drawObjects),
+ OPCODE(o1_loadMap),
+ OPCODE(o1_moveGoblin),
+ /* 40 */
+ OPCODE(o1_switchGoblin),
+ OPCODE(o1_loadGoblin),
+ OPCODE(o1_writeTreatItem),
+ OPCODE(o1_moveGoblin0),
+ /* 44 */
+ OPCODE(o1_setGoblinTarget),
+ OPCODE(o1_setGoblinObjectsPos),
+ OPCODE(o1_initGoblin)
+ };
+
+ _opcodesDrawV2 = opcodesDraw;
+ _opcodesFuncV2 = opcodesFunc;
+ _opcodesGoblinV2 = opcodesGoblin;
+}
+
+void Inter_v2::executeDrawOpcode(byte i) {
+ debug(4, "opcodeDraw %d (%s)", i, getOpcodeDrawDesc(i));
+
+ OpcodeDrawProcV2 op = _opcodesDrawV2[i].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeDraw: %d", i);
+ else
+ (this->*op) ();
+}
+
+bool Inter_v2::executeFuncOpcode(byte i, byte j, char &cmdCount, int16 &counter, int16 &retFlag) {
+ debug(4, "opcodeFunc %d (%s)", i, getOpcodeFuncDesc(i, j));
+
+ if ((i > 4) || (j > 15)) {
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ return false;
+ }
+
+ OpcodeFuncProcV2 op = _opcodesFuncV2[i*16 + j].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ else
+ return (this->*op) (cmdCount, counter, retFlag);
+ return false;
+}
+
+void Inter_v2::executeGoblinOpcode(int i, int16 &extraData, int32 *retVarPtr, Goblin::Gob_Object *objDesc) {
+ debug(4, "opcodeGoblin %d (%s)", i, getOpcodeGoblinDesc(i));
+
+ OpcodeGoblinProcV2 op = NULL;
+
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i) {
+ op = _opcodesGoblinV2[_goblinFuncLookUp[j][1]].proc;
+ break;
+ }
+
+ if (op == NULL) {
+ warning("unimplemented opcodeGoblin: %d", i);
+ _vm->_global->_inter_execPtr -= 2;
+ _vm->_global->_inter_execPtr += load16() * 2;
+ }
+ else
+ (this->*op) (extraData, retVarPtr, objDesc);
+}
+
+const char *Inter_v2::getOpcodeDrawDesc(byte i) {
+ return _opcodesDrawV2[i].desc;
+}
+
+const char *Inter_v2::getOpcodeFuncDesc(byte i, byte j) {
+ if ((i > 4) || (j > 15))
+ return "";
+
+ return _opcodesFuncV2[i*16 + j].desc;
+}
+
+const char *Inter_v2::getOpcodeGoblinDesc(int i) {
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i)
+ return _opcodesGoblinV2[_goblinFuncLookUp[j][1]].desc;
+ return "";
+}
+
+void Inter_v2::o2_stub0x80(void) {
+ _vm->_global->_inter_execPtr += 2;
+
+ int16 expr1 = _vm->_parse->parseValExpr();
+ int16 expr2 = _vm->_parse->parseValExpr();
+
+ warning("STUB: Gob2 drawOperation 0x80 (%d %d)", expr1, expr2);
+}
+
+void Inter_v2::o2_stub0x23(void) {
+ byte result;
+ char str[40];
+
+ result = evalExpr(NULL);
+ strcpy(str, _vm->_global->_inter_resStr);
+
+ warning("STUB: Gob2 drawOperation 0x23 (%d, \"%s\")", result, str);
+}
+
+bool Inter_v2::o2_evaluateStore(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char *savedPos;
+ int16 varOff;
+ int16 token;
+ int16 result;
+ byte loopCount;
+
+ savedPos = _vm->_global->_inter_execPtr;
+ varOff = _vm->_parse->parseVarIndex();
+
+ if (*_vm->_global->_inter_execPtr == 99) {
+ _vm->_global->_inter_execPtr++;
+ loopCount = *_vm->_global->_inter_execPtr++;
+ }
+ else
+ loopCount = 1;
+
+ for (int i = 0; i < loopCount; i++) {
+ token = evalExpr(&result);
+ switch (savedPos[0]) {
+ case 16:
+ case 18:
+ *(_vm->_global->_inter_variables + varOff + i) = _vm->_global->_inter_resVal;
+ break;
+
+ case 17:
+ case 27:
+ *(uint16*)(_vm->_global->_inter_variables + varOff + i * 2) = _vm->_global->_inter_resVal;
+ break;
+
+ case 23:
+ case 26:
+ WRITE_VAR_OFFSET(varOff + i * 4, _vm->_global->_inter_resVal);
+ break;
+
+ case 24:
+ *(uint16*)(_vm->_global->_inter_variables + varOff + i * 4) = _vm->_global->_inter_resVal;
+ break;
+
+ case 25:
+ case 28:
+ if (token == 20)
+ *(_vm->_global->_inter_variables + varOff) = result;
+ else
+ strcpy(_vm->_global->_inter_variables + varOff, _vm->_global->_inter_resStr);
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool Inter_v2::o2_palLoad(char &cmdCount, int16 &counter, int16 &retFlag) {
+ int16 i;
+ int16 ind1;
+ int16 ind2;
+ byte cmd;
+ char *palPtr;
+
+ cmd = *_vm->_global->_inter_execPtr++;
+
+ switch(cmd & 0x7f) {
+ case 48:
+ if ((_vm->_global->_videoMode < 0x32) || (_vm->_global->_videoMode > 0x63)) {
+ _vm->_global->_inter_execPtr += 48;
+ return false;
+ }
+ break;
+
+ case 49:
+ if ((_vm->_global->_videoMode != 5) && (_vm->_global->_videoMode != 7)) {
+ _vm->_global->_inter_execPtr += 18;
+ return false;
+ }
+ break;
+
+ case 50:
+ if (_vm->_global->_videoMode != 0x0D) { // || (word_2D479 == 256) {
+ _vm->_global->_inter_execPtr += 16;
+ return false;
+ }
+ break;
+
+ case 51:
+ if (_vm->_global->_videoMode < 0x64) {
+ _vm->_global->_inter_execPtr += 2;
+ return false;
+ }
+ break;
+
+ case 52:
+ if (_vm->_global->_videoMode != 0x0D) { // || (word_2D479 == 256) {
+ _vm->_global->_inter_execPtr += 48;
+ return false;
+ }
+ break;
+
+ case 53:
+ if (_vm->_global->_videoMode < 0x13) {
+ _vm->_global->_inter_execPtr += 2;
+ return false;
+ }
+ break;
+
+ case 54:
+ if (_vm->_global->_videoMode < 0x13) {
+ return false;
+ }
+ break;
+
+ case 61:
+ if (_vm->_global->_videoMode < 0x13) {
+ *_vm->_global->_inter_execPtr += 4;
+ return false;
+ }
+ break;
+ }
+
+ if ((cmd & 0x7f) == 0x30) {
+ _vm->_global->_inter_execPtr += 48;
+ return false;
+ }
+
+ _vm->_draw->_applyPal = 0;
+ if (cmd & 0x80)
+ cmd &= 0x7f;
+ else
+ _vm->_draw->_applyPal = 1;
+
+ if (cmd == 49) {
+ int dl = 0;
+ for (i = 2; i < 18; i++) {
+ dl = 1;
+ if(_vm->_global->_inter_execPtr[i] != 0)
+ dl = 0;
+ }
+ if (dl != 0) {
+ warning("GOB2 Stub! sub_27413");
+/* sub_27413(_draw_frontSurface);
+ byte_2E521 = 0;
+ _vm->_global->_inter_execPtr += 18;
+ break;*/
+ }
+// byte_2E521 = 1;
+
+ for (i = 0; i < 18; i++, _vm->_global->_inter_execPtr++) {
+ if (i < 2) {
+ if (_vm->_draw->_applyPal == 0)
+ continue;
+
+ _vm->_draw->_unusedPalette1[i] = *_vm->_global->_inter_execPtr;
+ continue;
+ }
+
+ ind1 = *_vm->_global->_inter_execPtr >> 4;
+ ind2 = (*_vm->_global->_inter_execPtr & 0xf);
+
+ _vm->_draw->_unusedPalette1[i] =
+ ((_vm->_draw->_palLoadData1[ind1] + _vm->_draw->_palLoadData2[ind2]) << 8) +
+ (_vm->_draw->_palLoadData2[ind1] + _vm->_draw->_palLoadData1[ind2]);
+ }
+
+ _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1;
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ return false;
+ }
+
+ switch (cmd) {
+ case 50:
+ for (i = 0; i < 16; i++, _vm->_global->_inter_execPtr++)
+ _vm->_draw->_unusedPalette2[i] = *_vm->_global->_inter_execPtr;
+ break;
+
+ case 52:
+ for (i = 0; i < 16; i++, _vm->_global->_inter_execPtr += 3) {
+ _vm->_draw->_vgaSmallPalette[i].red = _vm->_global->_inter_execPtr[0];
+ _vm->_draw->_vgaSmallPalette[i].green = _vm->_global->_inter_execPtr[1];
+ _vm->_draw->_vgaSmallPalette[i].blue = _vm->_global->_inter_execPtr[2];
+ }
+ _vm->_global->_inter_execPtr += 48;
+ if (_vm->_global->_videoMode >= 0x13)
+ return false;
+ break;
+
+ case 53:
+ palPtr = _vm->_game->loadTotResource(_vm->_inter->load16());
+ memcpy((char *)_vm->_draw->_vgaPalette, palPtr, 768);
+ break;
+
+ case 54:
+ memset((char *)_vm->_draw->_vgaPalette, 0, 768);
+ break;
+
+ case 61:
+ ind1 = *_vm->_global->_inter_execPtr++;
+ ind2 = (*_vm->_global->_inter_execPtr++ - ind1 + 1) * 3;
+ palPtr = _vm->_game->loadTotResource(_vm->_inter->load16());
+ memcpy((char *)_vm->_draw->_vgaPalette + ind1 * 3, palPtr + ind1 * 3, ind2);
+ if (_vm->_draw->_applyPal) {
+ _vm->_draw->_applyPal = 0;
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ return false;
+ }
+ break;
+ }
+
+ if (!_vm->_draw->_applyPal) {
+ _vm->_global->_pPaletteDesc->unused2 = _vm->_draw->_unusedPalette2;
+ _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1;
+ if (_vm->_global->_videoMode < 0x13) {
+ _vm->_global->_pPaletteDesc->vgaPal = (Video::Color *)_vm->_draw->_vgaSmallPalette;
+ _vm->_palanim->fade((Video::PalDesc *) _vm->_global->_pPaletteDesc, 0, 0);
+ return false;
+ }
+ if ((_vm->_global->_videoMode < 0x32) || (_vm->_global->_videoMode >= 0x64)) {
+ _vm->_global->_pPaletteDesc->vgaPal = (Video::Color *)_vm->_draw->_vgaPalette;
+ _vm->_palanim->fade((Video::PalDesc *) _vm->_global->_pPaletteDesc, 0, 0);
+ return false;
+ }
+ _vm->_global->_pPaletteDesc->vgaPal = (Video::Color *)_vm->_draw->_vgaSmallPalette;
+ _vm->_palanim->fade((Video::PalDesc *) _vm->_global->_pPaletteDesc, 0, 0);
+ }
+
+ return false;
+}
+
+void Inter_v2::o2_setRenderFlags(void) {
+ int16 expr;
+
+ expr = _vm->_parse->parseValExpr();
+
+ if (expr & 0x8000) {
+ if (expr & 0x4000)
+ _vm->_draw->_renderFlags = _vm->_parse->parseValExpr();
+ else
+ _vm->_draw->_renderFlags &= expr & 0x3fff;
+ }
+ else
+ _vm->_draw->_renderFlags |= expr & 0x3fff;
+}
+
+bool Inter_v2::o2_loadTot(char &cmdCount, int16 &counter, int16 &retFlag) {
+ char buf[20];
+ int8 size;
+ int16 i;
+
+ if ((*_vm->_global->_inter_execPtr & 0x80) != 0) {
+ _vm->_global->_inter_execPtr++;
+ evalExpr(0);
+ strcpy(buf, _vm->_global->_inter_resStr);
+ } else {
+ size = *_vm->_global->_inter_execPtr++;
+ for (i = 0; i < size; i++)
+ buf[i] = *_vm->_global->_inter_execPtr++;
+
+ buf[size] = 0;
+ }
+
+ if (strcmp(buf, "INSTALL") == 0) {
+ warning("GOB2 Stub! word_2E515 = _inter_variables[0E8h]");
+ }
+
+ strcat(buf, ".tot");
+ if (_terminate != 2)
+ _terminate = true;
+ strcpy(_vm->_game->_totToLoad, buf);
+
+ return false;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp
new file mode 100644
index 0000000000..ed08d1d401
--- /dev/null
+++ b/engines/gob/map.cpp
@@ -0,0 +1,785 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/map.h"
+#include "gob/video.h"
+#include "gob/util.h"
+#include "gob/dataio.h"
+#include "gob/inter.h"
+#include "gob/goblin.h"
+#include "gob/sound.h"
+#include "gob/scenery.h"
+
+namespace Gob {
+
+Map::Map(GobEngine *vm) : _vm(vm) {
+ int i;
+
+ for (i = 0; i < kMapHeight; i++)
+ for (int j = 0; j < kMapWidth; j++) {
+ _passMap[i][j] = 0;
+ _itemsMap[i][j] = 0;
+ }
+ for (i = 0; i < 40; i++) {
+ _wayPoints[i].x = 0;
+ _wayPoints[i].y = 0;
+ }
+ for (i = 0; i < 40; i++) {
+ _itemPoses[i].x = 0;
+ _itemPoses[i].y = 0;
+ _itemPoses[i].orient = 0;
+ }
+
+ _nearestWayPoint = 0;
+ _nearestDest = 0;
+ _curGoblinX = 0;
+ _curGoblinY = 0;
+ _destX = 0;
+ _destY = 0;
+ _loadFromAvo = 0;
+ _sourceFile[0] = 0;
+ _avoDataPtr = 0;
+}
+
+void Map::placeItem(int16 x, int16 y, int16 id) {
+ if ((_itemsMap[y][x] & 0xff00) != 0)
+ _itemsMap[y][x] = (_itemsMap[y][x] & 0xff00) | id;
+ else
+ _itemsMap[y][x] = (_itemsMap[y][x] & 0x00ff) | (id << 8);
+}
+
+enum {
+ kLeft = (1 << 0),
+ kUp = (1 << 1),
+ kRight = (1 << 2),
+ kDown = (1 << 3)
+};
+
+int16 Map::getDirection(int16 x0, int16 y0, int16 x1, int16 y1) {
+ int16 dir = 0;
+
+ if (x0 == x1 && y0 == y1)
+ return 0;
+
+ if (!(x1 >= 0 && x1 < kMapWidth && y1 >= 0 && y1 < kMapHeight))
+ return 0;
+
+ if (y1 > y0)
+ dir |= kDown;
+ else if (y1 < y0)
+ dir |= kUp;
+
+ if (x1 > x0)
+ dir |= kRight;
+ else if (x1 < x0)
+ dir |= kLeft;
+
+ if (_passMap[y0][x0] == 3 && (dir & kUp)) {
+ if (_passMap[y0 - 1][x0] != 0)
+ return kDirN;
+ }
+
+ if (_passMap[y0][x0] == 3 && (dir & kDown)) {
+ if (_passMap[y0 + 1][x0] != 0)
+ return kDirS;
+ }
+
+ if (_passMap[y0][x0] == 6 && (dir & kUp)) {
+ if (_passMap[y0 - 1][x0] != 0)
+ return kDirN;
+ }
+
+ if (_passMap[y0][x0] == 6 && (dir & kDown)) {
+ if (_passMap[y0 + 1][x0] != 0)
+ return kDirS;
+ }
+
+ if (dir == kLeft) {
+ if (x0 - 1 >= 0 && _passMap[y0][x0 - 1] != 0)
+ return kDirW;
+ return 0;
+ }
+
+ if (dir == kRight) {
+ if (x0 + 1 < kMapWidth && _passMap[y0][x0 + 1] != 0)
+ return kDirE;
+ return 0;
+ }
+
+ if (dir == kUp) {
+ if (y0 - 1 >= 0 && _passMap[y0 - 1][x0] != 0)
+ return kDirN;
+
+ if (y0 - 1 >= 0 && x0 - 1 >= 0
+ && _passMap[y0 - 1][x0 - 1] != 0)
+ return kDirNW;
+
+ if (y0 - 1 >= 0 && x0 + 1 < kMapWidth
+ && _passMap[y0 - 1][x0 + 1] != 0)
+ return kDirNE;
+
+ return 0;
+ }
+
+ if (dir == kDown) {
+ if (y0 + 1 < kMapHeight && _passMap[y0 + 1][x0] != 0)
+ return kDirS;
+
+ if (y0 + 1 < kMapHeight && x0 - 1 >= 0
+ && _passMap[y0 + 1][x0 - 1] != 0)
+ return kDirSW;
+
+ if (y0 + 1 < kMapHeight && x0 + 1 < kMapWidth
+ && _passMap[y0 + 1][x0 + 1] != 0)
+ return kDirSE;
+
+ return 0;
+ }
+
+ if (dir == (kRight | kUp)) {
+ if (y0 - 1 >= 0 && x0 + 1 < kMapWidth
+ && _passMap[y0 - 1][x0 + 1] != 0)
+ return kDirNE;
+
+ if (y0 - 1 >= 0 && _passMap[y0 - 1][x0] != 0)
+ return kDirN;
+
+ if (x0 + 1 < kMapWidth && _passMap[y0][x0 + 1] != 0)
+ return kDirE;
+
+ return 0;
+ }
+
+ if (dir == (kRight | kDown)) {
+ if (x0 + 1 < kMapWidth && y0 + 1 < kMapHeight
+ && _passMap[y0 + 1][x0 + 1] != 0)
+ return kDirSE;
+
+ if (y0 + 1 < kMapHeight && _passMap[y0 + 1][x0] != 0)
+ return kDirS;
+
+ if (x0 + 1 < kMapWidth && _passMap[y0][x0 + 1] != 0)
+ return kDirE;
+
+ return 0;
+ }
+
+ if (dir == (kLeft | kUp)) {
+ if (x0 - 1 >= 0 && y0 - 1 >= 0
+ && _passMap[y0 - 1][x0 - 1] != 0)
+ return kDirNW;
+
+ if (y0 - 1 >= 0 && _passMap[y0 - 1][x0] != 0)
+ return kDirN;
+
+ if (x0 - 1 >= 0 && _passMap[y0][x0 - 1] != 0)
+ return kDirW;
+
+ return 0;
+ }
+
+ if (dir == (kLeft | kDown)) {
+ if (x0 - 1 >= 0 && y0 + 1 < kMapHeight
+ && _passMap[y0 + 1][x0 - 1] != 0)
+ return kDirSW;
+
+ if (y0 + 1 < kMapHeight && _passMap[y0 + 1][x0] != 0)
+ return kDirS;
+
+ if (x0 - 1 >= 0 && _passMap[y0][x0 - 1] != 0)
+ return kDirW;
+
+ return 0;
+ }
+ return -1;
+}
+
+int16 Map::findNearestWayPoint(int16 x, int16 y) {
+ int16 lnearestWayPoint = -1;
+ int16 length;
+ int16 i;
+ int16 tmp;
+
+ length = 30000;
+
+ for (i = 0; i < 40; i++) {
+ if (_wayPoints[i].x < 0 ||
+ _wayPoints[i].x >= kMapWidth ||
+ _wayPoints[i].y < 0 || _wayPoints[i].y >= kMapHeight)
+ return -1;
+
+ tmp = ABS(x - _wayPoints[i].x) + ABS(y - _wayPoints[i].y);
+
+ if (tmp <= length) {
+ lnearestWayPoint = i;
+ length = tmp;
+ }
+ }
+
+ return lnearestWayPoint;
+}
+
+void Map::findNearestToGob(void) {
+ int16 wayPoint = findNearestWayPoint(_curGoblinX, _curGoblinY);
+
+ if (wayPoint != -1)
+ _nearestWayPoint = wayPoint;
+}
+
+void Map::findNearestToDest(void) {
+ int16 wayPoint = findNearestWayPoint(_destX, _destY);
+
+ if (wayPoint != -1)
+ _nearestDest = wayPoint;
+}
+
+int16 Map::checkDirectPath(int16 x0, int16 y0, int16 x1, int16 y1) {
+ uint16 dir;
+
+ while (1) {
+ dir = getDirection(x0, y0, x1, y1);
+
+ if (x0 == x1 && y0 == y1)
+ return 1;
+
+ if (dir == 0)
+ return 3;
+
+ switch (dir) {
+ case kDirNW:
+ x0--;
+ y0--;
+ break;
+
+ case kDirN:
+ y0--;
+ break;
+
+ case kDirNE:
+ x0++;
+ y0--;
+ break;
+
+ case kDirW:
+ x0--;
+ break;
+
+ case kDirE:
+ x0++;
+ break;
+
+ case kDirSW:
+ x0--;
+ y0++;
+ break;
+
+ case kDirS:
+ y0++;
+ break;
+
+ case kDirSE:
+ x0++;
+ y0++;
+ break;
+ }
+ }
+}
+
+int16 Map::checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1) {
+ uint16 dir;
+ int16 curX;
+ int16 curY;
+ int16 nextLink;
+
+ curX = x0;
+ curY = y0;
+ dir = 0;
+
+ nextLink = 1;
+
+ while (1) {
+ if (x0 == curX && y0 == curY)
+ nextLink = 1;
+
+ if (nextLink != 0) {
+ if (checkDirectPath(x0, y0, x1, y1) == 1)
+ return 1;
+
+ nextLink = 0;
+ if (i0 > i1) {
+ curX = _wayPoints[i0].x;
+ curY = _wayPoints[i0].y;
+ i0--;
+ } else if (i0 < i1) {
+ curX = _wayPoints[i0].x;
+ curY = _wayPoints[i0].y;
+ i0++;
+ } else if (i0 == i1) {
+ curX = _wayPoints[i0].x;
+ curY = _wayPoints[i0].y;
+ }
+ }
+ if (i0 == i1 && _wayPoints[i0].x == x0
+ && _wayPoints[i0].y == y0) {
+ if (checkDirectPath(x0, y0, x1, y1) == 1)
+ return 1;
+ return 0;
+ }
+ dir = getDirection(x0, y0, curX, curY);
+ switch (dir) {
+ case 0:
+ return 0;
+
+ case kDirNW:
+ x0--;
+ y0--;
+ break;
+
+ case kDirN:
+ y0--;
+ break;
+
+ case kDirNE:
+ x0++;
+ y0--;
+ break;
+
+ case kDirW:
+ x0--;
+ break;
+
+ case kDirE:
+ x0++;
+ break;
+
+ case kDirSW:
+ x0--;
+ y0++;
+ break;
+
+ case kDirS:
+ y0++;
+ break;
+
+ case kDirSE:
+ x0++;
+ y0++;
+ break;
+ }
+ }
+}
+
+void Map::optimizePoints(void) {
+ int16 i;
+
+ if (_nearestWayPoint < _nearestDest) {
+ for (i = _nearestWayPoint; i <= _nearestDest; i++) {
+ if (checkDirectPath(_curGoblinX, _curGoblinY,
+ _wayPoints[i].x, _wayPoints[i].y) == 1)
+ _nearestWayPoint = i;
+ }
+ } else if (_nearestWayPoint > _nearestDest) {
+ for (i = _nearestWayPoint; i >= _nearestDest; i--) {
+ if (checkDirectPath(_curGoblinX, _curGoblinY,
+ _wayPoints[i].x, _wayPoints[i].y) == 1)
+ _nearestWayPoint = i;
+ }
+ }
+}
+
+void Map::loadDataFromAvo(char *dest, int16 size) {
+ memcpy(dest, _avoDataPtr, size);
+ _avoDataPtr += size;
+}
+
+uint16 Map::loadFromAvo_LE_UINT16() {
+ uint16 tmp = READ_LE_UINT16(_avoDataPtr);
+ _avoDataPtr += 2;
+ return tmp;
+}
+
+void Map::loadItemToObject(void) {
+ int16 flag;
+ int16 count;
+ int16 i;
+
+ flag = loadFromAvo_LE_UINT16();
+ if (flag == 0)
+ return;
+
+ _avoDataPtr += 1456;
+ count = loadFromAvo_LE_UINT16();
+ for (i = 0; i < count; i++) {
+ _avoDataPtr += 20;
+ _vm->_goblin->_itemToObject[i] = loadFromAvo_LE_UINT16();
+ _avoDataPtr += 5;
+ }
+}
+
+void Map::loadMapObjects(char *avjFile) {
+ int16 i;
+ char avoName[128];
+ int16 handle;
+ char item;
+ int16 soundCount;
+ int16 tmp;
+ char *savedPtr;
+ char *savedPtr2;
+ char *savedPtr3;
+ int16 state;
+ int16 col;
+ int32 flag;
+ Goblin::Gob_State *pState;
+ char buf[128];
+ char sndNames[20][14];
+ char *dataBuf;
+ int16 x;
+ int16 y;
+ int16 count2;
+ int16 count3;
+
+ strcpy(avoName, _sourceFile);
+ strcat(avoName, ".avo");
+
+ handle = _vm->_dataio->openData(avoName);
+ if (handle >= 0) {
+ _loadFromAvo = 1;
+ _vm->_dataio->closeData(handle);
+ _avoDataPtr = _vm->_dataio->getData(avoName);
+ dataBuf = _avoDataPtr;
+ loadDataFromAvo((char *)_passMap, kMapHeight * kMapWidth);
+
+ for (y = 0; y < kMapHeight; y++) {
+ for (x = 0; x < kMapWidth; x++) {
+ loadDataFromAvo(&item, 1);
+ _itemsMap[y][x] = item;
+ }
+ }
+
+ for (i = 0; i < 40; i++) {
+ _wayPoints[i].x = loadFromAvo_LE_UINT16();
+ _wayPoints[i].y = loadFromAvo_LE_UINT16();
+ }
+ loadDataFromAvo((char *)_itemPoses, szMap_ItemPos * 20);
+ } else {
+ _loadFromAvo = 0;
+ _avoDataPtr = _vm->_dataio->getData(avjFile);
+ dataBuf = _avoDataPtr;
+ }
+
+ _avoDataPtr += 32;
+ _avoDataPtr += 76;
+ _avoDataPtr += 4;
+ _avoDataPtr += 20;
+
+ for (i = 0; i < 3; i++) {
+ tmp = loadFromAvo_LE_UINT16();
+ _avoDataPtr += tmp * 14;
+ }
+
+ soundCount = loadFromAvo_LE_UINT16();
+ savedPtr = _avoDataPtr;
+
+ _avoDataPtr += 14 * soundCount;
+ _avoDataPtr += 4;
+ _avoDataPtr += 24;
+
+ count2 = loadFromAvo_LE_UINT16();
+ count3 = loadFromAvo_LE_UINT16();
+
+ savedPtr2 = _avoDataPtr;
+ _avoDataPtr += count2 * 8;
+
+ savedPtr3 = _avoDataPtr;
+ _avoDataPtr += count3 * 8;
+
+ _vm->_goblin->_gobsCount = loadFromAvo_LE_UINT16();
+ for (i = 0; i < _vm->_goblin->_gobsCount; i++) {
+ _vm->_goblin->_goblins[i] = new Goblin::Gob_Object;
+
+ _vm->_goblin->_goblins[i]->xPos = READ_LE_UINT16(savedPtr2);
+ savedPtr2 += 2;
+
+ _vm->_goblin->_goblins[i]->yPos = READ_LE_UINT16(savedPtr2);
+ savedPtr2 += 2;
+
+ _vm->_goblin->_goblins[i]->order = READ_LE_UINT16(savedPtr2);
+ savedPtr2 += 2;
+
+ _vm->_goblin->_goblins[i]->state = READ_LE_UINT16(savedPtr2);
+ savedPtr2 += 2;
+
+ if (i == 3)
+ _vm->_goblin->_goblins[i]->stateMach = new Goblin::Gob_StateLine[70];
+ else
+ _vm->_goblin->_goblins[i]->stateMach = new Goblin::Gob_StateLine[40];
+
+ uint32* tempstatedata = new uint32[40*6];
+ for (state = 0; state < 40; ++state) {
+ for (col = 0; col < 6; ++col) {
+ tempstatedata[state*6+col] = READ_LE_UINT32(_avoDataPtr);
+ _avoDataPtr += 4;
+ }
+ }
+ _avoDataPtr += 160;
+ _vm->_goblin->_goblins[i]->multObjIndex = *_avoDataPtr;
+ _avoDataPtr += 2;
+
+ _vm->_goblin->_goblins[i]->realStateMach = _vm->_goblin->_goblins[i]->stateMach;
+ for (state = 0; state < 40; state++) {
+ for (col = 0; col < 6; col++) {
+ if (tempstatedata[state*6+col] == 0) {
+ _vm->_goblin->_goblins[i]->stateMach[state][col] = 0;
+ continue;
+ }
+
+ Goblin::Gob_State *tmpState = new Goblin::Gob_State;
+ _vm->_goblin->_goblins[i]->stateMach[state][col] = tmpState;
+
+ tmpState->animation = loadFromAvo_LE_UINT16();
+ tmpState->layer = loadFromAvo_LE_UINT16();
+ _avoDataPtr += 8;
+ tmpState->unk0 = loadFromAvo_LE_UINT16();
+ tmpState->unk1 = loadFromAvo_LE_UINT16();
+
+ _avoDataPtr += 2;
+ if (READ_LE_UINT32(_avoDataPtr) != 0) {
+ _avoDataPtr += 4;
+ tmpState->sndItem = loadFromAvo_LE_UINT16();
+ } else {
+ _avoDataPtr += 6;
+ tmpState->sndItem = -1;
+ }
+ tmpState->freq = loadFromAvo_LE_UINT16();
+ tmpState->repCount = loadFromAvo_LE_UINT16();
+ tmpState->sndFrame = loadFromAvo_LE_UINT16();
+ }
+ }
+ delete[] tempstatedata;
+ }
+
+ pState = new Goblin::Gob_State;
+ _vm->_goblin->_goblins[0]->stateMach[39][0] = pState;
+ pState->animation = 0;
+ pState->layer = 98;
+ pState->unk0 = 0;
+ pState->unk1 = 0;
+ pState->sndItem = -1;
+
+ pState = new Goblin::Gob_State;
+ _vm->_goblin->_goblins[1]->stateMach[39][0] = pState;
+ pState->animation = 0;
+ pState->layer = 99;
+ pState->unk0 = 0;
+ pState->unk1 = 0;
+ pState->sndItem = -1;
+
+ pState = new Goblin::Gob_State;
+ _vm->_goblin->_goblins[2]->stateMach[39][0] = pState;
+ pState->animation = 0;
+ pState->layer = 100;
+ pState->unk0 = 0;
+ pState->unk1 = 0;
+ pState->sndItem = -1;
+
+ _vm->_goblin->_goblins[2]->stateMach[10][0]->sndFrame = 13;
+ _vm->_goblin->_goblins[2]->stateMach[11][0]->sndFrame = 13;
+ _vm->_goblin->_goblins[2]->stateMach[28][0]->sndFrame = 13;
+ _vm->_goblin->_goblins[2]->stateMach[29][0]->sndFrame = 13;
+
+ _vm->_goblin->_goblins[1]->stateMach[10][0]->sndFrame = 13;
+ _vm->_goblin->_goblins[1]->stateMach[11][0]->sndFrame = 13;
+
+ for (state = 40; state < 70; state++) {
+ pState = new Goblin::Gob_State;
+ _vm->_goblin->_goblins[3]->stateMach[state][0] = pState;
+ _vm->_goblin->_goblins[3]->stateMach[state][1] = 0;
+
+ pState->animation = 9;
+ pState->layer = state - 40;
+ pState->sndItem = -1;
+ pState->sndFrame = 0;
+ }
+
+ _vm->_goblin->_objCount = loadFromAvo_LE_UINT16();
+ for (i = 0; i < _vm->_goblin->_objCount; i++) {
+ _vm->_goblin->_objects[i] = new Goblin::Gob_Object;
+
+ _vm->_goblin->_objects[i]->xPos = READ_LE_UINT16(savedPtr3);
+ savedPtr3 += 2;
+
+ _vm->_goblin->_objects[i]->yPos = READ_LE_UINT16(savedPtr3);
+ savedPtr3 += 2;
+
+ _vm->_goblin->_objects[i]->order = READ_LE_UINT16(savedPtr3);
+ savedPtr3 += 2;
+
+ _vm->_goblin->_objects[i]->state = READ_LE_UINT16(savedPtr3);
+ savedPtr3 += 2;
+
+ _vm->_goblin->_objects[i]->stateMach = new Goblin::Gob_StateLine[40];
+
+ uint32* tempstatedata = new uint32[40*6];
+ for (state = 0; state < 40; ++state) {
+ for (col = 0; col < 6; ++col) {
+ tempstatedata[state*6+col] = READ_LE_UINT32(_avoDataPtr);
+ _avoDataPtr += 4;
+ }
+ }
+ _avoDataPtr += 160;
+ _vm->_goblin->_objects[i]->multObjIndex = *_avoDataPtr;
+ _avoDataPtr += 2;
+
+ _vm->_goblin->_objects[i]->realStateMach = _vm->_goblin->_objects[i]->stateMach;
+ for (state = 0; state < 40; state++) {
+ for (col = 0; col < 6; col++) {
+ if (tempstatedata[state*6+col] == 0) {
+ _vm->_goblin->_objects[i]->stateMach[state][col] = 0;
+ continue;
+ }
+
+ Goblin::Gob_State *tmpState = new Goblin::Gob_State;
+ _vm->_goblin->_objects[i]->stateMach[state][col] = tmpState;
+
+ tmpState->animation = loadFromAvo_LE_UINT16();
+ tmpState->layer = loadFromAvo_LE_UINT16();
+ _avoDataPtr += 8;
+ tmpState->unk0 = loadFromAvo_LE_UINT16();
+ tmpState->unk1 = loadFromAvo_LE_UINT16();
+
+ _avoDataPtr += 2;
+ if (READ_LE_UINT32(_avoDataPtr) != 0) {
+ _avoDataPtr += 4;
+ tmpState->sndItem = loadFromAvo_LE_UINT16();
+ } else {
+ _avoDataPtr += 6;
+ tmpState->sndItem = -1;
+ }
+ tmpState->freq = loadFromAvo_LE_UINT16();
+ tmpState->repCount = loadFromAvo_LE_UINT16();
+ tmpState->sndFrame = loadFromAvo_LE_UINT16();
+ }
+ }
+ delete[] tempstatedata;
+ }
+
+ _vm->_goblin->_objects[10] = new Goblin::Gob_Object;
+ memset(_vm->_goblin->_objects[10], 0, sizeof(Goblin::Gob_Object));
+
+ _vm->_goblin->_objects[10]->stateMach = new Goblin::Gob_StateLine[40];
+ for (state = 0; state < 40; ++state)
+ for (col = 0; col < 6; ++col)
+ _vm->_goblin->_objects[10]->stateMach[state][col] = 0;
+
+ pState = new Goblin::Gob_State;
+ _vm->_goblin->_objects[10]->stateMach[0][0] = pState;
+
+ memset(pState, 0, sizeof(Goblin::Gob_State));
+ pState->animation = 9;
+ pState->layer = 27;
+ pState->unk0 = 0;
+ pState->unk1 = 0;
+ pState->sndItem = -1;
+ pState->sndFrame = 0;
+
+ _vm->_goblin->placeObject(_vm->_goblin->_objects[10], 1);
+
+ _vm->_goblin->_objects[10]->realStateMach = _vm->_goblin->_objects[10]->stateMach;
+ _vm->_goblin->_objects[10]->type = 1;
+ _vm->_goblin->_objects[10]->unk14 = 1;
+
+ state = loadFromAvo_LE_UINT16();
+ for (i = 0; i < state; i++) {
+ _avoDataPtr += 30;
+
+ loadDataFromAvo((char *)&flag, 4);
+ _avoDataPtr += 56;
+
+ if (flag != 0)
+ _avoDataPtr += 30;
+ }
+
+ loadDataFromAvo((char *)&tmp, 2);
+ _avoDataPtr += 48;
+ loadItemToObject();
+ _avoDataPtr = savedPtr;
+
+ for (i = 0; i < soundCount; i++) {
+ loadDataFromAvo(buf, 14);
+ strcat(buf, ".SND");
+ strcpy(sndNames[i], buf);
+ }
+
+ delete[] dataBuf;
+
+ _vm->_goblin->_soundData[14] = _vm->_snd->loadSoundData("diamant1.snd");
+
+ for (i = 0; i < soundCount; i++) {
+ handle = _vm->_dataio->openData(sndNames[i]);
+ if (handle < 0)
+ continue;
+
+ _vm->_dataio->closeData(handle);
+ _vm->_goblin->_soundData[i] = _vm->_snd->loadSoundData(sndNames[i]);
+ }
+}
+
+void Map::loadMapsInitGobs(void) {
+ int16 layer;
+ int16 i;
+
+ if (_loadFromAvo == 0)
+ error("load: Loading .pas/.pos files is not supported!");
+
+ for (i = 0; i < 3; i++) {
+ _vm->_goblin->nextLayer(_vm->_goblin->_goblins[i]);
+ }
+
+ for (i = 0; i < 3; i++) {
+
+ layer =
+ _vm->_goblin->_goblins[i]->stateMach[_vm->_goblin->_goblins[i]->state][0]->layer;
+
+ _vm->_scenery->updateAnim(layer, 0, _vm->_goblin->_goblins[i]->animation, 0,
+ _vm->_goblin->_goblins[i]->xPos, _vm->_goblin->_goblins[i]->yPos, 0);
+
+ _vm->_goblin->_goblins[i]->yPos = (_vm->_goblin->_gobPositions[i].y + 1) * 6 -
+ (_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop);
+
+ _vm->_goblin->_goblins[i]->xPos = _vm->_goblin->_gobPositions[i].x * 12 -
+ (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
+
+ _vm->_goblin->_goblins[i]->order = _vm->_scenery->_toRedrawBottom / 24 + 3;
+ }
+
+ _vm->_goblin->_currentGoblin = 0;
+ _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[0].x;
+ _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[0].y;
+ _vm->_goblin->_pathExistence = 0;
+
+ _vm->_goblin->_goblins[0]->doAnim = 0;
+ _vm->_goblin->_goblins[1]->doAnim = 1;
+ _vm->_goblin->_goblins[2]->doAnim = 1;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/map.h b/engines/gob/map.h
new file mode 100644
index 0000000000..59e9a3bdf9
--- /dev/null
+++ b/engines/gob/map.h
@@ -0,0 +1,104 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_MAP_H
+#define GOB_MAP_H
+
+namespace Gob {
+
+// The same numeric values are also used for the arrow keys.
+
+class Map {
+public:
+ enum {
+ kDirNW = 0x4700,
+ kDirN = 0x4800,
+ kDirNE = 0x4900,
+ kDirW = 0x4b00,
+ kDirE = 0x4d00,
+ kDirSW = 0x4f00,
+ kDirS = 0x5000,
+ kDirSE = 0x5100
+ };
+ enum {
+ kMapWidth = 26,
+ kMapHeight = 28
+ };
+
+#pragma START_PACK_STRUCTS
+
+ struct Point {
+ int16 x;
+ int16 y;
+ } GCC_PACK;
+
+#define szMap_ItemPos 3
+
+ struct ItemPos {
+ int8 x;
+ int8 y;
+ int8 orient; // ??
+ } GCC_PACK;
+
+#pragma END_PACK_STRUCTS
+
+ int8 _passMap[kMapHeight][kMapWidth]; // [y][x]
+ int16 _itemsMap[kMapHeight][kMapWidth]; // [y][x]
+ Point _wayPoints[40];
+ int16 _nearestWayPoint;
+ int16 _nearestDest;
+
+ int16 _curGoblinX;
+ int16 _curGoblinY;
+ int16 _destX;
+ int16 _destY;
+ int8 _loadFromAvo;
+
+ ItemPos _itemPoses[40];
+ char _sourceFile[15];
+
+ void placeItem(int16 x, int16 y, int16 id);
+
+ int16 getDirection(int16 x0, int16 y0, int16 x1, int16 y1);
+ void findNearestToGob(void);
+ void findNearestToDest(void);
+ int16 checkDirectPath(int16 x0, int16 y0, int16 x1, int16 y1);
+ int16 checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1);
+ void optimizePoints(void);
+ void loadItemToObject(void);
+ void loadMapObjects(char *avjFile);
+ void loadDataFromAvo(char *dest, int16 size);
+ void loadMapsInitGobs(void);
+
+ Map(GobEngine *vm);
+
+protected:
+ char *_avoDataPtr;
+ GobEngine *_vm;
+
+ int16 findNearestWayPoint(int16 x, int16 y);
+ uint16 loadFromAvo_LE_UINT16();
+};
+
+} // End of namespace Gob
+
+#endif /* __MAP_H */
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
new file mode 100644
index 0000000000..c8188d78b2
--- /dev/null
+++ b/engines/gob/module.mk
@@ -0,0 +1,40 @@
+MODULE := engines/gob
+
+MODULE_OBJS := \
+ engines/gob/anim.o \
+ engines/gob/cdrom.o \
+ engines/gob/dataio.o \
+ engines/gob/draw.o \
+ engines/gob/driver_vga.o \
+ engines/gob/game.o \
+ engines/gob/global.o \
+ engines/gob/gob.o \
+ engines/gob/goblin.o \
+ engines/gob/init.o \
+ engines/gob/inter.o \
+ engines/gob/inter_v1.o \
+ engines/gob/inter_v2.o \
+ engines/gob/map.o \
+ engines/gob/mult.o \
+ engines/gob/music.o \
+ engines/gob/pack.o \
+ engines/gob/palanim.o \
+ engines/gob/parse.o \
+ engines/gob/parse_v1.o \
+ engines/gob/parse_v2.o \
+ engines/gob/scenery.o \
+ engines/gob/sound.o \
+ engines/gob/timer.o \
+ engines/gob/util.o \
+ engines/gob/video.o
+
+MODULE_DIRS += \
+ engines/gob
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/common.rules
diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp
new file mode 100644
index 0000000000..96bffa80d1
--- /dev/null
+++ b/engines/gob/mult.cpp
@@ -0,0 +1,1214 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/video.h"
+#include "gob/anim.h"
+#include "gob/draw.h"
+#include "gob/scenery.h"
+#include "gob/mult.h"
+#include "gob/util.h"
+#include "gob/inter.h"
+#include "gob/parse.h"
+#include "gob/global.h"
+#include "gob/sound.h"
+#include "gob/palanim.h"
+#include "gob/game.h"
+
+namespace Gob {
+
+Mult::Mult(GobEngine *vm) : _vm(vm) {
+ _objects = 0;
+ _renderData = 0;
+ _objCount = 0;
+ _underAnimSurf = 0;
+ _multData = 0;
+ _frame = 0;
+ _doPalSubst = 0;
+ _counter = 0;
+ _frameRate = 0;
+
+ _animArrayX = 0;
+ _animArrayY = 0;
+ _animArrayData = 0;
+
+ _index = 0;
+
+ _staticKeysCount = 0;
+ _staticKeys = 0;
+ int i;
+ for (i = 0; i < 10; i++)
+ _staticIndices[i] = 0;
+
+ for (i = 0; i < 4; i++) {
+ _animKeys[i] = 0;
+ _animKeysCount[i] = 0;
+ }
+ _animLayer = 0;
+ for (i = 0; i < 10; i++)
+ _animIndices[i] = 0;
+
+ _textKeysCount = 0;
+ _textKeys = 0;
+
+ _frameStart = 0;
+
+ _palKeyIndex = 0;
+ _palKeysCount = 0;
+ _palKeys = 0;
+ _oldPalette = 0;
+ _palAnimKey = 0;
+ for (i = 0; i < 256; i++) {
+ _palAnimPalette[i].red = 0;
+ _palAnimPalette[i].green = 0;
+ _palAnimPalette[i].blue = 0;
+ }
+ for (i = 0; i < 4; i++) {
+ _palAnimIndices[i] = 0;
+ _palAnimRed[i] = 0;
+ _palAnimGreen[i] = 0;
+ _palAnimBlue[i] = 0;
+ }
+
+ _palFadeKeys = 0;
+ _palFadeKeysCount = 0;
+ _palFadingRed = 0;
+ _palFadingGreen = 0;
+ _palFadingBlue = 0;
+
+ _animDataAllocated = 0;
+
+ _dataPtr = 0;
+ for (i = 0; i < 10; i++) {
+ _staticLoaded[i] = 0;
+ _animLoaded[i] = 0;
+ }
+ _sndSlotsCount = 0;
+
+ _sndKeysCount = 0;
+ _sndKeys = 0;
+
+ for (i = 0; i < 5; i++)
+ for (int j = 0; j < 16; j++) {
+ _fadePal[i][j].red = 0;
+ _fadePal[i][j].green = 0;
+ _fadePal[i][j].blue = 0;
+ }
+}
+
+void Mult::animate(void) {
+ int16 minOrder;
+ int16 maxOrder;
+ int16 *pCurLefts;
+ int16 *pCurRights;
+ int16 *pCurTops;
+ int16 *pCurBottoms;
+ int16 *pDirtyLefts;
+ int16 *pDirtyRights;
+ int16 *pDirtyTops;
+ int16 *pDirtyBottoms;
+ int16 *pNeedRedraw;
+ Mult_AnimData *pAnimData;
+ int16 i, j;
+ int16 order;
+
+ if (_renderData == 0)
+ return;
+
+ pDirtyLefts = _renderData;
+ pDirtyRights = pDirtyLefts + _objCount;
+ pDirtyTops = pDirtyRights + _objCount;
+ pDirtyBottoms = pDirtyTops + _objCount;
+ pNeedRedraw = pDirtyBottoms + _objCount;
+ pCurLefts = pNeedRedraw + _objCount;
+ pCurRights = pCurLefts + _objCount;
+ pCurTops = pCurRights + _objCount;
+ pCurBottoms = pCurTops + _objCount;
+ minOrder = 100;
+ maxOrder = 0;
+
+ //Find dirty areas
+ for (i = 0; i < _objCount; i++) {
+ pNeedRedraw[i] = 0;
+ pDirtyTops[i] = 1000;
+ pDirtyLefts[i] = 1000;
+ pDirtyBottoms[i] = 1000;
+ pDirtyRights[i] = 1000;
+ pAnimData = _objects[i].pAnimData;
+
+ if (pAnimData->isStatic == 0 && pAnimData->isPaused == 0 &&
+ _objects[i].tick == pAnimData->maxTick) {
+ if (pAnimData->order < minOrder)
+ minOrder = pAnimData->order;
+
+ if (pAnimData->order > maxOrder)
+ maxOrder = pAnimData->order;
+
+ pNeedRedraw[i] = 1;
+ _vm->_scenery->updateAnim(pAnimData->layer, pAnimData->frame,
+ pAnimData->animation, 0,
+ *(_objects[i].pPosX), *(_objects[i].pPosY),
+ 0);
+
+ if (_objects[i].lastLeft != -1) {
+ pDirtyLefts[i] =
+ MIN(_objects[i].lastLeft,
+ _vm->_scenery->_toRedrawLeft);
+ pDirtyTops[i] =
+ MIN(_objects[i].lastTop,
+ _vm->_scenery->_toRedrawTop);
+ pDirtyRights[i] =
+ MAX(_objects[i].lastRight,
+ _vm->_scenery->_toRedrawRight);
+ pDirtyBottoms[i] =
+ MAX(_objects[i].lastBottom,
+ _vm->_scenery->_toRedrawBottom);
+ } else {
+ pDirtyLefts[i] = _vm->_scenery->_toRedrawLeft;
+ pDirtyTops[i] = _vm->_scenery->_toRedrawTop;
+ pDirtyRights[i] = _vm->_scenery->_toRedrawRight;
+ pDirtyBottoms[i] = _vm->_scenery->_toRedrawBottom;
+ }
+ pCurLefts[i] = _vm->_scenery->_toRedrawLeft;
+ pCurRights[i] = _vm->_scenery->_toRedrawRight;
+ pCurTops[i] = _vm->_scenery->_toRedrawTop;
+ pCurBottoms[i] = _vm->_scenery->_toRedrawBottom;
+ } else {
+ if (_objects[i].lastLeft != -1) {
+ if (pAnimData->order < minOrder)
+ minOrder = pAnimData->order;
+
+ if (pAnimData->order > maxOrder)
+ maxOrder = pAnimData->order;
+
+ if (pAnimData->isStatic)
+ *pNeedRedraw = 1;
+
+ pCurLefts[i] = _objects[i].lastLeft;
+ pDirtyLefts[i] = _objects[i].lastLeft;
+
+ pCurTops[i] = _objects[i].lastTop;
+ pDirtyTops[i] = _objects[i].lastTop;
+
+ pCurRights[i] = _objects[i].lastRight;
+ pDirtyRights[i] = _objects[i].lastRight;
+
+ pCurBottoms[i] = _objects[i].lastBottom;
+ pDirtyBottoms[i] = _objects[i].lastBottom;
+ }
+ }
+ }
+
+ // Find intersections
+ for (i = 0; i < _objCount; i++) {
+ pAnimData = _objects[i].pAnimData;
+ pAnimData->intersected = 200;
+
+ if (pAnimData->isStatic)
+ continue;
+
+ for (j = 0; j < _objCount; j++) {
+ if (i == j)
+ continue;
+
+ if (_objects[j].pAnimData->isStatic)
+ continue;
+
+ if (pCurRights[i] < pCurLefts[j])
+ continue;
+
+ if (pCurRights[j] < pCurLefts[i])
+ continue;
+
+ if (pCurBottoms[i] < pCurTops[j])
+ continue;
+
+ if (pCurBottoms[j] < pCurTops[i])
+ continue;
+
+ pAnimData->intersected = j;
+ break;
+ }
+ }
+
+ // Restore dirty areas
+ for (i = 0; i < _objCount; i++) {
+
+ if (pNeedRedraw[i] == 0 || _objects[i].lastLeft == -1)
+ continue;
+
+ _vm->_draw->_sourceSurface = 22;
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_spriteLeft = pDirtyLefts[i] - _vm->_anim->_areaLeft;
+ _vm->_draw->_spriteTop = pDirtyTops[i] - _vm->_anim->_areaTop;
+ _vm->_draw->_spriteRight = pDirtyRights[i] - pDirtyLefts[i] + 1;
+ _vm->_draw->_spriteBottom = pDirtyBottoms[i] - pDirtyTops[i] + 1;
+ _vm->_draw->_destSpriteX = pDirtyLefts[i];
+ _vm->_draw->_destSpriteY = pDirtyTops[i];
+ _vm->_draw->_transparency = 0;
+ _vm->_draw->spriteOperation(DRAW_BLITSURF);
+ _objects[i].lastLeft = -1;
+ }
+
+ // Update view
+ for (order = minOrder; order <= maxOrder; order++) {
+ for (i = 0; i < _objCount; i++) {
+ pAnimData = _objects[i].pAnimData;
+ if (pAnimData->order != order)
+ continue;
+
+ if (pNeedRedraw[i]) {
+ if (pAnimData->isStatic == 0) {
+
+ _vm->_scenery->updateAnim(pAnimData->layer,
+ pAnimData->frame,
+ pAnimData->animation, 2,
+ *(_objects[i].pPosX),
+ *(_objects[i].pPosY), 1);
+
+ if (_vm->_scenery->_toRedrawLeft != -12345) {
+ _objects[i].lastLeft =
+ _vm->_scenery->_toRedrawLeft;
+ _objects[i].lastTop =
+ _vm->_scenery->_toRedrawTop;
+ _objects[i].lastRight =
+ _vm->_scenery->_toRedrawRight;
+ _objects[i].lastBottom =
+ _vm->_scenery->_toRedrawBottom;
+ } else {
+ _objects[i].lastLeft = -1;
+ }
+ }
+ _vm->_scenery->updateStatic(order + 1);
+ } else if (pAnimData->isStatic == 0) {
+ for (j = 0; j < _objCount; j++) {
+ if (pNeedRedraw[j] == 0)
+ continue;
+
+ if (pDirtyRights[i] < pDirtyLefts[j])
+ continue;
+
+ if (pDirtyRights[j] < pDirtyLefts[i])
+ continue;
+
+ if (pDirtyBottoms[i] < pDirtyTops[j])
+ continue;
+
+ if (pDirtyBottoms[j] < pDirtyTops[i])
+ continue;
+
+ _vm->_scenery->_toRedrawLeft = pDirtyLefts[j];
+ _vm->_scenery->_toRedrawRight = pDirtyRights[j];
+ _vm->_scenery->_toRedrawTop = pDirtyTops[j];
+ _vm->_scenery->_toRedrawBottom = pDirtyBottoms[j];
+
+ _vm->_scenery->updateAnim(pAnimData->layer,
+ pAnimData->frame,
+ pAnimData->animation, 4,
+ *(_objects[i].pPosX),
+ *(_objects[i].pPosY), 1);
+
+ _vm->_scenery->updateStatic(order + 1);
+ }
+ }
+ }
+ }
+
+ // Advance animations
+ for (i = 0; i < _objCount; i++) {
+ pAnimData = _objects[i].pAnimData;
+ if (pAnimData->isStatic || pAnimData->isPaused)
+ continue;
+
+ if (_objects[i].tick == pAnimData->maxTick) {
+ _objects[i].tick = 0;
+ if (pAnimData->animType == 4) {
+ pAnimData->isPaused = 1;
+ pAnimData->frame = 0;
+ } else {
+ pAnimData->frame++;
+ if (pAnimData->frame >=
+ _vm->_scenery->_animations[(int)pAnimData->animation].layers[pAnimData->layer]->framesCount) {
+ switch (pAnimData->animType) {
+ case 0:
+ pAnimData->frame = 0;
+ break;
+
+ case 1:
+ pAnimData->frame = 0;
+
+ *(_objects[i].pPosX) =
+ *(_objects[i].pPosX) +
+ _vm->_scenery->_animations[(int)pAnimData->animation].layers[pAnimData->layer]->animDeltaX;
+
+ *(_objects[i].pPosY) =
+ *(_objects[i].pPosY) +
+ _vm->_scenery->_animations[(int)pAnimData->animation].layers[pAnimData->layer]->animDeltaY;
+ break;
+
+ case 2:
+ pAnimData->frame = 0;
+ pAnimData->animation =
+ pAnimData->newAnimation;
+ pAnimData->layer =
+ pAnimData->newLayer;
+ break;
+
+ case 3:
+ pAnimData->animType = 4;
+ pAnimData->frame = 0;
+ break;
+
+ case 5:
+ pAnimData->isStatic = 1;
+ pAnimData->frame = 0;
+ break;
+
+ case 6:
+ pAnimData->frame--;
+ pAnimData->isPaused = 1;
+ break;
+ }
+ pAnimData->newCycle = 1;
+ } else {
+ pAnimData->newCycle = 0;
+ }
+ }
+ } else {
+ _objects[i].tick++;
+ }
+ }
+}
+
+void Mult::interGetObjAnimSize(void) {
+ Mult_AnimData *pAnimData;
+ int16 objIndex;
+
+ _vm->_inter->evalExpr(&objIndex);
+ pAnimData = _objects[objIndex].pAnimData;
+ if (pAnimData->isStatic == 0) {
+ _vm->_scenery->updateAnim(pAnimData->layer, pAnimData->frame,
+ pAnimData->animation, 0, *(_objects[objIndex].pPosX),
+ *(_objects[objIndex].pPosY), 0);
+ }
+ WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawLeft);
+ WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawTop);
+ WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawRight);
+ WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawBottom);
+}
+
+void Mult::interInitMult(void) {
+ int16 oldAnimHeight;
+ int16 oldAnimWidth;
+ int16 oldObjCount;
+ int16 i;
+ int16 posXVar;
+ int16 posYVar;
+ int16 animDataVar;
+
+ oldAnimWidth = _vm->_anim->_areaWidth;
+ oldAnimHeight = _vm->_anim->_areaHeight;
+ oldObjCount = _objCount;
+
+ _vm->_anim->_areaLeft = _vm->_inter->load16();
+ _vm->_anim->_areaTop = _vm->_inter->load16();
+ _vm->_anim->_areaWidth = _vm->_inter->load16();
+ _vm->_anim->_areaHeight = _vm->_inter->load16();
+ _objCount = _vm->_inter->load16();
+ posXVar = _vm->_parse->parseVarIndex();
+ posYVar = _vm->_parse->parseVarIndex();
+ animDataVar = _vm->_parse->parseVarIndex();
+
+ if (_objects == 0) {
+ _renderData = new int16[_objCount * 9];
+ _objects = new Mult_Object[_objCount];
+
+ for (i = 0; i < _objCount; i++) {
+ _objects[i].pPosX = (int32 *)(_vm->_global->_inter_variables + i * 4 + (posXVar / 4) * 4);
+ _objects[i].pPosY = (int32 *)(_vm->_global->_inter_variables + i * 4 + (posYVar / 4) * 4);
+ _objects[i].pAnimData =
+ (Mult_AnimData *) (_vm->_global->_inter_variables + animDataVar +
+ i * 4 * _vm->_global->_inter_animDataSize);
+
+ _objects[i].pAnimData->isStatic = 1;
+ _objects[i].tick = 0;
+ _objects[i].lastLeft = -1;
+ _objects[i].lastRight = -1;
+ _objects[i].lastTop = -1;
+ _objects[i].lastBottom = -1;
+ }
+ } else if (oldObjCount != _objCount) {
+ error("interInitMult: Object count changed, but storage didn't (old count = %d, new count = %d)",
+ oldObjCount, _objCount);
+ }
+
+ if (_vm->_anim->_animSurf != 0 &&
+ (oldAnimWidth != _vm->_anim->_areaWidth
+ || oldAnimHeight != _vm->_anim->_areaHeight)) {
+ _vm->_video->freeSurfDesc(_vm->_anim->_animSurf);
+ _vm->_anim->_animSurf = 0;
+ }
+
+ if (_vm->_anim->_animSurf == 0) {
+ _vm->_anim->_animSurf = _vm->_video->initSurfDesc(_vm->_global->_videoMode,
+ _vm->_anim->_areaWidth, _vm->_anim->_areaHeight, 0);
+
+ _vm->_draw->_spritesArray[22] = _vm->_anim->_animSurf;
+ }
+
+ _vm->_video->drawSprite(_vm->_draw->_backSurface, _vm->_anim->_animSurf,
+ _vm->_anim->_areaLeft, _vm->_anim->_areaTop,
+ _vm->_anim->_areaLeft + _vm->_anim->_areaWidth - 1,
+ _vm->_anim->_areaTop + _vm->_anim->_areaHeight - 1, 0, 0, 0);
+
+ debug(4, "interInitMult: x = %d, y = %d, w = %d, h = %d",
+ _vm->_anim->_areaLeft, _vm->_anim->_areaTop, _vm->_anim->_areaWidth, _vm->_anim->_areaHeight);
+ debug(4, " _objCount = %d, animation data size = %d", _objCount, _vm->_global->_inter_animDataSize);
+}
+
+void Mult::freeMult(void) {
+ if (_vm->_anim->_animSurf != 0)
+ _vm->_video->freeSurfDesc(_vm->_anim->_animSurf);
+
+ delete[] _objects;
+ delete[] _renderData;
+
+ _objects = 0;
+ _renderData = 0;
+ _vm->_anim->_animSurf = 0;
+}
+
+void Mult::interLoadMult(void) {
+ int16 val;
+ int16 objIndex;
+ int16 i;
+ char *lmultData;
+
+ debug(4, "interLoadMult: Loading...");
+
+ _vm->_inter->evalExpr(&objIndex);
+ _vm->_inter->evalExpr(&val);
+ *_objects[objIndex].pPosX = val;
+ _vm->_inter->evalExpr(&val);
+ *_objects[objIndex].pPosY = val;
+
+ lmultData = (char *)_objects[objIndex].pAnimData;
+ for (i = 0; i < 11; i++) {
+ if ((char)READ_LE_UINT16(_vm->_global->_inter_execPtr) == (char)99) {
+ _vm->_inter->evalExpr(&val);
+ lmultData[i] = val;
+ } else {
+ _vm->_global->_inter_execPtr++;
+ }
+ }
+}
+
+void Mult::freeAll(void) {
+ int16 i;
+
+ freeMult();
+ for (i = 0; i < 10; i++)
+ _vm->_scenery->freeAnim(i);
+
+ for (i = 0; i < 10; i++)
+ _vm->_scenery->freeStatic(i);
+}
+
+void Mult::initAll(void) {
+ int16 i;
+
+ _objects = 0;
+ _vm->_anim->_animSurf = 0;
+ _renderData = 0;
+
+ for (i = 0; i < 10; i++)
+ _vm->_scenery->_animPictCount[i] = 0;
+
+ for (i = 0; i < 20; i++) {
+ _vm->_scenery->_spriteRefs[i] = 0;
+ _vm->_scenery->_spriteResId[i] = -1;
+ }
+
+ for (i = 0; i < 10; i++)
+ _vm->_scenery->_staticPictCount[i] = -1;
+
+ _vm->_scenery->_curStaticLayer = -1;
+ _vm->_scenery->_curStatic = -1;
+}
+
+void Mult::playSound(Snd::SoundDesc * soundDesc, int16 repCount, int16 freq,
+ int16 channel) {
+ _vm->_snd->playSample(soundDesc, repCount, freq);
+}
+
+char Mult::drawStatics(char stop) {
+ if (_staticKeys[_staticKeysCount - 1].frame > _frame)
+ stop = 0;
+
+ for (_counter = 0; _counter < _staticKeysCount;
+ _counter++) {
+ if (_staticKeys[_counter].frame != _frame
+ || _staticKeys[_counter].layer == -1)
+ continue;
+
+ for (_vm->_scenery->_curStatic = 0, _vm->_scenery->_curStaticLayer = _staticKeys[_counter].layer;
+ _vm->_scenery->_curStaticLayer >= _vm->_scenery->_statics[_staticIndices[_vm->_scenery->_curStatic]].layersCount;
+ _vm->_scenery->_curStatic++) {
+ _vm->_scenery->_curStaticLayer -=
+ _vm->_scenery->_statics[_staticIndices[_vm->_scenery->_curStatic]].layersCount;
+ }
+
+ _vm->_scenery->_curStatic = _staticIndices[_vm->_scenery->_curStatic];
+ _vm->_scenery->renderStatic(_vm->_scenery->_curStatic, _vm->_scenery->_curStaticLayer);
+ _vm->_video->drawSprite(_vm->_draw->_backSurface, _vm->_anim->_animSurf,
+ 0, 0, 319, 199, 0, 0, 0);
+ }
+ return stop;
+}
+
+void Mult::drawAnims(void) {
+ Mult_AnimKey *key;
+ Mult_Object *animObj;
+ int16 i;
+ int16 count;
+
+ for (_index = 0; _index < 4; _index++) {
+ for (_counter = 0; _counter < _animKeysCount[_index]; _counter++) {
+ key = &_animKeys[_index][_counter];
+ animObj = &_objects[_index];
+ if (key->frame != _frame)
+ continue;
+
+ if (key->layer != -1) {
+ (*animObj->pPosX) = key->posX;
+ (*animObj->pPosY) = key->posY;
+
+ animObj->pAnimData->frame = 0;
+ animObj->pAnimData->order = key->order;
+ animObj->pAnimData->animType = 1;
+
+ animObj->pAnimData->isPaused = 0;
+ animObj->pAnimData->isStatic = 0;
+ animObj->pAnimData->maxTick = 0;
+ animObj->tick = 0;
+ animObj->pAnimData->layer = key->layer;
+
+ count = _vm->_scenery->_animations[_animIndices[0]].layersCount;
+ i = 0;
+ while (animObj->pAnimData->layer >= count) {
+ animObj->pAnimData->layer -= count;
+ i++;
+
+ count = _vm->_scenery->_animations[_animIndices[i]].layersCount;
+ }
+ animObj->pAnimData->animation = _animIndices[i];
+ } else {
+ animObj->pAnimData->isStatic = 1;
+ }
+ }
+ }
+}
+
+void Mult::drawText(char *pStop, char *pStopNoClear) {
+ char *savedIP;
+
+ int16 cmd;
+ for (_index = 0; _index < _textKeysCount; _index++) {
+ if (_textKeys[_index].frame != _frame)
+ continue;
+
+ cmd = _textKeys[_index].cmd;
+ if (cmd == 0) {
+ *pStop = 0;
+ } else if (cmd == 1) {
+ *pStopNoClear = 1;
+ _frameStart = 0;
+ } else if (cmd == 3) {
+ *pStop = 0;
+ savedIP = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr = (char *)(&_textKeys[_index].index);
+ _vm->_global->_inter_execPtr = savedIP;
+ }
+ }
+}
+
+char Mult::prepPalAnim(char stop) {
+ _palKeyIndex = -1;
+ do {
+ _palKeyIndex++;
+ if (_palKeyIndex >= _palKeysCount)
+ return stop;
+ } while (_palKeys[_palKeyIndex].frame != _frame);
+
+ if (_palKeys[_palKeyIndex].cmd == -1) {
+ stop = 0;
+ _doPalSubst = 0;
+ _vm->_global->_pPaletteDesc->vgaPal = _oldPalette;
+
+ memcpy((char *)_palAnimPalette, (char *)_vm->_global->_pPaletteDesc->vgaPal, 768);
+
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ } else {
+ stop = 0;
+ _doPalSubst = 1;
+ _palAnimKey = _palKeyIndex;
+
+ _palAnimIndices[0] = 0;
+ _palAnimIndices[1] = 0;
+ _palAnimIndices[2] = 0;
+ _palAnimIndices[3] = 0;
+
+ _vm->_global->_pPaletteDesc->vgaPal = _palAnimPalette;
+ }
+ return stop;
+}
+
+void Mult::doPalAnim(void) {
+ int16 off;
+ int16 off2;
+ Video::Color *palPtr;
+ Mult_PalKey *palKey;
+
+ if (_doPalSubst == 0)
+ return;
+
+ for (_index = 0; _index < 4; _index++) {
+ palKey = &_palKeys[_palAnimKey];
+
+ if ((_frame % palKey->rates[_index]) != 0)
+ continue;
+
+ _palAnimRed[_index] =
+ _vm->_global->_pPaletteDesc->vgaPal[palKey->subst[0][_index] - 1].red;
+ _palAnimGreen[_index] =
+ _vm->_global->_pPaletteDesc->vgaPal[palKey->subst[0][_index] - 1].green;
+ _palAnimBlue[_index] =
+ _vm->_global->_pPaletteDesc->vgaPal[palKey->subst[0][_index] - 1].blue;
+
+ while (1) {
+ off = palKey->subst[(_palAnimIndices[_index] + 1) % 16][_index];
+ if (off == 0) {
+ off = palKey->subst[_palAnimIndices[_index]][_index] - 1;
+
+ _vm->_global->_pPaletteDesc->vgaPal[off].red = _palAnimRed[_index];
+ _vm->_global->_pPaletteDesc->vgaPal[off].green = _palAnimGreen[_index];
+ _vm->_global->_pPaletteDesc->vgaPal[off].blue = _palAnimBlue[_index];
+ } else {
+ off = palKey->subst[(_palAnimIndices[_index] + 1) % 16][_index] - 1;
+ off2 = palKey->subst[_palAnimIndices[_index]][_index] - 1;
+
+ _vm->_global->_pPaletteDesc->vgaPal[off2].red = _vm->_global->_pPaletteDesc->vgaPal[off].red;
+ _vm->_global->_pPaletteDesc->vgaPal[off2].green = _vm->_global->_pPaletteDesc->vgaPal[off].green;
+ _vm->_global->_pPaletteDesc->vgaPal[off2].blue = _vm->_global->_pPaletteDesc->vgaPal[off].blue;
+ }
+
+ _palAnimIndices[_index] = (_palAnimIndices[_index] + 1) % 16;
+
+ off = palKey->subst[_palAnimIndices[_index]][_index];
+
+ if (off == 0) {
+ _palAnimIndices[_index] = 0;
+ off = palKey->subst[0][_index] - 1;
+
+ _palAnimRed[_index] = _vm->_global->_pPaletteDesc->vgaPal[off].red;
+ _palAnimGreen[_index] = _vm->_global->_pPaletteDesc->vgaPal[off].green;
+ _palAnimBlue[_index] = _vm->_global->_pPaletteDesc->vgaPal[off].blue;
+ }
+ if (_palAnimIndices[_index] == 0)
+ break;
+ }
+ }
+
+ if (_vm->_global->_colorCount == 256) {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+
+ palPtr = _vm->_global->_pPaletteDesc->vgaPal;
+ for (_counter = 0; _counter < 16; _counter++) {
+ _vm->_video->setPalElem(_counter, palPtr->red, palPtr->green, palPtr->blue, 0, 0x13);
+ palPtr++;
+ }
+
+ palPtr = _vm->_global->_pPaletteDesc->vgaPal;
+ for (_counter = 0; _counter < 16; _counter++) {
+ _vm->_global->_redPalette[_counter] = palPtr->red;
+ _vm->_global->_greenPalette[_counter] = palPtr->green;
+ _vm->_global->_bluePalette[_counter] = palPtr->blue;
+ palPtr++;
+ }
+ } else {
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ }
+}
+
+char Mult::doFadeAnim(char stop) {
+ Mult_PalFadeKey *fadeKey;
+
+ for (_index = 0; _index < _palFadeKeysCount; _index++) {
+ fadeKey = &_palFadeKeys[_index];
+
+ if (fadeKey->frame != _frame)
+ continue;
+
+ stop = 0;
+ if ((fadeKey->flag & 1) == 0) {
+ if (fadeKey->fade == 0) {
+ _vm->_global->_pPaletteDesc->vgaPal = _fadePal[fadeKey->palIndex];
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ } else {
+ _vm->_global->_pPaletteDesc->vgaPal = _fadePal[fadeKey->palIndex];
+ _vm->_palanim->fade(_vm->_global->_pPaletteDesc, fadeKey->fade, 0);
+ }
+ } else {
+ _vm->_global->_pPaletteDesc->vgaPal = _fadePal[fadeKey->palIndex];
+ _vm->_palanim->fade(_vm->_global->_pPaletteDesc, fadeKey->fade, -1);
+
+ _palFadingRed = (fadeKey->flag >> 1) & 1;
+ _palFadingGreen = (fadeKey->flag >> 2) & 1;
+ _palFadingBlue = (fadeKey->flag >> 3) & 1;
+ }
+ }
+
+ if (_palFadingRed) {
+ _palFadingRed = !_vm->_palanim->fadeStep(1);
+ stop = 0;
+ }
+ if (_palFadingGreen) {
+ _palFadingGreen = !_vm->_palanim->fadeStep(2);
+ stop = 0;
+ }
+ if (_palFadingBlue) {
+ _palFadingBlue = !_vm->_palanim->fadeStep(3);
+ stop = 0;
+ }
+ return stop;
+}
+
+char Mult::doSoundAnim(char stop) {
+ Mult_SndKey *sndKey;
+ for (_index = 0; _index < _sndKeysCount; _index++) {
+ sndKey = &_sndKeys[_index];
+ if (sndKey->frame != _frame)
+ continue;
+
+ if (sndKey->cmd != -1) {
+ if (sndKey->cmd == 1) {
+ _vm->_snd->stopSound(0);
+ stop = 0;
+ playSound(_vm->_game->_soundSamples[sndKey->soundIndex], sndKey->repCount,
+ sndKey->freq, sndKey->channel);
+
+ } else if (sndKey->cmd == 4) {
+ _vm->_snd->stopSound(0);
+ stop = 0;
+ playSound(_vm->_game->_soundSamples[sndKey->soundIndex], sndKey->repCount,
+ sndKey->freq, sndKey->channel);
+ }
+ } else {
+ if (_vm->_snd->_playingSound)
+ _vm->_snd->stopSound(sndKey->channel);
+ }
+ }
+ return stop;
+}
+
+void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape,
+ char handleMouse) {
+ char stopNoClear;
+ char stop;
+ Mult_Object *multObj;
+ Mult_AnimData *animData;
+
+ if (_multData == 0)
+ return;
+
+ stopNoClear = 0;
+ _frame = startFrame;
+ if (endFrame == -1)
+ endFrame = 32767;
+
+ if (_frame == -1) {
+ _doPalSubst = 0;
+ _palFadingRed = 0;
+ _palFadingGreen = 0;
+ _palFadingBlue = 0;
+
+ _oldPalette = _vm->_global->_pPaletteDesc->vgaPal;
+ memcpy((char *)_palAnimPalette, (char *)_vm->_global->_pPaletteDesc->vgaPal, 768);
+
+ if (_vm->_anim->_animSurf == 0) {
+ _vm->_util->setFrameRate(_frameRate);
+ _vm->_anim->_areaTop = 0;
+ _vm->_anim->_areaLeft = 0;
+ _vm->_anim->_areaWidth = 320;
+ _vm->_anim->_areaHeight = 200;
+ _objCount = 4;
+
+ _objects = new Mult_Object[_objCount];
+ _renderData = new int16[9 * _objCount];
+
+ _animArrayX = new int32[_objCount];
+ _animArrayY = new int32[_objCount];
+
+ _animArrayData = new Mult_AnimData[_objCount];
+
+ for (_counter = 0; _counter < _objCount; _counter++) {
+ multObj = &_objects[_counter];
+
+ multObj->pPosX = (int32 *)&_animArrayX[_counter];
+ multObj->pPosY = (int32 *)&_animArrayY[_counter];
+
+ multObj->pAnimData = &_animArrayData[_counter];
+
+ animData = multObj->pAnimData;
+ animData->isStatic = 1;
+
+ multObj->tick = 0;
+ multObj->lastLeft = -1;
+ multObj->lastTop = -1;
+ multObj->lastRight = -1;
+ multObj->lastBottom = -1;
+ }
+
+ _vm->_anim->_animSurf =
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, 320, 200, 0);
+ _vm->_draw->_spritesArray[22] = _vm->_anim->_animSurf;
+
+ _vm->_video->drawSprite(_vm->_draw->_backSurface, _vm->_anim->_animSurf,
+ 0, 0, 319, 199, 0, 0, 0);
+
+ _animDataAllocated = 1;
+ } else
+ _animDataAllocated = 0;
+ _frame = 0;
+ }
+
+ do {
+ stop = 1;
+
+ if (VAR(58) == 0) {
+ stop = drawStatics(stop);
+ drawAnims();
+ }
+
+ animate();
+ if (handleMouse) {
+ _vm->_draw->animateCursor(-1);
+ } else {
+ _vm->_draw->blitInvalidated();
+ }
+
+ if (VAR(58) == 0) {
+ drawText(&stop, &stopNoClear);
+ }
+
+ stop = prepPalAnim(stop);
+ doPalAnim();
+
+ stop = doFadeAnim(stop);
+ stop = doSoundAnim(stop);
+
+ if (_frame >= endFrame)
+ stopNoClear = 1;
+
+ if (_vm->_snd->_playingSound)
+ stop = 0;
+
+ _vm->_util->processInput();
+ if (checkEscape && _vm->_util->checkKey() == 0x11b) // Esc
+ stop = 1;
+
+ _frame++;
+ _vm->_util->waitEndFrame();
+ } while (stop == 0 && stopNoClear == 0);
+
+ if (stopNoClear == 0) {
+ if (_animDataAllocated) {
+ delete[] _objects;
+ _objects = 0;
+
+ delete[] _renderData;
+ _renderData = 0;
+
+ delete[] _animArrayX;
+ _animArrayX = 0;
+
+ delete[] _animArrayY;
+ _animArrayY = 0;
+
+ delete[] _animArrayData;
+ _animArrayData = 0;
+
+ if (_vm->_anim->_animSurf)
+ _vm->_video->freeSurfDesc(_vm->_anim->_animSurf);
+ _vm->_anim->_animSurf = 0;
+
+ _animDataAllocated = 0;
+ }
+
+ if (_vm->_snd->_playingSound != 0)
+ _vm->_snd->stopSound(10);
+
+ WRITE_VAR(57, (uint32)-1);
+ } else {
+ WRITE_VAR(57, _frame - 1 - _frameStart);
+ }
+}
+
+void Mult::zeroMultData(void) {
+ _multData = 0;
+}
+
+void Mult::loadMult(int16 resId) {
+ char animCount;
+ char staticCount;
+ int16 palIndex;
+ int16 i, j;
+
+ _sndSlotsCount = 0;
+ _frameStart = 0;
+ _multData = _vm->_game->loadExtData(resId, 0, 0);
+ _dataPtr = _multData;
+
+ staticCount = _dataPtr[0];
+ animCount = _dataPtr[1];
+ _dataPtr += 2;
+ staticCount++;
+ animCount++;
+
+ for (i = 0; i < staticCount; i++, _dataPtr += 14) {
+ _staticIndices[i] = _vm->_scenery->loadStatic(1);
+
+ if (_staticIndices[i] >= 100) {
+ _staticIndices[i] -= 100;
+ _staticLoaded[i] = 1;
+ } else {
+ _staticLoaded[i] = 0;
+ }
+ }
+
+ for (i = 0; i < animCount; i++, _dataPtr += 14) {
+ _animIndices[i] = _vm->_scenery->loadAnim(1);
+
+ if (_animIndices[i] >= 100) {
+ _animIndices[i] -= 100;
+ _animLoaded[i] = 1;
+ } else {
+ _animLoaded[i] = 0;
+ }
+ }
+
+ _frameRate = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+
+ _staticKeysCount = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+
+ _staticKeys = new Mult_StaticKey[_staticKeysCount];
+ for (i = 0; i < _staticKeysCount; i++, _dataPtr += 4) {
+ _staticKeys[i].frame = (int16)READ_LE_UINT16(_dataPtr);
+ _staticKeys[i].layer = (int16)READ_LE_UINT16(_dataPtr + 2);
+ }
+
+ for (j = 0; j < 4; j++) {
+ _animKeysCount[j] = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+
+ _animKeys[j] = new Mult_AnimKey[_animKeysCount[j]];
+ for (i = 0; i < _animKeysCount[j]; i++, _dataPtr += 10) {
+ _animKeys[j][i].frame = (int16)READ_LE_UINT16(_dataPtr);
+ _animKeys[j][i].layer = (int16)READ_LE_UINT16(_dataPtr + 2);
+ _animKeys[j][i].posX = (int16)READ_LE_UINT16(_dataPtr + 4);
+ _animKeys[j][i].posY = (int16)READ_LE_UINT16(_dataPtr + 6);
+ _animKeys[j][i].order = (int16)READ_LE_UINT16(_dataPtr + 8);
+ }
+ }
+
+ for (palIndex = 0; palIndex < 5; palIndex++) {
+ for (i = 0; i < 16; i++) {
+ _fadePal[palIndex][i].red = _dataPtr[0];
+ _fadePal[palIndex][i].green = _dataPtr[1];
+ _fadePal[palIndex][i].blue = _dataPtr[2];
+ _dataPtr += 3;
+ }
+ }
+
+ _palFadeKeysCount = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+ _palFadeKeys = new Mult_PalFadeKey[_palFadeKeysCount];
+
+ for (i = 0; i < _palFadeKeysCount; i++, _dataPtr += 7) {
+ _palFadeKeys[i].frame = (int16)READ_LE_UINT16(_dataPtr);
+ _palFadeKeys[i].fade = (int16)READ_LE_UINT16(_dataPtr + 2);
+ _palFadeKeys[i].palIndex = (int16)READ_LE_UINT16(_dataPtr + 4);
+ _palFadeKeys[i].flag = *(_dataPtr + 6);
+ }
+
+ _palKeysCount = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+
+ _palKeys = new Mult_PalKey[_palKeysCount];
+ for (i = 0; i < _palKeysCount; i++, _dataPtr += 80) {
+ _palKeys[i].frame = (int16)READ_LE_UINT16(_dataPtr);
+ _palKeys[i].cmd = (int16)READ_LE_UINT16(_dataPtr + 2);
+ _palKeys[i].rates[0] = (int16)READ_LE_UINT16(_dataPtr + 4);
+ _palKeys[i].rates[1] = (int16)READ_LE_UINT16(_dataPtr + 6);
+ _palKeys[i].rates[2] = (int16)READ_LE_UINT16(_dataPtr + 8);
+ _palKeys[i].rates[3] = (int16)READ_LE_UINT16(_dataPtr + 10);
+ _palKeys[i].unknown0 = (int16)READ_LE_UINT16(_dataPtr + 12);
+ _palKeys[i].unknown1 = (int16)READ_LE_UINT16(_dataPtr + 14);
+ memcpy(_palKeys[i].subst, _dataPtr + 16, 64);
+ }
+
+ _textKeysCount = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+ _textKeys = new Mult_TextKey[_textKeysCount];
+
+ for (i = 0; i < _textKeysCount; i++, _dataPtr += 28) {
+ _textKeys[i].frame = (int16)READ_LE_UINT16(_dataPtr);
+ _textKeys[i].cmd = (int16)READ_LE_UINT16(_dataPtr + 2);
+ for (int k = 0; k < 9; ++k)
+ _textKeys[i].unknown0[k] = (int16)READ_LE_UINT16(_dataPtr + 4 + (k * 2));
+ _textKeys[i].index = (int16)READ_LE_UINT16(_dataPtr + 22);
+ _textKeys[i].unknown1[0] = (int16)READ_LE_UINT16(_dataPtr + 24);
+ _textKeys[i].unknown1[1] = (int16)READ_LE_UINT16(_dataPtr + 26);
+ }
+
+ _sndKeysCount = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+
+ _sndKeys = new Mult_SndKey[_sndKeysCount];
+ for (i = 0; i < _sndKeysCount; i++) {
+ _sndKeys[i].frame = (int16)READ_LE_UINT16(_dataPtr);
+ _sndKeys[i].cmd = (int16)READ_LE_UINT16(_dataPtr + 2);
+ _sndKeys[i].freq = (int16)READ_LE_UINT16(_dataPtr + 4);
+ _sndKeys[i].channel = (int16)READ_LE_UINT16(_dataPtr + 6);
+ _sndKeys[i].repCount = (int16)READ_LE_UINT16(_dataPtr + 8);
+ _sndKeys[i].resId = (int16)READ_LE_UINT16(_dataPtr + 10);
+ _sndKeys[i].soundIndex = (int16)READ_LE_UINT16(_dataPtr + 12);
+
+ _sndKeys[i].soundIndex = -1;
+ _sndKeys[i].resId = -1;
+ _dataPtr += 36;
+ switch (_sndKeys[i].cmd) {
+ case 1:
+ case 4:
+ _sndKeys[i].resId = READ_LE_UINT16(_vm->_global->_inter_execPtr);
+
+ for (j = 0; j < i; j++) {
+ if (_sndKeys[i].resId ==
+ _sndKeys[j].resId) {
+ _sndKeys[i].soundIndex =
+ _sndKeys[j].soundIndex;
+ _vm->_global->_inter_execPtr += 2;
+ break;
+ }
+ }
+ if (i == j) {
+ _vm->_game->interLoadSound(19 - _sndSlotsCount);
+ _sndKeys[i].soundIndex =
+ 19 - _sndSlotsCount;
+ _sndSlotsCount++;
+ }
+ break;
+
+ case 3:
+ _vm->_global->_inter_execPtr += 6;
+ break;
+
+ case 5:
+ _vm->_global->_inter_execPtr += _sndKeys[i].freq * 2;
+ break;
+ }
+ }
+}
+
+void Mult::freeMultKeys(void) {
+ int i;
+ char animCount;
+ char staticCount;
+
+ _dataPtr = _multData;
+ staticCount = _dataPtr[0];
+ animCount = _dataPtr[1];
+
+ delete[] _dataPtr;
+
+ staticCount++;
+ animCount++;
+ for (i = 0; i < staticCount; i++) {
+
+ if (_staticLoaded[i] != 0)
+ _vm->_scenery->freeStatic(_staticIndices[i]);
+ }
+
+ for (i = 0; i < animCount; i++) {
+ if (_animLoaded[i] != 0)
+ _vm->_scenery->freeAnim(_animIndices[i]);
+ }
+
+ delete[] _staticKeys;
+
+ for (i = 0; i < 4; i++)
+ delete[] _animKeys[i];
+
+ delete[] _palFadeKeys;
+ delete[] _palKeys;
+ delete[] _textKeys;
+
+ for (i = 0; i < _sndSlotsCount; i++) {
+ _vm->_game->freeSoundSlot(19 - i);
+ }
+
+ delete[] _sndKeys;
+
+ _multData = 0;
+
+ if (_animDataAllocated != 0) {
+ delete[] _objects;
+ _objects = 0;
+
+ delete[] _renderData;
+ _renderData = 0;
+
+ delete[] _animArrayX;
+ _animArrayX = 0;
+
+ delete[] _animArrayY;
+ _animArrayY = 0;
+
+ delete[] _animArrayData;
+ _animArrayData = 0;
+
+ if (_vm->_anim->_animSurf)
+ _vm->_video->freeSurfDesc(_vm->_anim->_animSurf);
+ _vm->_anim->_animSurf = 0;
+
+ _animDataAllocated = 0;
+ }
+}
+
+void Mult::checkFreeMult(void) {
+ if (_multData != 0)
+ freeMultKeys();
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/mult.h b/engines/gob/mult.h
new file mode 100644
index 0000000000..992c01cba3
--- /dev/null
+++ b/engines/gob/mult.h
@@ -0,0 +1,208 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_MULT_H
+#define GOB_MULT_H
+
+#include "gob/sound.h"
+
+namespace Gob {
+
+class Mult {
+public:
+#pragma START_PACK_STRUCTS
+ struct Mult_AnimData {
+ int8 animation;
+ int8 layer;
+ int8 frame;
+ int8 animType;
+ int8 order;
+ int8 isPaused;
+ int8 isStatic;
+ int8 maxTick;
+ int8 unknown;
+ int8 newLayer;
+ int8 newAnimation;
+ byte intersected;
+ int8 newCycle;
+ } GCC_PACK;
+
+ struct Mult_Object {
+ int32 *pPosX;
+ int32 *pPosY;
+ Mult_AnimData *pAnimData;
+ int16 tick;
+ int16 lastLeft;
+ int16 lastRight;
+ int16 lastTop;
+ int16 lastBottom;
+ };
+
+ struct Mult_StaticKey {
+ int16 frame;
+ int16 layer;
+ } GCC_PACK;
+
+ struct Mult_AnimKey {
+ int16 frame;
+ int16 layer;
+ int16 posX;
+ int16 posY;
+ int16 order;
+ } GCC_PACK;
+
+ struct Mult_TextKey {
+ int16 frame;
+ int16 cmd;
+ int16 unknown0[9];
+ int16 index;
+ int16 unknown1[2];
+ } GCC_PACK;
+
+ struct Mult_PalKey {
+ int16 frame;
+ int16 cmd;
+ int16 rates[4];
+ int16 unknown0;
+ int16 unknown1;
+ int8 subst[16][4];
+ } GCC_PACK;
+
+ struct Mult_PalFadeKey {
+ int16 frame;
+ int16 fade;
+ int16 palIndex;
+ int8 flag;
+ } GCC_PACK;
+
+ struct Mult_SndKey {
+ int16 frame;
+ int16 cmd;
+ int16 freq;
+ int16 channel;
+ int16 repCount;
+ int16 resId;
+ int16 soundIndex;
+ } GCC_PACK;
+#pragma END_PACK_STRUCTS
+
+ // Globals
+
+ Mult_Object *_objects;
+ int16 *_renderData;
+ int16 _objCount;
+ Video::SurfaceDesc *_underAnimSurf;
+
+ char *_multData;
+ int16 _frame;
+ char _doPalSubst;
+ int16 _counter;
+ int16 _frameRate;
+
+ int32 *_animArrayX;
+ int32 *_animArrayY;
+
+ Mult_AnimData *_animArrayData;
+
+ int16 _index;
+
+ // Static keys
+ int16 _staticKeysCount;
+ Mult_StaticKey *_staticKeys;
+ int16 _staticIndices[10];
+
+ // Anim keys
+ Mult_AnimKey *_animKeys[4];
+ int16 _animKeysCount[4];
+ int16 _animLayer;
+ int16 _animIndices[10];
+
+ // Text keys
+ int16 _textKeysCount;
+ Mult_TextKey *_textKeys;
+
+ int16 _frameStart;
+
+ // Palette keys
+ int16 _palKeyIndex;
+ int16 _palKeysCount;
+ Mult_PalKey *_palKeys;
+ Video::Color *_oldPalette;
+ Video::Color _palAnimPalette[256];
+ int16 _palAnimKey;
+ int16 _palAnimIndices[4];
+ int16 _palAnimRed[4];
+ int16 _palAnimGreen[4];
+ int16 _palAnimBlue[4];
+
+ // Palette fading
+ Mult_PalFadeKey *_palFadeKeys;
+ int16 _palFadeKeysCount;
+ char _palFadingRed;
+ char _palFadingGreen;
+ char _palFadingBlue;
+
+ char _animDataAllocated;
+
+ char *_dataPtr;
+ int16 _staticLoaded[10];
+ int16 _animLoaded[10];
+ int16 _sndSlotsCount;
+
+ // Sound keys
+ int16 _sndKeysCount;
+ Mult_SndKey *_sndKeys;
+
+ void zeroMultData(void);
+ void loadMult(int16 resId);
+ void freeMultKeys(void);
+ void checkFreeMult(void);
+ void playMult(int16 startFrame, int16 endFrame, char checkEscape,
+ char handleMouse);
+ void animate(void);
+ void interGetObjAnimSize(void);
+ void interInitMult(void);
+ void freeMult(void);
+ void interLoadMult(void);
+ void freeAll(void);
+ void initAll(void);
+ void playSound(Snd::SoundDesc * soundDesc, int16 repCount, int16 freq,
+ int16 channel);
+
+ Mult(GobEngine *vm);
+
+protected:
+ Video::Color _fadePal[5][16];
+ GobEngine *_vm;
+
+ char drawStatics(char stop);
+ void drawAnims(void);
+ void drawText(char *pStop, char *pStopNoClear);
+ char prepPalAnim(char stop);
+ void doPalAnim(void);
+ char doFadeAnim(char stop);
+ char doSoundAnim(char stop);
+};
+
+} // End of namespace Gob
+
+#endif /* __MULT_H */
diff --git a/engines/gob/music.cpp b/engines/gob/music.cpp
new file mode 100644
index 0000000000..3fbb37160f
--- /dev/null
+++ b/engines/gob/music.cpp
@@ -0,0 +1,436 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ * Original ADL-Player source Copyright (C) 2004 by Dorian Gray
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "gob/music.h"
+#include "gob/gob.h"
+#include "gob/game.h"
+
+namespace Gob {
+
+const char *Music::_tracks[][2] = {
+ {"avt00.tot", "mine"},
+ {"avt001.tot", "nuit"},
+ {"avt002.tot", "campagne"},
+ {"avt003.tot", "extsor1"},
+ {"avt004.tot", "interieure"},
+ {"avt005.tot", "zombie"},
+ {"avt006.tot", "zombie"},
+ {"avt007.tot", "campagne"},
+ {"avt008.tot", "campagne"},
+ {"avt009.tot", "extsor1"},
+ {"avt010.tot", "extsor1"},
+ {"avt011.tot", "interieure"},
+ {"avt012.tot", "zombie"},
+ {"avt014.tot", "nuit"},
+ {"avt015.tot", "interieure"},
+ {"avt016.tot", "statue"},
+ {"avt017.tot", "zombie"},
+ {"avt018.tot", "statue"},
+ {"avt019.tot", "mine"},
+ {"avt020.tot", "statue"},
+ {"avt021.tot", "mine"},
+ {"avt022.tot", "zombie"}
+};
+
+const char *Music::_tracksToFiles[][2] = {
+ {"campagne", "Musmac2.adl"},
+ {"extsor1", "Musmac3.adl"},
+ {"interieure", "Musmac4.adl"},
+ {"mine", "Musmac5.adl"},
+ {"nuit", "Musmac6.adl"},
+ {"statue", "Musmac2.adl"},
+ {"zombie", "Musmac3.adl"}
+};
+
+const unsigned char Music::_operators[] = {0, 1, 2, 8, 9, 10, 16, 17, 18};
+const unsigned char Music::_volRegNums[] = {
+ 3, 4, 5,
+ 11, 12, 13,
+ 19, 20, 21
+};
+
+Music::Music(GobEngine *vm) : _vm(vm) {
+ _data = 0;
+ _playPos = 0;
+ _dataSize = 0;
+ _rate = _vm->_mixer->getOutputRate();
+ _opl = makeAdlibOPL(_rate);
+ _vm->_mixer->setupPremix(this, Audio::Mixer::kMusicSoundType);
+ _first = true;
+ _ended = false;
+ _playing = false;
+ _looping = true;
+ _samplesTillPoll = 0;
+
+ setFreqs();
+}
+
+Music::~Music(void) {
+ if (_data);
+ delete _data;
+ _vm->_mixer->setupPremix(0);
+}
+
+void Music::premixerCall(int16 *buf, uint len) {
+ if (!_playing) {
+ memset(buf, 0, 2 * len * sizeof(int16));
+ return;
+ }
+ else {
+ if (_first) {
+ memset(buf, 0, 2 * len * sizeof(int16));
+ pollMusic();
+ return;
+ }
+ else {
+ uint32 render;
+ int16 *data = buf;
+ uint datalen = len;
+ while (datalen) {
+ if (_samplesTillPoll) {
+ render = (datalen > _samplesTillPoll) ? (_samplesTillPoll) : (datalen);
+ datalen -= render;
+ _samplesTillPoll -= render;
+ YM3812UpdateOne(_opl, data, render);
+ data += render;
+ } else {
+ pollMusic();
+ if (_ended) {
+ memset(data, 0, datalen * sizeof(int16));
+ datalen = 0;
+ }
+ }
+ }
+ }
+ if (_ended) {
+ _first = true;
+ _ended = false;
+ _playPos = _data + 3 + (_data[1] + 1) * 0x38;
+ _samplesTillPoll = 0;
+ if (_looping) {
+ reset();
+ setVoices();
+ }
+ else
+ _playing = false;
+ }
+ // Convert mono data to stereo
+ for (int i = (len - 1); i >= 0; i--) {
+ buf[2 * i] = buf[2 * i + 1] = buf[i];
+ }
+ }
+}
+
+void Music::writeOPL(byte reg, byte val) {
+ debug(5, "writeOPL(%02X, %02X)", reg, val);
+ OPLWriteReg(_opl, reg, val);
+}
+
+void Music::setFreqs(void) {
+ byte lin;
+ byte col;
+ long val = 0;
+
+ // Run through the 11 channels
+ for (lin = 0; lin < 11; lin ++) {
+ _notes[lin] = 0;
+ _notCol[lin] = 0;
+ _notLin[lin] = 0;
+ _notOn[lin] = false;
+ }
+
+ // Run through the 25 lines
+ for (lin = 0; lin < 25; lin ++) {
+ // Run through the 12 columns
+ for (col = 0; col < 12; col ++) {
+ if (!col)
+ val = (((0x2710L + lin * 0x18) * 0xCB78 / 0x3D090) << 0xE) * 9 / 0x1B503;
+ _freqs[lin][col] = (short)((val + 4) >> 3);
+ val = val * 0x6A / 0x64;
+ // val = val * 392 / 370;
+ }
+ }
+}
+
+void Music::reset() {
+ // Set frequencies and octave to 0; notes off
+ for (int i = 0; i < 9; i++) {
+ writeOPL(0xA0 | i, 0);
+ writeOPL(0xB0 | i, 0);
+ writeOPL(0xE0 | _operators[i] , 0);
+ writeOPL(0xE0 | _operators[i] + 3, 0);
+ }
+
+ // Authorize the control of the waveformes
+ writeOPL(0x01, 0x20);
+}
+
+void Music::setVoices() {
+ // Definitions of the 9 instruments
+ for (int i = 0; i < 9; i++)
+ setVoice(i, i, true);
+}
+
+void Music::setVoice(byte voice, byte instr, bool set) {
+ unsigned short *strct;
+ byte channel;
+
+ // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26
+ // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27
+ for (int i = 0; i < 2; i++) {
+ strct = (unsigned short*)(_data + 3 + instr * 0x38 + i * 0x1A);
+ channel = _operators[voice] + i * 3;
+ writeOPL(0xBD, 0x00);
+ writeOPL(0x08, 0x00);
+ writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F));
+ if (!i)
+ writeOPL(0xC0 | voice , ((strct[2] & 7) << 1) | (1 - (strct[12] & 1)));
+ writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF));
+ writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF));
+ writeOPL(0x20 | channel, ((strct[9] & 1) << 7) |
+ ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) |
+ ((strct[11] & 1) << 4) | (strct[1] & 0xF));
+ if (!i)
+ writeOPL(0xE0 | channel, (strct[26] & 3));
+ else
+ writeOPL(0xE0 | channel, (strct[14] & 3));
+ if (i && set)
+ writeOPL(0x40 | channel, 0);
+ }
+}
+
+void Music::setKey(byte voice, byte note, bool on, bool spec) {
+ short freq = 0;
+ short octa = 0;
+
+ // Instruction AX
+ if (spec) {
+ // 0x7F donne 0x16B;
+ // 7F
+ // << 7 = 3F80
+ // + E000 = 11F80
+ // & FFFF = 1F80
+ // * 19 = 31380
+ // / 2000 = 18 => Ligne 18h, colonne 0 => freq 16B
+
+ // 0x3A donne 0x2AF;
+ // 3A
+ // << 7 = 1D00
+ // + E000 = FD00 négatif
+ // * 19 = xB500
+ // / 2000 = -2 => Ligne 17h, colonne -1
+
+ // 2E
+ // << 7 = 1700
+ // + E000 = F700 négatif
+ // * 19 = x1F00
+ // / 2000 =
+ short a;
+ short lin;
+ short col;
+
+ a = (note << 7) + 0xE000; // Volontairement tronqué
+ a = (short)((long)a * 25 / 0x2000);
+ if (a < 0) {
+ col = - ((24 - a) / 25);
+ lin = (-a % 25);
+ if (lin)
+ lin = 25 - lin;
+ }
+ else {
+ col = a / 25;
+ lin = a % 25;
+ }
+
+ _notCol[voice] = col;
+ _notLin[voice] = lin;
+ note = _notes[voice];
+ }
+ // Instructions 0X 9X 8X
+ else {
+ note -= 12;
+ _notOn[voice] = on;
+ }
+
+ _notes[voice] = note;
+ note += _notCol[voice];
+ note = MIN(0x5F, (int)note);
+ octa = note / 12;
+ freq = _freqs[_notLin[voice]][note - octa * 12];
+
+ writeOPL(0xA0 + voice, freq & 0xff);
+ writeOPL(0xB0 + voice, (freq >> 8) | (octa << 2) | 0x20 * on);
+
+ if (!freq)
+ warning("Voice %d, note %02X unknown\n", voice, note);
+}
+
+void Music::setVolume(byte voice, byte volume) {
+ volume = 0x3F - (volume * 0x7E + 0x7F) / 0xFE;
+ writeOPL(0x40 + _volRegNums[voice], volume);
+}
+
+void Music::pollMusic(void) {
+ unsigned char instr;
+ byte channel;
+ byte note;
+ byte volume;
+ uint16 tempo;
+
+ if (_playPos > (_data + _dataSize)) {
+ _ended = true;
+ return;
+ }
+
+ // First tempo, we'll ignore it...
+ if (_first) {
+ tempo = *(_playPos++);
+ // Tempo on 2 bytes
+ if (tempo & 0x80)
+ tempo = ((tempo & 3) << 8) | *(_playPos++);
+ }
+ _first = false;
+
+ // Instruction
+ instr = *(_playPos++);
+ channel = instr & 0x0F;
+
+ switch (instr & 0xF0) {
+ // Note on + Volume
+ case 0x00:
+ note = *(_playPos++);
+ _pollNotes[channel] = note;
+ setVolume(channel, *(_playPos++));
+ setKey(channel, note, true, false);
+ break;
+ // Note on
+ case 0x90:
+ note = *(_playPos++);
+ _pollNotes[channel] = note;
+ setKey(channel, note, true, false);
+ break;
+ // Last note off
+ case 0x80:
+ note = _pollNotes[channel];
+ setKey(channel, note, false, false);
+ break;
+ // Frequency on/off
+ case 0xA0:
+ note = *(_playPos++);
+ setKey(channel, note, _notOn[channel], true);
+ break;
+ // Volume
+ case 0xB0:
+ volume = *(_playPos++);
+ setVolume(channel, volume);
+ break;
+ // Program change
+ case 0xC0:
+ setVoice(channel, *(_playPos++), false);
+ break;
+ // Special
+ case 0xF0:
+ break;
+ default:
+ warning("Unknown command in ADL, stopping playback");
+ _looping = false;
+ _ended = true;
+ break;
+ }
+ // End instruction
+ if (instr == 0xFF) {
+ _ended = true;
+ }
+
+ // Temporization
+ tempo = *(_playPos++);
+ // End tempo
+ if (tempo == 0xFF) {
+ _ended = true;
+ return;
+ }
+ // Tempo on 2 bytes
+ if (tempo & 0x80)
+ tempo = ((tempo & 3) << 8) | *(_playPos++);
+ if (!tempo)
+ tempo ++;
+
+ _samplesTillPoll = tempo * (_rate / 1000);
+}
+
+void Music::startPlay(void) {
+ if (!_data)
+ return;
+
+ _playing = true;
+}
+
+void Music::playBgMusic(void) {
+ debug(2, "Music::playBgMusic()");
+ for (int i = 0; i < ARRAYSIZE(_tracks); i++)
+ if (!scumm_stricmp(_vm->_game->_curTotFile, _tracks[i][0])) {
+ playTrack(_tracks[i][1]);
+ break;
+ }
+}
+
+void Music::playTrack(const char *trackname) {
+ if (_playing) return;
+
+ debug(2, "Music::playTrack(%s)", trackname);
+ unloadMusic();
+ for (int i = 0; i < ARRAYSIZE(_tracksToFiles); i++)
+ if (!scumm_stricmp(trackname, _tracksToFiles[i][0])) {
+ loadMusic(_tracksToFiles[i][1]);
+ startPlay();
+ break;
+ }
+}
+
+bool Music::loadMusic(const char *filename) {
+ Common::File song;
+
+ song.open(filename);
+ if (!song.isOpen())
+ return false;
+
+ _dataSize = song.size();
+ _data = new byte[_dataSize];
+ song.read(_data, _dataSize);
+ song.close();
+
+ reset();
+ setVoices();
+ _playPos = _data + 3 + (_data[1] + 1) * 0x38;
+
+ return true;
+}
+
+void Music::unloadMusic(void) {
+ _playing = false;
+
+ if (_data)
+ delete _data;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/music.h b/engines/gob/music.h
new file mode 100644
index 0000000000..e6421ea32c
--- /dev/null
+++ b/engines/gob/music.h
@@ -0,0 +1,96 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ * Original ADL-Player source Copyright (C) 2004 by Dorian Gray
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GOB_MUSIC_H
+#define GOB_MUSIC_H
+
+#include "sound/audiostream.h"
+#include "sound/fmopl.h"
+
+#include "gob/gob.h"
+
+namespace Gob {
+
+class GobEngine;
+
+class Music : public AudioStream {
+public:
+ Music(GobEngine *vm);
+ ~Music();
+
+ bool playing() { return _playing; }
+ bool getLooping() { return _looping; }
+ void setLooping(bool looping) { _looping = looping; }
+ void startPlay(void);
+ void stopPlay(void) { _playing = false; }
+ void playTrack(const char *trackname);
+ void playBgMusic(void);
+ bool loadMusic(const char *filename);
+ void unloadMusic(void);
+
+// AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples) {
+ premixerCall(buffer, numSamples / 2);
+ return numSamples;
+ }
+ bool isStereo() const { return true; }
+ bool endOfData() const { return false; }
+ int getRate() const { return _rate; }
+
+protected:
+ static const char *_tracks[][2];
+ static const char *_tracksToFiles[][2];
+ static const unsigned char _operators[];
+ static const unsigned char _volRegNums [];
+ FM_OPL *_opl;
+ byte *_data;
+ byte *_playPos;
+ uint32 _dataSize;
+ uint32 _rate;
+ short _freqs[25][12];
+ byte _notes[11];
+ byte _notCol[11];
+ byte _notLin[11];
+ bool _notOn[11];
+ byte _pollNotes[16];
+ uint32 _samplesTillPoll;
+ bool _playing;
+ bool _first;
+ bool _ended;
+ bool _looping;
+ GobEngine *_vm;
+
+ void premixerCall(int16 *buf, uint len);
+ void writeOPL(byte reg, byte val);
+ void setFreqs(void);
+ void reset(void);
+ void setVoices();
+ void setVoice(byte voice, byte instr, bool set);
+ void setKey(byte voice, byte note, bool on, bool spec);
+ void setVolume(byte voice, byte volume);
+ void pollMusic(void);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/pack.cpp b/engines/gob/pack.cpp
new file mode 100644
index 0000000000..c255a70ace
--- /dev/null
+++ b/engines/gob/pack.cpp
@@ -0,0 +1,108 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/pack.h"
+
+namespace Gob {
+
+int32 Pack::unpackData(char *sourceBuf, char *destBuf) {
+ uint32 realSize;
+ uint32 counter;
+ uint16 cmd;
+ byte *src;
+ byte *dest;
+ byte *tmpBuf;
+ int16 off;
+ byte len;
+ byte i;
+ int16 j;
+ uint16 tmpIndex;
+
+ realSize = READ_LE_UINT32(sourceBuf);
+ counter = READ_LE_UINT32(sourceBuf);
+
+ tmpBuf = new byte[4114];
+
+ /*
+ * Can use assembler unpacker for small blocks - for speed.
+ * Don't need this anymore :)
+ */
+ /*
+ * if (realSize < 65000)
+ * {
+ * asm_unpackData(sourceBuf, destBuf, tmpBuf);
+ * free(tmpBuf);
+ * return realSize;
+ * }
+ */
+
+ if (tmpBuf == 0)
+ return 0;
+
+ for (j = 0; j < 4078; j++)
+ tmpBuf[j] = 0x20;
+ tmpIndex = 4078;
+
+ src = (byte *)(sourceBuf + 4);
+ dest = (byte *)destBuf;
+
+ cmd = 0;
+ while (1) {
+ cmd >>= 1;
+ if ((cmd & 0x0100) == 0) {
+ cmd = *src | 0xff00;
+ src++;
+ }
+ if ((cmd & 1) != 0) { /* copy */
+ *dest++ = *src;
+ tmpBuf[tmpIndex] = *src;
+ src++;
+ tmpIndex++;
+ tmpIndex %= 4096;
+ counter--;
+ if (counter == 0)
+ break;
+ } else { /* copy string */
+
+ off = *src++;
+ off |= (*src & 0xf0) << 4;
+ len = (*src & 0x0f) + 3;
+ src++;
+ for (i = 0; i < len; i++) {
+ *dest++ = tmpBuf[(off + i) % 4096];
+ counter--;
+ if (counter == 0) {
+ delete[] tmpBuf;
+ return realSize;
+ }
+ tmpBuf[tmpIndex] = tmpBuf[(off + i) % 4096];
+ tmpIndex++;
+ tmpIndex %= 4096;
+ }
+ }
+ }
+ delete[] tmpBuf;
+ return realSize;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pack.h b/engines/gob/pack.h
new file mode 100644
index 0000000000..9df0d97b24
--- /dev/null
+++ b/engines/gob/pack.h
@@ -0,0 +1,36 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_UNPACKER_H
+#define GOB_UNPACKER_H
+
+namespace Gob {
+
+class Pack {
+public:
+ int32 asm_unpackData(char *source, char *dest, char *temp);
+ int32 unpackData(char *source, char *dest);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/palanim.cpp b/engines/gob/palanim.cpp
new file mode 100644
index 0000000000..7946639c4e
--- /dev/null
+++ b/engines/gob/palanim.cpp
@@ -0,0 +1,227 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/video.h"
+#include "gob/util.h"
+#include "gob/global.h"
+#include "gob/palanim.h"
+
+namespace Gob {
+
+PalAnim::PalAnim(GobEngine *vm) : _vm(vm) {
+ _fadeValue = 1;
+ for (int i = 0; i < 256; i++) {
+ _toFadeRed[i] = 0;
+ _toFadeGreen[i] = 0;
+ _toFadeBlue[i] = 0;
+ }
+}
+
+char PalAnim::fadeColor(char from, char to) {
+ if ((int16)from - _fadeValue > (int16)to)
+ return from - _fadeValue;
+ else if ((int16)from + _fadeValue < (int16)to)
+ return from + _fadeValue;
+ else
+ return to;
+}
+
+char PalAnim::fadeStep(int16 oper) {
+ byte newRed;
+ byte newGreen;
+ byte newBlue;
+ char stop;
+ int16 i;
+
+ if (_vm->_global->_colorCount != 256)
+ error("fadeStep: Only 256 color mode is supported!");
+
+ if (oper == 0) {
+ stop = 1;
+ if (_vm->_global->_setAllPalette) {
+ if (_vm->_global->_inVM != 0)
+ error("fade: _vm->_global->_inVM != 0 not supported.");
+
+ for (i = 0; i < 256; i++) {
+ newRed = fadeColor(_vm->_global->_redPalette[i], _toFadeRed[i]);
+ newGreen = fadeColor(_vm->_global->_greenPalette[i], _toFadeGreen[i]);
+ newBlue = fadeColor(_vm->_global->_bluePalette[i], _toFadeBlue[i]);
+
+ if (_vm->_global->_redPalette[i] != newRed
+ || _vm->_global->_greenPalette[i] != newGreen
+ || _vm->_global->_bluePalette[i] != newBlue) {
+
+ _vm->_video->setPalElem(i, newRed, newGreen, newBlue, 0, 0x13);
+
+ _vm->_global->_redPalette[i] = newRed;
+ _vm->_global->_greenPalette[i] = newGreen;
+ _vm->_global->_bluePalette[i] = newBlue;
+ stop = 0;
+ }
+ }
+ } else {
+ for (i = 0; i < 16; i++) {
+
+ _vm->_video->setPalElem(i,
+ fadeColor(_vm->_global->_redPalette[i],
+ _toFadeRed[i]),
+ fadeColor(_vm->_global->_greenPalette[i],
+ _toFadeGreen[i]),
+ fadeColor(_vm->_global->_bluePalette[i],
+ _toFadeBlue[i]), -1, _vm->_global->_videoMode);
+
+ if (_vm->_global->_redPalette[i] != _toFadeRed[i] ||
+ _vm->_global->_greenPalette[i] != _toFadeGreen[i] ||
+ _vm->_global->_bluePalette[i] != _toFadeBlue[i])
+ stop = 0;
+ }
+ }
+ return stop;
+ } else if (oper == 1) {
+ stop = 1;
+ for (i = 0; i < 16; i++) {
+ _vm->_video->setPalElem(i,
+ fadeColor(_vm->_global->_redPalette[i], _toFadeRed[i]),
+ _vm->_global->_greenPalette[i], _vm->_global->_bluePalette[i], -1, _vm->_global->_videoMode);
+
+ if (_vm->_global->_redPalette[i] != _toFadeRed[i])
+ stop = 0;
+ }
+ return stop;
+ } else if (oper == 2) {
+ stop = 1;
+ for (i = 0; i < 16; i++) {
+ _vm->_video->setPalElem(i,
+ _vm->_global->_redPalette[i],
+ fadeColor(_vm->_global->_greenPalette[i], _toFadeGreen[i]),
+ _vm->_global->_bluePalette[i], -1, _vm->_global->_videoMode);
+
+ if (_vm->_global->_greenPalette[i] != _toFadeGreen[i])
+ stop = 0;
+ }
+ return stop;
+ } else if (oper == 3) {
+ stop = 1;
+ for (i = 0; i < 16; i++) {
+ _vm->_video->setPalElem(i,
+ _vm->_global->_redPalette[i],
+ _vm->_global->_greenPalette[i],
+ fadeColor(_vm->_global->_bluePalette[i], _toFadeBlue[i]),
+ -1, _vm->_global->_videoMode);
+
+ if (_vm->_global->_bluePalette[i] != _toFadeBlue[i])
+ stop = 0;
+ }
+ return stop;
+ }
+ return 1;
+}
+
+void PalAnim::fade(Video::PalDesc *palDesc, int16 fadeV, int16 allColors) {
+ char stop;
+ int16 i;
+
+ if (fadeV < 0)
+ _fadeValue = -fadeV;
+ else
+ _fadeValue = 2;
+
+ if (_vm->_global->_colorCount < 256) {
+ if (palDesc != 0)
+ _vm->_video->setFullPalette(palDesc);
+ return;
+ }
+
+ if (_vm->_global->_setAllPalette == 0) {
+ if (palDesc == 0) {
+ for (i = 0; i < 16; i++) {
+ _toFadeRed[i] = 0;
+ _toFadeGreen[i] = 0;
+ _toFadeBlue[i] = 0;
+ }
+ } else {
+ for (i = 0; i < 16; i++) {
+ _toFadeRed[i] = palDesc->vgaPal[i].red;
+ _toFadeGreen[i] = palDesc->vgaPal[i].green;
+ _toFadeBlue[i] = palDesc->vgaPal[i].blue;
+ }
+ }
+ } else {
+ if (_vm->_global->_inVM != 0)
+ error("fade: _vm->_global->_inVM != 0 is not supported");
+
+ if (palDesc == 0) {
+ for (i = 0; i < 256; i++) {
+ _toFadeRed[i] = 0;
+ _toFadeGreen[i] = 0;
+ _toFadeBlue[i] = 0;
+ }
+ } else {
+ for (i = 0; i < 256; i++) {
+ _toFadeRed[i] = palDesc->vgaPal[i].red;
+ _toFadeGreen[i] = palDesc->vgaPal[i].green;
+ _toFadeBlue[i] = palDesc->vgaPal[i].blue;
+ }
+ }
+ }
+
+ if (allColors == 0) {
+ do {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+
+ stop = fadeStep(0);
+
+ if (fadeV > 0)
+ _vm->_util->delay(fadeV);
+ } while (stop == 0);
+
+ if (palDesc != 0)
+ _vm->_video->setFullPalette(palDesc);
+ else
+ _vm->_util->clearPalette();
+ }
+
+ if (allColors == 1) {
+ do {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+ stop = fadeStep(1);
+ } while (stop == 0);
+
+ do {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+ stop = fadeStep(2);
+ } while (stop == 0);
+
+ do {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+ stop = fadeStep(3);
+ } while (stop == 0);
+
+ if (palDesc != 0)
+ _vm->_video->setFullPalette(palDesc);
+ else
+ _vm->_util->clearPalette();
+ }
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/palanim.h b/engines/gob/palanim.h
new file mode 100644
index 0000000000..8bc661a052
--- /dev/null
+++ b/engines/gob/palanim.h
@@ -0,0 +1,47 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_PALANIM_H
+#define GOB_PALANIM_H
+
+namespace Gob {
+
+class PalAnim {
+public:
+ char fadeColor(char from, char to);
+ char fadeStep(int16 oper); // oper == 0 - fade all colors, 1, 2, 3 - red,green, blue
+ void fade(Video::PalDesc * palDesc, int16 fade, int16 all);
+
+ PalAnim(GobEngine *vm);
+
+protected:
+ int16 _fadeValue;
+
+ byte _toFadeRed[256];
+ byte _toFadeGreen[256];
+ byte _toFadeBlue[256];
+ GobEngine *_vm;
+};
+
+} // End of namespace Gob
+
+#endif /* __PALANIM_H */
diff --git a/engines/gob/parse.cpp b/engines/gob/parse.cpp
new file mode 100644
index 0000000000..45de528adb
--- /dev/null
+++ b/engines/gob/parse.cpp
@@ -0,0 +1,420 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/game.h"
+#include "gob/parse.h"
+#include "gob/util.h"
+#include "gob/inter.h"
+
+namespace Gob {
+
+Parse::Parse(GobEngine *vm) : _vm(vm) {
+}
+
+int32 Parse::encodePtr(char *ptr, int type) {
+ int32 offset;
+
+ switch (type) {
+ case kExecPtr:
+ offset = ptr - _vm->_game->_totFileData;
+ break;
+ case kInterVar:
+ offset = ptr - _vm->_global->_inter_variables;
+ break;
+ case kResStr:
+ offset = ptr - _vm->_global->_inter_resStr;
+ break;
+ default:
+ error("encodePtr: Unknown pointer type");
+ }
+ assert((offset & 0xF0000000) == 0);
+ return (type << 28) | offset;
+}
+
+char *Parse::decodePtr(int32 n) {
+ char *ptr;
+
+ switch (n >> 28) {
+ case kExecPtr:
+ ptr = _vm->_game->_totFileData;
+ break;
+ case kInterVar:
+ ptr = _vm->_global->_inter_variables;
+ break;
+ case kResStr:
+ ptr = _vm->_global->_inter_resStr;
+ break;
+ default:
+ error("decodePtr: Unknown pointer type");
+ }
+ return ptr + (n & 0x0FFFFFFF);
+}
+
+void Parse::skipExpr(char stopToken) {
+ int16 dimCount;
+ char operation;
+ int16 num;
+ int16 dim;
+
+ num = 0;
+ while (1) {
+ operation = *_vm->_global->_inter_execPtr++;
+
+ if (operation >= 19 && operation <= 29) {
+ switch (operation) {
+ case 20:
+ case 23:
+ _vm->_global->_inter_execPtr += 2;
+ break;
+
+ case 19:
+ _vm->_global->_inter_execPtr += 4;
+ break;
+
+ case 22:
+ _vm->_global->_inter_execPtr += strlen(_vm->_global->_inter_execPtr) + 1;
+ break;
+
+ case 25:
+ _vm->_global->_inter_execPtr += 2;
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ skipExpr(12);
+ }
+ break;
+
+ case 26:
+ case 28:
+ dimCount = _vm->_global->_inter_execPtr[2];
+ _vm->_global->_inter_execPtr += 3 + dimCount; // ???
+ for (dim = 0; dim < dimCount; dim++)
+ skipExpr(12);
+
+ if (operation == 28 && *_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ skipExpr(12);
+ }
+ break;
+
+ case 29:
+ _vm->_global->_inter_execPtr++;
+ skipExpr(10);
+ }
+ continue;
+ } // if (operation >= 19 && operation <= 29)
+
+ if (operation == 9) {
+ num++;
+ continue;
+ }
+
+ if (operation == 11 || (operation >= 1 && operation <= 8))
+ continue;
+
+ if (operation >= 30 && operation <= 37)
+ continue;
+
+ if (operation == 10)
+ num--;
+
+ if (operation != stopToken)
+ continue;
+
+ if (stopToken != 10 || num < 0)
+ return;
+ }
+}
+
+void Parse::printExpr(char stopToken) {
+ int16 dimCount;
+ char operation;
+ int16 num;
+ int16 dim;
+ char *arrDesc;
+ char func;
+ char saved = 0;
+ static char *savedPos = 0;
+
+ if (savedPos == 0) {
+ savedPos = _vm->_global->_inter_execPtr;
+ saved = 1;
+ }
+
+ num = 0;
+ while (1) {
+ operation = *_vm->_global->_inter_execPtr++;
+
+ if (operation >= 19 && operation <= 29) {
+ switch (operation) {
+ case 19:
+ debugN(5, "%l", READ_LE_UINT32(_vm->_global->_inter_execPtr));
+ _vm->_global->_inter_execPtr += 4;
+ break;
+
+ case 20:
+ debugN(5, "%d", _vm->_inter->load16());
+ break;
+
+ case 22:
+ debugN(5, "\42%s\42", _vm->_global->_inter_execPtr);
+ _vm->_global->_inter_execPtr += strlen(_vm->_global->_inter_execPtr) + 1;
+ break;
+
+ case 23:
+ {
+ int16 varnum = _vm->_inter->load16();
+ debugN(5, "var_%d (val=%d)", varnum, READ_LE_UINT32(_vm->_global->_inter_variables + varnum * 4) );
+ break;
+ }
+ case 25:
+ debugN(5, "(&var_%d)", _vm->_inter->load16());
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ debugN(5, "{");
+ printExpr(12);
+ debugN(5, "}");
+ }
+ break;
+
+ case 26:
+ case 28:
+ if (operation == 28)
+ debugN(5, "(&");
+
+ debugN(5, "var_%d[", _vm->_inter->load16());
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDesc = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ for (dim = 0; dim < dimCount; dim++) {
+ printExpr(12);
+ debugN(5, " of %d", (int16)arrDesc[dim]);
+ if (dim != dimCount - 1)
+ debugN(5, ",");
+ }
+ debugN(5, "]");
+ if (operation == 28)
+ debugN(5, ")");
+
+ if (operation == 28 && *_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ debugN(5, "{");
+ printExpr(12);
+// debugN(5, "}");
+ }
+ break;
+
+ case 29:
+ func = *_vm->_global->_inter_execPtr++;
+ if (func == 5)
+ debugN(5, "sqr(");
+ else if (func == 10)
+ debugN(5, "rand(");
+ else if (func == 7)
+ debugN(5, "abs(");
+ else if (func == 0 || func == 1 || func == 6)
+ debugN(5, "sqrt(");
+ else
+ debugN(5, "id(");
+ printExpr(10);
+ break;
+
+ default:
+ debugN(5, "<%d>", (int16)operation);
+ break;
+ }
+ continue;
+ } // if (operation >= 19 && operation <= 29)
+ switch (operation) {
+ case 9:
+ debugN(5, "(");
+ break;
+
+ case 11:
+ debugN(5, "!");
+ break;
+
+ case 10:
+ debugN(5, ")");
+ break;
+
+ case 1:
+ debugN(5, "-");
+ break;
+
+ case 2:
+ debugN(5, "+");
+ break;
+
+ case 3:
+ debugN(5, "-");
+ break;
+
+ case 4:
+ debugN(5, "|");
+ break;
+
+ case 5:
+ debugN(5, "*");
+ break;
+
+ case 6:
+ debugN(5, "/");
+ break;
+
+ case 7:
+ debugN(5, "%");
+ break;
+
+ case 8:
+ debugN(5, "&");
+ break;
+
+ case 30:
+ debugN(5, "||");
+ break;
+
+ case 31:
+ debugN(5, "&&");
+ break;
+
+ case 32:
+ debugN(5, "<");
+ break;
+
+ case 33:
+ debugN(5, "<=");
+ break;
+
+ case 34:
+ debugN(5, ">");
+ break;
+
+ case 35:
+ debugN(5, ">=");
+ break;
+
+ case 36:
+ debugN(5, "==");
+ break;
+
+ case 37:
+ debugN(5, "!=");
+ break;
+
+ case 99:
+ debugN(5, "\n");
+ break;
+
+ case 12:
+ debugN(5, "}");
+ if (stopToken != 12) {
+ debugN(5, "Closing paren without opening?");
+ }
+ break;
+
+ default:
+ debugN(5, "<%d>", (int16)operation);
+ break;
+ }
+
+ if (operation == 9) {
+ num++;
+ continue;
+ }
+
+ if (operation == 11 || (operation >= 1 && operation <= 8))
+ continue;
+
+ if (operation >= 30 && operation <= 37)
+ continue;
+
+ if (operation == 10)
+ num--;
+
+ if (operation == stopToken) {
+ if (stopToken != 10 || num < 0) {
+
+ if (saved != 0) {
+ _vm->_global->_inter_execPtr = savedPos;
+ savedPos = 0;
+ }
+ return;
+ }
+ }
+ }
+}
+
+void Parse::printVarIndex() {
+ char *arrDesc;
+ int16 dim;
+ int16 dimCount;
+ int16 operation;
+ int16 temp;
+
+ char *pos = _vm->_global->_inter_execPtr;
+
+ operation = *_vm->_global->_inter_execPtr++;
+ switch (operation) {
+ case 23:
+ case 25:
+ temp = _vm->_inter->load16() * 4;
+ debugN(5, "&var_%d", temp);
+ if (operation == 25 && *_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ debugN(5, "+");
+ printExpr(12);
+ }
+ break;
+
+ case 26:
+ case 28:
+ debugN(5, "&var_%d[", _vm->_inter->load16());
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDesc = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ for (dim = 0; dim < dimCount; dim++) {
+ printExpr(12);
+ debugN(5, " of %d", (int16)arrDesc[dim]);
+ if (dim != dimCount - 1)
+ debugN(5, ",");
+ }
+ debugN(5, "]");
+
+ if (operation == 28 && *_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ debugN(5, "+");
+ printExpr(12);
+ }
+ break;
+
+ default:
+ debugN(5, "var_0");
+ break;
+ }
+ debugN(5, "\n");
+ _vm->_global->_inter_execPtr = pos;
+ return;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/parse.h b/engines/gob/parse.h
new file mode 100644
index 0000000000..e85fbebcfa
--- /dev/null
+++ b/engines/gob/parse.h
@@ -0,0 +1,75 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_PARSE_H
+#define GOB_PARSE_H
+
+namespace Gob {
+
+class Parse {
+public:
+ void skipExpr(char stopToken);
+ void printExpr(char stopToken);
+ void printVarIndex(void);
+ virtual int16 parseVarIndex(void) = 0;
+ virtual int16 parseValExpr(unsigned stopToken=99) = 0;
+ virtual int16 parseExpr(char stopToken, byte *resultPtr) = 0;
+
+ Parse(GobEngine *vm);
+ virtual ~Parse() {};
+
+protected:
+ enum PointerType {
+ kExecPtr = 0,
+ kInterVar = 1,
+ kResStr = 2
+ };
+
+ GobEngine *_vm;
+
+ int32 encodePtr(char *ptr, int type);
+ char *decodePtr(int32 n);
+};
+
+class Parse_v1 : public Parse {
+public:
+ Parse_v1(GobEngine *vm);
+ virtual ~Parse_v1() {};
+
+ virtual int16 parseVarIndex(void);
+ virtual int16 parseValExpr(unsigned stopToken=99);
+ virtual int16 parseExpr(char stopToken, byte *resultPtr);
+};
+
+class Parse_v2 : public Parse_v1 {
+public:
+ Parse_v2(GobEngine *vm);
+ virtual ~Parse_v2() {};
+
+ virtual int16 parseVarIndex(void);
+ virtual int16 parseValExpr(unsigned stopToken=99);
+ virtual int16 parseExpr(char stopToken, byte *resultPtr);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/parse_v1.cpp b/engines/gob/parse_v1.cpp
new file mode 100644
index 0000000000..fc0dc91d5b
--- /dev/null
+++ b/engines/gob/parse_v1.cpp
@@ -0,0 +1,883 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/parse.h"
+#include "gob/inter.h"
+#include "gob/global.h"
+
+namespace Gob {
+
+Parse_v1::Parse_v1(GobEngine *vm) : Parse(vm) {
+}
+
+int16 Parse_v1::parseVarIndex() {
+ int16 temp2;
+ char *arrDesc;
+ int16 dim;
+ int16 dimCount;
+ int16 operation;
+ int16 temp;
+ int16 offset;
+ int16 val;
+
+ operation = *_vm->_global->_inter_execPtr++;
+ debug(5, "var parse = %d", operation);
+ switch (operation) {
+ case 23:
+ case 25:
+ temp = _vm->_inter->load16() * 4;
+ debug(5, "oper = %d", (int16)*_vm->_global->_inter_execPtr);
+ if (operation == 25 && *_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ val = parseValExpr(12);
+ temp += val;
+ debug(5, "parse subscript = %d", val);
+ }
+ return temp;
+
+ case 26:
+ case 28:
+ temp = _vm->_inter->load16() * 4;
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDesc = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ offset = 0;
+ for (dim = 0; dim < dimCount; dim++) {
+ temp2 = parseValExpr(12);
+ offset = arrDesc[dim] * offset + temp2;
+ }
+ offset *= 4;
+ if (operation != 28)
+ return temp + offset;
+
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ temp += parseValExpr(12);
+ }
+ return offset * _vm->_global->_inter_animDataSize + temp;
+
+ default:
+ return 0;
+ }
+}
+
+int16 Parse_v1::parseValExpr(unsigned stopToken) {
+ int16 values[20];
+ byte operStack[20];
+ int16 *valPtr;
+ byte *operPtr;
+ byte *arrDesc;
+ unsigned operation;
+ int16 temp2;
+ int16 dim;
+ int16 dimCount;
+ int16 temp;
+ int16 offset;
+ int16 stkPos;
+ int16 brackPos;
+ static int16 flag = 0;
+ int16 oldflag;
+
+ oldflag = flag;
+ if (flag == 0) {
+ flag = 1;
+ printExpr(stopToken);
+ }
+
+ stkPos = -1;
+ operPtr = operStack - 1;
+ valPtr = values - 1;
+
+ while (1) {
+ stkPos++;
+ operPtr++;
+ valPtr++;
+
+ operation = *_vm->_global->_inter_execPtr++;
+ if (operation >= 19 && operation <= 29) {
+ *operPtr = 20;
+ switch (operation) {
+ case 19:
+ *valPtr = READ_LE_UINT32(_vm->_global->_inter_execPtr);
+ _vm->_global->_inter_execPtr += 4;
+ break;
+
+ case 20:
+ *valPtr = _vm->_inter->load16();
+ break;
+
+ case 23:
+ *valPtr = (uint16)VAR(_vm->_inter->load16());
+ break;
+
+ case 25:
+ temp = _vm->_inter->load16() * 4;
+ _vm->_global->_inter_execPtr++;
+ temp += parseValExpr(12);
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp);
+ break;
+
+ case 26:
+ case 28:
+ temp = _vm->_inter->load16();
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDesc = (byte*)_vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ offset = 0;
+ for (dim = 0; dim < dimCount; dim++) {
+ temp2 = parseValExpr(12);
+ offset = arrDesc[dim] * offset + temp2;
+ }
+ if (operation == 26) {
+ *valPtr = (uint16)VAR(temp + offset);
+ } else {
+ _vm->_global->_inter_execPtr++;
+ temp2 = parseValExpr(12);
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp * 4 + offset * 4 * _vm->_global->_inter_animDataSize + temp2);
+ }
+ break;
+
+ case 29:
+ operation = *_vm->_global->_inter_execPtr++;
+ parseExpr(10, 0);
+
+ if (operation == 5) {
+ _vm->_global->_inter_resVal = _vm->_global->_inter_resVal * _vm->_global->_inter_resVal;
+ } else if (operation == 7) {
+ if (_vm->_global->_inter_resVal < 0)
+ _vm->_global->_inter_resVal = -_vm->_global->_inter_resVal;
+ } else if (operation == 10) {
+ _vm->_global->_inter_resVal = _vm->_util->getRandom(_vm->_global->_inter_resVal);
+ }
+ *valPtr = _vm->_global->_inter_resVal;
+ break;
+
+ } // switch
+ if (stkPos > 0 && operPtr[-1] == 1) {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ operPtr[0] = 20;
+ valPtr[0] = -valPtr[1];
+ }
+
+ if (stkPos > 0 && operPtr[-1] > 4 && operPtr[-1] < 9) {
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+
+ switch (operPtr[1]) {
+ case 5:
+ valPtr[0] *= valPtr[2];
+ break;
+
+ case 6:
+ valPtr[0] /= valPtr[2];
+ break;
+
+ case 7:
+ valPtr[0] %= valPtr[2];
+ break;
+
+ case 8:
+ valPtr[0] &= valPtr[2];
+ break;
+ }
+ } // if (stkPos > 0 && cmdPtr[-1] > 4 && cmdPtr[-1] < 9)
+ continue;
+ }
+
+ if (operation >= 1 && operation <= 9) {
+ *operPtr = operation;
+ continue;
+ }
+
+ while (stkPos >= 2) {
+ if (operPtr[-2] == 9) {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+
+ operPtr[-1] = operPtr[0];
+ valPtr[-1] = valPtr[0];
+ if (stkPos > 1 && operPtr[-2] == 1) {
+ valPtr[-2] = 20;
+ valPtr[-2] = -valPtr[-1];
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+
+ if (stkPos > 2 && operPtr[-2] > 4
+ && operPtr[-2] < 9) {
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ switch (operPtr[0]) {
+ case 5:
+ operPtr[-1] *= operPtr[1];
+ break;
+
+ case 6:
+ operPtr[-1] /= operPtr[1];
+ break;
+
+ case 7:
+ operPtr[-1] %= operPtr[1];
+ break;
+
+ case 8:
+ operPtr[-1] &= operPtr[1];
+ break;
+ }
+ }
+ if (operation == 10)
+ break;
+ } // operPtr[-2] == 9
+
+ for (brackPos = stkPos - 2; brackPos > 0 &&
+ operStack[brackPos] < 30
+ && operStack[brackPos] != 9; brackPos--);
+
+ if (operStack[brackPos] >= 30
+ || operStack[brackPos] == 9)
+ brackPos++;
+
+ if (operPtr[-2] < 2 || operPtr[-2] > 8)
+ break;
+
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ switch (operPtr[0]) {
+ case 2:
+ values[brackPos] += valPtr[1];
+ continue;
+ case 3:
+ values[brackPos] -= valPtr[1];
+ continue;
+ case 4:
+ values[brackPos] |= valPtr[1];
+ continue;
+ case 5:
+ valPtr[-1] *= valPtr[1];
+ continue;
+ case 6:
+ valPtr[-1] /= valPtr[1];
+ continue;
+ case 7:
+ valPtr[-1] %= valPtr[1];
+ continue;
+ case 8:
+ valPtr[-1] &= valPtr[1];
+ continue;
+ }
+ }
+
+ if (operation != 10) {
+ if (operation != stopToken) {
+ debug(5, "stoptoken error: %d != %d", operation, stopToken);
+ }
+ flag = oldflag;
+ return values[0];
+ }
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+}
+
+int16 Parse_v1::parseExpr(char stopToken, byte *arg_2) {
+ int32 values[20];
+ byte operStack[20];
+ int32 prevPrevVal;
+ int32 prevVal;
+ int32 curVal;
+ int32 *valPtr;
+ char *operPtr;
+ byte *arrDescPtr;
+ char var_C;
+ byte operation;
+ int16 dimCount;
+ int16 temp;
+ int16 temp2;
+ uint16 offset;
+ int16 dim;
+ char var_1A;
+ int16 stkPos;
+ int16 brackStart;
+
+ stkPos = -1;
+ operPtr = (char *)(operStack - 1);
+ valPtr = values - 1;
+
+ while (1) {
+ stkPos++;
+ operPtr++;
+ valPtr++;
+ operation = *_vm->_global->_inter_execPtr++;
+ if (operation >= 19 && operation <= 29) {
+ switch (operation) {
+ case 19:
+ *operPtr = 20;
+ *valPtr = READ_LE_UINT32(_vm->_global->_inter_execPtr);
+ _vm->_global->_inter_execPtr += 4;
+ break;
+
+ case 20:
+ *operPtr = 20;
+ *valPtr = _vm->_inter->load16();
+ break;
+
+ case 22:
+ *operPtr = 22;
+ *valPtr = encodePtr(_vm->_global->_inter_execPtr, kExecPtr);
+ _vm->_global->_inter_execPtr += strlen(_vm->_global->_inter_execPtr) + 1;
+ break;
+
+ case 23:
+ *operPtr = 20;
+ *valPtr = VAR(_vm->_inter->load16());
+ break;
+
+ case 25:
+ *operPtr = 22;
+ temp = _vm->_inter->load16() * 4;
+ *valPtr = encodePtr(_vm->_global->_inter_variables + temp, kInterVar);
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ temp += parseValExpr(12);
+ *operPtr = 20;
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp);
+ }
+ break;
+
+ case 26:
+ case 28:
+ *operPtr = operation - 6;
+ temp = _vm->_inter->load16();
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDescPtr = (byte *)_vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ offset = 0;
+ dim = 0;
+ for (dim = 0; dim < dimCount; dim++) {
+ temp2 = parseValExpr(12);
+ offset = offset * arrDescPtr[dim] + temp2;
+ }
+
+ if (operation == 26) {
+ *valPtr = VAR(temp + offset);
+ break;
+ }
+ *valPtr = encodePtr(_vm->_global->_inter_variables + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, kInterVar);
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ temp2 = parseValExpr(12);
+ *operPtr = 20;
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp * 4 + offset * 4 * _vm->_global->_inter_animDataSize + temp2);
+ }
+ break;
+
+ case 29:
+ operation = *_vm->_global->_inter_execPtr++;
+ parseExpr(10, 0);
+
+ switch (operation) {
+ case 5:
+ _vm->_global->_inter_resVal = _vm->_global->_inter_resVal * _vm->_global->_inter_resVal;
+ break;
+
+ case 0:
+ case 1:
+ case 6:
+ curVal = 1;
+ prevVal = 1;
+
+ do {
+ prevPrevVal = prevVal;
+ prevVal = curVal;
+ curVal = (curVal + _vm->_global->_inter_resVal / curVal) / 2;
+ } while (curVal != prevVal && curVal != prevPrevVal);
+ _vm->_global->_inter_resVal = curVal;
+ break;
+
+ case 10:
+ _vm->_global->_inter_resVal = _vm->_util->getRandom(_vm->_global->_inter_resVal);
+ break;
+
+ case 7:
+ if (_vm->_global->_inter_resVal < 0)
+ _vm->_global->_inter_resVal = -_vm->_global->_inter_resVal;
+ break;
+ }
+ *operPtr = 20;
+ *valPtr = _vm->_global->_inter_resVal;
+ }
+
+ if (stkPos > 0 && (operPtr[-1] == 1 || operPtr[-1] == 11)) {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+
+ if (*operPtr == 1) {
+ *operPtr = 20;
+ valPtr[0] = -valPtr[1];
+ } else if (*operPtr == 11) {
+ if (operPtr[1] == 23)
+ *operPtr = 24;
+ else
+ *operPtr = 23;
+ }
+ }
+
+ if (stkPos <= 0)
+ continue;
+
+ switch (operPtr[-1]) {
+ case 2:
+ if (operPtr[-2] == 22) {
+ if (decodePtr(valPtr[-2]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-2]));
+ valPtr[-2] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ strcat(_vm->_global->_inter_resStr, decodePtr(valPtr[0]));
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ }
+ break;
+
+ case 5:
+ valPtr[-2] *= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 6:
+ valPtr[-2] /= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 7:
+ valPtr[-2] %= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 8:
+ valPtr[-2] &= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+ }
+ continue;
+ } // op>= 19 && op <= 29
+
+ if (operation == stopToken || operation == 30 || operation == 31 || operation == 10) {
+ while (stkPos >= 2) {
+ var_1A = 0;
+ if (operPtr[-2] == 9 && (operation == 10 || operation == stopToken)) {
+ operPtr[-2] = operPtr[-1];
+ if (operPtr[-2] == 20 || operPtr[-2] == 22)
+ valPtr[-2] = valPtr[-1];
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+
+ if (stkPos > 1) {
+ if (operPtr[-2] == 1) {
+ operPtr[-2] = 20;
+ valPtr[-2] = -valPtr[-1];
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ } else if (operPtr[-2] == 11) {
+ if (operPtr[-1] == 23)
+ operPtr[-2] = 24;
+ else
+ operPtr[-2] = 23;
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+ } // stkPos > 1
+
+ if (stkPos > 2) {
+ switch (operPtr[-2]) {
+ case 5:
+ valPtr[-3] *= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+ case 6:
+ valPtr[-3] /= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 7:
+ valPtr[-3] %= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 8:
+ valPtr[-3] &= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+ } // switch
+ } // stkPos > 2
+
+ if (operation != stopToken)
+ break;
+ } // if (operPtr[-2] == 9 && ...)
+
+ for (brackStart = stkPos - 2; brackStart > 0 &&
+ operStack[brackStart] < 30 &&
+ operStack[brackStart] != 9; brackStart--);
+
+ if (operStack[brackStart] >= 30 || operStack[brackStart] == 9)
+ brackStart++;
+
+ switch (operPtr[-2]) {
+ case 2:
+ if (operStack[brackStart] == 20) {
+ values[brackStart] += valPtr[-1];
+ } else if (operStack[brackStart] == 22) {
+ if (decodePtr(values[brackStart]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(values[brackStart]));
+ values[brackStart] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ strcat(_vm->_global->_inter_resStr, decodePtr(valPtr[-1]));
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ continue;
+
+ case 3:
+ values[brackStart] -= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ continue;
+
+ case 4:
+ values[brackStart] |= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ continue;
+
+ case 5:
+ valPtr[-3] *= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 6:
+ valPtr[-3] /= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 7:
+ valPtr[-3] %= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 8:
+ valPtr[-3] &= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 30:
+ if (operPtr[-3] == 23)
+ operPtr[-3] = operPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 31:
+ if (operPtr[-3] == 24)
+ operPtr[-3] = operPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 32:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] < valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) < 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 33:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] <= valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) <= 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 34:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] > valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) > 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 35:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] >= valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) >= 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 36:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] == valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) == 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 37:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] != valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) != 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ default:
+ var_1A = 1;
+ break;
+ } // switch
+
+ if (var_1A != 0)
+ break;
+ } // while (stkPos >= 2)
+
+ if (operation == 30 || operation == 31) {
+ if (operPtr[-1] == 20) {
+ if (valPtr[-1] != 0)
+ operPtr[-1] = 24;
+ else
+ operPtr[-1] = 23;
+ }
+
+ if ((operation == 30 && operPtr[-1] == 24) ||
+ (operation == 31 && operPtr[-1] == 23)) {
+ if (stkPos > 1 && operPtr[-2] == 9) {
+ skipExpr(10);
+ operPtr[-2] = operPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ } else {
+ skipExpr(stopToken);
+ }
+ operation = _vm->_global->_inter_execPtr[-1];
+ if (stkPos > 0 && operPtr[-1] == 11) {
+ if (operPtr[0] == 23)
+ operPtr[-1] = 24;
+ else
+ operPtr[-1] = 23;
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+ } else
+ operPtr[0] = operation;
+ } else {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+
+ if (operation != stopToken)
+ continue;
+
+ if (arg_2 != 0)
+ *arg_2 = operStack[0];
+
+ switch (operStack[0]) {
+ case 20:
+ _vm->_global->_inter_resVal = values[0];
+ break;
+
+ case 22:
+ if (decodePtr(values[0]) != _vm->_global->_inter_resStr)
+ strcpy(_vm->_global->_inter_resStr, decodePtr(values[0]));
+ break;
+
+ case 11:
+ if (arg_2 != 0)
+ *arg_2 ^= 1;
+ break;
+
+ case 23:
+ case 24:
+ break;
+
+ default:
+ _vm->_global->_inter_resVal = 0;
+ if (arg_2 != 0)
+ *arg_2 = 20;
+ break;
+ }
+ return 0;
+ } // operation == stopToken || operation == 30 || operation == 31 || operation == 10
+
+ if (operation < 1 || operation > 11) {
+ if (operation < 32 || operation > 37)
+ continue;
+
+ if (stkPos > 2) {
+ if (operPtr[-2] == 2) {
+ if (operPtr[-3] == 20) {
+ valPtr[-3] += valPtr[-1];
+ } else if (operPtr[-3] == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ strcat(_vm->_global->_inter_resStr, decodePtr(valPtr[-1]));
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+
+ } else if (operPtr[-2] == 3) {
+ valPtr[-3] -= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ } else if (operPtr[-2] == 4) {
+ valPtr[-3] |= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ }
+ }
+ }
+ *operPtr = operation;
+ }
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp
new file mode 100644
index 0000000000..d4dfdc863f
--- /dev/null
+++ b/engines/gob/parse_v2.cpp
@@ -0,0 +1,942 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/parse.h"
+#include "gob/inter.h"
+#include "gob/global.h"
+
+namespace Gob {
+
+Parse_v2::Parse_v2(GobEngine *vm) : Parse_v1(vm) {
+}
+
+int16 Parse_v2::parseVarIndex() {
+ int16 temp2;
+ char *arrDesc;
+ int16 dim;
+ int16 dimCount;
+ int16 operation;
+ int16 temp;
+ int16 offset;
+ int16 val;
+
+ operation = *_vm->_global->_inter_execPtr++;
+ debug(5, "var parse = %d", operation);
+ switch (operation) {
+ case 16:
+ case 26:
+ case 27:
+ case 28:
+ temp = _vm->_inter->load16();
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDesc = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ offset = 0;
+ for (dim = 0; dim < dimCount; dim++) {
+ temp2 = parseValExpr(12);
+ offset = arrDesc[dim] * offset + temp2;
+ }
+ if (operation == 16)
+ return temp + offset;
+ if (operation == 26)
+ return (temp + offset) * 4;
+ if (operation == 27)
+ return (temp + offset) * 2;
+ temp *= 4;
+ offset *= 4;
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ temp += parseValExpr(12);
+ }
+ return offset * _vm->_global->_inter_animDataSize + temp;
+
+ case 17:
+ return _vm->_inter->load16() * 2;
+
+ case 18:
+ return _vm->_inter->load16();
+
+ case 23:
+ case 24:
+ case 25:
+ temp = _vm->_inter->load16() * 4;
+ debug(5, "oper = %d", (int16)*_vm->_global->_inter_execPtr);
+ if (operation == 25 && *_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ val = parseValExpr(12);
+ temp += val;
+ debug(5, "parse subscript = %d", val);
+ }
+ return temp;
+
+ default:
+ return 0;
+ }
+}
+
+int16 Parse_v2::parseValExpr(unsigned stopToken) {
+ int16 values[20];
+ byte operStack[20];
+ int16 *valPtr;
+ byte *operPtr;
+ byte *arrDesc;
+ unsigned operation;
+ int16 temp2;
+ int16 dim;
+ int16 dimCount;
+ int16 temp;
+ int16 offset;
+ int16 stkPos;
+ int16 brackPos;
+ static int16 flag = 0;
+ int16 oldflag;
+
+ oldflag = flag;
+ if (flag == 0) {
+ flag = 1;
+ printExpr(stopToken);
+ }
+
+ stkPos = -1;
+ operPtr = operStack - 1;
+ valPtr = values - 1;
+
+ while (1) {
+ stkPos++;
+ operPtr++;
+ valPtr++;
+
+ operation = *_vm->_global->_inter_execPtr++;
+ if (operation >= 16 && operation <= 29) {
+ *operPtr = 20;
+ switch (operation) {
+ case 16:
+ case 26:
+ case 27:
+ case 28:
+ temp = _vm->_inter->load16();
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDesc = (byte*)_vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ offset = 0;
+ for (dim = 0; dim < dimCount; dim++) {
+ temp2 = parseValExpr(12);
+ offset = arrDesc[dim] * offset + temp2;
+ }
+ if (operation == 16)
+ *valPtr = *(_vm->_global->_inter_variables + temp + offset);
+ else if (operation == 26)
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + temp * 4 + offset * 4);
+ else if (operation == 27)
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + temp * 2 + offset * 2);
+ else if (operation == 28) {
+ _vm->_global->_inter_execPtr++;
+ temp2 = parseValExpr(12);
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp * 4 + offset * 4 * _vm->_global->_inter_animDataSize + temp2);
+ }
+ break;
+
+ case 17:
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + _vm->_inter->load16() * 2);
+ break;
+
+ case 18:
+ *valPtr = *(_vm->_global->_inter_variables + _vm->_inter->load16());
+ break;
+
+ case 19:
+ *valPtr = _vm->_inter->load16();
+ _vm->_global->_inter_execPtr += 2;
+ break;
+
+ case 20:
+ *valPtr = _vm->_inter->load16();
+ break;
+
+ case 21:
+ *valPtr = *_vm->_global->_inter_execPtr++;
+ break;
+
+ case 23:
+ case 24:
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + _vm->_inter->load16() * 4);
+ break;
+
+ case 25:
+ temp = _vm->_inter->load16() * 4;
+ _vm->_global->_inter_execPtr++;
+ temp += parseValExpr(12);
+ *valPtr = *(_vm->_global->_inter_variables + temp);
+ break;
+
+ case 29:
+ operation = *_vm->_global->_inter_execPtr++;
+ parseExpr(10, 0);
+
+ if (operation == 5) {
+ _vm->_global->_inter_resVal = _vm->_global->_inter_resVal * _vm->_global->_inter_resVal;
+ } else if (operation == 7) {
+ if (_vm->_global->_inter_resVal < 0)
+ _vm->_global->_inter_resVal = -_vm->_global->_inter_resVal;
+ } else if (operation == 10) {
+ _vm->_global->_inter_resVal = _vm->_util->getRandom(_vm->_global->_inter_resVal);
+ }
+ *valPtr = _vm->_global->_inter_resVal;
+ break;
+
+ } // switch
+ if (stkPos > 0 && operPtr[-1] == 1) {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ operPtr[0] = 20;
+ valPtr[0] = -valPtr[1];
+ }
+
+ if (stkPos > 0 && operPtr[-1] > 4 && operPtr[-1] < 9) {
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+
+ switch (operPtr[1]) {
+ case 5:
+ valPtr[0] *= valPtr[2];
+ break;
+
+ case 6:
+ valPtr[0] /= valPtr[2];
+ break;
+
+ case 7:
+ valPtr[0] %= valPtr[2];
+ break;
+
+ case 8:
+ valPtr[0] &= valPtr[2];
+ break;
+ }
+ } // if (stkPos > 0 && cmdPtr[-1] > 4 && cmdPtr[-1] < 9)
+ continue;
+ }
+
+ if (operation >= 1 && operation <= 9) {
+ *operPtr = operation;
+ continue;
+ }
+
+ while (stkPos >= 2) {
+ if (operPtr[-2] == 9) {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+
+ operPtr[-1] = operPtr[0];
+ valPtr[-1] = valPtr[0];
+ if (stkPos > 1 && operPtr[-2] == 1) {
+ valPtr[-2] = 20;
+ valPtr[-2] = -valPtr[-1];
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+
+ if (stkPos > 2 && operPtr[-2] > 4
+ && operPtr[-2] < 9) {
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ switch (operPtr[0]) {
+ case 5:
+ operPtr[-1] *= operPtr[1];
+ break;
+
+ case 6:
+ operPtr[-1] /= operPtr[1];
+ break;
+
+ case 7:
+ operPtr[-1] %= operPtr[1];
+ break;
+
+ case 8:
+ operPtr[-1] &= operPtr[1];
+ break;
+ }
+ }
+ if (operation == 10)
+ break;
+ } // operPtr[-2] == 9
+
+ for (brackPos = stkPos - 2; brackPos > 0 &&
+ operStack[brackPos] < 30
+ && operStack[brackPos] != 9; brackPos--);
+
+ if (operStack[brackPos] >= 30
+ || operStack[brackPos] == 9)
+ brackPos++;
+
+ if (operPtr[-2] < 2 || operPtr[-2] > 8)
+ break;
+
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ switch (operPtr[0]) {
+ case 2:
+ values[brackPos] += valPtr[1];
+ continue;
+ case 3:
+ values[brackPos] -= valPtr[1];
+ continue;
+ case 4:
+ values[brackPos] |= valPtr[1];
+ continue;
+ case 5:
+ valPtr[-1] *= valPtr[1];
+ continue;
+ case 6:
+ valPtr[-1] /= valPtr[1];
+ continue;
+ case 7:
+ valPtr[-1] %= valPtr[1];
+ continue;
+ case 8:
+ valPtr[-1] &= valPtr[1];
+ continue;
+ }
+ }
+
+ if (operation != 10) {
+ if (operation != stopToken) {
+ debug(5, "stoptoken error: %d != %d", operation, stopToken);
+ }
+ flag = oldflag;
+ return values[0];
+ }
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+}
+
+int16 Parse_v2::parseExpr(char stopToken, byte *arg_2) {
+ int32 values[20];
+ byte operStack[20];
+ int32 prevPrevVal;
+ int32 prevVal;
+ int32 curVal;
+ int32 *valPtr;
+ char *operPtr;
+ byte *arrDescPtr;
+ char var_C;
+ byte operation;
+ int16 dimCount;
+ int16 temp;
+ int16 temp2;
+ uint16 offset;
+ int16 dim;
+ char var_1A;
+ int16 stkPos;
+ int16 brackStart;
+
+ stkPos = -1;
+ operPtr = (char *)(operStack - 1);
+ valPtr = values - 1;
+
+ while (1) {
+ stkPos++;
+ operPtr++;
+ valPtr++;
+ operation = *_vm->_global->_inter_execPtr++;
+ if (operation >= 19 && operation <= 29) {
+ switch (operation) {
+ case 16:
+ case 26:
+ case 27:
+ case 28:
+ if ((operation == 27) || (operation == 16))
+ *operPtr = 20;
+ else
+ *operPtr = operation - 6;
+ temp = _vm->_inter->load16();
+ dimCount = *_vm->_global->_inter_execPtr++;
+ arrDescPtr = (byte *)_vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += dimCount;
+ offset = 0;
+ for (dim = 0; dim < dimCount; dim++) {
+ temp2 = parseValExpr(12);
+ offset = offset * arrDescPtr[dim] + temp2;
+ }
+ if (operation == 16)
+ *valPtr = *(_vm->_global->_inter_variables + temp + offset);
+ else if (operation == 26)
+ *valPtr = *(uint32*)(_vm->_global->_inter_variables + temp * 4 + offset * 4);
+ else if (operation == 27)
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + temp * 2 + offset * 2);
+ else if (operation == 28) {
+ *valPtr = encodePtr(_vm->_global->_inter_variables + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, kInterVar);
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ temp2 = parseValExpr(12);
+ *operPtr = 20;
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp * 4 + offset * 4 * _vm->_global->_inter_animDataSize + temp2);
+ }
+ }
+ break;
+
+ case 17:
+ *operPtr = 20;
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + _vm->_inter->load16() * 2);
+ break;
+
+ case 18:
+ *operPtr = 20;
+ *valPtr = *(_vm->_global->_inter_variables + _vm->_inter->load16());
+ break;
+
+ case 19:
+ *operPtr = 20;
+ *valPtr = READ_LE_UINT32(_vm->_global->_inter_execPtr);
+ _vm->_global->_inter_execPtr += 4;
+ break;
+
+ case 20:
+ *operPtr = 20;
+ *valPtr = _vm->_inter->load16();
+ break;
+
+ case 21:
+ *operPtr = 20;
+ *valPtr = *_vm->_global->_inter_execPtr++;
+ break;
+
+ case 22:
+ *operPtr = 22;
+ *valPtr = encodePtr(_vm->_global->_inter_execPtr, kExecPtr);
+ _vm->_global->_inter_execPtr += strlen(_vm->_global->_inter_execPtr) + 1;
+ break;
+
+ case 23:
+ *operPtr = 20;
+ *valPtr = VAR(_vm->_inter->load16());
+ break;
+
+ case 24:
+ *operPtr = 20;
+ *valPtr = *(uint16*)(_vm->_global->_inter_variables + _vm->_inter->load16() * 4);
+ break;
+
+ case 25:
+ *operPtr = 22;
+ temp = _vm->_inter->load16() * 4;
+ *valPtr = encodePtr(_vm->_global->_inter_variables + temp, kInterVar);
+ if (*_vm->_global->_inter_execPtr == 13) {
+ _vm->_global->_inter_execPtr++;
+ temp += parseValExpr(12);
+ *operPtr = 20;
+ *valPtr = (uint8)*(_vm->_global->_inter_variables + temp);
+ }
+ break;
+
+ case 29:
+ operation = *_vm->_global->_inter_execPtr++;
+ parseExpr(10, 0);
+
+ switch (operation) {
+ case 5:
+ _vm->_global->_inter_resVal = _vm->_global->_inter_resVal * _vm->_global->_inter_resVal;
+ break;
+
+ case 0:
+ case 1:
+ case 6:
+ curVal = 1;
+ prevVal = 1;
+
+ do {
+ prevPrevVal = prevVal;
+ prevVal = curVal;
+ curVal = (curVal + _vm->_global->_inter_resVal / curVal) / 2;
+ } while (curVal != prevVal && curVal != prevPrevVal);
+ _vm->_global->_inter_resVal = curVal;
+ break;
+
+ case 10:
+ _vm->_global->_inter_resVal = _vm->_util->getRandom(_vm->_global->_inter_resVal);
+ break;
+
+ case 7:
+ if (_vm->_global->_inter_resVal < 0)
+ _vm->_global->_inter_resVal = -_vm->_global->_inter_resVal;
+ break;
+ }
+ *operPtr = 20;
+ *valPtr = _vm->_global->_inter_resVal;
+ break;
+ }
+ if (stkPos > 0 && (operPtr[-1] == 1 || operPtr[-1] == 11)) {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+
+ if (*operPtr == 1) {
+ *operPtr = 20;
+ valPtr[0] = -valPtr[1];
+ } else if (*operPtr == 11) {
+ if (operPtr[1] == 23)
+ *operPtr = 24;
+ else
+ *operPtr = 23;
+ }
+ }
+
+ if (stkPos <= 0)
+ continue;
+
+ switch (operPtr[-1]) {
+ case 2:
+ if (operPtr[-2] == 22) {
+ if (decodePtr(valPtr[-2]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-2]));
+ valPtr[-2] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ strcat(_vm->_global->_inter_resStr, decodePtr(valPtr[0]));
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ }
+ break;
+
+ case 5:
+ valPtr[-2] *= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 6:
+ valPtr[-2] /= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 7:
+ valPtr[-2] %= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 8:
+ valPtr[-2] &= valPtr[0];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+ }
+ continue;
+ } // op>= 19 && op <= 29
+
+ if (operation == stopToken || operation == 30 || operation == 31 || operation == 10) {
+ while (stkPos >= 2) {
+ var_1A = 0;
+ if (operPtr[-2] == 9 && (operation == 10 || operation == stopToken)) {
+ operPtr[-2] = operPtr[-1];
+ if (operPtr[-2] == 20 || operPtr[-2] == 22)
+ valPtr[-2] = valPtr[-1];
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+
+ if (stkPos > 1) {
+ if (operPtr[-2] == 1) {
+ operPtr[-2] = 20;
+ valPtr[-2] = -valPtr[-1];
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ } else if (operPtr[-2] == 11) {
+ if (operPtr[-1] == 23)
+ operPtr[-2] = 24;
+ else
+ operPtr[-2] = 23;
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+ } // stkPos > 1
+
+ if (stkPos > 2) {
+ switch (operPtr[-2]) {
+ case 5:
+ valPtr[-3] *= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+ case 6:
+ valPtr[-3] /= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 7:
+ valPtr[-3] %= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 8:
+ valPtr[-3] &= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+ } // switch
+ } // stkPos > 2
+
+ if (operation != stopToken)
+ break;
+ } // if (operPtr[-2] == 9 && ...)
+
+ for (brackStart = stkPos - 2; brackStart > 0 &&
+ operStack[brackStart] < 30 &&
+ operStack[brackStart] != 9; brackStart--);
+
+ if (operStack[brackStart] >= 30 || operStack[brackStart] == 9)
+ brackStart++;
+
+ switch (operPtr[-2]) {
+ case 2:
+ if (operStack[brackStart] == 20) {
+ values[brackStart] += valPtr[-1];
+ } else if (operStack[brackStart] == 22) {
+ if (decodePtr(values[brackStart]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(values[brackStart]));
+ values[brackStart] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ strcat(_vm->_global->_inter_resStr, decodePtr(valPtr[-1]));
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ continue;
+
+ case 3:
+ values[brackStart] -= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ continue;
+
+ case 4:
+ values[brackStart] |= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ continue;
+
+ case 5:
+ valPtr[-3] *= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 6:
+ valPtr[-3] /= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 7:
+ valPtr[-3] %= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 8:
+ valPtr[-3] &= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 30:
+ if (operPtr[-3] == 23)
+ operPtr[-3] = operPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 31:
+ if (operPtr[-3] == 24)
+ operPtr[-3] = operPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 32:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] < valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) < 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 33:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] <= valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) <= 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 34:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] > valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) > 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 35:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] >= valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) >= 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 36:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] == valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) == 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ case 37:
+ var_C = operPtr[-3];
+ operPtr[-3] = 23;
+ if (var_C == 20) {
+ if (valPtr[-3] != valPtr[-1])
+ operPtr[-3] = 24;
+ } else if (var_C == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ if (strcmp(_vm->_global->_inter_resStr, decodePtr(valPtr[-1])) != 0)
+ operPtr[-3] = 24;
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ break;
+
+ default:
+ var_1A = 1;
+ break;
+ } // switch
+
+ if (var_1A != 0)
+ break;
+ } // while (stkPos >= 2)
+
+ if (operation == 30 || operation == 31) {
+ if (operPtr[-1] == 20) {
+ if (valPtr[-1] != 0)
+ operPtr[-1] = 24;
+ else
+ operPtr[-1] = 23;
+ }
+
+ if ((operation == 30 && operPtr[-1] == 24) ||
+ (operation == 31 && operPtr[-1] == 23)) {
+ if (stkPos > 1 && operPtr[-2] == 9) {
+ skipExpr(10);
+ operPtr[-2] = operPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ } else {
+ skipExpr(stopToken);
+ }
+ operation = _vm->_global->_inter_execPtr[-1];
+ if (stkPos > 0 && operPtr[-1] == 11) {
+ if (operPtr[0] == 23)
+ operPtr[-1] = 24;
+ else
+ operPtr[-1] = 23;
+
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+ } else
+ operPtr[0] = operation;
+ } else {
+ stkPos--;
+ operPtr--;
+ valPtr--;
+ }
+
+ if (operation != stopToken)
+ continue;
+
+ if (arg_2 != 0)
+ *arg_2 = operStack[0];
+
+ switch (operStack[0]) {
+ case 20:
+ _vm->_global->_inter_resVal = values[0];
+ break;
+
+ case 22:
+ if (decodePtr(values[0]) != _vm->_global->_inter_resStr)
+ strcpy(_vm->_global->_inter_resStr, decodePtr(values[0]));
+ break;
+
+ case 11:
+ if (arg_2 != 0)
+ *arg_2 ^= 1;
+ break;
+
+ case 23:
+ case 24:
+ break;
+
+ default:
+ _vm->_global->_inter_resVal = 0;
+ if (arg_2 != 0)
+ *arg_2 = 20;
+ break;
+ }
+ return 0;
+ } // operation == stopToken || operation == 30 || operation == 31 || operation == 10
+
+ if (operation < 1 || operation > 11) {
+ if (operation < 32 || operation > 37)
+ continue;
+
+ if (stkPos > 2) {
+ if (operPtr[-2] == 2) {
+ if (operPtr[-3] == 20) {
+ valPtr[-3] += valPtr[-1];
+ } else if (operPtr[-3] == 22) {
+ if (decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) {
+ strcpy(_vm->_global->_inter_resStr, decodePtr(valPtr[-3]));
+ valPtr[-3] = encodePtr(_vm->_global->_inter_resStr, kResStr);
+ }
+ strcat(_vm->_global->_inter_resStr, decodePtr(valPtr[-1]));
+ }
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+
+ } else if (operPtr[-2] == 3) {
+ valPtr[-3] -= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ } else if (operPtr[-2] == 4) {
+ valPtr[-3] |= valPtr[-1];
+ stkPos -= 2;
+ operPtr -= 2;
+ valPtr -= 2;
+ }
+ }
+ }
+ *operPtr = operation;
+ }
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp
new file mode 100644
index 0000000000..6061e75272
--- /dev/null
+++ b/engines/gob/scenery.cpp
@@ -0,0 +1,784 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/scenery.h"
+#include "gob/inter.h"
+#include "gob/video.h"
+#include "gob/draw.h"
+#include "gob/game.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "gob/anim.h"
+#include "gob/parse.h"
+#include "gob/cdrom.h"
+
+namespace Gob {
+
+Scenery::Scenery(GobEngine *vm) : _vm(vm) {
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ _spriteRefs[i] = 0;
+ _spriteResId[i] = 0;
+ }
+ for (i = 0; i < 70; i++ ) {
+ _staticPictToSprite[i] = 0;
+ _animPictToSprite[i] = 0;
+ }
+ for (i = 0; i < 10; i++) {
+ _staticPictCount[i] = 0;
+ _staticFromExt[i] = 0;
+ _staticResId[i] = 0;
+ _animPictCount[i] = 0;
+ _animFromExt[i] = 0;
+ _animResId[i] = 0;
+ }
+
+ _curStatic = 0;
+ _curStaticLayer = 0;
+
+ _toRedrawLeft = 0;
+ _toRedrawRight = 0;
+ _toRedrawTop = 0;
+ _toRedrawBottom = 0;
+
+ _animTop = 0;
+ _animLeft = 0;
+
+ _pCaptureCounter = 0;
+}
+
+int16 Scenery::loadStatic(char search) {
+ int16 tmp;
+ int16 *backsPtr;
+ int16 picsCount;
+ int16 resId;
+ int16 i;
+ int16 sceneryIndex;
+ char *dataPtr;
+ Static *ptr;
+ int16 offset;
+ int16 pictDescId;
+ int16 width;
+ int16 height;
+ int16 sprResId;
+ int16 sprIndex;
+
+ _vm->_inter->evalExpr(&sceneryIndex);
+ tmp = _vm->_inter->load16();
+ backsPtr = (int16 *)_vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += tmp * 2;
+ picsCount = _vm->_inter->load16();
+ resId = _vm->_inter->load16();
+ if (search) {
+ for (i = 0; i < 10; i++) {
+ if (_staticPictCount[i] != -1 && _staticResId[i] == resId) {
+ _vm->_global->_inter_execPtr += 8 * _staticPictCount[i];
+ return i;
+ }
+
+ if (_staticPictCount[i] == -1 && i < sceneryIndex)
+ sceneryIndex = i;
+ }
+ }
+
+ _staticPictCount[sceneryIndex] = picsCount;
+ _staticResId[sceneryIndex] = resId;
+
+ if (resId >= 30000) {
+ _staticFromExt[sceneryIndex] = 1;
+ dataPtr = _vm->_game->loadExtData(resId, 0, 0);
+ } else {
+ _staticFromExt[sceneryIndex] = 0;
+ dataPtr = _vm->_game->loadTotResource(resId);
+ }
+
+ ptr = &_statics[sceneryIndex];
+ ptr->dataPtr = dataPtr;
+
+ ptr->layersCount = (int16)READ_LE_UINT16(dataPtr);
+ dataPtr += 2;
+
+ ptr->layers = new StaticLayer*[ptr->layersCount];
+ ptr->pieces = new PieceDesc*[picsCount];
+ ptr->piecesFromExt = new int8[picsCount];
+
+ for (i = 0; i < ptr->layersCount; i++) {
+ offset = (int16)READ_LE_UINT16(&((int16 *)dataPtr)[i]);
+ ptr->layers[i] = (StaticLayer *)(dataPtr + offset - 2);
+
+ ptr->layers[i]->planeCount = (int16)READ_LE_UINT16(&ptr->layers[i]->planeCount);
+
+ for (int j = 0; j < ptr->layers[i]->planeCount; ++j) {
+ ptr->layers[i]->planes[j].destX = (int16)READ_LE_UINT16(&ptr->layers[i]->planes[j].destX);
+ ptr->layers[i]->planes[j].destY = (int16)READ_LE_UINT16(&ptr->layers[i]->planes[j].destY);
+ }
+
+ ptr->layers[i]->backResId = (int16)READ_LE_UINT16(backsPtr);
+ backsPtr++;
+ }
+
+ for (i = 0; i < picsCount; i++) {
+ pictDescId = _vm->_inter->load16();
+ if (pictDescId >= 30000) {
+ ptr->pieces[i] =
+ (PieceDesc *) _vm->_game->loadExtData(pictDescId, 0,
+ 0);
+ ptr->piecesFromExt[i] = 1;
+ } else {
+ ptr->pieces[i] =
+ (PieceDesc *)
+ _vm->_game->loadTotResource(pictDescId);
+ ptr->piecesFromExt[i] = 0;
+ }
+
+ width = _vm->_inter->load16();
+ height = _vm->_inter->load16();
+ sprResId = _vm->_inter->load16();
+ for (sprIndex = 0; sprIndex < 20; sprIndex++) {
+ if (_spriteResId[sprIndex] == sprResId)
+ break;
+ }
+
+ if (sprIndex < 20) {
+ _staticPictToSprite[7 * sceneryIndex + i] =
+ sprIndex;
+ _spriteRefs[sprIndex]++;
+ } else {
+ for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0;
+ sprIndex--);
+
+ _staticPictToSprite[7 * sceneryIndex + i] =
+ sprIndex;
+ _spriteRefs[sprIndex] = 1;
+ _spriteResId[sprIndex] = sprResId;
+ _vm->_draw->_spritesArray[sprIndex] =
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, width, height, 2);
+
+ _vm->_video->clearSurf(_vm->_draw->_spritesArray[sprIndex]);
+ _vm->_draw->_destSurface = sprIndex;
+ _vm->_draw->_spriteLeft = sprResId;
+ _vm->_draw->_transparency = 0;
+ _vm->_draw->_destSpriteX = 0;
+ _vm->_draw->_destSpriteY = 0;
+ _vm->_draw->spriteOperation(DRAW_LOADSPRITE);
+ }
+ }
+ return sceneryIndex + 100;
+}
+
+void Scenery::freeStatic(int16 index) {
+ int16 i;
+ int16 spr;
+
+ if (index == -1)
+ _vm->_inter->evalExpr(&index);
+
+ if (_staticPictCount[index] == -1)
+ return;
+
+ for (i = 0; i < _staticPictCount[index]; i++) {
+ if (_statics[index].piecesFromExt[i] == 1)
+ delete[] _statics[index].pieces[i];
+
+ spr = _staticPictToSprite[index * 7 + i];
+ _spriteRefs[spr]--;
+ if (_spriteRefs[spr] == 0) {
+ _vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[spr]);
+ _vm->_draw->_spritesArray[spr] = 0;
+ _spriteResId[spr] = -1;
+ }
+ }
+
+ delete[] _statics[index].layers;
+ delete[] _statics[index].pieces;
+ delete[] _statics[index].piecesFromExt;
+ if (_staticFromExt[index] == 1)
+ delete[] _statics[index].dataPtr;
+
+ _staticFromExt[index] = 0;
+ _staticPictCount[index] = -1;
+}
+
+void Scenery::renderStatic(int16 scenery, int16 layer) {
+ Static *ptr;
+ StaticLayer *layerPtr;
+ StaticPlane *planePtr;
+ int16 planeCount;
+ int16 order;
+ int16 plane;
+
+ int16 pieceIndex;
+ int16 pictIndex;
+
+ int16 left;
+ int16 right;
+ int16 top;
+ int16 bottom;
+
+ ptr = &_statics[scenery];
+ if (layer >= ptr->layersCount)
+ return;
+
+ layerPtr = ptr->layers[layer];
+
+ _vm->_draw->_spriteLeft = layerPtr->backResId;
+ if (_vm->_draw->_spriteLeft != -1) {
+ _vm->_draw->_destSpriteX = 0;
+ _vm->_draw->_destSpriteY = 0;
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_transparency = 0;
+ _vm->_draw->spriteOperation(DRAW_LOADSPRITE);
+ }
+
+ planeCount = layerPtr->planeCount;
+ for (order = 0; order < 10; order++) {
+ for (plane = 0, planePtr = layerPtr->planes;
+ plane < planeCount; plane++, planePtr++) {
+ if (planePtr->drawOrder != order)
+ continue;
+
+ pieceIndex = planePtr->pieceIndex;
+ pictIndex = planePtr->pictIndex - 1;
+
+ _vm->_draw->_destSpriteX = planePtr->destX;
+ _vm->_draw->_destSpriteY = planePtr->destY;
+ left = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].left);
+ right = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].right);
+ top = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].top);
+ bottom = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].bottom);
+
+ _vm->_draw->_sourceSurface =
+ _staticPictToSprite[scenery * 7 + pictIndex];
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_spriteLeft = left;
+ _vm->_draw->_spriteTop = top;
+ _vm->_draw->_spriteRight = right - left + 1;
+ _vm->_draw->_spriteBottom = bottom - top + 1;
+ _vm->_draw->_transparency = planePtr->transp ? 3 : 0;
+ _vm->_draw->spriteOperation(DRAW_BLITSURF);
+ }
+ }
+}
+
+void Scenery::interRenderStatic(void) {
+ int16 layer;
+ int16 index;
+
+ _vm->_inter->evalExpr(&index);
+ _vm->_inter->evalExpr(&layer);
+ renderStatic(index, layer);
+}
+
+void Scenery::interLoadCurLayer(void) {
+ _vm->_inter->evalExpr(&_curStatic);
+ _vm->_inter->evalExpr(&_curStaticLayer);
+}
+
+void Scenery::updateStatic(int16 orderFrom) {
+ StaticLayer *layerPtr;
+ PieceDesc **pictPtr;
+ StaticPlane *planePtr;
+ int16 planeCount;
+ int16 order;
+ int16 plane;
+ int16 pieceIndex;
+ int16 pictIndex;
+
+ int16 left;
+ int16 right;
+ int16 top;
+ int16 bottom;
+
+ if (_curStatic == -1)
+ return;
+
+ if (_curStaticLayer >= _statics[_curStatic].layersCount)
+ return;
+
+ layerPtr = _statics[_curStatic].layers[_curStaticLayer];
+ pictPtr = _statics[_curStatic].pieces;
+
+ planeCount = layerPtr->planeCount;
+
+ for (order = orderFrom; order < 10; order++) {
+ for (planePtr = layerPtr->planes, plane = 0;
+ plane < planeCount; plane++, planePtr++) {
+ if (planePtr->drawOrder != order)
+ continue;
+
+ pieceIndex = planePtr->pieceIndex;
+ pictIndex = planePtr->pictIndex - 1;
+ _vm->_draw->_destSpriteX = planePtr->destX;
+ _vm->_draw->_destSpriteY = planePtr->destY;
+
+ left = FROM_LE_16(pictPtr[pictIndex][pieceIndex].left);
+ right = FROM_LE_16(pictPtr[pictIndex][pieceIndex].right);
+ top = FROM_LE_16(pictPtr[pictIndex][pieceIndex].top);
+ bottom = FROM_LE_16(pictPtr[pictIndex][pieceIndex].bottom);
+
+ if (_vm->_draw->_destSpriteX > _toRedrawRight)
+ continue;
+
+ if (_vm->_draw->_destSpriteY > _toRedrawBottom)
+ continue;
+
+ if (_vm->_draw->_destSpriteX < _toRedrawLeft) {
+ left += _toRedrawLeft - _vm->_draw->_destSpriteX;
+ _vm->_draw->_destSpriteX = _toRedrawLeft;
+ }
+
+ if (_vm->_draw->_destSpriteY < _toRedrawTop) {
+ top += _toRedrawTop - _vm->_draw->_destSpriteY;
+ _vm->_draw->_destSpriteY = _toRedrawTop;
+ }
+
+ _vm->_draw->_spriteLeft = left;
+ _vm->_draw->_spriteTop = top;
+ _vm->_draw->_spriteRight = right - left + 1;
+ _vm->_draw->_spriteBottom = bottom - top + 1;
+
+ if (_vm->_draw->_spriteRight <= 0 || _vm->_draw->_spriteBottom <= 0)
+ continue;
+
+ if (_vm->_draw->_destSpriteX + _vm->_draw->_spriteRight - 1 >
+ _toRedrawRight)
+ _vm->_draw->_spriteRight =
+ _toRedrawRight - _vm->_draw->_destSpriteX + 1;
+
+ if (_vm->_draw->_destSpriteY + _vm->_draw->_spriteBottom - 1 >
+ _toRedrawBottom)
+ _vm->_draw->_spriteBottom =
+ _toRedrawBottom - _vm->_draw->_destSpriteY + 1;
+
+ _vm->_draw->_sourceSurface =
+ _staticPictToSprite[_curStatic * 7 +
+ pictIndex];
+ _vm->_draw->_destSurface = 21;
+ _vm->_draw->_transparency = planePtr->transp ? 3 : 0;
+ _vm->_draw->spriteOperation(DRAW_BLITSURF);
+ }
+ }
+}
+
+int16 Scenery::loadAnim(char search) {
+ int16 picsCount;
+ int16 resId;
+ int16 i;
+ int16 sceneryIndex;
+ char *dataPtr;
+ Animation *ptr;
+ int16 offset;
+ int16 pictDescId;
+ int16 width;
+ int16 height;
+ int16 sprResId;
+ int16 sprIndex;
+
+ if (_vm->_cdrom->_cdPlaying) {
+ while (_vm->_cdrom->getTrackPos() != -1)
+ _vm->_util->longDelay(50);
+
+ _vm->_cdrom->_cdPlaying = false;
+ }
+
+ _vm->_inter->evalExpr(&sceneryIndex);
+ picsCount = _vm->_inter->load16();
+ resId = _vm->_inter->load16();
+
+ if (search) {
+ for (i = 0; i < 10; i++) {
+ if (_animPictCount[i] != 0
+ && _animResId[i] == resId) {
+ _vm->_global->_inter_execPtr += 8 * _animPictCount[i];
+ return i;
+ }
+
+ if (_animPictCount[i] == 0 && i < sceneryIndex)
+ sceneryIndex = i;
+ }
+ }
+
+ _animPictCount[sceneryIndex] = picsCount;
+ _animResId[sceneryIndex] = resId;
+
+ if (resId >= 30000) {
+ _animFromExt[sceneryIndex] = 1;
+ dataPtr = _vm->_game->loadExtData(resId, 0, 0);
+ } else {
+ _animFromExt[sceneryIndex] = 0;
+ dataPtr = _vm->_game->loadTotResource(resId);
+ }
+
+ ptr = &_animations[sceneryIndex];
+ ptr->dataPtr = dataPtr;
+
+ ptr->layersCount = READ_LE_UINT16(dataPtr);
+ dataPtr += 2;
+
+ ptr->layers = new AnimLayer*[ptr->layersCount];
+ ptr->pieces = new PieceDesc*[picsCount];
+ ptr->piecesFromExt = new int8[picsCount];
+
+ for (i = 0; i < ptr->layersCount; i++) {
+ offset = (int16)READ_LE_UINT16(&((int16 *)dataPtr)[i]);
+ ptr->layers[i] = (AnimLayer *) (dataPtr + offset - 2);
+
+ ptr->layers[i]->unknown0 = (int16)READ_LE_UINT16(&ptr->layers[i]->unknown0);
+ ptr->layers[i]->posX = (int16)READ_LE_UINT16(&ptr->layers[i]->posX);
+ ptr->layers[i]->posY = (int16)READ_LE_UINT16(&ptr->layers[i]->posY);
+ ptr->layers[i]->animDeltaX = (int16)READ_LE_UINT16(&ptr->layers[i]->animDeltaX);
+ ptr->layers[i]->animDeltaY = (int16)READ_LE_UINT16(&ptr->layers[i]->animDeltaY);
+ ptr->layers[i]->framesCount = (int16)READ_LE_UINT16(&ptr->layers[i]->framesCount);
+ }
+
+ for (i = 0; i < picsCount; i++) {
+ pictDescId = _vm->_inter->load16();
+ if (pictDescId >= 30000) {
+ ptr->pieces[i] =
+ (PieceDesc *) _vm->_game->loadExtData(pictDescId, 0,
+ 0);
+ ptr->piecesFromExt[i] = 1;
+ } else {
+ ptr->pieces[i] =
+ (PieceDesc *)
+ _vm->_game->loadTotResource(pictDescId);
+ ptr->piecesFromExt[i] = 0;
+ }
+
+ width = _vm->_inter->load16();
+ height = _vm->_inter->load16();
+ sprResId = _vm->_inter->load16();
+ for (sprIndex = 0; sprIndex < 20; sprIndex++) {
+ if (_spriteResId[sprIndex] == sprResId)
+ break;
+ }
+
+ if (sprIndex < 20) {
+ _animPictToSprite[7 * sceneryIndex + i] = sprIndex;
+ _spriteRefs[sprIndex]++;
+ } else {
+ for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0;
+ sprIndex--);
+
+ _animPictToSprite[7 * sceneryIndex + i] = sprIndex;
+ _spriteRefs[sprIndex] = 1;
+ _spriteResId[sprIndex] = sprResId;
+ _vm->_draw->_spritesArray[sprIndex] =
+ _vm->_video->initSurfDesc(_vm->_global->_videoMode, width, height, 2);
+
+ _vm->_video->clearSurf(_vm->_draw->_spritesArray[sprIndex]);
+ _vm->_draw->_destSurface = sprIndex;
+ _vm->_draw->_spriteLeft = sprResId;
+ _vm->_draw->_transparency = 0;
+ _vm->_draw->_destSpriteX = 0;
+ _vm->_draw->_destSpriteY = 0;
+ _vm->_draw->spriteOperation(DRAW_LOADSPRITE);
+ }
+ }
+ return sceneryIndex + 100;
+}
+
+// flags & 1 - do capture all area animation is occupying
+// flags & 4 == 0 - calculate animation final size
+// flags & 2 != 0 - don't check with "toRedraw"'s
+// flags & 4 != 0 - checkk view toRedraw
+void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags,
+ int16 drawDeltaX, int16 drawDeltaY, char doDraw) {
+ AnimLayer *layerPtr;
+ PieceDesc **pictPtr;
+ AnimFramePiece *framePtr;
+
+ uint16 pieceIndex;
+ uint16 pictIndex;
+
+ int16 left;
+ int16 right;
+ int16 top;
+ int16 bottom;
+
+ byte highX;
+ byte highY;
+
+ int16 i;
+ int16 transp;
+
+ int16 destX;
+ int16 destY;
+
+ if (layer >= _animations[animation].layersCount)
+ return;
+
+ layerPtr = _animations[animation].layers[layer];
+
+ if (frame >= layerPtr->framesCount)
+ return;
+
+ if (flags & 1) // Do capture
+ {
+ updateAnim(layer, frame, animation, 0, drawDeltaX,
+ drawDeltaY, 0);
+
+ if (_toRedrawLeft == -12345) // Some magic number?
+ return;
+
+ _vm->_game->capturePush(_toRedrawLeft, _toRedrawTop,
+ _toRedrawRight - _toRedrawLeft + 1,
+ _toRedrawBottom - _toRedrawTop + 1);
+
+ *_pCaptureCounter = *_pCaptureCounter + 1;
+ }
+ pictPtr = _animations[animation].pieces;
+ framePtr = layerPtr->frames;
+
+ for (i = 0; i < frame; i++, framePtr++) {
+ while (framePtr->notFinal == 1)
+ framePtr++;
+ }
+
+ if ((flags & 4) == 0) {
+ _toRedrawLeft = -12345;
+ } else {
+ _toRedrawLeft =
+ MAX(_toRedrawLeft, _vm->_anim->_areaLeft);
+ _toRedrawTop =
+ MAX(_toRedrawTop, _vm->_anim->_areaTop);
+ _toRedrawRight =
+ MIN(_toRedrawRight,
+ (int16)(_vm->_anim->_areaLeft + _vm->_anim->_areaWidth - 1));
+ _toRedrawBottom =
+ MIN(_toRedrawBottom,
+ (int16)(_vm->_anim->_areaTop + _vm->_anim->_areaHeight - 1));
+ }
+
+ transp = layerPtr->transp ? 3 : 0;
+
+ framePtr--;
+ do {
+ framePtr++;
+
+ pieceIndex = framePtr->pieceIndex;
+ pictIndex = framePtr->pictIndex;
+
+ destX = framePtr->destX;
+ destY = framePtr->destY;
+
+ highX = pictIndex & 0xc0;
+ highY = pictIndex & 0x30;
+ highX >>= 6;
+ highY >>= 4;
+ if (destX >= 0)
+ destX += ((uint16)highX) << 7;
+ else
+ destX -= ((uint16)highX) << 7;
+
+ if (destY >= 0)
+ destY += ((uint16)highY) << 7;
+ else
+ destY -= ((uint16)highY) << 7;
+
+ if (drawDeltaX == 1000)
+ destX += layerPtr->posX;
+ else
+ destX += drawDeltaX;
+
+ if (drawDeltaY == 1000)
+ destY += layerPtr->posY;
+ else
+ destY += drawDeltaY;
+
+ pictIndex = (pictIndex & 15) - 1;
+
+ left = FROM_LE_16(pictPtr[pictIndex][pieceIndex].left);
+ right = FROM_LE_16(pictPtr[pictIndex][pieceIndex].right);
+ top = FROM_LE_16(pictPtr[pictIndex][pieceIndex].top);
+ bottom = FROM_LE_16(pictPtr[pictIndex][pieceIndex].bottom);
+
+ if (flags & 2) {
+ if (destX < _vm->_anim->_areaLeft) {
+ left += _vm->_anim->_areaLeft - destX;
+ destX = _vm->_anim->_areaLeft;
+ }
+
+ if (left <= right
+ && destX + right - left >=
+ _vm->_anim->_areaLeft + _vm->_anim->_areaWidth)
+ right -=
+ (destX + right - left) -
+ (_vm->_anim->_areaLeft + _vm->_anim->_areaWidth) +
+ 1;
+
+ if (destY < _vm->_anim->_areaTop) {
+ top += _vm->_anim->_areaTop - destY;
+ destY = _vm->_anim->_areaTop;
+ }
+
+ if (top <= bottom
+ && destY + bottom - top >=
+ _vm->_anim->_areaTop + _vm->_anim->_areaHeight)
+ bottom -=
+ (destY + bottom - top) -
+ (_vm->_anim->_areaTop + _vm->_anim->_areaHeight) +
+ 1;
+
+ } else if (flags & 4) {
+ if (destX < _toRedrawLeft) {
+ left += _toRedrawLeft - destX;
+ destX = _toRedrawLeft;
+ }
+
+ if (left <= right
+ && destX + right - left > _toRedrawRight)
+ right -=
+ destX + right - left - _toRedrawRight;
+
+ if (destY < _toRedrawTop) {
+ top += _toRedrawTop - destY;
+ destY = _toRedrawTop;
+ }
+
+ if (top <= bottom
+ && destY + bottom - top > _toRedrawBottom)
+ bottom -=
+ destY + bottom - top - _toRedrawBottom;
+ }
+
+ if (left > right || top > bottom)
+ continue;
+
+ if (doDraw) {
+ _vm->_draw->_sourceSurface =
+ _animPictToSprite[animation * 7 + pictIndex];
+ _vm->_draw->_destSurface = 21;
+
+ _vm->_draw->_spriteLeft = left;
+ _vm->_draw->_spriteTop = top;
+ _vm->_draw->_spriteRight = right - left + 1;
+ _vm->_draw->_spriteBottom = bottom - top + 1;
+ _vm->_draw->_destSpriteX = destX;
+ _vm->_draw->_destSpriteY = destY;
+ _vm->_draw->_transparency = transp;
+ _vm->_draw->spriteOperation(DRAW_BLITSURF);
+ }
+
+ if ((flags & 4) == 0) {
+ if (_toRedrawLeft == -12345) {
+ _toRedrawLeft = destX;
+ _animLeft = destX;
+ _toRedrawTop = destY;
+ _animTop = destY;
+ _toRedrawRight = destX + right - left;
+ _toRedrawBottom = destY + bottom - top;
+ } else {
+ _toRedrawLeft =
+ MIN(_toRedrawLeft, destX);
+ _toRedrawTop =
+ MIN(_toRedrawTop, destY);
+ _toRedrawRight =
+ MAX(_toRedrawRight,
+ (int16)(destX + right - left));
+ _toRedrawBottom =
+ MAX(_toRedrawBottom,
+ (int16)(destY + bottom - top));
+ }
+ }
+ } while (framePtr->notFinal == 1);
+}
+
+void Scenery::freeAnim(int16 animation) {
+ int16 i;
+ int16 spr;
+
+ if (animation == -1)
+ _vm->_inter->evalExpr(&animation);
+
+ if (_animPictCount[animation] == 0)
+ return;
+
+ for (i = 0; i < _animPictCount[animation]; i++) {
+ if (_animations[animation].piecesFromExt[i] == 1)
+ delete[] _animations[animation].pieces[i];
+
+ spr = _animPictToSprite[animation * 7 + i];
+ _spriteRefs[spr]--;
+ if (_spriteRefs[spr] == 0) {
+ _vm->_video->freeSurfDesc(_vm->_draw->_spritesArray[spr]);
+
+ _vm->_draw->_spritesArray[spr] = 0;
+ _spriteResId[spr] = -1;
+ }
+ }
+
+ delete[] _animations[animation].layers;
+ delete[] _animations[animation].pieces;
+ delete[] _animations[animation].piecesFromExt;
+ if (_animFromExt[animation] == 1)
+ delete[] _animations[animation].dataPtr;
+
+ _animFromExt[animation] = 0;
+ _animPictCount[animation] = 0;
+}
+
+void Scenery::interUpdateAnim(void) {
+ int16 deltaX;
+ int16 deltaY;
+ int16 flags;
+ int16 frame;
+ int16 layer;
+ int16 animation;
+
+ _vm->_inter->evalExpr(&deltaX);
+ _vm->_inter->evalExpr(&deltaY);
+ _vm->_inter->evalExpr(&animation);
+ _vm->_inter->evalExpr(&layer);
+ _vm->_inter->evalExpr(&frame);
+ flags = _vm->_inter->load16();
+ updateAnim(layer, frame, animation, flags, deltaX, deltaY, 1);
+}
+
+void Scenery::interStoreParams(void) {
+ AnimLayer *layerPtr;
+ int16 animation;
+ int16 layer;
+ int16 var;
+
+ warning("interStoreParams: Storing...");
+
+ _vm->_inter->evalExpr(&animation);
+ _vm->_inter->evalExpr(&layer);
+ layerPtr = _animations[animation].layers[layer];
+
+ var = _vm->_parse->parseVarIndex();
+ WRITE_VAR_OFFSET(var, layerPtr->animDeltaX);
+
+ var = _vm->_parse->parseVarIndex();
+ WRITE_VAR_OFFSET(var, layerPtr->animDeltaY);
+
+ var = _vm->_parse->parseVarIndex();
+ WRITE_VAR_OFFSET(var, layerPtr->unknown0);
+
+ var = _vm->_parse->parseVarIndex();
+ WRITE_VAR_OFFSET(var, layerPtr->framesCount);
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/scenery.h b/engines/gob/scenery.h
new file mode 100644
index 0000000000..119055f7bd
--- /dev/null
+++ b/engines/gob/scenery.h
@@ -0,0 +1,148 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_SCENERY_H
+#define GOB_SCENERY_H
+
+namespace Gob {
+
+class Scenery {
+public:
+#pragma START_PACK_STRUCTS
+ struct PieceDesc {
+ int16 left; //NOTE:
+ int16 right; //These are stored in Little Endian format
+ int16 top; //And should be converted by client code when accessed
+ int16 bottom; //i.e. use FROM_LE_16()
+ } GCC_PACK;
+
+ struct StaticPlane {
+ int8 pictIndex;
+ int8 pieceIndex;
+ int8 drawOrder;
+ int16 destX;
+ int16 destY;
+ int8 transp;
+ } GCC_PACK;
+
+ struct StaticLayer {
+ int16 backResId;
+ int16 planeCount;
+ StaticPlane planes[1];
+ } GCC_PACK;
+
+ // Animations
+
+ struct AnimFramePiece {
+ byte pictIndex;
+ byte pieceIndex;
+ int8 destX;
+ int8 destY;
+ int8 notFinal;
+ } GCC_PACK;
+
+ struct AnimLayer {
+ int16 unknown0;
+ int16 posX;
+ int16 posY;
+ int16 animDeltaX;
+ int16 animDeltaY;
+ int8 transp;
+ int16 framesCount;
+ AnimFramePiece frames[1];
+ } GCC_PACK;
+#pragma END_PACK_STRUCTS
+
+ struct Static {
+ int16 layersCount;
+ StaticLayer **layers;
+ PieceDesc **pieces;
+ int8 *piecesFromExt;
+ char *dataPtr;
+ Static() : layersCount(0), layers(0), pieces(0),
+ piecesFromExt(0), dataPtr(0) {}
+ };
+
+ struct Animation {
+ int16 layersCount;
+ AnimLayer **layers;
+ PieceDesc **pieces;
+ int8 *piecesFromExt;
+ char *dataPtr;
+ Animation() : layersCount(0), layers(0), pieces(0),
+ piecesFromExt(0), dataPtr(0) {}
+ };
+
+ // Global variables
+
+ char _spriteRefs[20];
+ int16 _spriteResId[20];
+
+ char _staticPictToSprite[70];
+ int16 _staticPictCount[10];
+ Static _statics[10];
+ char _staticFromExt[10];
+ int16 _staticResId[10];
+
+ char _animPictToSprite[70];
+ int16 _animPictCount[10];
+ char _animFromExt[10];
+ Animation _animations[10];
+ int16 _animResId[10];
+
+ int16 _curStatic;
+ int16 _curStaticLayer;
+
+ int16 _toRedrawLeft;
+ int16 _toRedrawRight;
+ int16 _toRedrawTop;
+ int16 _toRedrawBottom;
+
+ int16 _animTop;
+ int16 _animLeft;
+
+ int16 *_pCaptureCounter;
+
+ // Functions
+
+ int16 loadStatic(char search);
+ void freeStatic(int16 index);
+ void renderStatic(int16 scenery, int16 layer);
+ void interRenderStatic(void);
+ void interLoadCurLayer(void);
+ void updateStatic(int16 orderFrom);
+ int16 loadAnim(char search);
+ void updateAnim(int16 layer, int16 frame, int16 animation, int16 flags,
+ int16 drawDeltaX, int16 drawDeltaY, char doDraw);
+ void freeAnim(int16 animation);
+ void interUpdateAnim(void);
+ void interStoreParams(void);
+
+ Scenery(GobEngine *vm);
+
+protected:
+ GobEngine *_vm;
+};
+
+} // End of namespace Gob
+
+#endif /* __SCENERY_H */
diff --git a/engines/gob/sound.cpp b/engines/gob/sound.cpp
new file mode 100644
index 0000000000..51c36ef22a
--- /dev/null
+++ b/engines/gob/sound.cpp
@@ -0,0 +1,145 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/sound.h"
+
+namespace Gob {
+
+void Snd::SquareWaveStream::playNote(int freq, int32 ms, uint rate) {
+ _rate = rate;
+ _periodLength = _rate / (2 * freq);
+ _periodSamples = 0;
+ _sampleValue = 6000;
+ if (ms == -1) {
+ _remainingSamples = 1;
+ _beepForever = true;
+ } else {
+ _remainingSamples = (_rate * ms) / 1000;
+ _beepForever = false;
+ }
+}
+
+int Snd::SquareWaveStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samples = 0;
+
+ while (samples < numSamples && _remainingSamples > 0) {
+ *buffer++ = _sampleValue;
+ if (_periodSamples++ > _periodLength) {
+ _periodSamples = 0;
+ _sampleValue = -_sampleValue;
+ }
+ samples++;
+ if (!_beepForever)
+ _remainingSamples--;
+ }
+
+ return samples;
+}
+
+Snd::Snd(GobEngine *vm) : _vm(vm) {
+ //CleanupFuncPtr cleanupFunc;// = &snd_cleanupFuncCallback();
+ _cleanupFunc = 0;
+ for (int i = 0; i < ARRAYSIZE(_loopingSounds); i++)
+ _loopingSounds[i] = NULL;
+ _playingSound = 0;
+}
+
+void Snd::loopSounds(void) {
+ for (int i = 0; i < ARRAYSIZE(_loopingSounds); i++) {
+ SoundDesc *snd = _loopingSounds[i];
+ if (snd && !_vm->_mixer->isSoundHandleActive(snd->handle)) {
+ if (snd->repCount-- > 0) {
+ _vm->_mixer->playRaw(&snd->handle, snd->data, snd->size, snd->frequency, 0);
+ } else {
+ _loopingSounds[i] = NULL;
+ }
+ }
+ }
+}
+
+void Snd::setBlasterPort(int16 port) {return;}
+
+void Snd::speakerOn(int16 frequency, int32 length) {
+ _speakerStream.playNote(frequency, length, _vm->_mixer->getOutputRate());
+ if (!_vm->_mixer->isSoundHandleActive(_speakerHandle)) {
+ _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, &_speakerStream, -1, 255, 0, false);
+ }
+}
+
+void Snd::speakerOff(void) {
+ _vm->_mixer->stopHandle(_speakerHandle);
+}
+
+void Snd::playSample(Snd::SoundDesc *sndDesc, int16 repCount, int16 frequency) {
+ assert(frequency > 0);
+
+ if (!_vm->_mixer->isSoundHandleActive(sndDesc->handle)) {
+ _vm->_mixer->playRaw(&sndDesc->handle, sndDesc->data, sndDesc->size, frequency, 0);
+ }
+
+ sndDesc->repCount = repCount - 1;
+ sndDesc->frequency = frequency;
+
+ if (repCount > 1) {
+ for (int i = 0; i < ARRAYSIZE(_loopingSounds); i++) {
+ if (!_loopingSounds[i]) {
+ _loopingSounds[i] = sndDesc;
+ return;
+ }
+ }
+ warning("Looping sounds list is full");
+ }
+}
+
+void Snd::writeAdlib(int16 port, int16 data) {
+ return;
+}
+
+Snd::SoundDesc *Snd::loadSoundData(const char *path) {
+ Snd::SoundDesc *sndDesc;
+
+ sndDesc = new Snd::SoundDesc;
+ sndDesc->size = _vm->_dataio->getDataSize(path);
+ sndDesc->data = _vm->_dataio->getData(path);
+
+ return sndDesc;
+}
+
+void Snd::freeSoundData(Snd::SoundDesc *sndDesc) {
+ _vm->_mixer->stopHandle(sndDesc->handle);
+
+ for (int i = 0; i < ARRAYSIZE(_loopingSounds); i++) {
+ if (_loopingSounds[i] == sndDesc)
+ _loopingSounds[i] = NULL;
+ }
+
+ delete[] sndDesc->data;
+ delete sndDesc;
+}
+
+} // End of namespace Gob
+
+
+
diff --git a/engines/gob/sound.h b/engines/gob/sound.h
new file mode 100644
index 0000000000..169c2e03a4
--- /dev/null
+++ b/engines/gob/sound.h
@@ -0,0 +1,104 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_SOUND_H
+#define GOB_SOUND_H
+
+#include "sound/audiostream.h"
+
+namespace Gob {
+
+class Snd {
+public:
+ struct SoundDesc {
+ Audio::SoundHandle handle;
+ char *data;
+ int32 size;
+ int16 repCount;
+ int16 timerTicks;
+ int16 inClocks;
+ int16 frequency;
+ int16 flag;
+ SoundDesc() : data(0), size(0), repCount(0), timerTicks(0),
+ inClocks(0), frequency(0), flag(0) {}
+ };
+
+ typedef void (*CleanupFuncPtr) (int16);
+
+ SoundDesc *_loopingSounds[5]; // Should be enough
+ char _playingSound;
+ CleanupFuncPtr _cleanupFunc;
+
+ Snd(GobEngine *vm);
+ void speakerOn(int16 frequency, int32 length);
+ void speakerOff(void);
+ SoundDesc *loadSoundData(const char *path);
+ void stopSound(int16 arg){return;}
+ void loopSounds(void);
+ void playSample(SoundDesc *sndDesc, int16 repCount, int16 frequency);
+ void playComposition(Snd::SoundDesc ** samples, int16 *composit, int16 freqVal) {;}
+ void waitEndPlay(void) {;}
+ void freeSoundData(SoundDesc *sndDesc);
+
+protected:
+ // TODO: This is a very primitive square wave generator. The only thing is
+ // has in common with the PC speaker is that it sounds terrible.
+ class SquareWaveStream : public AudioStream {
+ private:
+ uint _rate;
+ bool _beepForever;
+ uint32 _periodLength;
+ uint32 _periodSamples;
+ uint32 _remainingSamples;
+ int16 _sampleValue;
+
+ public:
+ SquareWaveStream() {}
+ ~SquareWaveStream() {}
+
+ void playNote(int freq, int32 ms, uint rate);
+
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool endOfData() const { return _remainingSamples == 0; }
+ bool isStereo() const { return false; }
+ int getRate() const { return _rate; }
+ };
+
+ SquareWaveStream _speakerStream;
+ Audio::SoundHandle _speakerHandle;
+
+ GobEngine *_vm;
+
+ void cleanupFuncCallback() {;}
+ int16 checkProAudio(void) {return 0;}
+ int16 checkAdlib(void) {return 0;}
+ int16 checkBlaster(void) {return 0;}
+
+ void writeAdlib(int16 port, int16 data);
+ void setBlasterPort(int16 port);
+ void setResetTimerFlag(char flag){return;}
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/timer.cpp b/engines/gob/timer.cpp
new file mode 100644
index 0000000000..0b3bc06588
--- /dev/null
+++ b/engines/gob/timer.cpp
@@ -0,0 +1,37 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/sound.h"
+#include "gob/timer.h"
+
+namespace Gob {
+
+void GTimer::enableTimer() {
+ debug(4, "STUB: GTimer::enableTimer()");
+}
+
+void GTimer::disableTimer() {
+ debug(4, "STUB: GTimer::disableTimer()");
+}
+}
diff --git a/engines/gob/timer.h b/engines/gob/timer.h
new file mode 100644
index 0000000000..d47d20b376
--- /dev/null
+++ b/engines/gob/timer.h
@@ -0,0 +1,43 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_TIMER_H
+#define GOB_TIMER_H
+
+namespace Gob {
+
+class GTimer {
+public:
+ typedef void (* TickHandler) (void);
+
+ void enableTimer(void);
+ void disableTimer(void);
+ void setHandler(void);
+ void restoreHandler(void);
+ void addTicks(int16 ticks);
+ void setTickHandler(TickHandler handler);
+ int32 getTicks(void);
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
new file mode 100644
index 0000000000..7e6996f00f
--- /dev/null
+++ b/engines/gob/util.cpp
@@ -0,0 +1,486 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/timer.h"
+#include "gob/util.h"
+#include "gob/draw.h"
+#include "gob/game.h"
+
+namespace Gob {
+
+Util::Util(GobEngine *vm) : _vm(vm) {
+ _mouseX = 0;
+ _mouseY = 0;
+ _mouseButtons = 0;
+ for (int i = 0; i < KEYBUFSIZE; i++)
+ _keyBuffer[i] = 0;
+ _keyBufferHead = 0;
+ _keyBufferTail = 0;
+}
+
+void Util::addKeyToBuffer(int16 key) {
+ if ((_keyBufferHead + 1) % KEYBUFSIZE == _keyBufferTail) {
+ warning("key buffer overflow!");
+ return;
+ }
+
+ _keyBuffer[_keyBufferHead] = key;
+ _keyBufferHead = (_keyBufferHead + 1) % KEYBUFSIZE;
+}
+
+bool Util::keyBufferEmpty() {
+ return (_keyBufferHead == _keyBufferTail);
+}
+
+bool Util::getKeyFromBuffer(int16& key) {
+ if (_keyBufferHead == _keyBufferTail) return false;
+
+ key = _keyBuffer[_keyBufferTail];
+ _keyBufferTail = (_keyBufferTail + 1) % KEYBUFSIZE;
+
+ return true;
+}
+
+
+void Util::initInput(void) {
+ _mouseX = _mouseY = _mouseButtons = 0;
+ _keyBufferHead = _keyBufferTail = 0;
+}
+
+void Util::waitKey(void) {
+ // FIXME: wrong function name? This functions clears the keyboard buffer.
+ processInput();
+ _keyBufferHead = _keyBufferTail = 0;
+}
+
+int16 Util::translateKey(int16 key) {
+ struct keyS {
+ int16 from;
+ int16 to;
+ } keys[] = {
+ {8, 0x0e08}, // Backspace
+ {32, 0x3920}, // Space
+ {13, 0x1C0D}, // Enter
+ {27, 0x011b}, // ESC
+ {127, 0x5300}, // Del
+ {273, 0x4800}, // Up arrow
+ {274, 0x5000}, // Down arrow
+ {275, 0x4D00}, // Right arrow
+ {276, 0x4B00}, // Left arrow
+ {282, 0x3b00}, // F1
+ {283, 0x3c00}, // F2
+ {284, 0x3d00}, // F3
+ {285, 0x3E00}, // F4
+ {286, 0x011b}, // F5
+ {287, 0x4000}, // F6
+ {288, 0x4100}, // F7
+ {289, 0x4200}, // F8
+ {290, 0x4300}, // F9
+ {291, 0x4400} // F10
+ };
+ int i;
+
+ for (i = 0; i < ARRAYSIZE(keys); i++)
+ if (key == keys[i].from)
+ return keys[i].to;
+
+ if (key < 32 || key >= 128)
+ return 0;
+
+ return key;
+}
+
+int16 Util::getKey(void) {
+ int16 key;
+
+ while (!getKeyFromBuffer(key)) {
+ processInput();
+
+ if (keyBufferEmpty())
+ g_system->delayMillis(10);
+ }
+ return translateKey(key);
+}
+
+int16 Util::checkKey(void) {
+ int16 key;
+
+ if (!getKeyFromBuffer(key))
+ key = 0;
+
+ return translateKey(key);
+}
+
+int16 Util::getRandom(int16 max) {
+ return _vm->_rnd.getRandomNumber(max - 1);
+}
+
+void Util::processInput() {
+ OSystem::Event event;
+ while (g_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ _mouseButtons |= 1;
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ _mouseButtons |= 2;
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _mouseButtons &= ~1;
+ break;
+ case OSystem::EVENT_RBUTTONUP:
+ _mouseButtons &= ~2;
+ break;
+ case OSystem::EVENT_KEYDOWN:
+ addKeyToBuffer(event.kbd.keycode);
+ break;
+ case OSystem::EVENT_KEYUP:
+ break;
+ case OSystem::EVENT_QUIT:
+ g_system->quit();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void Util::getMouseState(int16 *pX, int16 *pY, int16 *pButtons) {
+ *pX = _mouseX;
+ *pY = _mouseY;
+
+ if (pButtons != 0)
+ *pButtons = _mouseButtons;
+}
+
+void Util::setMousePos(int16 x, int16 y) {
+ g_system->warpMouse(x, y);
+}
+
+void Util::longDelay(uint16 msecs) {
+ uint32 time = g_system->getMillis() + msecs;
+ do {
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+ processInput();
+ delay(25);
+ } while (g_system->getMillis() < time);
+}
+
+void Util::delay(uint16 msecs) {
+ g_system->delayMillis(msecs);
+}
+
+void Util::beep(int16 freq) {
+ if (_vm->_global->_soundFlags == 0)
+ return;
+
+ _vm->_snd->speakerOn(freq, 50);
+}
+
+uint32 Util::getTimeKey(void) {
+ return g_system->getMillis();
+}
+
+void Util::waitMouseUp(void) {
+ int16 x;
+ int16 y;
+ int16 buttons;
+
+ do {
+ processInput();
+ getMouseState(&x, &y, &buttons);
+ if (buttons != 0) delay(10);
+ } while (buttons != 0);
+}
+
+void Util::waitMouseDown(void) {
+ int16 x;
+ int16 y;
+ int16 buttons;
+
+ do {
+ processInput();
+ getMouseState(&x, &y, &buttons);
+ if (buttons == 0) delay(10);
+ } while (buttons == 0);
+}
+
+/* NOT IMPLEMENTED */
+int16 Util::calcDelayTime() {
+ return 0;
+}
+
+/* NOT IMPLEMENTED */
+void Util::checkJoystick() {
+ _vm->_global->_useJoystick = 0;
+}
+
+void Util::setFrameRate(int16 rate) {
+ if (rate == 0)
+ rate = 1;
+
+ _vm->_global->_frameWaitTime = 1000 / rate;
+ _vm->_global->_startFrameTime = getTimeKey();
+}
+
+void Util::waitEndFrame() {
+ int32 time;
+
+ _vm->_video->waitRetrace(_vm->_global->_videoMode);
+
+ time = getTimeKey() - _vm->_global->_startFrameTime;
+ if (time > 1000 || time < 0) {
+ _vm->_global->_startFrameTime = getTimeKey();
+ return;
+ }
+ if (_vm->_global->_frameWaitTime - time > 0) {
+ delay(_vm->_global->_frameWaitTime - time);
+ }
+ _vm->_global->_startFrameTime = getTimeKey();
+}
+
+int16 joy_getState() {
+ return 0;
+}
+
+int16 joy_calibrate() {
+ return 0;
+}
+
+Video::FontDesc *Util::loadFont(const char *path) {
+ Video::FontDesc *fontDesc = new Video::FontDesc;
+ char *data;
+
+ if (fontDesc == 0)
+ return 0;
+
+ data = _vm->_dataio->getData(path);
+ if (data == 0) {
+ delete fontDesc;
+ return 0;
+ }
+
+ fontDesc->dataPtr = data + 4;
+ fontDesc->itemWidth = data[0] & 0x7f;
+ fontDesc->itemHeight = data[1];
+ fontDesc->startItem = data[2];
+ fontDesc->endItem = data[3];
+
+ fontDesc->itemSize =
+ ((fontDesc->itemWidth - 1) / 8 + 1) * fontDesc->itemHeight;
+ fontDesc->bitWidth = fontDesc->itemWidth;
+
+ if (data[0] & 0x80)
+ fontDesc->extraData =
+ data + 4 + fontDesc->itemSize * (fontDesc->endItem -
+ fontDesc->startItem + 1);
+ else
+ fontDesc->extraData = 0;
+ return fontDesc;
+}
+
+void Util::freeFont(Video::FontDesc * fontDesc) {
+ delete[] (fontDesc->dataPtr - 4);
+ delete fontDesc;
+}
+
+void Util::clearPalette(void) {
+ int16 i;
+ byte colors[768];
+
+ if (_vm->_global->_videoMode != 0x13)
+ error("clearPalette: Video mode 0x%x is not supported!",
+ _vm->_global->_videoMode);
+
+ if (_vm->_global->_setAllPalette) {
+ for (i = 0; i < 768; i++)
+ colors[i] = 0;
+ g_system->setPalette(colors, 0, 256);
+
+ return;
+ }
+
+ for (i = 0; i < 16; i++)
+ _vm->_video->setPalElem(i, 0, 0, 0, 0, _vm->_global->_videoMode);
+}
+
+void Util::insertStr(const char *str1, char *str2, int16 pos) {
+ int16 len1;
+ int16 i;
+ int16 from;
+
+ i = strlen(str2);
+ len1 = strlen(str1);
+ if (pos < i)
+ from = pos;
+ else
+ from = i;
+
+ for (; i >= from; i--)
+ str2[len1 + i] = str2[i];
+
+ for (i = 0; i < len1; i++)
+ str2[i + from] = str1[i];
+}
+
+void Util::cutFromStr(char *str, int16 from, int16 cutlen) {
+ int16 len;
+ int16 i;
+
+ //log_write("cutFromStr: str = %s, ", str);
+ len = strlen(str);
+ if (from >= len)
+ return;
+ if (from + cutlen > len) {
+ str[from] = 0;
+ //log_write("res = %s\n", str);
+ return;
+ }
+
+ i = from;
+ do {
+ str[i] = str[i + cutlen];
+ i++;
+ } while (str[i] != 0);
+ //log_write("res = %s\n", str);
+}
+
+void Util::listInsertFront(List * list, void *data) {
+ ListNode *node;
+
+ node = new ListNode;
+ if (list->pHead != 0) {
+ node->pData = data;
+ node->pNext = list->pHead;
+ node->pPrev = 0;
+ list->pHead->pPrev = node;
+ list->pHead = node;
+ } else {
+ list->pHead = node;
+ list->pTail = node;
+ node->pData = data;
+ node->pNext = 0;
+ node->pPrev = 0;
+ }
+}
+
+void Util::listInsertBack(List * list, void *data) {
+ ListNode *node;
+
+ if (list->pHead != 0) {
+ if (list->pTail == 0) {
+ list->pTail = list->pHead;
+ warning("listInsertBack: Broken list!");
+ }
+
+ node = new ListNode;
+ node->pData = data;
+ node->pPrev = list->pTail;
+ node->pNext = 0;
+ list->pTail->pNext = node;
+ list->pTail = node;
+ } else {
+ listInsertFront(list, data);
+ }
+}
+
+void Util::listDropFront(List * list) {
+ if (list->pHead->pNext == 0) {
+ delete list->pHead;
+ list->pHead = 0;
+ list->pTail = 0;
+ } else {
+ list->pHead = list->pHead->pNext;
+ delete list->pHead->pPrev;
+ list->pHead->pPrev = 0;
+ }
+}
+
+void Util::deleteList(List * list) {
+ while (list->pHead != 0) {
+ listDropFront(list);
+ }
+
+ delete list;
+}
+
+const char Util::trStr1[] =
+ " ' + - :0123456789: <=> abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz ";
+const char Util::trStr2[] =
+ " ueaaaaceeeiii ooouu aioun ";
+const char Util::trStr3[] = " ";
+
+void Util::prepareStr(char *str) {
+ uint16 i;
+ char *start, *end;
+ char buf[300];
+
+ strcpy(buf, trStr1);
+ strcat(buf, trStr2);
+ strcat(buf, trStr3);
+
+ for (i = 0; i < strlen(str); i++)
+ str[i] = buf[str[i] - 32];
+
+ while (str[0] == ' ')
+ cutFromStr(str, 0, 1);
+
+ while (strlen(str) > 0 && str[strlen(str) - 1] == ' ')
+ cutFromStr(str, strlen(str) - 1, 1);
+
+ start = strchr(str, ' ');
+
+ while (start != 0) {
+ if (*(start+1) == ' ') {
+ cutFromStr(str, start - str, 1);
+ continue;
+ }
+
+ end = strchr(start + 1, ' ');
+ if (end != 0)
+ start = end + 1;
+ else
+ start = 0;
+ }
+}
+
+void Util::waitMouseRelease(char drawMouse) {
+ int16 buttons;
+ int16 mouseX;
+ int16 mouseY;
+
+ do {
+ _vm->_game->checkKeys(&mouseX, &mouseY, &buttons, drawMouse);
+ if (drawMouse != 0)
+ _vm->_draw->animateCursor(2);
+ delay(10);
+ } while (buttons != 0);
+}
+
+void Util::keyboard_release(void) {;}
+} // End of namespace Gob
diff --git a/engines/gob/util.h b/engines/gob/util.h
new file mode 100644
index 0000000000..1e707b42c1
--- /dev/null
+++ b/engines/gob/util.h
@@ -0,0 +1,106 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_UTIL_H
+#define GOB_UTIL_H
+
+#include "gob/video.h"
+
+namespace Gob {
+
+#define KEYBUFSIZE 16
+
+class Util {
+public:
+ struct ListNode;
+ struct ListNode {
+ void *pData;
+ struct ListNode *pNext;
+ struct ListNode *pPrev;
+ ListNode() : pData(0), pNext(0), pPrev(0) {}
+ };
+
+ struct List {
+ ListNode *pHead;
+ ListNode *pTail;
+ List() : pHead(0), pTail(0) {}
+ };
+
+ void initInput(void);
+ void processInput(void);
+ void waitKey(void);
+ int16 getKey(void);
+ int16 checkKey(void);
+ int16 getRandom(int16 max);
+ void getMouseState(int16 *pX, int16 *pY, int16 *pButtons);
+ void setMousePos(int16 x, int16 y);
+ void longDelay(uint16 msecs);
+ void delay(uint16 msecs);
+ void beep(int16 freq);
+ uint32 getTimeKey(void);
+ void waitMouseUp(void);
+ void waitMouseDown(void);
+
+ void keyboard_init(void);
+ void keyboard_release(void);
+
+ void clearPalette(void);
+
+ void asm_setPaletteBlock(char *tmpPalBuffer, int16 start, int16 end);
+
+ void vid_waitRetrace(int16 mode);
+
+ Video::FontDesc *loadFont(const char *path);
+ void freeFont(Video::FontDesc * fontDesc);
+ static void insertStr(const char *str1, char *str2, int16 pos);
+ static void cutFromStr(char *str, int16 from, int16 cutlen);
+ void waitEndFrame();
+ void setFrameRate(int16 rate);
+
+ static void listInsertBack(List * list, void *data);
+ static void listInsertFront(List * list, void *data);
+ static void listDropFront(List * list);
+ static void deleteList(List * list);
+ static void prepareStr(char *str);
+ void waitMouseRelease(char drawMouse);
+
+ static const char trStr1[];
+ static const char trStr2[];
+ static const char trStr3[];
+ Util(GobEngine *vm);
+
+protected:
+ int16 _mouseX, _mouseY, _mouseButtons;
+ int16 _keyBuffer[KEYBUFSIZE], _keyBufferHead, _keyBufferTail;
+ GobEngine *_vm;
+
+ void addKeyToBuffer(int16 key);
+ bool keyBufferEmpty();
+ bool getKeyFromBuffer(int16& key);
+ int16 translateKey(int16 key);
+ int16 calcDelayTime();
+ void checkJoystick();
+};
+
+} // End of namespace Gob
+
+#endif
diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp
new file mode 100644
index 0000000000..83259c068d
--- /dev/null
+++ b/engines/gob/video.cpp
@@ -0,0 +1,541 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/video.h"
+#include "gob/dataio.h"
+
+#include "gob/driver_vga.h"
+
+namespace Gob {
+
+/* NOT IMPLEMENTED */
+
+Video::Video(GobEngine *vm) : _vm(vm) {
+}
+
+//XXX: Use this function to update the screen for now.
+// This should be moved to a better location later on.
+void Video::waitRetrace(int16) {
+ if (_vm->_global->_pPrimarySurfDesc) {
+ g_system->copyRectToScreen(_vm->_global->_pPrimarySurfDesc->vidPtr, 320, 0, 0, 320, 200);
+ g_system->updateScreen();
+ }
+}
+
+char Video::initDriver(int16 vidMode) {
+ warning("STUB: Video::initDriver");
+
+ // FIXME: Finish all this stuff :)
+ _videoDriver = new VGAVideoDriver();
+
+ return 1;
+}
+
+void Video::freeDriver() {
+ delete _videoDriver;
+ warning("STUB: Video::freeDriver");
+}
+
+int32 Video::getRectSize(int16 width, int16 height, int16 flag, int16 mode) {
+ int32 size;
+
+ if ((mode & 0x7f) != 0x13)
+ warning
+ ("Video::getRectSize: Video mode %d is not fully supported!",
+ mode & 0x7f);
+ switch (mode & 0x7f) {
+ case 5:
+ case 7:
+ size = ((int32)((width + 3) / 4)) * height * (flag + 1);
+ break;
+ case 0x13:
+ size = (int32)width *height;
+ break;
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ size = ((int32)((width + 3) / 4)) * height * 4;
+ break;
+ default:
+ size = ((int32)((width + 7) / 8)) * height * (flag + 4);
+ break;
+ }
+ return size;
+}
+
+Video::SurfaceDesc *Video::initSurfDesc(int16 vidMode, int16 width, int16 height, int16 flags) {
+ int8 flagsAnd2;
+ byte *vidMem = 0;
+ int32 sprSize;
+ int16 someFlags = 1;
+ SurfaceDesc *descPtr;
+
+ if (flags != PRIMARY_SURFACE)
+ _vm->_global->_sprAllocated++;
+
+ if (flags & RETURN_PRIMARY)
+ return _vm->_global->_pPrimarySurfDesc;
+
+ if (vidMode != 0x13)
+ error("Video::initSurfDesc: Only VGA 0x13 mode is supported!");
+
+ if ((flags & PRIMARY_SURFACE) == 0)
+ vidMode += 0x80;
+
+ if (flags & 2)
+ flagsAnd2 = 1;
+ else
+ flagsAnd2 = 0;
+
+ if (flags & PRIMARY_SURFACE) {
+ _vm->_global->_primaryWidth = width;
+ _vm->_global->_mouseMaxCol = width;
+ _vm->_global->_primaryHeight = height;
+ _vm->_global->_mouseMaxRow = height;
+ sprSize = 0;
+ } else {
+ sprSize = Video::getRectSize(width, height, flagsAnd2, vidMode);
+ if (flagsAnd2)
+ someFlags += 0x80;
+ }
+ if (flags & PRIMARY_SURFACE) {
+ descPtr = _vm->_global->_pPrimarySurfDesc;
+ delete[] descPtr->vidPtr;
+ assert(descPtr);
+ vidMem = new byte[320 * 200];
+ } else {
+ if (flags & DISABLE_SPR_ALLOC) {
+ descPtr = new SurfaceDesc;
+ // this case causes vidPtr to be set to invalid memory
+ assert(false);
+ } else {
+ descPtr = new SurfaceDesc;
+ descPtr->vidPtr = new byte[sprSize];
+ vidMem = descPtr->vidPtr;
+ }
+ }
+ if (descPtr == 0)
+ return 0;
+
+ descPtr->width = width;
+ descPtr->height = height;
+ descPtr->flag = someFlags;
+ descPtr->vidMode = vidMode;
+ descPtr->vidPtr = vidMem;
+
+ descPtr->reserved1 = 0;
+ descPtr->reserved2 = 0;
+ return descPtr;
+}
+
+void Video::freeSurfDesc(SurfaceDesc * surfDesc) {
+ delete[] surfDesc->vidPtr;
+ if (surfDesc != _vm->_global->_pPrimarySurfDesc) {
+ _vm->_global->_sprAllocated--;
+ delete surfDesc;
+ }
+}
+
+int16 Video::clampValue(int16 val, int16 max) {
+ if (val >= max)
+ val = max - 1;
+
+ if (val < 0)
+ val = 0;
+
+ return val;
+}
+
+void Video::drawSprite(SurfaceDesc *source, SurfaceDesc *dest,
+ int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp) {
+ int16 temp;
+ int16 destRight;
+ int16 destBottom;
+
+ if (_vm->_global->_doRangeClamp) {
+ if (left > right) {
+ temp = left;
+ left = right;
+ right = temp;
+ }
+ if (top > bottom) {
+ temp = top;
+ top = bottom;
+ bottom = temp;
+ }
+ if (right < 0)
+ return;
+ if (bottom < 0)
+ return;
+ if (left >= source->width)
+ return;
+ if (top >= source->height)
+ return;
+
+ if (left < 0) {
+ x -= left;
+ left = 0;
+ }
+ if (top < 0) {
+ y -= top;
+ top = 0;
+ }
+ right = Video::clampValue(right, source->width);
+ bottom = Video::clampValue(bottom, source->height);
+ if (right - left >= source->width)
+ right = left + source->width - 1;
+ if (bottom - top >= source->height)
+ bottom = top + source->height - 1;
+
+ if (x < 0) {
+ left -= x;
+ x = 0;
+ }
+ if (y < 0) {
+ top -= y;
+ y = 0;
+ }
+ if (left > right)
+ return;
+ if (top > bottom)
+ return;
+
+ if (x >= dest->width)
+ return;
+
+ if (y >= dest->height)
+ return;
+
+ destRight = x + right - left;
+ destBottom = y + bottom - top;
+ if (destRight >= dest->width)
+ right -= destRight - dest->width + 1;
+
+ if (destBottom >= dest->height)
+ bottom -= destBottom - dest->height + 1;
+ }
+
+ _videoDriver->drawSprite(source, dest, left, top, right, bottom, x, y, transp);
+}
+
+void Video::fillRect(SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom,
+ int16 color) {
+ int16 temp;
+
+ if (_vm->_global->_doRangeClamp) {
+ if (left > right) {
+ temp = left;
+ left = right;
+ right = temp;
+ }
+ if (top > bottom) {
+ temp = top;
+ top = bottom;
+ bottom = temp;
+ }
+ if (right < 0)
+ return;
+ if (bottom < 0)
+ return;
+ if (left >= dest->width)
+ return;
+ if (top >= dest->height)
+ return;
+
+ left = Video::clampValue(left, dest->width);
+ top = Video::clampValue(top, dest->height);
+ right = Video::clampValue(right, dest->width);
+ bottom = Video::clampValue(bottom, dest->height);
+ }
+
+ _videoDriver->fillRect(dest, left, top, right, bottom, color);
+}
+
+void Video::drawLine(SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, int16 y1, int16 color) {
+ if (x0 == x1 || y0 == y1) {
+ Video::fillRect(dest, x0, y0, x1, y1, color);
+ return;
+ }
+
+ _videoDriver->drawLine(dest, x0, y0, x1, y1, color);
+}
+
+void Video::putPixel(int16 x, int16 y, int16 color, SurfaceDesc *dest) {
+ if (x < 0 || y < 0 || x >= dest->width || y >= dest->height)
+ return;
+
+ _videoDriver->putPixel(x, y, color, dest);
+}
+
+void Video::drawLetter(unsigned char item, int16 x, int16 y, FontDesc *fontDesc, int16 color1,
+ int16 color2, int16 transp, SurfaceDesc *dest) {
+
+ _videoDriver->drawLetter(item, x, y, fontDesc, color1, color2, transp, dest);
+}
+
+void Video::clearSurf(SurfaceDesc *dest) {
+ Video::fillRect(dest, 0, 0, dest->width - 1, dest->height - 1, 0);
+}
+
+void Video::drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y,
+ int16 transp, SurfaceDesc *dest) {
+
+ if (Video::spriteUncompressor(sprBuf, width, height, x, y, transp, dest))
+ return;
+
+ if ((dest->vidMode & 0x7f) != 0x13)
+ error("Video::drawPackedSprite: Video mode 0x%x is not fully supported!",
+ dest->vidMode & 0x7f);
+
+ _videoDriver->drawPackedSprite(sprBuf, width, height, x, y, transp, dest);
+}
+
+void Video::setPalElem(int16 index, char red, char green, char blue, int16 unused,
+ int16 vidMode) {
+ byte pal[4];
+
+ _vm->_global->_redPalette[index] = red;
+ _vm->_global->_greenPalette[index] = green;
+ _vm->_global->_bluePalette[index] = blue;
+
+ if (vidMode != 0x13)
+ error("Video::setPalElem: Video mode 0x%x is not supported!",
+ vidMode);
+
+ pal[0] = (red << 2) | (red >> 4);
+ pal[1] = (green << 2) | (green >> 4);
+ pal[2] = (blue << 2) | (blue >> 4);
+ pal[3] = 0;
+ g_system->setPalette(pal, index, 1);
+}
+
+void Video::setPalette(PalDesc *palDesc) {
+ int16 i;
+ byte pal[1024];
+ int16 numcolors;
+
+ if (_vm->_global->_videoMode != 0x13)
+ error("Video::setPalette: Video mode 0x%x is not supported!",
+ _vm->_global->_videoMode);
+
+ if (_vm->_global->_setAllPalette)
+ numcolors = 256;
+ else
+ numcolors = 16;
+
+ for (i = 0; i < numcolors; i++) {
+ pal[i * 4 + 0] = (palDesc->vgaPal[i].red << 2) | (palDesc->vgaPal[i].red >> 4);
+ pal[i * 4 + 1] = (palDesc->vgaPal[i].green << 2) | (palDesc->vgaPal[i].green >> 4);
+ pal[i * 4 + 2] = (palDesc->vgaPal[i].blue << 2) | (palDesc->vgaPal[i].blue >> 4);
+ pal[i * 4 + 3] = 0;
+ }
+
+ g_system->setPalette(pal, 0, numcolors);
+}
+
+void Video::setFullPalette(PalDesc *palDesc) {
+ Color *colors;
+ int16 i;
+ byte pal[1024];
+
+ if (_vm->_global->_setAllPalette) {
+ colors = palDesc->vgaPal;
+ for (i = 0; i < 256; i++) {
+ _vm->_global->_redPalette[i] = colors[i].red;
+ _vm->_global->_greenPalette[i] = colors[i].green;
+ _vm->_global->_bluePalette[i] = colors[i].blue;
+ }
+
+ for (i = 0; i < 256; i++) {
+ pal[i * 4 + 0] = (colors[i].red << 2) | (colors[i].red >> 4);
+ pal[i * 4 + 1] = (colors[i].green << 2) | (colors[i].green >> 4);
+ pal[i * 4 + 2] = (colors[i].blue << 2) | (colors[i].blue >> 4);
+ pal[i * 4 + 3] = 0;
+ }
+ g_system->setPalette(pal, 0, 256);
+ } else {
+ Video::setPalette(palDesc);
+ }
+}
+
+void Video::initPrimary(int16 mode) {
+ int16 old;
+ if (mode != 0x13 && mode != 3 && mode != -1)
+ error("Video::initPrimary: Video mode 0x%x is not supported!",
+ mode);
+
+ if (_vm->_global->_videoMode != 0x13)
+ error("Video::initPrimary: Video mode 0x%x is not supported!",
+ mode);
+
+ old = _vm->_global->_oldMode;
+ if (mode == -1)
+ mode = 3;
+
+ _vm->_global->_oldMode = mode;
+ if (mode != 3)
+ Video::initDriver(mode);
+
+ if (mode != 3) {
+ Video::initSurfDesc(mode, 320, 200, PRIMARY_SURFACE);
+
+ if (_vm->_global->_dontSetPalette)
+ return;
+
+ Video::setFullPalette(_vm->_global->_pPaletteDesc);
+ }
+}
+
+char Video::spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight,
+ int16 x, int16 y, int16 transp, SurfaceDesc *destDesc) {
+ SurfaceDesc sourceDesc;
+ byte *memBuffer;
+ byte *srcPtr;
+ byte *destPtr;
+ byte *linePtr;
+ byte temp;
+ uint16 sourceLeft;
+ int16 curWidth;
+ int16 curHeight;
+ int16 offset;
+ int16 counter2;
+ uint16 cmdVar;
+ int16 bufPos;
+ int16 strLen;
+
+ if (!destDesc)
+ return 1;
+
+ if ((destDesc->vidMode & 0x7f) != 0x13)
+ error("Video::spriteUncompressor: Video mode 0x%x is not supported!",
+ destDesc->vidMode & 0x7f);
+
+ if (sprBuf[0] != 1)
+ return 0;
+
+ if (sprBuf[1] != 2)
+ return 0;
+
+ if (sprBuf[2] == 2) {
+ sourceDesc.width = srcWidth;
+ sourceDesc.height = srcHeight;
+ sourceDesc.vidMode = 0x93;
+ sourceDesc.vidPtr = sprBuf + 3;
+ Video::drawSprite(&sourceDesc, destDesc, 0, 0, srcWidth - 1,
+ srcHeight - 1, x, y, transp);
+ return 1;
+ } else {
+ memBuffer = new byte[4114];
+ if (memBuffer == 0)
+ return 0;
+
+ srcPtr = sprBuf + 3;
+ sourceLeft = READ_LE_UINT16(srcPtr);
+
+ destPtr = destDesc->vidPtr + destDesc->width * y + x;
+
+ curWidth = 0;
+ curHeight = 0;
+
+ linePtr = destPtr;
+ srcPtr += 4;
+
+ for (offset = 0; offset < 4078; offset++)
+ memBuffer[offset] = 0x20;
+
+ cmdVar = 0;
+ bufPos = 4078;
+ while (1) {
+ cmdVar >>= 1;
+ if ((cmdVar & 0x100) == 0) {
+ cmdVar = *srcPtr | 0xff00;
+ srcPtr++;
+ }
+ if ((cmdVar & 1) != 0) {
+ temp = *srcPtr++;
+ if (temp != 0 || transp == 0)
+ *destPtr = temp;
+ destPtr++;
+ curWidth++;
+ if (curWidth >= srcWidth) {
+ curWidth = 0;
+ linePtr += destDesc->width;
+ destPtr = linePtr;
+ curHeight++;
+ if (curHeight >= srcHeight)
+ break;
+ }
+ sourceLeft--;
+ if (sourceLeft == 0)
+ break;
+
+ memBuffer[bufPos] = temp;
+ bufPos++;
+ bufPos %= 4096;
+ } else {
+ offset = *srcPtr;
+ srcPtr++;
+ offset |= (*srcPtr & 0xf0) << 4;
+ strLen = (*srcPtr & 0x0f) + 3;
+ srcPtr++;
+
+ for (counter2 = 0; counter2 < strLen;
+ counter2++) {
+ temp =
+ memBuffer[(offset +
+ counter2) % 4096];
+ if (temp != 0 || transp == 0)
+ *destPtr = temp;
+ destPtr++;
+
+ curWidth++;
+ if (curWidth >= srcWidth) {
+ curWidth = 0;
+ linePtr += destDesc->width;
+ destPtr = linePtr;
+ curHeight++;
+ if (curHeight >= srcHeight) {
+ delete[] memBuffer;
+ return 1;
+ }
+ }
+ sourceLeft--;
+ if (sourceLeft == 0) {
+ delete[] memBuffer;
+ return 1;
+ }
+ memBuffer[bufPos] = temp;
+ bufPos++;
+ bufPos %= 4096;
+ }
+ }
+ }
+ }
+ delete[] memBuffer;
+ return 1;
+}
+
+void Video::setHandlers() { _vm->_global->_setAllPalette = 1; }
+
+} // End of namespace Gob
diff --git a/engines/gob/video.h b/engines/gob/video.h
new file mode 100644
index 0000000000..58c6bdb3c2
--- /dev/null
+++ b/engines/gob/video.h
@@ -0,0 +1,141 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef GOB_VIDEO_H
+#define GOB_VIDEO_H
+
+#include "common/stdafx.h"
+#include "common/util.h"
+#include "gob/gob.h"
+
+namespace Gob {
+
+#define VID_SET_CURSOR(val) { _AH = 1; _CX = (val); geninterrupt(0x10); }
+#define VID_RESTORE_MODE { _AX = 3; geninterrupt(0x10); }
+
+#define TEXT_VID_SEG 0xB800
+#define TEXT_VID_OFF 0
+#define TEXT_COL_COUNT 80
+#define TEXT_ROW_COUNT 25
+
+extern int16 setAllPalette;
+
+class Video {
+public:
+ struct SurfaceDesc {
+ int16 width;
+ int16 height;
+ int8 reserved1;
+ int8 flag;
+ int16 vidMode;
+ byte *vidPtr;
+ int16 reserved2;
+ SurfaceDesc() : width(0), height(0), reserved1(0), flag(0),
+ vidMode(0), vidPtr(0), reserved2(0) {}
+ };
+
+ struct FontDesc {
+ char *dataPtr;
+ int8 itemWidth;
+ int8 itemHeight;
+ int8 startItem;
+ int8 endItem;
+ int8 itemSize;
+ int8 bitWidth;
+ void *extraData;
+ FontDesc() : dataPtr(0), itemWidth(0), itemHeight(0), startItem(0),
+ endItem(0), itemSize(0), bitWidth(0) {}
+ };
+
+#define GDR_VERSION 4
+
+#define PRIMARY_SURFACE 0x80
+#define RETURN_PRIMARY 0x01
+#define DISABLE_SPR_ALLOC 0x20
+
+#pragma START_PACK_STRUCTS
+
+ struct Color {
+ byte red;
+ byte green;
+ byte blue;
+ } GCC_PACK;
+
+#pragma END_PACK_STRUCTS
+
+ struct PalDesc {
+ Color *vgaPal;
+ int16 *unused1;
+ int16 *unused2;
+ PalDesc() : vgaPal(0), unused1(0), unused2(0) {}
+ };
+
+ Video(class GobEngine *vm);
+ int32 getRectSize(int16 width, int16 height, int16 flag, int16 mode);
+ SurfaceDesc *initSurfDesc(int16 vidMode, int16 width, int16 height, int16 flags);
+ void freeSurfDesc(SurfaceDesc * surfDesc);
+ int16 clampValue(int16 val, int16 max);
+ void drawSprite(SurfaceDesc * source, SurfaceDesc * dest, int16 left,
+ int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp);
+ void fillRect(SurfaceDesc * dest, int16 left, int16 top, int16 right, int16 bottom,
+ int16 color);
+ void drawLine(SurfaceDesc * dest, int16 x0, int16 y0, int16 x1, int16 y1,
+ int16 color);
+ void putPixel(int16 x, int16 y, int16 color, SurfaceDesc * dest);
+ void drawLetter(unsigned char item, int16 x, int16 y, FontDesc * fontDesc, int16 color1,
+ int16 color2, int16 transp, SurfaceDesc * dest);
+ void clearSurf(SurfaceDesc * dest);
+ void drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y,
+ int16 transp, SurfaceDesc * dest);
+ void setPalElem(int16 index, char red, char green, char blue, int16 unused,
+ int16 vidMode);
+ void setPalette(PalDesc * palDesc);
+ void setFullPalette(PalDesc * palDesc);
+ void initPrimary(int16 mode);
+ char spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight, int16 x,
+ int16 y, int16 transp, SurfaceDesc * destDesc);
+ void waitRetrace(int16);
+ void freeDriver(void);
+ void setHandlers();
+
+protected:
+ class VideoDriver *_videoDriver;
+ GobEngine *_vm;
+
+ char initDriver(int16 vidMode);
+};
+
+class VideoDriver {
+public:
+ VideoDriver() {}
+ virtual ~VideoDriver() {}
+ virtual void drawSprite(Video::SurfaceDesc *source, Video::SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp) = 0;
+ virtual void fillRect(Video::SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, byte color) = 0;
+ virtual void putPixel(int16 x, int16 y, byte color, Video::SurfaceDesc *dest) = 0;
+ virtual void drawLetter(unsigned char item, int16 x, int16 y, Video::FontDesc *fontDesc, byte color1, byte color2, byte transp, Video::SurfaceDesc *dest) = 0;
+ virtual void drawLine(Video::SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, int16 y1, byte color) = 0;
+ virtual void drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y, byte transp, Video::SurfaceDesc *dest) = 0;
+};
+
+} // End of namespace Gob
+
+#endif