diff options
Diffstat (limited to 'engines/gob')
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 |