diff options
-rw-r--r-- | Makefile.common | 6 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | base/plugins.cpp | 4 | ||||
-rw-r--r-- | base/plugins.h | 1 | ||||
-rwxr-xr-x | configure | 13 | ||||
-rw-r--r-- | gob/anim.cpp | 20 | ||||
-rw-r--r-- | gob/anim.h | 21 | ||||
-rw-r--r-- | gob/dataio.cpp | 356 | ||||
-rw-r--r-- | gob/dataio.h | 46 | ||||
-rw-r--r-- | gob/debug.cpp | 171 | ||||
-rw-r--r-- | gob/debug.h | 27 | ||||
-rw-r--r-- | gob/draw.cpp | 908 | ||||
-rw-r--r-- | gob/draw.h | 111 | ||||
-rw-r--r-- | gob/driver_vga.cpp | 59 | ||||
-rw-r--r-- | gob/driver_vga.h | 22 | ||||
-rw-r--r-- | gob/game.cpp | 1909 | ||||
-rw-r--r-- | gob/game.h | 151 | ||||
-rw-r--r-- | gob/global.cpp | 175 | ||||
-rw-r--r-- | gob/global.h | 191 | ||||
-rw-r--r-- | gob/gob.cpp | 130 | ||||
-rw-r--r-- | gob/gob.h | 51 | ||||
-rw-r--r-- | gob/goblin.cpp | 3320 | ||||
-rw-r--r-- | gob/goblin.h | 192 | ||||
-rw-r--r-- | gob/init.cpp | 293 | ||||
-rw-r--r-- | gob/init.h | 20 | ||||
-rw-r--r-- | gob/inter.cpp | 1496 | ||||
-rw-r--r-- | gob/inter.h | 85 | ||||
-rw-r--r-- | gob/map.cpp | 736 | ||||
-rw-r--r-- | gob/map.h | 57 | ||||
-rw-r--r-- | gob/module.mk | 36 | ||||
-rw-r--r-- | gob/mult.cpp | 1205 | ||||
-rw-r--r-- | gob/mult.h | 185 | ||||
-rw-r--r-- | gob/pack.cpp | 94 | ||||
-rw-r--r-- | gob/pack.h | 18 | ||||
-rw-r--r-- | gob/palanim.cpp | 224 | ||||
-rw-r--r-- | gob/palanim.h | 21 | ||||
-rw-r--r-- | gob/parse.cpp | 1210 | ||||
-rw-r--r-- | gob/parse.h | 22 | ||||
-rw-r--r-- | gob/resource.cpp | 90 | ||||
-rw-r--r-- | gob/resource.h | 20 | ||||
-rw-r--r-- | gob/scenery.cpp | 738 | ||||
-rw-r--r-- | gob/scenery.h | 121 | ||||
-rw-r--r-- | gob/sound.cpp | 44 | ||||
-rw-r--r-- | gob/sound.h | 47 | ||||
-rw-r--r-- | gob/timer.cpp | 21 | ||||
-rw-r--r-- | gob/timer.h | 25 | ||||
-rw-r--r-- | gob/util.cpp | 465 | ||||
-rw-r--r-- | gob/util.h | 68 | ||||
-rw-r--r-- | gob/video.cpp | 547 | ||||
-rw-r--r-- | gob/video.h | 125 |
50 files changed, 15896 insertions, 2 deletions
diff --git a/Makefile.common b/Makefile.common index 81ff6edf55..178fb5b3c6 100644 --- a/Makefile.common +++ b/Makefile.common @@ -81,6 +81,12 @@ else MODULES += kyra endif +ifdef DISABLE_GOB +DEFINES += -DDISABLE_GOB +else +MODULES += gob +endif + # After the game specific modules follow the shared modules MODULES += \ gui \ @@ -5,6 +5,7 @@ For a more comprehensive changelog for the latest experimental CVS code, see: New Games: - Added SAGA engine (for the games and "I Have No Mouth and I Must Scream" and "Inherit the Earth"). + - Added Gob engine (for Goblins series) General: - Reworked cursor handling in SDL backend. Now cursors can have their own diff --git a/base/plugins.cpp b/base/plugins.cpp index fe785731bc..695ed6ede6 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -278,9 +278,11 @@ void PluginManager::loadPlugins() { #ifndef DISABLE_KYRA LINK_PLUGIN(KYRA) #endif + #ifndef DISABLE_GOB + LINK_PLUGIN(GOB) + #endif #endif - } void PluginManager::unloadPlugins() { diff --git a/base/plugins.h b/base/plugins.h index d8276800c8..f9a5567834 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -155,5 +155,4 @@ public: DetectedGameList detectGames(const FSList &fslist) const; }; - #endif @@ -30,6 +30,7 @@ _build_sword2=yes _build_queen=yes _build_kyra=no _build_saga=yes +_build_gob=no _need_memalign=no _build_plugins=no _nasm=auto @@ -268,6 +269,7 @@ Optional Features: --disable-queen don't build the Flight of the Amazon Queen engine --disable-saga don't build the SAGA engine --enable-kyra build the Legend of Kyrandia engine + --enable-gob build the Gobli*ns engine --enable-plugins build engines as loadable modules instead of static linking them --disable-mt32emu don't enable the integrated MT-32 emulator @@ -322,6 +324,7 @@ for ac_option in $@; do --disable-queen) _build_queen=no ;; --disable-saga) _build_saga=no ;; --enable-kyra) _build_kyra=yes ;; + --enable-gob) _build_gob=yes ;; --enable-alsa) _alsa=yes ;; --disable-alsa) _alsa=no ;; --enable-vorbis) _vorbis=yes ;; @@ -581,6 +584,12 @@ else _mak_saga='# DISABLE_SAGA = 1' fi +if test "$_build_gob" = no ; then + _mak_gob='DISABLE_GOB = 1' +else + _mak_gob='# DISABLE_GOB = 1' +fi + if test -n "$_host"; then # Cross-compiling mode - add your target here if needed case "$_host" in @@ -1041,6 +1050,9 @@ fi if test "$_build_kyra" = yes ; then echo " Legend of Kyrandia" fi +if test "$_build_gob" = yes ; then + echo " Gobli*ns" +fi echo @@ -1166,6 +1178,7 @@ $_mak_sword2 $_mak_queen $_mak_kyra $_mak_saga +$_mak_gob $_mak_mt32emu INCLUDES += $INCLUDES diff --git a/gob/anim.cpp b/gob/anim.cpp new file mode 100644 index 0000000000..41556d97b7 --- /dev/null +++ b/gob/anim.cpp @@ -0,0 +1,20 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/video.h" +#include "gob/anim.h" + +namespace Gob { + +int16 anim_animAreaLeft; +int16 anim_animAreaTop; +int16 anim_animAreaWidth; +int16 anim_animAreaHeight; +SurfaceDesc *anim_underAnimSurf = 0; + +} // End of namespace Gob diff --git a/gob/anim.h b/gob/anim.h new file mode 100644 index 0000000000..d84ed04950 --- /dev/null +++ b/gob/anim.h @@ -0,0 +1,21 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __ANIM_H +#define __ANIM_H + +namespace Gob { + +extern int16 anim_animAreaLeft; +extern int16 anim_animAreaTop; +extern int16 anim_animAreaWidth; +extern int16 anim_animAreaHeight; +extern SurfaceDesc *anim_underAnimSurf; + +} // End of namespace Gob + +#endif diff --git a/gob/dataio.cpp b/gob/dataio.cpp new file mode 100644 index 0000000000..450bb5cd31 --- /dev/null +++ b/gob/dataio.cpp @@ -0,0 +1,356 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/dataio.h" +#include "gob/debug.h" +#include "gob/pack.h" + +namespace Gob { + +int16 file_write(int16 handle, char *buf, int16 size) { + return filesHandles[handle].write(buf, size); +} + +int16 file_open(const char *path, File::AccessMode mode) { + int16 i; + + for (i = 0; i < MAX_FILES; i++) { + if (!filesHandles[i].isOpen()) + break; + } + if (i == MAX_FILES) + return -1; + + filesHandles[i].open(path, mode); + + if (filesHandles[i].isOpen()) + return i; + + return -1; +} + +File *file_getHandle(int16 handle) { + return &filesHandles[handle]; +} + +int16 data_getChunk(const char *chunkName) { + int16 file; + int16 slot; + int16 chunk; + struct ChunkDesc *dataDesc; + + for (file = 0; file < MAX_DATA_FILES; file++) { + if (dataFiles[file] == 0) + return -1; + + for (slot = 0; slot < MAX_SLOT_COUNT; slot++) + if (chunkPos[file * MAX_SLOT_COUNT + slot] == -1) + break; + + if (slot == MAX_SLOT_COUNT) + return -1; + + dataDesc = dataFiles[file]; + for (chunk = 0; chunk < numDataChunks[file]; + chunk++, dataDesc++) { + if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) + continue; + + isCurrentSlot[file * MAX_SLOT_COUNT + slot] = 0; + chunkSize[file * MAX_SLOT_COUNT + slot] = + dataDesc->size; + chunkOffset[file * MAX_SLOT_COUNT + slot] = + dataDesc->offset; + chunkPos[file * MAX_SLOT_COUNT + slot] = 0; + return file * 10 + slot + 50; + } + } + return -1; +} + +char data_freeChunk(int16 handle) { + if (handle >= 50 && handle < 100) { + handle -= 50; + chunkPos[(handle / 10) * MAX_SLOT_COUNT + (handle % 10)] = -1; + return 0; + } + return 1; +} + +int32 data_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 (isCurrentSlot[file * MAX_SLOT_COUNT + slot] == 0) { + for (i = 0; i < MAX_SLOT_COUNT; i++) + isCurrentSlot[file * MAX_SLOT_COUNT + i] = 0; + + offset = + chunkOffset[file * MAX_SLOT_COUNT + slot] + + chunkPos[file * MAX_SLOT_COUNT + slot]; + debug(0, "seek: %ld, %ld", chunkOffset[file * MAX_SLOT_COUNT + slot], chunkPos[file * MAX_SLOT_COUNT + slot]); + file_getHandle(dataFileHandles[file])->seek(offset, SEEK_SET); + } + + isCurrentSlot[file * MAX_SLOT_COUNT + slot] = 1; + if (chunkPos[file * MAX_SLOT_COUNT + slot] + size > + chunkSize[file * MAX_SLOT_COUNT + slot]) + size = + chunkSize[file * MAX_SLOT_COUNT + slot] - + chunkPos[file * MAX_SLOT_COUNT + slot]; + + file_getHandle(dataFileHandles[file])->read(buf, size); + chunkPos[file * MAX_SLOT_COUNT + slot] += size; + return size; +} + +int16 data_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; + isCurrentSlot[file * MAX_SLOT_COUNT + slot] = 0; + if (from == SEEK_SET) + chunkPos[file * MAX_SLOT_COUNT + slot] = pos; + else + chunkPos[file * MAX_SLOT_COUNT + slot] += pos; + + return chunkPos[file * MAX_SLOT_COUNT + slot]; +} + +int32 data_getChunkSize(const char *chunkName) { + int16 file; + int16 chunk; + struct ChunkDesc *dataDesc; + int16 slot; + int32 realSize; + + for (file = 0; file < MAX_DATA_FILES; file++) { + if (dataFiles[file] == 0) + return -1; + + dataDesc = dataFiles[file]; + for (chunk = 0; chunk < numDataChunks[file]; + chunk++, dataDesc++) { + if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) + continue; + + if (dataDesc->packed == 0) { + packedSize = -1; + return dataDesc->size; + } + + for (slot = 0; slot < MAX_SLOT_COUNT; slot++) + isCurrentSlot[slot] = 0; + + file_getHandle(dataFileHandles[file])->seek(dataDesc->offset, SEEK_SET); + realSize = file_getHandle(dataFileHandles[file])->readUint32LE(); + packedSize = dataDesc->size; + return realSize; + } + } + return -1; +} + +void data_openDataFile(const char *src) { + char path[128]; + int16 i; + int16 file; + struct 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 (dataFiles[file] == 0) + break; + + if (file == MAX_DATA_FILES) + error("data_dataFileOpen: Data file slots are full\n"); + dataFileHandles[file] = file_open(path); + + if (dataFileHandles[file] == -1) + error("data_dataFileOpen: Can't open %s data file\n", path); + + numDataChunks[file] = file_getHandle(dataFileHandles[file])->readUint16LE(); + + debug(0, "DataChunks: %d [for %s]", numDataChunks[file], path); + + dataFiles[file] = dataDesc = + (struct ChunkDesc *)malloc(sizeof(struct ChunkDesc) * + numDataChunks[file]); + + for (i = 0; i < numDataChunks[file]; i++) { + file_getHandle(dataFileHandles[file])->read(dataDesc[i].chunkName, 13); + dataDesc[i].size = file_getHandle(dataFileHandles[file])->readUint32LE(); + dataDesc[i].offset = file_getHandle(dataFileHandles[file])->readUint32LE(); + dataDesc[i].packed = file_getHandle(dataFileHandles[file])->readByte(); + } + + for (i = 0; i < numDataChunks[file]; i++) + debug(0, "%d: %s %d", i, dataDesc[i].chunkName, dataDesc[i].size); + + for (i = 0; i < MAX_SLOT_COUNT; i++) + chunkPos[file * MAX_SLOT_COUNT + i] = -1; + +} + +void data_closeDataFile() { + int16 file; + for (file = MAX_DATA_FILES - 1; file >= 0; file--) { + if (dataFiles[file] != 0) { + free((char *)dataFiles[file]); + dataFiles[file] = 0; + file_getHandle(dataFileHandles[file])->close(); + return; + } + } +} + +char *data_getUnpackedData(const char *name) { + int32 realSize; + int16 chunk; + char *unpackBuf; + char *packBuf; + char *ptr; + int32 sizeLeft; + + realSize = data_getChunkSize(name); + if (packedSize == -1 || realSize == -1) + return 0; + + chunk = data_getChunk(name); + if (chunk == -1) + return 0; + + unpackBuf = (char *)malloc(realSize); + if (unpackBuf == 0) + return 0; + + packBuf = (char *)malloc(packedSize); + if (packBuf == 0) { + free(unpackBuf); + return 0; + } + + sizeLeft = packedSize; + ptr = packBuf; + while (sizeLeft > 0x4000) { + data_readChunk(chunk, (char *)ptr, 0x4000); + sizeLeft -= 0x4000; + ptr += 0x4000; + } + data_readChunk(chunk, (char *)ptr, sizeLeft); + data_freeChunk(chunk); + unpackData((char *)packBuf, (char *)unpackBuf); + free(packBuf); + return unpackBuf; +} + +void data_closeData(int16 handle) { + if (data_freeChunk(handle) != 0) + file_getHandle(handle)->close(); +} + +int16 data_openData(const char *path, File::AccessMode mode) { + int16 handle; + + if (mode != File::kFileReadMode) + return file_open(path, mode); + + handle = data_getChunk(path); + if (handle >= 0) + return handle; + + return file_open(path, mode); +} + +int32 data_readData(int16 handle, char *buf, int16 size) { + int32 res; + + res = data_readChunk(handle, buf, size); + if (res >= 0) + return res; + + return file_getHandle(handle)->read(buf, size); +} + +void data_seekData(int16 handle, int32 pos, int16 from) { + int32 resPos; + + resPos = data_seekChunk(handle, pos, from); + if (resPos != -1) + return; + + file_getHandle(handle)->seek(pos, from); +} + +int32 data_getDataSize(const char *name) { + char buf[128]; + int32 chunkSz; + struct stat statBuf; + + strcpy(buf, name); + chunkSz = data_getChunkSize(buf); + if (chunkSz >= 0) + return chunkSz; + + if (stat(buf, &statBuf) == -1) + error("data_getDataSize: Can't find data (%s)", name); + + return statBuf.st_size; +} + +char *data_getData(const char *path) { + char *data; + char *ptr; + int32 size; + int16 handle; + + data = data_getUnpackedData(path); + if (data != 0) + return data; + + size = data_getDataSize(path); + data = (char *)malloc(size); + if (data == 0) + return 0; + + handle = data_openData(path); + + ptr = data; + while (size > 0x4000) { + data_readData(handle, (char *)ptr, 0x4000); + size -= 0x4000; + ptr += 0x4000; + } + data_readData(handle, (char *)ptr, size); + data_closeData(handle); + return data; + +} + +char *data_getSmallData(const char *path) { + return data_getData(path); +} + +} // End of namespace Gob diff --git a/gob/dataio.h b/gob/dataio.h new file mode 100644 index 0000000000..3b104f4164 --- /dev/null +++ b/gob/dataio.h @@ -0,0 +1,46 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __DATAIO_H +#define __DATAIO_H + +#include "common/file.h" +#include <sys/stat.h> + +namespace Gob { + +#define MAX_DATA_FILES 3 +#define MAX_SLOT_COUNT 4 + +struct ChunkDesc { + char chunkName[13]; + uint32 size; + uint32 offset; + byte packed; +}; + +int16 file_open(const char *path, File::AccessMode mode = File::kFileReadMode); +File *file_getHandle(int16 handle); +int16 data_getChunk(const char *chunkName); +char data_freeChunk(int16 handle); +int32 data_readChunk(int16 handle, char *buf, int16 size); +int16 data_seekChunk(int16 handle, int32 pos, int16 from); +int32 data_getChunkSize(const char *chunkName); +void data_openDataFile(const char *src); +void data_closeDataFile(void); +char *data_getUnpackedData(const char *name); +void data_closeData(int16 handle); +int16 data_openData(const char *path, File::AccessMode mode = File::kFileReadMode); +int32 data_readData(int16 handle, char *buf, int16 size); +void data_seekData(int16 handle, int32 pos, int16 from); +int32 data_getDataSize(const char *name); +char *data_getData(const char *path); +char *data_getSmallData(const char *path); + +} // End of namespace Gob + +#endif diff --git a/gob/debug.cpp b/gob/debug.cpp new file mode 100644 index 0000000000..0a7582e39b --- /dev/null +++ b/gob/debug.cpp @@ -0,0 +1,171 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ + +#include "gob/gob.h" +#include "gob/debug.h" +#include "gob/scenery.h" + +namespace Gob { + +static int16 logFile = -2; +static char buf[256]; + +extern uint32 always0_dword_23EC_560; + +static void log_close(void) { + if (logFile != -2) + close(logFile); + logFile = -2; +} + +static void log_init(void) { + if (logFile == -2) { + logFile = open(LOG_NAME, O_WRONLY | O_CREAT); + if (logFile != -1) + atexit(&log_close); + } +} + +void log_write(const char *format, ...) { + va_list lst; + va_start(lst, format); + + log_init(); + if (logFile >= 0) { + vsprintf(buf, format, lst); + write(logFile, buf, strlen(buf)); + } + + va_end(lst); +} + +void dbg_printInt(int16 val) { + log_write("dbg_printInt: %d\n", val); +} + +void dbg_printPtr(void *ptr) { + log_write("dbg_printPtr: %p\n", ptr); +} + +void dbg_printStr(char *str) { + log_write("dbg_printStr: "); + log_write(str); + log_write("\n"); +} + +void dbg_dumpMem(char *ptr, int16 size) { + int16 i; + log_write("dbg_dumpMem %p %d:", ptr, size); + for (i = 0; i < size; i++) + log_write("%02x ", (uint16)(byte)ptr[i]); + log_write("\n"); +} + +void dbg_dumpMemChars(char *ptr, int16 size) { + int16 i; + log_write("dbg_dumpMem %p %ld:", ptr, size); + for (i = 0; i < size; i++) + log_write("%c ", ptr[i]); + log_write("\n"); +} + +void dbg_printDelim() { + log_write("-------------------\n"); +} + +void dbg_printHexInt(int16 val) { + log_write("%02x\n", val); +} + +void dbg_dumpStaticScenery(Scen_Static * st) { + int16 i, j; + Scen_StaticPlane *ptr; + + log_write("dbg_dumpStaticScenery\n"); + log_write("----------\n"); + log_write("Layers count = %d\n", st->layersCount); + + for (i = 0; i < st->layersCount; i++) { + log_write("Layer %d:\n", i); + log_write("Back sprite resource id = %d\n", + st->layers[i]->backResId); + log_write("Plane count = %d\n", st->layers[i]->planeCount); + + for (j = 0; j < st->layers[i]->planeCount; j++) { + ptr = &st->layers[i]->planes[j]; + log_write + ("Plane %d: pictIndex = %d, pieceIndex = %d, drawOrder = %d\n", + j, (int16)ptr->pictIndex, (int16)ptr->pieceIndex, + (int16)ptr->drawOrder); + + log_write + ("destX = %d, destY = %d, transparency = %d\n", + ptr->destX, ptr->destY, (char *)ptr->transp); + } + } + log_write("----------\n\n"); +} + +int16 calcDest(char dest, byte add) { + if (dest >= 0) + return dest + ((uint16)add << 7); + else + return dest - ((uint16)add << 7); +} + +/* +void dbg_dumpFramePiece(Scen_AnimFramePiece* piece, int16 j, Scen_AnimLayer* layer) { + log_write("Piece for %d anim, %p: ", j, piece); + log_write("pictIndex = %x, pieceIndex = %d, destX = %d, destY = %d, not final = %d\n", + (uint16)piece->pictIndex, + (uint16)piece->pieceIndex, + layer->deltaX+calcDest(piece->destX, (char)((piece->pictIndex & 0xc0)>>6)), + layer->deltaY+calcDest(piece->destY, (char)((piece->pictIndex & 0x30)>>4)), + (int16)piece->notFinal); +} + +void dbg_dumpAnimation(Scen_Animation* anim) { + int16 i, j; + Scen_AnimLayer* layer; + Scen_AnimFramePiece* piece; + + log_write("dbg_dumpAnimation\n"); + log_write("----------\n"); + log_write("Layers count = %d\n", anim->layersCount); + + for(i = 0; i < anim->layersCount; i++) + { + layer = anim->layers[i]; + + log_write("Layer %d:\n", i); + + log_write("unknown0 = %d\n", layer->unknown0); + log_write("deltaX = %d\n", layer->deltaX); + log_write("deltaY = %d\n", layer->deltaY); + log_write("unknown1 = %d\n", layer->unknown1); + log_write("unknown2 = %d\n", layer->unknown2); + log_write("transparency = %d\n", (int16)layer->transp); + log_write("animsCount %d\n", layer->framesCount); + + piece = layer->frames; + j = 0; + while(j < layer->framesCount) + { + dbg_dumpFramePiece(piece, j, layer); + if(piece->notFinal != 1) + j++; + piece++; + } + } + + log_write("----------\n\n"); +} + +*/ + +} // End of namespace Gob diff --git a/gob/debug.h b/gob/debug.h new file mode 100644 index 0000000000..f68188d440 --- /dev/null +++ b/gob/debug.h @@ -0,0 +1,27 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __MY_DEBUG_H +#define __MY_DEBUG_H + +#define LOG_NAME "log.txt" + +#include "scenery.h" + +namespace Gob { + +void log_write(const char *format, ...); + +void dbg_dumpMem(char *ptr, int16 size); + +void dbg_dumpAnimation(Scen_Animation *anim); +void dbg_dumpFramePiece(Scen_AnimFramePiece *piece, int16 j, + Scen_AnimLayer *layer); + +} // End of namespace Gob + +#endif diff --git a/gob/draw.cpp b/gob/draw.cpp new file mode 100644 index 0000000000..dfd742f974 --- /dev/null +++ b/gob/draw.cpp @@ -0,0 +1,908 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#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/debug.h" +#include "gob/inter.h" +#include "gob/video.h" +#include "gob/palanim.h" + +namespace Gob { + +int16 draw_fontIndex = 0; +int16 draw_spriteLeft = 0; +int16 draw_spriteTop = 0; +int16 draw_spriteRight = 0; +int16 draw_spriteBottom = 0; +int16 draw_destSpriteX = 0; +int16 draw_destSpriteY = 0; +int16 draw_backColor = 0; +int16 draw_frontColor = 0; +char draw_letterToPrint = 0; +Draw_FontToSprite draw_fontToSprite[4]; +int16 draw_destSurface = 0; +int16 draw_sourceSurface = 0; +int16 draw_renderFlags = 0; +int16 draw_backDeltaX = 0; +int16 draw_backDeltaY = 0; +FontDesc *draw_fonts[4]; +char *draw_textToPrint = 0; +int16 draw_transparency = 0; +SurfaceDesc *draw_spritesArray[50]; + +int16 draw_invalidatedCount; +int16 draw_invalidatedTops[30]; +int16 draw_invalidatedLefts[30]; +int16 draw_invalidatedRights[30]; +int16 draw_invalidatedBottoms[30]; + +char draw_noInvalidated = 0; +char draw_applyPal = 0; +char draw_paletteCleared = 0; + +SurfaceDesc *draw_backSurface = 0; +SurfaceDesc *draw_frontSurface = 0; + +int16 draw_unusedPalette1[18]; +int16 draw_unusedPalette2[16]; +Color draw_vgaPalette[256]; +Color draw_vgaSmallPalette[16]; + +int16 draw_cursorX = 0; +int16 draw_cursorY = 0; +int16 draw_cursorWidth = 0; +int16 draw_cursorHeight = 0; + +int16 draw_cursorXDeltaVar = -1; +int16 draw_cursorYDeltaVar = -1; + +int16 draw_cursorIndex = 0; +int16 draw_transparentCursor = 0; +SurfaceDesc *draw_cursorSprites = 0; +SurfaceDesc *draw_cursorBack = 0; +int16 draw_cursorAnim = 0; +char draw_cursorAnimLow[40]; +char draw_cursorAnimHigh[40]; +char draw_cursorAnimDelays[40]; +static uint32 draw_cursorTimeKey = 0; + +int16 draw_palLoadData1[] = { 0, 17, 34, 51 }; +int16 draw_palLoadData2[] = { 0, 68, 136, 204 }; + +void draw_invalidateRect(int16 left, int16 top, int16 right, int16 bottom) { + int16 temp; + int16 rect; + int16 i; + + if (draw_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; + + draw_noInvalidated = 0; + + if (draw_invalidatedCount >= 30) { + draw_invalidatedLefts[0] = 0; + draw_invalidatedTops[0] = 0; + draw_invalidatedRights[0] = 319; + draw_invalidatedBottoms[0] = 199; + draw_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 < draw_invalidatedCount; rect++) { + + if (draw_invalidatedTops[rect] > top) { + if (draw_invalidatedTops[rect] > bottom) { + for (i = draw_invalidatedCount; i > rect; i--) { + draw_invalidatedLefts[i] = + draw_invalidatedLefts[i - 1]; + draw_invalidatedTops[i] = + draw_invalidatedTops[i - 1]; + draw_invalidatedRights[i] = + draw_invalidatedRights[i - 1]; + draw_invalidatedBottoms[i] = + draw_invalidatedBottoms[i - 1]; + } + draw_invalidatedLefts[rect] = left; + draw_invalidatedTops[rect] = top; + draw_invalidatedRights[rect] = right; + draw_invalidatedBottoms[rect] = bottom; + draw_invalidatedCount++; + return; + } + if (draw_invalidatedBottoms[rect] < bottom) + draw_invalidatedBottoms[rect] = bottom; + + if (draw_invalidatedLefts[rect] > left) + draw_invalidatedLefts[rect] = left; + + if (draw_invalidatedRights[rect] < right) + draw_invalidatedRights[rect] = right; + + draw_invalidatedTops[rect] = top; + return; + } + + if (draw_invalidatedBottoms[rect] < top) + continue; + + if (draw_invalidatedBottoms[rect] < bottom) + draw_invalidatedBottoms[rect] = bottom; + + if (draw_invalidatedLefts[rect] > left) + draw_invalidatedLefts[rect] = left; + + if (draw_invalidatedRights[rect] < right) + draw_invalidatedRights[rect] = right; + + return; + } + + draw_invalidatedLefts[draw_invalidatedCount] = left; + draw_invalidatedTops[draw_invalidatedCount] = top; + draw_invalidatedRights[draw_invalidatedCount] = right; + draw_invalidatedBottoms[draw_invalidatedCount] = bottom; + draw_invalidatedCount++; + return; +} + +void draw_blitInvalidated(void) { + int16 i; + + if (draw_cursorIndex == 4) + draw_blitCursor(); + + if (inter_terminate) + return; + + if (draw_noInvalidated && draw_applyPal == 0) + return; + + if (draw_noInvalidated) { + draw_setPalette(); + draw_applyPal = 0; + return; + } + + if (draw_applyPal) { + draw_clearPalette(); + + vid_drawSprite(draw_backSurface, draw_frontSurface, 0, 0, 319, + 199, 0, 0, 0); + draw_setPalette(); + draw_invalidatedCount = 0; + draw_noInvalidated = 1; + draw_applyPal = 0; + return; + } + + doRangeClamp = 0; + for (i = 0; i < draw_invalidatedCount; i++) { + vid_drawSprite(draw_backSurface, draw_frontSurface, + draw_invalidatedLefts[i], draw_invalidatedTops[i], + draw_invalidatedRights[i], draw_invalidatedBottoms[i], + draw_invalidatedLefts[i], draw_invalidatedTops[i], 0); + } + doRangeClamp = 1; + + draw_invalidatedCount = 0; + draw_noInvalidated = 1; + draw_applyPal = 0; +} + +void draw_setPalette(void) { + if (videoMode != 0x13) + error("draw_setPalette: Video mode 0x%x is not supported!\n", + videoMode); + + pPaletteDesc->unused1 = draw_unusedPalette1; + pPaletteDesc->unused2 = draw_unusedPalette2; + pPaletteDesc->vgaPal = draw_vgaPalette; + vid_setFullPalette(pPaletteDesc); + draw_paletteCleared = 0; +} + +void draw_clearPalette(void) { + if (draw_paletteCleared == 0) { + draw_paletteCleared = 1; + util_clearPalette(); + } +} + +void draw_blitCursor(void) { + if (draw_cursorIndex == -1) + return; + + draw_cursorIndex = -1; + if (draw_cursorX + draw_cursorWidth > 320) + draw_cursorWidth = 320 - draw_cursorX; + + if (draw_cursorY + draw_cursorHeight > 200) + draw_cursorHeight = 200 - draw_cursorY; + + if (draw_noInvalidated) { + vid_drawSprite(draw_backSurface, draw_frontSurface, + draw_cursorX, draw_cursorY, + draw_cursorX + draw_cursorWidth - 1, + draw_cursorY + draw_cursorHeight - 1, draw_cursorX, + draw_cursorY, 0); + } else { + draw_invalidateRect(draw_cursorX, draw_cursorY, + draw_cursorX + draw_cursorWidth - 1, + draw_cursorY + draw_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 (draw_sourceSurface >= 100) + draw_sourceSurface -= 80; + + if (draw_destSurface >= 100) + draw_destSurface -= 80; + + if (draw_renderFlags & RENDERFLAG_USEDELTAS) { + if (draw_sourceSurface == 21) { + draw_spriteLeft += draw_backDeltaX; + draw_spriteTop += draw_backDeltaY; + } + + if (draw_destSurface == 21) { + draw_destSpriteX += draw_backDeltaX; + draw_destSpriteY += draw_backDeltaY; + if (operation == DRAW_DRAWLINE || + (operation >= DRAW_DRAWBAR + && operation <= DRAW_FILLRECTABS)) { + draw_spriteRight += draw_backDeltaX; + draw_spriteBottom += draw_backDeltaY; + } + } + } + + switch (operation) { + case DRAW_BLITSURF: + vid_drawSprite(draw_spritesArray[draw_sourceSurface], + draw_spritesArray[draw_destSurface], + draw_spriteLeft, draw_spriteTop, + draw_spriteLeft + draw_spriteRight - 1, + draw_spriteTop + draw_spriteBottom - 1, + draw_destSpriteX, draw_destSpriteY, draw_transparency); + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX + draw_spriteRight - 1, + draw_destSpriteY + draw_spriteBottom - 1); + } + break; + + case DRAW_PUTPIXEL: + vid_putPixel(draw_destSpriteX, draw_destSpriteY, + draw_frontColor, draw_spritesArray[draw_destSurface]); + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX, draw_destSpriteY); + } + break; + + case DRAW_FILLRECT: + vid_fillRect(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX + draw_spriteRight - 1, + draw_destSpriteY + draw_spriteBottom - 1, draw_backColor); + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX + draw_spriteRight - 1, + draw_destSpriteY + draw_spriteBottom - 1); + } + break; + + case DRAW_DRAWLINE: + vid_fillRect(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom, draw_frontColor); + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom); + } + break; + + case DRAW_INVALIDATE: + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX - draw_spriteRight, draw_destSpriteY - draw_spriteBottom, // !! + draw_destSpriteX + draw_spriteRight, + draw_destSpriteY + draw_spriteBottom); + } + break; + + case DRAW_LOADSPRITE: + id = draw_spriteLeft; + if (id >= 30000) { + dataBuf = + game_loadExtData(id, &draw_spriteRight, + &draw_spriteBottom); + vid_drawPackedSprite((byte *)dataBuf, draw_spriteRight, + draw_spriteBottom, draw_destSpriteX, + draw_destSpriteY, draw_transparency, + draw_spritesArray[draw_destSurface]); + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, + draw_destSpriteY, + draw_destSpriteX + draw_spriteRight - 1, + draw_destSpriteY + draw_spriteBottom - 1); + } + free(dataBuf); + break; + } + // Load from .TOT resources + itemPtr = &game_totResourceTable->items[id]; + offset = itemPtr->offset; + if (offset >= 0) { + dataBuf = + ((char *)game_totResourceTable) + + szGame_TotResTable + szGame_TotResItem * + game_totResourceTable->itemsCount + offset; + } else { + dataBuf = + game_imFileData + + ((int32 *)game_imFileData)[-offset - 1]; + } + + draw_spriteRight = itemPtr->width; + draw_spriteBottom = itemPtr->height; + vid_drawPackedSprite((byte *)dataBuf, + draw_spriteRight, draw_spriteBottom, + draw_destSpriteX, draw_destSpriteY, + draw_transparency, draw_spritesArray[draw_destSurface]); + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX + draw_spriteRight - 1, + draw_destSpriteY + draw_spriteBottom - 1); + } + break; + + case DRAW_PRINTTEXT: + len = strlen(draw_textToPrint); + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX + + len * draw_fonts[draw_fontIndex]->itemWidth - 1, + draw_destSpriteY + + draw_fonts[draw_fontIndex]->itemHeight - 1); + } + + for (i = 0; i < len; i++) { + vid_drawLetter(draw_textToPrint[i], + draw_destSpriteX, draw_destSpriteY, + draw_fonts[draw_fontIndex], + draw_transparency, + draw_frontColor, draw_backColor, + draw_spritesArray[draw_destSurface]); + + draw_destSpriteX += draw_fonts[draw_fontIndex]->itemWidth; + } + break; + + case DRAW_DRAWBAR: + vid_drawLine(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_spriteBottom, + draw_spriteRight, draw_spriteBottom, draw_frontColor); + + vid_drawLine(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX, draw_spriteBottom, draw_frontColor); + + vid_drawLine(draw_spritesArray[draw_destSurface], + draw_spriteRight, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom, draw_frontColor); + + vid_drawLine(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_destSpriteY, draw_frontColor); + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom); + } + break; + + case DRAW_CLEARRECT: + if (draw_backColor < 16) { + vid_fillRect(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom, + draw_backColor); + } + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom); + } + break; + + case DRAW_FILLRECTABS: + vid_fillRect(draw_spritesArray[draw_destSurface], + draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom, draw_backColor); + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom); + } + break; + + case DRAW_DRAWLETTER: + if (draw_fontToSprite[draw_fontIndex].sprite == -1) { + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, + draw_destSpriteY, + draw_destSpriteX + + draw_fonts[draw_fontIndex]->itemWidth - 1, + draw_destSpriteY + + draw_fonts[draw_fontIndex]->itemHeight - + 1); + } + vid_drawLetter(draw_letterToPrint, + draw_destSpriteX, draw_destSpriteY, + draw_fonts[draw_fontIndex], + draw_transparency, + draw_frontColor, draw_backColor, + draw_spritesArray[draw_destSurface]); + break; + } + + perLine = + draw_spritesArray[(int16)draw_fontToSprite[draw_fontIndex]. + sprite]->width / draw_fontToSprite[draw_fontIndex].width; + + y = (draw_letterToPrint - + draw_fontToSprite[draw_fontIndex].base) / perLine * + draw_fontToSprite[draw_fontIndex].height; + + x = (draw_letterToPrint - + draw_fontToSprite[draw_fontIndex].base) % perLine * + draw_fontToSprite[draw_fontIndex].width; + + if (draw_destSurface == 21) { + draw_invalidateRect(draw_destSpriteX, draw_destSpriteY, + draw_destSpriteX + + draw_fontToSprite[draw_fontIndex].width, + draw_destSpriteY + + draw_fontToSprite[draw_fontIndex].height); + } + + vid_drawSprite(draw_spritesArray[(int16)draw_fontToSprite + [draw_fontIndex].sprite], + draw_spritesArray[draw_destSurface], x, y, + x + draw_fontToSprite[draw_fontIndex].width, + y + draw_fontToSprite[draw_fontIndex].height, + draw_destSpriteX, draw_destSpriteY, draw_transparency); + + break; + } + + if (draw_renderFlags & RENDERFLAG_USEDELTAS) { + if (draw_sourceSurface == 21) { + draw_spriteLeft -= draw_backDeltaX; + draw_spriteTop -= draw_backDeltaY; + } + + if (draw_destSurface == 21) { + draw_destSpriteX -= draw_backDeltaX; + draw_destSpriteY -= draw_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 = game_collisionAreas; ptr->left != -1; ptr++) { + if (ptr->flags & 0xfff0) + continue; + + if (ptr->left > inter_mouseX) + continue; + + if (ptr->right < inter_mouseX) + continue; + + if (ptr->top > inter_mouseY) + continue; + + if (ptr->bottom < inter_mouseY) + continue; + + if ((ptr->flags & 0xf) < 3) + cursorIndex = 1; + else + cursorIndex = 3; + break; + } + if (draw_cursorAnimLow[cursorIndex] == -1) + cursorIndex = 1; + } + + if (draw_cursorAnimLow[cursorIndex] != -1) { + if (cursorIndex == draw_cursorIndex) { + if (draw_cursorAnimDelays[draw_cursorIndex] != 0 && + draw_cursorAnimDelays[draw_cursorIndex] * 10 + + draw_cursorTimeKey <= util_getTimeKey()) { + draw_cursorAnim++; + draw_cursorTimeKey = util_getTimeKey(); + } else { +/* if(draw_noInvalidated && + inter_mouseX == draw_cursorX && inter_mouseY == draw_cursorY) + return;*/ + } + } else { + draw_cursorIndex = cursorIndex; + if (draw_cursorAnimDelays[draw_cursorIndex] != 0) { + draw_cursorAnim = + draw_cursorAnimLow[draw_cursorIndex]; + draw_cursorTimeKey = util_getTimeKey(); + } else { + draw_cursorAnim = draw_cursorIndex; + } + } + + if (draw_cursorAnimDelays[draw_cursorIndex] != 0 && + (draw_cursorAnimHigh[draw_cursorIndex] < draw_cursorAnim || + draw_cursorAnimLow[draw_cursorIndex] > + draw_cursorAnim)) { + draw_cursorAnim = draw_cursorAnimLow[draw_cursorIndex]; + } + + newX = inter_mouseX; + newY = inter_mouseY; + if (draw_cursorXDeltaVar != -1) { + newX -= READ_LE_UINT16(inter_variables + draw_cursorIndex * 4 + + (draw_cursorXDeltaVar / 4) * 4); + newY -= READ_LE_UINT16(inter_variables + draw_cursorIndex * 4 + + (draw_cursorYDeltaVar / 4) * 4); + } + + minX = MIN(newX, draw_cursorX); + minY = MIN(newY, draw_cursorY); + maxX = MAX(draw_cursorX, newX) + draw_cursorWidth - 1; + maxY = MAX(draw_cursorY, newY) + draw_cursorHeight - 1; + vid_drawSprite(draw_backSurface, draw_cursorBack, + newX, newY, newX + draw_cursorWidth - 1, + newY + draw_cursorHeight - 1, 0, 0, 0); + + vid_drawSprite(draw_cursorSprites, draw_backSurface, + draw_cursorWidth * draw_cursorAnim, 0, + draw_cursorWidth * (draw_cursorAnim + 1) - 1, + draw_cursorHeight - 1, newX, newY, draw_transparentCursor); + + if (draw_noInvalidated == 0) { + cursorIndex = draw_cursorIndex; + draw_cursorIndex = -1; + draw_blitInvalidated(); + draw_cursorIndex = cursorIndex; + } else { + vid_waitRetrace(videoMode); + if (minY < 50) + util_delay(5); + } + + vid_drawSprite(draw_backSurface, draw_frontSurface, + minX, minY, maxX, maxY, minX, minY, 0); + + vid_drawSprite(draw_cursorBack, draw_backSurface, + 0, 0, draw_cursorWidth - 1, draw_cursorHeight - 1, + newX, newY, 0); + } else { + draw_blitCursor(); + } + + draw_cursorX = newX; + draw_cursorY = newY; +} + +void draw_interPalLoad(void) { + int16 i; + int16 ind1; + int16 ind2; + byte cmd; + char *palPtr; + + cmd = *inter_execPtr++; + draw_applyPal = 0; + if (cmd & 0x80) + cmd &= 0x7f; + else + draw_applyPal = 1; + + if (cmd == 49) { + warning("inter_palLoad: cmd == 49 is not supported"); + //var_B = 1; + for (i = 0; i < 18; i++, inter_execPtr++) { + if (i < 2) { + if (draw_applyPal == 0) + continue; + + draw_unusedPalette1[i] = *inter_execPtr; + continue; + } + //if(*inter_execPtr != 0) + // var_B = 0; + + ind1 = *inter_execPtr >> 4; + ind2 = (*inter_execPtr & 0xf); + + draw_unusedPalette1[i] = + ((draw_palLoadData1[ind1] + draw_palLoadData2[ind2]) << 8) + + (draw_palLoadData2[ind1] + draw_palLoadData1[ind2]); + } + + pPaletteDesc->unused1 = draw_unusedPalette1; + } + + switch (cmd) { + case 52: + for (i = 0; i < 16; i++, inter_execPtr += 3) { + draw_vgaSmallPalette[i].red = inter_execPtr[0]; + draw_vgaSmallPalette[i].green = inter_execPtr[1]; + draw_vgaSmallPalette[i].blue = inter_execPtr[2]; + } + break; + + case 50: + for (i = 0; i < 16; i++, inter_execPtr++) + draw_unusedPalette2[i] = *inter_execPtr; + break; + + case 53: + palPtr = game_loadTotResource(inter_load16()); + memcpy((char *)draw_vgaPalette, palPtr, 768); + break; + + case 54: + memset((char *)draw_vgaPalette, 0, 768); + break; + } + if (!draw_applyPal) { + pPaletteDesc->unused2 = draw_unusedPalette2; + pPaletteDesc->unused1 = draw_unusedPalette1; + + if (videoMode != 0x13) + pPaletteDesc->vgaPal = (Color *)draw_vgaSmallPalette; + else + pPaletteDesc->vgaPal = (Color *)draw_vgaPalette; + + pal_fade((PalDesc *) pPaletteDesc, 0, 0); + } +} + +void draw_printText(void) { + int16 savedFlags; + int16 destSpriteX; + char *dataPtr; + char *ptr; + char *ptr2; + int16 index; + int16 destX; + int16 destY; + char cmd; + int16 val; + char buf[20]; + + index = inter_load16(); + dataPtr = (char *)game_totTextData + game_totTextData->items[index].offset; + ptr = dataPtr; + + if (draw_renderFlags & RENDERFLAG_CAPTUREPUSH) { + draw_destSpriteX = READ_LE_UINT16(ptr); + draw_destSpriteY = READ_LE_UINT16(ptr + 2); + draw_spriteRight = READ_LE_UINT16(ptr + 4) - draw_destSpriteX + 1; + draw_spriteBottom = READ_LE_UINT16(ptr + 6) - draw_destSpriteY + 1; + game_capturePush(draw_destSpriteX, draw_destSpriteY, + draw_spriteRight, draw_spriteBottom); + (*scen_pCaptureCounter)++; + } + draw_destSpriteX = READ_LE_UINT16(ptr); + destX = draw_destSpriteX; + + draw_destSpriteY = READ_LE_UINT16(ptr + 2); + destY = draw_destSpriteY; + + draw_spriteRight = READ_LE_UINT16(ptr + 4); + draw_spriteBottom = READ_LE_UINT16(ptr + 6); + draw_destSurface = 21; + + ptr += 8; + + draw_backColor = *ptr++; + draw_transparency = 1; + draw_spriteOperation(DRAW_CLEARRECT); + + draw_backColor = 0; + savedFlags = draw_renderFlags; + + draw_renderFlags &= ~RENDERFLAG_NOINVALIDATE; + for (; (draw_destSpriteX = READ_LE_UINT16(ptr)) != -1; ptr++) { + draw_destSpriteX += destX; + draw_destSpriteY = READ_LE_UINT16(ptr + 2) + destY; + draw_spriteRight = READ_LE_UINT16(ptr + 4) + destX; + draw_spriteBottom = READ_LE_UINT16(ptr + 6) + destY; + ptr += 8; + + cmd = (*ptr & 0xf0) >> 4; + if (cmd == 0) { + draw_frontColor = *ptr & 0xf; + draw_spriteOperation(DRAW_DRAWLINE); + } else if (cmd == 1) { + draw_frontColor = *ptr & 0xf; + draw_spriteOperation(DRAW_DRAWBAR); + } else if (cmd == 2) { + draw_backColor = *ptr & 0xf; + draw_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++; + draw_fontIndex = (*ptr & 0xf0) >> 4; + draw_frontColor = *ptr & 0xf; + ptr++; + continue; + } else if (cmd == 2) { + ptr++; + draw_destSpriteX = destX + READ_LE_UINT16(ptr); + draw_destSpriteY = destY + READ_LE_UINT16(ptr + 2); + ptr += 4; + continue; + } + + if ((byte)*ptr != 0xba) { + draw_letterToPrint = *ptr; + draw_spriteOperation(DRAW_DRAWLETTER); + draw_destSpriteX += + draw_fonts[draw_fontIndex]->itemWidth; + ptr++; + } else { + cmd = ptr2[17] & 0x7f; + if (cmd == 0) { + val = READ_LE_UINT16(ptr2 + 18) * 4; + sprintf(buf, "%ld", READ_LE_UINT32(inter_variables + val)); + } else if (cmd == 1) { + val = READ_LE_UINT16(ptr2 + 18) * 4; + + strcpy(buf, inter_variables + val); + } else { + val = READ_LE_UINT16(ptr2 + 18) * 4; + + sprintf(buf, "%ld", READ_LE_UINT32(inter_variables + val)); + if (buf[0] == '-') { + while (strlen(buf) - 1 < (uint32)ptr2[17]) { + util_insertStr((char *)"0", buf, 1); + } + } else { + while (strlen(buf) - 1 < (uint32)ptr2[17]) { + util_insertStr((char *)"0", buf, 0); + } + } + + util_insertStr((char *)",", buf, strlen(buf) + 1 - ptr2[17]); + } + + draw_textToPrint = buf; + destSpriteX = draw_destSpriteX; + draw_spriteOperation(DRAW_PRINTTEXT); + if (ptr2[17] & 0x80) { + if (ptr[1] == ' ') { + draw_destSpriteX += draw_fonts[draw_fontIndex]->itemWidth; + while (ptr[1] == ' ') + ptr++; + if (ptr[1] == 2) { + if (READ_LE_UINT16(ptr + 4) == draw_destSpriteY) + ptr += 5; + } + } else if (ptr[1] == 2 && READ_LE_UINT16(ptr + 4) == draw_destSpriteY) { + ptr += 5; + draw_destSpriteX += draw_fonts[draw_fontIndex]->itemWidth; + } + } else { + draw_destSpriteX = destSpriteX + draw_fonts[draw_fontIndex]->itemWidth; + } + ptr2 += 23; + ptr++; + } + } + + draw_renderFlags = savedFlags; + if (draw_renderFlags & 4) { + warning("draw_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 ((draw_renderFlags & RENDERFLAG_CAPTUREPOP) && *scen_pCaptureCounter != 0) { + (*scen_pCaptureCounter)--; + game_capturePop(1); + } +} + +} // End of namespace Gob diff --git a/gob/draw.h b/gob/draw.h new file mode 100644 index 0000000000..71e0baa35b --- /dev/null +++ b/gob/draw.h @@ -0,0 +1,111 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __DRAW_H +#define __DRAW_H + +#include "gob/video.h" + +namespace Gob { + +#define RENDERFLAG_NOINVALIDATE 1 +#define RENDERFLAG_CAPTUREPUSH 2 +#define RENDERFLAG_CAPTUREPOP 8 +#define RENDERFLAG_USEDELTAS 0x10 + +typedef struct Draw_FontToSprite { + char sprite; + char base; + char width; + char height; +} Draw_FontToSprite; + +extern int16 draw_fontIndex; +extern int16 draw_spriteLeft; +extern int16 draw_spriteTop; +extern int16 draw_spriteRight; +extern int16 draw_spriteBottom; +extern int16 draw_destSpriteX; +extern int16 draw_destSpriteY; +extern int16 draw_backColor; +extern int16 draw_frontColor; +extern char draw_letterToPrint; +extern Draw_FontToSprite draw_fontToSprite[4]; +extern int16 draw_destSurface; +extern int16 draw_sourceSurface; +extern int16 draw_renderFlags; +extern int16 draw_backDeltaX; +extern int16 draw_backDeltaY; +extern FontDesc *draw_fonts[4]; +extern char *draw_textToPrint; +extern int16 draw_transparency; +extern SurfaceDesc *draw_spritesArray[50]; + +extern int16 draw_invalidatedCount; +extern int16 draw_invalidatedTops[30]; +extern int16 draw_invalidatedLefts[30]; +extern int16 draw_invalidatedRights[30]; +extern int16 draw_invalidatedBottoms[30]; + +extern char draw_noInvalidated; +extern char draw_doFullFlip; +extern char draw_paletteCleared; + +extern int16 draw_cursorIndex; +extern int16 draw_transparentCursor; + +extern SurfaceDesc *draw_backSurface; +extern SurfaceDesc *draw_frontSurface; + +extern int16 draw_unusedPalette1[18]; +extern int16 draw_unusedPalette2[16]; +extern Color draw_vgaPalette[256]; +extern Color draw_vgaSmallPalette[16]; + +extern int16 draw_cursorX; +extern int16 draw_cursorY; +extern int16 draw_cursorWidth; +extern int16 draw_cursorHeight; + +extern int16 draw_cursorXDeltaVar; +extern int16 draw_cursorYDeltaVar; + +extern SurfaceDesc *draw_cursorSprites; +extern SurfaceDesc *draw_cursorBack; +extern int16 draw_cursorAnim; +extern char draw_cursorAnimLow[40]; +extern char draw_cursorAnimHigh[40]; +extern char draw_cursorAnimDelays[40]; +extern char draw_applyPal; + +void draw_invalidateRect(int16 left, int16 top, int16 right, int16 bottom); +void draw_blitInvalidated(void); +void draw_setPalette(void); +void draw_clearPalette(void); +void draw_blitCursor(void); + +void draw_spriteOperation(int16 operation); +void draw_animateCursor(int16 cursor); +void draw_interPalLoad(void); +void draw_printText(void); +// 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/gob/driver_vga.cpp b/gob/driver_vga.cpp new file mode 100644 index 0000000000..2ad914340c --- /dev/null +++ b/gob/driver_vga.cpp @@ -0,0 +1,59 @@ +#include "driver_vga.h" + +#define STUB_FUNC printf("STUB: %s\n", __PRETTY_FUNCTION__) + +namespace Gob { + +void VGAVideoDriver::drawSprite(SurfaceDesc *source, 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--) { + for (int16 i = 0; i < width; ++i) { + if (srcPos[i]) + destPos[i] = srcPos[i]; + } + + srcPos += source->width; //width ? + destPos += dest->width; + } + } +} + +void VGAVideoDriver::fillRect(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, SurfaceDesc *dest) { + if (x >= 0 && x < dest->width && y >= 0 && y < dest->height) + dest->vidPtr[(y * dest->width) + x] = color; +} + +void VGAVideoDriver::drawLetter(char item, int16 x, int16 y, FontDesc *fontDesc, byte color1, byte color2, byte transp, SurfaceDesc *dest) { + STUB_FUNC; +} + +void VGAVideoDriver::drawLine(SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, int16 y1, byte color) { + STUB_FUNC; +} + +void VGAVideoDriver::drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y, byte transp, SurfaceDesc *dest) { + STUB_FUNC; +} + +} + diff --git a/gob/driver_vga.h b/gob/driver_vga.h new file mode 100644 index 0000000000..0c31cd874d --- /dev/null +++ b/gob/driver_vga.h @@ -0,0 +1,22 @@ +#ifndef DRIVER_VGA +#define DRIVER_VGA + +#include "video.h" + +namespace Gob { + +class VGAVideoDriver : public VideoDriver { +public: + VGAVideoDriver() {} + virtual ~VGAVideoDriver() {} + 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, byte color); + void putPixel(int16 x, int16 y, byte color, SurfaceDesc *dest); + void drawLetter(char item, int16 x, int16 y, FontDesc *fontDesc, byte color1, byte color2, byte transp, SurfaceDesc *dest); + void drawLine(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, SurfaceDesc *dest); +}; + +} + +#endif diff --git a/gob/game.cpp b/gob/game.cpp new file mode 100644 index 0000000000..ebca665114 --- /dev/null +++ b/gob/game.cpp @@ -0,0 +1,1909 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#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/debug.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" + +namespace Gob { + +Game_ExtTable *game_extTable = 0; + +char *game_totFileData = 0; +Game_TotTextTable *game_totTextData; +Game_TotResTable *game_totResourceTable = 0; +char *game_imFileData = 0; +int16 game_extHandle = 0; +char game_curExtFile[14]; +char game_curTotFile[14]; +char game_curImaFile[18]; + +Game_Collision *game_collisionAreas = 0; +char game_shouldPushColls = 0; +char game_collStr[256]; + +int16 game_lastCollKey; +int16 game_lastCollAreaIndex; +int16 game_lastCollId; + +char game_handleMouse; +char game_forceHandleMouse; + +char game_tempStr[256]; + +int16 game_activeCollResId; +int16 game_activeCollIndex; + +// Collisions stack +int16 game_collStackSize = 0; +Game_Collision *game_collStack[3]; +int16 game_collStackElemSizes[3]; + +int16 game_mouseButtons = 0; + +// Capture +static Rectangle game_captureStack[20]; +static int16 game_captureCount = 0; + +Snd_SoundDesc *game_soundSamples[20]; + +char game_soundFromExt[20]; +char game_totToLoad[20]; + +int32 game_startTimeKey; + +char *game_loadExtData(int16 itemId, int16 *pResWidth, int16 *pResHeight) { + int16 commonHandle; + int16 itemsCount; + int32 offset; + uint32 size; + Game_ExtItem *item; + char isPacked; + int16 handle; + int32 tableSize; + char path[20]; + char *dataBuf; + char *packedBuf; + char *dataPtr; + + itemId -= 30000; + if (game_extTable == 0) + return 0; + + commonHandle = -1; + itemsCount = game_extTable->itemsCount; + item = &game_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(0, "game_loadExtData(%d, %d, %d)", itemId, *pResWidth, *pResHeight); + } + + debug(0, "game_loadExtData(%d, 0, 0)", itemId); + + if (item->height == 0) + size += (item->width & 0x7fff) << 16; + + debug(0, "size: %d off: %d", size, offset); + if (offset >= 0) { + handle = game_extHandle; + } else { + offset = -(offset + 1); + tableSize = 0; + data_closeData(game_extHandle); + strcpy(path, "commun.ex1"); + path[strlen(path) - 1] = *(game_totFileData + 0x3c) + '0'; + commonHandle = data_openData(path); + handle = commonHandle; + } + + debug(0, "off: %ld size: %ld", offset, tableSize); + data_seekData(handle, offset + tableSize, SEEK_SET); + if (isPacked) + dataBuf = (char *)malloc(size); + else + dataBuf = (char *)malloc(size); + + dataPtr = dataBuf; + while (size > 32000) { + // BUG: huge->far conversion. Need normalization? + data_readData(handle, (char *)dataPtr, 32000); + size -= 32000; + dataPtr += 32000; + } + data_readData(handle, (char *)dataPtr, size); + if (commonHandle != -1) { + data_closeData(commonHandle); + game_extHandle = data_openData(game_curExtFile); + } + + if (isPacked != 0) { + packedBuf = dataBuf; + dataBuf = (char *)malloc(READ_LE_UINT32(packedBuf)); + unpackData(packedBuf, dataBuf); + free(packedBuf); + } + + for (int16 i = 0; i < 16; i++) + printf("%02x ", (byte)dataBuf[i]); + printf("\n"); + + return dataBuf; + +} + +void game_clearCollisions() { + int16 i; + for (i = 0; i < 250; i++) + game_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; + Game_Collision *ptr; + + debug(5, "game_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 (game_collisionAreas[i].left != -1) + continue; + + ptr = &game_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("game_addNewCollision: Collision array full!\n"); +} + +void game_freeCollision(int16 id) { + int16 i; + + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].id == id) + game_collisionAreas[i].left = -1; + } +} + +void game_pushCollisions(char all) { + Game_Collision *srcPtr; + Game_Collision *destPtr; + int16 size; + + debug(0, "game_pushCollisions"); + for (size = 0, srcPtr = game_collisionAreas; srcPtr->left != -1; + srcPtr++) { + if (all || (srcPtr->id & 0x8000)) + size++; + } + + destPtr = (Game_Collision *)malloc(size * sizeof(Game_Collision)); + game_collStack[game_collStackSize] = destPtr; + game_collStackElemSizes[game_collStackSize] = size; + game_collStackSize++; + + for (srcPtr = game_collisionAreas; srcPtr->left != -1; srcPtr++) { + if (all || (srcPtr->id & 0x8000)) { + memcpy(destPtr, srcPtr, sizeof(Game_Collision)); + srcPtr->left = -1; + destPtr++; + } + } +} + +void game_popCollisions(void) { + Game_Collision *destPtr; + Game_Collision *srcPtr; + + debug(0, "game_popCollision"); + + game_collStackSize--; + for (destPtr = game_collisionAreas; destPtr->left != -1; destPtr++); + + srcPtr = game_collStack[game_collStackSize]; + memcpy(destPtr, srcPtr, + game_collStackElemSizes[game_collStackSize] * + sizeof(Game_Collision)); + + free((char *)game_collStack[game_collStackSize]); +} + +int16 game_checkMousePoint(int16 all, int16 *resId, int16 *resIndex) { + Game_Collision *ptr; + int16 i; + + if (resId != 0) + *resId = 0; + + *resIndex = 0; + + ptr = game_collisionAreas; + for (i = 0; ptr->left != -1; ptr++, i++) { + if (all) { + if ((ptr->flags & 0xf) > 1) + continue; + + if ((ptr->flags & 0xff00) != 0) + continue; + + if (inter_mouseX < ptr->left + || inter_mouseX > ptr->right + || inter_mouseY < ptr->top + || 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 != game_mouseButtons - 1 + && (ptr->flags & 0xf0) >> 4 != 2) + continue; + + if (inter_mouseX < ptr->left + || inter_mouseX > ptr->right + || inter_mouseY < ptr->top + || inter_mouseY > ptr->bottom) + continue; + + if (resId != 0) + *resId = ptr->id; + *resIndex = i; + return ptr->key; + } + } + + if (game_mouseButtons != 1 && all == 0) + return 0x11b; + + return 0; +} + +void game_capturePush(int16 left, int16 top, int16 width, int16 height) { + int16 right; + + if (game_captureCount == 20) + error("game_capturePush: Capture stack overflow!"); + + game_captureStack[game_captureCount].left = left; + game_captureStack[game_captureCount].top = top; + game_captureStack[game_captureCount].width = width; + game_captureStack[game_captureCount].height = height; + + draw_spriteTop = top; + draw_spriteBottom = height; + + right = left + width - 1; + left &= 0xfff0; + right |= 0xf; + + draw_spritesArray[30 + game_captureCount] = + vid_initSurfDesc(videoMode, right - left + 1, height, 0); + + draw_sourceSurface = 21; + draw_destSurface = 30 + game_captureCount; + + draw_spriteLeft = left; + draw_spriteRight = right - left + 1; + draw_destSpriteX = 0; + draw_destSpriteY = 0; + draw_transparency = 0; + draw_spriteOperation(0); + game_captureCount++; +} + +void game_capturePop(char doDraw) { + if (game_captureCount <= 0) + return; + + game_captureCount--; + if (doDraw) { + draw_destSpriteX = game_captureStack[game_captureCount].left; + draw_destSpriteY = game_captureStack[game_captureCount].top; + draw_spriteRight = game_captureStack[game_captureCount].width; + draw_spriteBottom = + game_captureStack[game_captureCount].height; + + draw_transparency = 0; + draw_sourceSurface = 30 + game_captureCount; + draw_destSurface = 21; + draw_spriteLeft = draw_destSpriteX & 0xf; + draw_spriteTop = 0; + draw_spriteOperation(0); + } + vid_freeSurfDesc(draw_spritesArray[30 + game_captureCount]); +} + +char *game_loadTotResource(int16 id) { + Game_TotResItem *itemPtr; + int32 offset; + + itemPtr = &game_totResourceTable->items[id]; + offset = itemPtr->offset; + if (offset >= 0) { + return (char *)((char *)game_totResourceTable) + szGame_TotResTable + + szGame_TotResItem * game_totResourceTable->itemsCount + offset; + } else { + return (char *)(game_imFileData + + ((int32 *)game_imFileData)[-offset - 1]); + } +} + +void game_loadSound(int16 slot, char *dataPtr) { + Snd_SoundDesc *soundDesc; + + soundDesc = (Snd_SoundDesc *)malloc(sizeof(Snd_SoundDesc)); + + game_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 = parse_parseValExpr(); + + id = inter_load16(); + if (id == -1) { + inter_execPtr += 9; + return; + } + + if (id >= 30000) { + dataPtr = game_loadExtData(id, 0, 0); + game_soundFromExt[slot] = 1; + } else { + dataPtr = game_loadTotResource(id); + game_soundFromExt[slot] = 0; + } + + game_loadSound(slot, dataPtr); +} + +void game_freeSoundSlot(int16 slot) { + if (slot == -1) + slot = parse_parseValExpr(); + + if (game_soundSamples[slot] == 0) + return; + + if (game_soundFromExt[slot] == 1) { + free(game_soundSamples[slot]->data - 6); + game_soundFromExt[slot] = 0; + } + + free((char *)game_soundSamples[slot]); + game_soundSamples[slot] = 0; +} + +int16 game_checkKeys(int16 *pMouseX, int16 *pMouseY, int16 *pButtons, char handleMouse) { + util_processInput(); + + if (READ_LE_UINT32(inter_variables + 0xe8) != 0) { + if (mult_frameStart != READ_LE_UINT32(inter_variables + 0xe8) - 1) + mult_frameStart++; + else + mult_frameStart = 0; + + mult_playMult(mult_frameStart + READ_LE_UINT32(inter_variables + 0xe4), + mult_frameStart + READ_LE_UINT32(inter_variables + 0xe4), 1, + handleMouse); + } + + if (inter_soundEndTimeKey != 0 + && util_getTimeKey() >= inter_soundEndTimeKey) { + snd_stopSound(inter_soundStopVal); + inter_soundEndTimeKey = 0; + } + + if (useMouse == 0) + error("game_checkKeys: Can't work without mouse!"); + + util_getMouseState(pMouseX, pMouseY, pButtons); + + if (*pButtons == 3) + *pButtons = 0; + return 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) { + game_lastCollKey = 0; + game_lastCollAreaIndex = 0; + game_lastCollId = 0; + } + + if (pResId != 0) + *pResId = 0; + + resIndex = 0; + + if (draw_cursorIndex == -1 && handleMouse != 0 + && game_lastCollKey == 0) { + game_lastCollKey = + game_checkMousePoint(1, &game_lastCollId, + &game_lastCollAreaIndex); + + if (game_lastCollKey != 0 && (game_lastCollId & 0x8000) != 0) { + savedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + + game_collisionAreas[game_lastCollAreaIndex].funcEnter; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + } + + if (handleMouse != 0) + draw_animateCursor(-1); + + timeKey = util_getTimeKey(); + while (1) { + if (inter_terminate != 0) { + if (handleMouse) + draw_blitCursor(); + return 0; + } + + if (draw_noInvalidated == 0) { + if (handleMouse) + draw_animateCursor(-1); + else + draw_blitInvalidated(); + } + + key = game_checkKeys(&inter_mouseX, &inter_mouseY, &game_mouseButtons, handleMouse); + if (deltaTime < 0) { + if (util_getTimeKey() + deltaTime > timeKey) { + if (pResId != 0) + *pResId = 0; + + if (pResIndex != 0) + *pResIndex = 0; + return 0; + } + } + + if (handleMouse == 0 && game_mouseButtons != 0) { + util_waitMouseRelease(0); + key = 3; + } + + if (key != 0) { + + if (handleMouse == 1) + draw_blitCursor(); + + if (pResId != 0) + *pResId = 0; + + if (pResIndex != 0) + *pResIndex = 0; + + if (game_lastCollKey != 0 && + game_collisionAreas[game_lastCollAreaIndex].funcLeave != 0) { + savedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + + game_collisionAreas[game_lastCollAreaIndex].funcLeave; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + + game_lastCollKey = 0; + if (key != 0) + return key; + } + + if (handleMouse != 0) { + if (game_mouseButtons != 0) { + oldIndex = 0; + + draw_animateCursor(2); + if (deltaTime <= 0) { + if (handleMouse == 1) + util_waitMouseRelease(1); + } else if (deltaTime > 0) { + util_delay(deltaTime); + } + + draw_animateCursor(-1); + if (pResId != 0) + *pResId = 0; + + key = game_checkMousePoint(0, pResId, &resIndex); + + if (pResIndex != 0) + *pResIndex = resIndex; + + if (key != 0 || (pResId != 0 && *pResId != 0)) { + if (handleMouse == 1 && (deltaTime <= 0 + || game_mouseButtons == 0)) + draw_blitCursor(); + + if (game_lastCollKey != 0 && + game_collisionAreas[game_lastCollAreaIndex].funcLeave != 0) { + savedIP = inter_execPtr; + inter_execPtr = + (char *)game_totFileData + + game_collisionAreas[game_lastCollAreaIndex].funcLeave; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + game_lastCollKey = 0; + return key; + } + + if (game_lastCollKey != 0 && + game_collisionAreas[game_lastCollAreaIndex].funcLeave != 0) { + savedIP = inter_execPtr; + inter_execPtr = + (char *)game_totFileData + + game_collisionAreas[game_lastCollAreaIndex].funcLeave; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + + game_lastCollKey = + game_checkMousePoint(1, &game_lastCollId, + &game_lastCollAreaIndex); + + if (game_lastCollKey != 0 + && (game_lastCollId & 0x8000) != 0) { + savedIP = inter_execPtr; + inter_execPtr = + (char *)game_totFileData + + game_collisionAreas[game_lastCollAreaIndex].funcEnter; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + } else { + + if (handleMouse != 0 && + (inter_mouseX != draw_cursorX + || inter_mouseY != draw_cursorY)) { + oldIndex = game_lastCollAreaIndex; + oldId = game_lastCollId; + + key = + game_checkMousePoint(1, + &game_lastCollId, + &game_lastCollAreaIndex); + + if (key != game_lastCollKey) { + if (game_lastCollKey != 0 + && (oldId & 0x8000) != 0) { + savedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + + game_collisionAreas[oldIndex].funcLeave; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + + game_lastCollKey = key; + if (game_lastCollKey != 0 && (game_lastCollId & 0x8000) != 0) { + savedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + + game_collisionAreas[game_lastCollAreaIndex].funcEnter; + + inter_funcBlock(0); + inter_execPtr = savedIP; + } + } + } + } + + } + + if (handleMouse != 0) + draw_animateCursor(-1); + } +} + +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; + FontDesc *pFont; + char curSym; + int16 key; + const char *str1; + const char *str2; + int16 i; + uint32 pos; + int16 flag; + int16 savedKey; + + if (game_handleMouse != 0 && + (useMouse != 0 || game_forceHandleMouse != 0)) + handleMouse = 1; + else + handleMouse = 0; + + pos = strlen(str); + pFont = draw_fonts[fontIndex]; + editSize = width / pFont->itemWidth; + + while (1) { + strcpy(game_tempStr, str); + strcat(game_tempStr, " "); + if (strlen(game_tempStr) > editSize) + strcpy(game_tempStr, str); + + draw_destSpriteX = xPos; + draw_destSpriteY = yPos; + draw_spriteRight = editSize * pFont->itemWidth; + draw_spriteBottom = height; + + draw_destSurface = 21; + draw_backColor = backColor; + draw_frontColor = frontColor; + draw_textToPrint = game_tempStr; + draw_transparency = 1; + draw_fontIndex = fontIndex; + draw_spriteOperation(DRAW_FILLRECT); + + draw_destSpriteY = yPos + (height - 8) / 2; + + draw_spriteOperation(DRAW_PRINTTEXT); + if (pos == editSize) + pos--; + + curSym = game_tempStr[pos]; + + flag = 1; + + while (1) { + game_tempStr[0] = curSym; + game_tempStr[1] = 0; + + draw_destSpriteX = xPos + pFont->itemWidth * pos; + draw_destSpriteY = yPos + height - 1; + draw_spriteRight = pFont->itemWidth; + draw_spriteBottom = 1; + draw_destSurface = 21; + draw_backColor = frontColor; + draw_spriteOperation(DRAW_FILLRECT); + + if (flag != 0) { + key = game_checkCollisions(handleMouse, -1, + &game_activeCollResId, + &game_activeCollIndex); + } + flag = 0; + + key = game_checkCollisions(handleMouse, -300, + &game_activeCollResId, &game_activeCollIndex); + + if (*pTotTime > 0) { + *pTotTime -= 300; + if (*pTotTime <= 1) { + key = 0; + game_activeCollResId = 0; + break; + } + } + + game_tempStr[0] = curSym; + game_tempStr[1] = 0; + draw_destSpriteX = xPos + pFont->itemWidth * pos; + draw_destSpriteY = yPos + height - 1; + draw_spriteRight = pFont->itemWidth; + draw_spriteBottom = 1; + draw_destSurface = 21; + draw_backColor = backColor; + draw_frontColor = frontColor; + draw_textToPrint = game_tempStr; + draw_transparency = 1; + draw_spriteOperation(DRAW_FILLRECT); + + draw_destSpriteY = yPos + (height - 8) / 2; + draw_spriteOperation(DRAW_PRINTTEXT); + + if (key != 0 || game_activeCollResId != 0) + break; + + key = game_checkCollisions(handleMouse, -300, + &game_activeCollResId, &game_activeCollIndex); + + if (*pTotTime > 0) { + *pTotTime -= 300; + if (*pTotTime <= 1) { + key = 0; + game_activeCollResId = 0; + break; + } + + } + if (key != 0 || game_activeCollResId != 0) + break; + + if (inter_terminate != 0) + return 0; + } + + if (key == 0 || game_activeCollResId != 0 + || inter_terminate != 0) + 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) { + util_cutFromStr(str, pos - 1, 1); + pos--; + continue; + } + + case 0x5300: // Del + + if (pos >= strlen(str)) + continue; + + 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 (useMouse != 0) + continue; + + game_forceHandleMouse = !game_forceHandleMouse; + + if (game_handleMouse != 0 && + (useMouse != 0 || game_forceHandleMouse != 0)) + handleMouse = 1; + else + handleMouse = 0; + + if (pressedKeys[1] == 0) + continue; + + while (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)) + util_cutFromStr(str, strlen(str) - 1, + 1); + + pos++; + game_tempStr[0] = key; + game_tempStr[1] = 0; + + util_insertStr(game_tempStr, str, pos - 1); + //strupr(str); + } + } + } +} + +int16 game_multiEdit(int16 time, int16 index, int16 *pCurPos, Game_InputDesc * inpDesc) { + Game_Collision *collArea; + int16 descInd; + int16 key; + int16 found = -1; + int16 i; + + descInd = 0; + for (i = 0; i < 250; i++) { + collArea = &game_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(game_tempStr, inter_variables + collArea->key); + + draw_destSpriteX = collArea->left; + draw_destSpriteY = collArea->top; + draw_spriteRight = collArea->right - collArea->left + 1; + draw_spriteBottom = collArea->bottom - collArea->top + 1; + + draw_destSurface = 21; + + draw_backColor = inpDesc[descInd].backColor; + draw_frontColor = inpDesc[descInd].frontColor; + draw_textToPrint = game_tempStr; + draw_transparency = 1; + draw_fontIndex = inpDesc[descInd].fontIndex; + draw_spriteOperation(DRAW_FILLRECT); + draw_destSpriteY += + ((collArea->bottom - collArea->top + 1) - 8) / 2; + + draw_spriteOperation(DRAW_PRINTTEXT); + descInd++; + } + + for (i = 0; i < 40; i++) { + WRITE_LE_UINT32(inter_variables + i * 4 + 0x44, 0); + } + + while (1) { + descInd = 0; + + for (i = 0; i < 250; i++) { + collArea = &game_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 = &game_collisionAreas[found]; + + key = game_inputArea(collArea->left, collArea->top, + collArea->right - collArea->left + 1, + collArea->bottom - collArea->top + 1, + inpDesc[*pCurPos].backColor, inpDesc[*pCurPos].frontColor, + inter_variables + collArea->key, + inpDesc[*pCurPos].fontIndex, collArea->flags, &time); + + if (inter_terminate != 0) + return 0; + + switch (key) { + case 0: + if (game_activeCollResId == 0) + return 0; + + if ((game_collisionAreas[game_activeCollIndex]. + flags & 0x0f) < 3) + return 0; + + if ((game_collisionAreas[game_activeCollIndex]. + flags & 0x0f) > 10) + return 0; + + *pCurPos = 0; + for (i = 0; i < 250; i++) { + collArea = &game_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 == game_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) { + Game_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 pos; + int16 savedCollStackSize; + int16 i; + int16 counter; + int16 var_24; + int16 var_26; + int16 collStackPos; + Game_Collision *collPtr; + int16 timeKey; + char *savedIP; + + if (game_shouldPushColls) + game_pushCollisions(1); + + collResId = -1; + inter_execPtr++; + count = *inter_execPtr++; + game_handleMouse = inter_execPtr[0]; + deltaTime = 1000 * (byte)inter_execPtr[1]; + descIndex2 = (byte)inter_execPtr[2]; + stackPos2 = (byte)inter_execPtr[3]; + descIndex = (byte)inter_execPtr[4]; + + if (stackPos2 != 0 || descIndex != 0) + deltaTime /= 100; + + timeVal = deltaTime; + inter_execPtr += 6; + + startIP = inter_execPtr; + WRITE_LE_UINT32(inter_variables + 0x40, 0); + var_22 = 0; + index = 0; + curEditIndex = 0; + + for (curCmd = 0; curCmd < count; curCmd++) { + array[curCmd] = 0; + cmd = *inter_execPtr++; + + if ((cmd & 0x40) != 0) { + cmd -= 0x40; + cmdHigh = (byte)*inter_execPtr; + inter_execPtr++; + cmdHigh <<= 8; + } else { + cmdHigh = 0; + } + + if ((cmd & 0x80) != 0) { + left = parse_parseValExpr(); + top = parse_parseValExpr(); + width = parse_parseValExpr(); + height = parse_parseValExpr(); + } else { + left = inter_load16(); + top = inter_load16(); + width = inter_load16(); + height = inter_load16(); + } + cmd &= 0x7f; + + switch (cmd) { + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + + util_waitKey(); + var_22 = 1; + key = parse_parseVarIndex(); + descArray[index].fontIndex = inter_load16(); + descArray[index].backColor = *inter_execPtr++; + descArray[index].frontColor = *inter_execPtr++; + + if (cmd < 5 || cmd > 8) { + descArray[index].ptr = 0; + } else { + descArray[index].ptr = inter_execPtr + 2; + inter_execPtr += inter_load16(); + } + + if (left == -1) + break; + + if ((cmd & 1) == 0) { + game_addNewCollision(curCmd + 0x8000, left, + top, + left + + width * + draw_fonts[descArray[index].fontIndex]-> + itemWidth - 1, top + height - 1, cmd, key, + 0, + inter_execPtr - (char *)game_totFileData); + + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + } else { + game_addNewCollision(curCmd + 0x8000, left, + top, + left + + width * + draw_fonts[descArray[index].fontIndex]-> + itemWidth - 1, top + height - 1, cmd, key, + 0, 0); + } + index++; + break; + + case 21: + key = inter_load16(); + array[curCmd] = inter_load16(); + flags = inter_load16() & 3; + + game_addNewCollision(curCmd + 0x8000, left, top, + left + width - 1, + top + height - 1, + (flags << 4) + cmdHigh + 2, key, + inter_execPtr - (char *)game_totFileData, 0); + + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + break; + + case 20: + collResId = curCmd; + + case 2: + key = inter_load16(); + array[curCmd] = inter_load16(); + flags = inter_load16() & 3; + + game_addNewCollision(curCmd + 0x8000, left, top, + left + width - 1, + top + height - 1, + (flags << 4) + cmdHigh + 2, key, 0, + inter_execPtr - (char *)game_totFileData); + + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + break; + + case 0: + inter_execPtr += 6; + startIP = inter_execPtr; + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + key = curCmd + 0xA000; + + game_addNewCollision(curCmd + 0x8000, left, top, + left + width - 1, + top + height - 1, + cmd + cmdHigh, key, + startIP - (char *)game_totFileData, + inter_execPtr - (char *)game_totFileData); + + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + break; + + case 1: + key = inter_load16(); + array[curCmd] = inter_load16(); + flags = inter_load16() & 3; + + startIP = inter_execPtr; + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + if (key == 0) + key = curCmd + 0xa000; + + game_addNewCollision(curCmd + 0x8000, left, top, + left + width - 1, + top + height - 1, + (flags << 4) + cmd + cmdHigh, key, + startIP - (char *)game_totFileData, + inter_execPtr - (char *)game_totFileData); + + inter_execPtr += 2; + inter_execPtr += READ_LE_UINT16(inter_execPtr); + break; + } + } + + game_forceHandleMouse = 0; + util_waitKey(); + + do { + if (var_22 != 0) { + key = + game_multiEdit(deltaTime, index, &curEditIndex, + descArray); + + if (key == 0x1c0d) { + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i].id & 0x8000) == 0) + continue; + + if ((game_collisionAreas[i].flags & 1) != 0) + continue; + + if ((game_collisionAreas[i].flags & 0x0f) <= 2) + continue; + + collResId = game_collisionAreas[i].id; + game_activeCollResId = collResId; + collResId &= 0x7fff; + game_activeCollIndex = i; + break; + } + break; + } + } else { + key = + game_checkCollisions(game_handleMouse, -deltaTime, + &game_activeCollResId, &game_activeCollIndex); + } + + if ((key & 0xff) >= ' ' && (key & 0xff) <= 0xff && + (key >> 8) > 1 && (key >> 8) < 12) { + key = '0' + (((key >> 8) - 1) % 10) + (key & 0xff00); + } + + if (game_activeCollResId == 0) { + if (key != 0) { + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i]. + id & 0x8000) == 0) + continue; + + if (game_collisionAreas[i].key == key + || game_collisionAreas[i].key == + 0x7fff) { + + game_activeCollResId = + game_collisionAreas[i].id; + game_activeCollIndex = i; + break; + } + } + + if (game_activeCollResId == 0) { + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i].id & 0x8000) == 0) + continue; + + if ((game_collisionAreas[i].key & 0xff00) != 0) + continue; + + if (game_collisionAreas[i].key == 0) + continue; + + if (game_adjustKey(key & 0xff) == game_adjustKey(game_collisionAreas[i].key) || game_collisionAreas[i].key == 0x7fff) { + game_activeCollResId = game_collisionAreas[i].id; + game_activeCollIndex = i; + break; + } + } + } + } else { + + if (deltaTime != 0 && READ_LE_UINT32(inter_variables + 0x40) == 0) { + if (stackPos2 != 0) { + collStackPos = 0; + collPtr = game_collisionAreas; + + for (i = 0, collPtr = game_collisionAreas; collPtr->left != -1; i++, collPtr++) { + if ((collPtr->id & 0x8000) == 0) + continue; + + collStackPos++; + if (collStackPos != stackPos2) + continue; + + game_activeCollResId = collPtr->id; + game_activeCollIndex = i; + WRITE_LE_UINT32(inter_variables + 0x08, inter_mouseX); + WRITE_LE_UINT32(inter_variables + 0x0c, inter_mouseY); + WRITE_LE_UINT32(inter_variables + 0x10, game_mouseButtons); + WRITE_LE_UINT32(inter_variables + 0x40, array[(uint16)game_activeCollResId & ~0x8000]); + + if (collPtr->funcLeave != 0) { + timeKey = util_getTimeKey(); + savedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + collPtr->funcLeave; + game_shouldPushColls = 1; + savedCollStackSize = game_collStackSize; + inter_funcBlock(0); + + if (savedCollStackSize != game_collStackSize) + game_popCollisions(); + + game_shouldPushColls = 0; + inter_execPtr = savedIP; + deltaTime = timeVal - (util_getTimeKey() - timeKey); + + if (deltaTime < 2) + deltaTime = 2; + } + + if (READ_LE_UINT32(inter_variables + 0x40) == 0) + game_activeCollResId = 0; + break; + } + } else { + if (descIndex != 0) { + counter = 0; + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i].id & 0x8000) == 0) + continue; + + counter++; + if (counter != descIndex) + continue; + + game_activeCollResId = game_collisionAreas[i].id; + game_activeCollIndex = i; + break; + } + } else { + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i].id & 0x8000) == 0) + continue; + + game_activeCollResId = game_collisionAreas[i].id; + game_activeCollIndex = i; + break; + } + } + } + } else { + if (descIndex2 != 0) { + counter = 0; + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i].id & 0x8000) == 0) + continue; + + counter++; + if (counter != descIndex2) + continue; + + game_activeCollResId = game_collisionAreas[i].id; + game_activeCollIndex = i; + break; + } + } + } + } + } + + if (game_activeCollResId == 0) + continue; + + if (game_collisionAreas[game_activeCollIndex].funcLeave != 0) + continue; + + WRITE_LE_UINT32(inter_variables + 0x08, inter_mouseX); + WRITE_LE_UINT32(inter_variables + 0x0c, inter_mouseY); + WRITE_LE_UINT32(inter_variables + 0x10, game_mouseButtons); + WRITE_LE_UINT32(inter_variables + 0x40, array[(uint16)game_activeCollResId & ~0x8000]); + + if (game_collisionAreas[game_activeCollIndex].funcEnter != 0) { + savedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + + game_collisionAreas[game_activeCollIndex]. + funcEnter; + + game_shouldPushColls = 1; + + collStackPos = game_collStackSize; + inter_funcBlock(0); + if (collStackPos != game_collStackSize) + game_popCollisions(); + game_shouldPushColls = 0; + inter_execPtr = savedIP; + } + + WRITE_LE_UINT32(inter_variables + 0x40, 0); + game_activeCollResId = 0; + } + while (game_activeCollResId == 0 && inter_terminate == 0); + + if (((uint16)game_activeCollResId & ~0x8000) == collResId) { + collStackPos = 0; + var_24 = 0; + var_26 = 1; + for (i = 0; i < 250; i++) { + if (game_collisionAreas[i].left == -1) + continue; + + if ((game_collisionAreas[i].id & 0x8000) == 0) + continue; + + if ((game_collisionAreas[i].flags & 0x0f) < 3) + continue; + + if ((game_collisionAreas[i].flags & 0x0f) > 10) + continue; + + if ((game_collisionAreas[i].flags & 0x0f) > 8) { + strcpy(game_tempStr, + inter_variables + game_collisionAreas[i].key); + while ((pos = + util_strstr(" ", game_tempStr)) != 0) { + util_cutFromStr(game_tempStr, pos - 1, 1); + pos = util_strstr(" ", game_tempStr); + } + strcpy(inter_variables + game_collisionAreas[i].key, game_tempStr); + } + + if ((game_collisionAreas[i].flags & 0x0f) >= 5 && + (game_collisionAreas[i].flags & 0x0f) <= 8) { + str = descArray[var_24].ptr; + + strcpy(game_tempStr, inter_variables + game_collisionAreas[i].key); + + if ((game_collisionAreas[i].flags & 0x0f) < 7) + util_prepareStr(game_tempStr); + + pos = 0; + do { + strcpy(game_collStr, str); + pos += strlen(str) + 1; + + str += strlen(str) + 1; + + if ((game_collisionAreas[i].flags & 0x0f) < 7) + util_prepareStr(game_collStr); + + if (strcmp(game_tempStr, game_collStr) == 0) { + WRITE_LE_UINT32(inter_variables + 0x44, + READ_LE_UINT32(inter_variables + 0x44) + 1); + WRITE_LE_UINT32(inter_variables + 0x44 + var_26 * 4, 1); + break; + } + } while (READ_LE_UINT16(descArray[var_24].ptr - 2) > pos); + collStackPos++; + } else { + WRITE_LE_UINT32(inter_variables + 0x44 + var_26 * 4, 2); + } + var_24++; + var_26++; + } + + if (collStackPos != READ_LE_UINT16(inter_variables + 0x44)) + WRITE_LE_UINT32(inter_variables + 0x44, 0); + else + WRITE_LE_UINT32(inter_variables + 0x44, 1); + } + + savedIP = 0; + if (inter_terminate == 0) { + savedIP = (char *)game_totFileData + + game_collisionAreas[game_activeCollIndex].funcLeave; + + WRITE_LE_UINT32(inter_variables + 0x08, inter_mouseX); + WRITE_LE_UINT32(inter_variables + 0x0c, inter_mouseY); + WRITE_LE_UINT32(inter_variables + 0x10, game_mouseButtons); + WRITE_LE_UINT32(inter_variables + 0x40, array[(uint16)game_activeCollResId & ~0x8000]); + + if (READ_LE_UINT32(inter_variables + 0x40) == 0) { + WRITE_LE_UINT32(inter_variables + 0x40, array[(uint16)game_activeCollResId & ~0x8000]); + } + } + + for (curCmd = 0; curCmd < count; curCmd++) { + game_freeCollision(curCmd + 0x8000); + } + inter_execPtr = savedIP; +} + +void game_prepareStart(void) { + int16 i; + + game_clearCollisions(); + + pPaletteDesc->unused2 = draw_unusedPalette2; + pPaletteDesc->unused1 = draw_unusedPalette1; + pPaletteDesc->vgaPal = draw_vgaPalette; + + vid_setFullPalette(pPaletteDesc); + + draw_backSurface = vid_initSurfDesc(videoMode, 320, 200, 0); + + vid_fillRect(draw_backSurface, 0, 0, 319, 199, 1); + draw_frontSurface = pPrimarySurfDesc; + vid_fillRect(draw_frontSurface, 0, 0, 319, 199, 1); + + util_setMousePos(152, 92); + + draw_cursorX = 152; + inter_mouseX = 152; + + draw_cursorY = 92; + inter_mouseY = 92; + draw_invalidatedCount = 0; + draw_noInvalidated = 1; + draw_applyPal = 0; + draw_paletteCleared = 0; + draw_cursorWidth = 16; + draw_cursorHeight = 16; + draw_transparentCursor = 1; + + for (i = 0; i < 40; i++) { + draw_cursorAnimLow[i] = -1; + draw_cursorAnimDelays[i] = 0; + draw_cursorAnimHigh[i] = 0; + } + + draw_cursorAnimLow[1] = 0; + trySmallForBig = 1; + draw_cursorSprites = vid_initSurfDesc(videoMode, 32, 16, 2); + draw_cursorBack = vid_initSurfDesc(videoMode, 16, 16, 0); + trySmallForBig = 0; + draw_renderFlags = 0; + draw_backDeltaX = 0; + draw_backDeltaY = 0; + + game_startTimeKey = util_getTimeKey(); +} + +void game_loadTotFile(char *path) { + int16 handle; + + handle = data_openData(path); + if (handle >= 0) { + data_closeData(handle); + game_totFileData = data_getData(path); + } else { + game_totFileData = 0; + } +} + +void game_loadExtTable(void) { + int16 count, i; + + // Function is correct. [sev] + + game_extHandle = data_openData(game_curExtFile); + if (game_extHandle < 0) + return; + + data_readData(game_extHandle, (char *)&count, 2); + count = FROM_LE_16(count); + + data_seekData(game_extHandle, 0, 0); + game_extTable = (Game_ExtTable *)malloc(sizeof(Game_ExtTable) + + sizeof(Game_ExtItem) * count); + + data_readData(game_extHandle, (char *)&game_extTable->itemsCount, 2); + game_extTable->itemsCount = FROM_LE_16(game_extTable->itemsCount); + data_readData(game_extHandle, (char *)&game_extTable->unknown, 1); + + for(i = 0; i < count; i++) { + data_readData(game_extHandle, (char *)&game_extTable->items[i].offset, 4); + game_extTable->items[i].offset = FROM_LE_32(game_extTable->items[i].offset); + data_readData(game_extHandle, (char *)&game_extTable->items[i].size, 2); + game_extTable->items[i].size = FROM_LE_16(game_extTable->items[i].size); + data_readData(game_extHandle, (char *)&game_extTable->items[i].width, 2); + game_extTable->items[i].width = FROM_LE_16(game_extTable->items[i].width); + data_readData(game_extHandle, (char *)&game_extTable->items[i].height, 2); + game_extTable->items[i].height = FROM_LE_16(game_extTable->items[i].height); + } +} + +void game_loadImFile(void) { + char path[20]; + int16 handle; + + if (game_totFileData[0x3d] != 0 && game_totFileData[0x3b] == 0) + return; + + strcpy(path, "commun.im1"); + if (game_totFileData[0x3b] != 0) + path[strlen(path) - 1] = '0' + game_totFileData[0x3b]; + + handle = data_openData(path); + if (handle < 0) + return; + + data_closeData(handle); + game_imFileData = data_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; + //struct date dateVal; + int16 i; + int16 j; + + oldNestLevel = inter_nestLevel; + oldBreakFrom = inter_breakFromLevel; + oldCaptureCounter = scen_pCaptureCounter; + savedIP = inter_execPtr; + + inter_nestLevel = &nestLevel; + inter_breakFromLevel = &breakFrom; + scen_pCaptureCounter = &captureCounter; + strcpy(savedTotName, game_curTotFile); + + if (skipPlay == 0) { + while (1) { + for (i = 0; i < 4; i++) { + draw_fontToSprite[i].sprite = -1; + draw_fontToSprite[i].base = -1; + draw_fontToSprite[i].width = -1; + draw_fontToSprite[i].height = -1; + } + + draw_animateCursor(4); + inter_initControlVars(); + mult_initAll(); + mult_zeroMultData(); + + for (i = 0; i < 20; i++) + draw_spritesArray[i] = 0; + + draw_spritesArray[20] = draw_frontSurface; + draw_spritesArray[21] = draw_backSurface; + draw_spritesArray[23] = draw_cursorSprites; + + for (i = 0; i < 20; i++) + game_soundSamples[i] = 0; + + game_totTextData = 0; + game_totResourceTable = 0; + game_imFileData = 0; + game_extTable = 0; + game_extHandle = -1; + + needFreeResTable = 1; + needTextFree = 1; + + game_totToLoad[0] = 0; + + if (game_curTotFile[0] == 0 && game_totFileData == 0) + break; + + game_loadTotFile(game_curTotFile); + if (game_totFileData == 0) { + draw_blitCursor(); + break; + } + + strcpy(game_curImaFile, game_curTotFile); + strcpy(game_curExtFile, game_curTotFile); + + game_curImaFile[strlen(game_curImaFile) - 4] = 0; + strcat(game_curImaFile, ".ima"); + + game_curExtFile[strlen(game_curExtFile) - 4] = 0; + strcat(game_curExtFile, ".ext"); + + debug(0, "IMA: %s", game_curImaFile); + debug(0, "EXT: %s", game_curExtFile); + + filePtr = (char *)game_totFileData + 0x30; + + if (READ_LE_UINT32(filePtr) != -1) { + curPtr = game_totFileData; + game_totTextData = + (Game_TotTextTable *) (curPtr + + READ_LE_UINT32((char *)game_totFileData + 0x30)); + needTextFree = 0; + } + + filePtr = (char *)game_totFileData + 0x34; + if (READ_LE_UINT32(filePtr) != -1) { + curPtr = game_totFileData; + + game_totResourceTable = + (Game_TotResTable *)(curPtr + + READ_LE_UINT32((char *)game_totFileData + 0x34)); + needFreeResTable = 0; + } + + game_loadImFile(); + game_loadExtTable(); + + inter_animDataSize = READ_LE_UINT16((char *)game_totFileData + 0x38); + if (inter_variables == 0) { + variablesCount = READ_LE_UINT32((char *)game_totFileData + 0x2c); + inter_variables = (char *)malloc(variablesCount * 4); + for (i = 0; i < variablesCount; i++) + WRITE_LE_UINT32(inter_variables + i * 4, 0); + } + + inter_execPtr = (char *)game_totFileData; + inter_execPtr += READ_LE_UINT32((char *)game_totFileData + 0x64); + +/* + * removed by olki to get it to compile. + getdate(&dateVal); + + WRITE_LE_UINT32(inter_variables + 0x14), dateVal.da_year); + WRITE_LE_UINT32(inter_variables + 0x18), dateVal.da_mon); + WRITE_LE_UINT32(inter_variables + 0x1c), 0); + WRITE_LE_UINT32(inter_variables + 0x20), dateVal.da_day); +*/ + + inter_renewTimeInVars(); + + WRITE_LE_UINT32(inter_variables + 0x34, useMouse); + WRITE_LE_UINT32(inter_variables + 0x38, soundFlags); + WRITE_LE_UINT32(inter_variables + 0x3c,videoMode); + WRITE_LE_UINT32(inter_variables + 0x40, language); + + inter_callSub(2); + + if (game_totToLoad[0] != 0) + inter_terminate = 0; + + variablesCount = READ_LE_UINT32((char *)game_totFileData + 0x2c); + draw_blitInvalidated(); + free(game_totFileData); + game_totFileData = 0; + if (game_totTextData != 0 && needTextFree != 0) + free((char *)game_totTextData); + + game_totTextData = 0; + + if (game_totResourceTable != 0 + && needFreeResTable != 0) + free((char *)game_totResourceTable); + + game_totResourceTable = 0; + + if (game_imFileData != 0) + free(game_imFileData); + + game_imFileData = 0; + + if (game_extTable != 0) + free((char *)game_extTable); + + game_extTable = 0; + if (game_extHandle >= 0) + data_closeData(game_extHandle); + + game_extHandle = -1; + + for (i = 0; i < *scen_pCaptureCounter; i++) + game_capturePop(0); + + mult_checkFreeMult(); + mult_freeAll(); + + for (i = 0; i < 20; i++) { + if (draw_spritesArray[i] != 0) + vid_freeSurfDesc(draw_spritesArray[i]); + draw_spritesArray[i] = 0; + } + snd_stopSound(0); + + for (i = 0; i < 20; i++) + game_freeSoundSlot(i); + + if (game_totToLoad[0] == 0) + break; + + strcpy(game_curTotFile, game_totToLoad); + } + } + + strcpy(game_curTotFile, savedTotName); + + inter_nestLevel = oldNestLevel; + inter_breakFromLevel = oldBreakFrom; + scen_pCaptureCounter = oldCaptureCounter; + inter_execPtr = savedIP; +} + +void game_start(void) { + game_collisionAreas = (Game_Collision *)malloc(250 * sizeof(Game_Collision)); + game_prepareStart(); + game_playTot(0); + + free((char *)game_collisionAreas); + + vid_freeSurfDesc(draw_cursorSprites); + vid_freeSurfDesc(draw_cursorBack); + vid_freeSurfDesc(draw_backSurface); +} + +} // End of namespace Gob diff --git a/gob/game.h b/gob/game.h new file mode 100644 index 0000000000..bee9dd9649 --- /dev/null +++ b/gob/game.h @@ -0,0 +1,151 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __GAME_H +#define __GAME_H + +#include "gob/sound.h" + +namespace Gob { + +#pragma START_PACK_STRUCTS +#define szGame_ExtItem (4 + 2 + 2 + 2) +typedef struct Game_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 Game_ExtItem; + +#define szGame_ExtTable (2 + 1) +typedef struct Game_ExtTable { + int16 itemsCount; + byte unknown; + Game_ExtItem items[1]; +} GCC_PACK Game_ExtTable; + +#define szGame_TotResItem (4 + 2 + 2 + 2) +typedef struct Game_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 Game_TotResItem; + +#define szGame_TotResTable (2 + 1) +typedef struct Game_TotResTable { + int16 itemsCount; + byte unknown; + Game_TotResItem items[1]; +} GCC_PACK Game_TotResTable; + +#define szGame_TotTextItem (2 + 2) +typedef struct Game_TotTextItem { + int16 offset; + int16 size; +} GCC_PACK Game_TotTextItem; + +#define szGame_TotTextTable (2) +typedef struct Game_TotTextTable { + int16 itemsCount; + Game_TotTextItem items[1]; +} GCC_PACK Game_TotTextTable; + +typedef struct Game_Collision { + int16 id; + int16 left; + int16 top; + int16 right; + int16 bottom; + int16 flags; + int16 key; + int16 funcEnter; + int16 funcLeave; +} GCC_PACK Game_Collision; + +typedef struct Game_InputDesc { + int16 fontIndex; + int16 backColor; + int16 frontColor; + char *ptr; +} GCC_PACK Game_InputDesc; +#pragma END_PACK_STRUCTS + +extern Game_Collision *game_collisionAreas; + +extern int16 game_lastCollKey; +extern int16 game_lastCollAreaIndex; +extern int16 game_lastCollId; + +extern int16 game_activeCollResId; +extern int16 game_activeCollIndex; +extern char game_handleMouse; +extern char game_forceHandleMouse; + +extern char game_tempStr[256]; + +extern Game_ExtTable *game_extTable; +extern char *game_totFileData; +extern Game_TotTextTable *game_totTextData; +extern Game_TotResTable *game_totResourceTable; +extern char *game_imFileData; +extern int16 game_extHandle; +extern char game_curExtFile[14]; +extern char game_curTotFile[14]; +extern char game_curImaFile[18]; + +extern int16 game_collStackSize; +extern Game_Collision *game_collStack[3]; +extern int16 game_collStackElemSizes[3]; + +extern int16 game_mouseButtons; + +extern Snd_SoundDesc *game_soundSamples[20]; + +extern char game_soundFromExt[20]; +extern char game_totToLoad[20]; + +extern int32 game_startTimeKey; +extern char game_shouldPushColls; + +// Functions + +char *game_loadExtData(int16 dataId, int16 *pResWidth, int16 *pResHeight); +void game_clearCollisions(void); +void game_addNewCollision(int16 val_0, int16 left, int16 top, int16 right, int16 bottom, + int16 flags, int16 key, int16 val_E, int16 val_10); +void game_freeCollision(int16 id); +char *game_loadTotResource(int16 id); +void game_capturePush(int16 left, int16 top, int16 width, int16 height); + +void game_capturePush(int16 left, int16 top, int16 width, int16 height); +void game_capturePop(char doDraw); + +void game_loadSound(int16 slot, char *dataPtr); +void game_interLoadSound(int16 slot); +void game_freeSoundSlot(int16 slot); +int16 game_checkKeys(int16 *pMousex, int16 *pMouseY, int16 *pButtons, + char handleMouse); +int16 game_checkCollisions(char handleMouse, int16 deltaTime, int16 *pResId, + int16 *pResIndex); +int16 game_inputArea(int16 xPos, int16 yPos, int16 width, int16 height, int16 backColor, + int16 frontColor, char *str, int16 fontIndex, char inpType, int16 *pTotTime); +int16 game_multiEdit(int16 time, int16 index, int16 *pCurPos, + Game_InputDesc * inpDesc); +int16 game_adjustKey(int16 key); +void game_collisionsBlock(void); +void game_prepareStart(void); +void game_loadTotFile(char *path); +void game_loadExtTable(void); +void game_loadImFile(void); +void game_playTot(int16 skipPlay); +void game_start(void); + +} // End of namespace Gob + +#endif diff --git a/gob/global.cpp b/gob/global.cpp new file mode 100644 index 0000000000..3cff3d7c4b --- /dev/null +++ b/gob/global.cpp @@ -0,0 +1,175 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" + +namespace Gob { + +char pressedKeys[128]; + +char useMouse = UNDEF; +int16 mousePresent = UNDEF; + +int16 presentCGA = UNDEF; +int16 presentEGA = UNDEF; +int16 presentVGA = UNDEF; +int16 presentHER = UNDEF; + +int16 videoMode = 0; + +int16 disableVideoCfg; + +/* Sound */ +uint16 presentSound = 0x8000; /* undefined values */ +uint16 soundFlags = 0x8000; +int16 blasterPort = 0; +int16 disableSoundCfg = 0; + +//char playingSound = 0; + +/* Mouse */ +int16 disableMouseCfg = 0; + +int16 mouseXShift = 3; +int16 mouseYShift = 3; + +int16 mouseMaxCol = 320; +int16 mouseMaxRow = 200; + +/* Language */ +uint16 disableLangCfg = 0x8000; +uint16 language = 0x8000; + +/* Configuration */ +char batFileName[8]; + +/* */ +int16 requiredSpace = 0; + +/* Timer variables */ +int32 startTime = 0; +char timer_enabled = 0; +int16 timer_delta = 1000; + +int16 frameWaitTime = 0; +int32 startFrameTime = 0; + +/* Memory */ +int16 allocatedBlocks[2] = { 0, 0 }; +char *heapHeads[2] = { 0, 0 }; +char *heapFence = 0; +int32 heapSize = 10000000; +char inAllocSub = 0; + +/* Runtime */ +//CleanupFuncPtr soundCleanup = 0; + +/* Timer and delays */ +int16 delayTime = 0; +int16 fastComputer = 1; + +/* Joystick */ +char useJoystick = 1; + +/* Files */ +int16 filesCount = 0; +File filesHandles[MAX_FILES]; + +/* Data files */ +struct 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 = 0; + + +int16 sprAllocated = 0; + +SurfaceDesc primarySurfDesc; +SurfaceDesc *pPrimarySurfDesc; + +int16 primaryWidth; +int16 primaryHeight; + +int16 doRangeClamp = 0; + +DrawPackedSpriteFunc pDrawPacked; + +char redPalette[256]; +char greenPalette[256]; +char bluePalette[256]; + +int16 setAllPalette = 0; + +int16 oldMode = 3; +int16 needDriverInit = 1; +char dontSetPalette = 0; +SurfaceDesc *curPrimaryDesc = 0; +SurfaceDesc *allocatedPrimary = 0; + +PalDesc *pPaletteDesc = 0; + +FileHandler pFileHandler = 0; + +int16 unusedPalette1[18] = { + 0, 0x0b, 0, 0x5555, 0xAAAA, 0xFFFF, 0, 0x5555, 0xAAAA, 0xFFFF, 0, + 0x5555, + 0xAAAA, 0xFFFF, 0, 0x5555, 0xAAAA, 0xFFFF +}; + +int16 unusedPalette2[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +Color vgaPalette[16] = { + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x2a}, + {0x00, 0x2a, 0x00}, + {0x00, 0x2a, 0x2a}, + {0x2a, 0x00, 0x00}, + {0x2a, 0x00, 0x2a}, + {0x2a, 0x15, 0x00}, + {0x2a, 0x2a, 0x2a}, + {0x15, 0x15, 0x15}, + {0x15, 0x15, 0x3f}, + {0x15, 0x3f, 0x15}, + {0x15, 0x3f, 0x3f}, + {0x3f, 0x15, 0x15}, + {0x3f, 0x15, 0x3f}, + {0x3f, 0x3f, 0x15}, + {0x3f, 0x3f, 0x3f} +}; + +PalDesc paletteStruct; + +int16 debugFlag = 0; +int16 breakSet = 0; +int16 inVM = 0; +int16 colorCount = 16; + +int16 slowCD = 0; +int16 checkMemFlag = 0; + +int16 trySmallForBig = 0; + +char inter_resStr[200]; +int32 inter_resVal = 0; + +char *inter_variables = 0; +char *inter_execPtr = 0; +int16 inter_animDataSize = 10; + +int16 inter_mouseX = 0; +int16 inter_mouseY = 0; + +char *tmpPalBuffer = 0; + +} // End of namespace Gob diff --git a/gob/global.h b/gob/global.h new file mode 100644 index 0000000000..0a8a7fd70b --- /dev/null +++ b/gob/global.h @@ -0,0 +1,191 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef _GLOBAL_H +#define _GLOBAL_H + +#include "gob/dataio.h" +#include "gob/video.h" + +#include "common/file.h" + +namespace Gob { + +extern char pressedKeys[128]; + +extern char useMouse; +extern int16 mousePresent; + +extern int16 presentCGA; +extern int16 presentEGA; +extern int16 presentVGA; +extern int16 presentHER; + +extern int16 videoMode; + +extern int16 disableVideoCfg; + +#define VIDMODE_CGA 0x05 +#define VIDMODE_EGA 0x0d +#define VIDMODE_VGA 0x13 +#define VIDMODE_HER 7 + +extern uint16 presentSound; +extern uint16 soundFlags; +extern int16 disableSoundCfg; +//extern int16 blasterPort; + +#define PROAUDIO_FLAG 0x10 +#define ADLIB_FLAG 0x08 +#define BLASTER_FLAG 0x04 +#define INTERSOUND_FLAG 0x02 +#define SPEAKER_FLAG 0x01 +#define MIDI_FLAG 0x4000 + +extern uint16 disableLangCfg; +extern uint16 language; + +#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 + +/* Configuration */ +extern char batFileName[8]; + +/* Init */ +extern int16 requiredSpace; + +/* Timer variables */ +extern int32 startTime; +extern char timer_enabled; +extern int16 timer_delta; + +extern int16 frameWaitTime; +extern int32 startFrameTime; + +/* Mouse */ +extern int16 disableMouseCfg; + +extern int16 mouseXShift; +extern int16 mouseYShift; +extern int16 mouseMaxCol; +extern int16 mouseMaxRow; + +/* Memory */ +extern int16 allocatedBlocks[2]; +extern char *heapHeads[2]; +extern int32 heapSize; +extern char *heapFence; +extern char inAllocSub; + +/* Timer and delays */ +extern int16 delayTime; +extern int16 fastComputer; + +/* Joystick */ +extern char useJoystick; + +/* Files */ +#define MAX_FILES 30 + +extern int16 filesCount; +extern File filesHandles[MAX_FILES]; + +/* Data files */ +extern struct ChunkDesc *dataFiles[MAX_DATA_FILES]; +extern int16 numDataChunks[MAX_DATA_FILES]; +extern int16 dataFileHandles[MAX_DATA_FILES]; +extern int32 chunkPos[MAX_SLOT_COUNT * MAX_DATA_FILES]; +extern int32 chunkOffset[MAX_SLOT_COUNT * MAX_DATA_FILES]; +extern int32 chunkSize[MAX_SLOT_COUNT * MAX_DATA_FILES]; +extern char isCurrentSlot[MAX_SLOT_COUNT * MAX_DATA_FILES]; +extern int32 packedSize; + +/* Video drivers */ +#define UNK_DRIVER 0 +#define VGA_DRIVER 1 +#define EGA_DRIVER 2 +#define CGA_DRIVER 3 +#define HER_DRIVER 4 + +extern SurfaceDesc primarySurfDesc; +extern SurfaceDesc *pPrimarySurfDesc; +extern int16 sprAllocated; + +extern int16 primaryWidth; +extern int16 primaryHeight; + +extern int16 doRangeClamp; + +extern DrawPackedSpriteFunc pDrawPacked; + +extern char redPalette[256]; +extern char greenPalette[256]; +extern char bluePalette[256]; + +extern int16 setAllPalette; + +extern SurfaceDesc *curPrimaryDesc; +extern SurfaceDesc *allocatedPrimary; + +extern int16 oldMode; +extern int16 needDriverInit; +extern char dontSetPalette; + +extern PalDesc *pPaletteDesc; + +typedef void (*FileHandler) (char *path); +extern FileHandler pFileHandler; + + //extern void interrupt(*oldInt5Handler) (void); + //extern void interrupt(*oldInt0Handler) (void); + //extern void interrupt(*oldInt1bHandler) (void); + +extern int16 unusedPalette1[18]; +extern int16 unusedPalette2[16]; +extern Color vgaPalette[16]; +extern PalDesc paletteStruct; + +extern int16 debugFlag; +extern int16 breakSet; +extern int16 inVM; +extern int16 colorCount; + +extern int16 trySmallForBig; +extern int16 checkMemFlag; + +extern char inter_resStr[200]; +extern int32 inter_resVal; + +extern char *inter_variables; +extern char *inter_execPtr; +extern int16 inter_animDataSize; + +extern int16 inter_mouseX; +extern int16 inter_mouseY; + +extern char *tmpPalBuffer; + +typedef struct Rectangle { + int16 left; + int16 top; + int16 width; + int16 height; +} Rectangle; + +} // End of namespace Gob + +#endif diff --git a/gob/gob.cpp b/gob/gob.cpp new file mode 100644 index 0000000000..1f0f75aac8 --- /dev/null +++ b/gob/gob.cpp @@ -0,0 +1,130 @@ +/* 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 + * aint32 with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#include "stdafx.h" + +#include "base/gameDetector.h" +#include "base/plugins.h" +#include "backends/fs/fs.h" + +#include "gob/gob.h" + +#include "gob/global.h" +#include "gob/game.h" +#include "gob/sound.h" +#include "gob/init.h" + +static const GameSettings gob_games[] = { + {"gob1", "Gobliiins", 0}, + {0, 0, 0} +}; + +GameList Engine_GOB_gameList() { + GameList games; + const GameSettings *g = gob_games; + + while (g->name) { + games.push_back(*g); + g++; + } + + return games; +} + +DetectedGameList Engine_GOB_detectGames(const FSList &fslist) { + DetectedGameList detectedGames; + + return detectedGames; +} + +Engine *Engine_GOB_create(GameDetector * detector, OSystem *syst) { + return new Gob::GobEngine(detector, syst); +} + +REGISTER_PLUGIN(GOB, "Gob Engine") + +namespace Gob { +#define MAX_TIME_DELTA 100 + GobEngine *_vm = NULL; + +GobEngine::GobEngine(GameDetector *detector, OSystem * syst) : Engine(syst) { + + // Setup mixer + if (!_mixer->isReady()) { + warning("Sound initialization failed."); + } + + _mixer->setVolumeForSoundType(SoundMixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(SoundMixer::kMusicSoundType, ConfMan.getInt("music_volume")); + + _vm = this; +} + +GobEngine::~GobEngine() { +} + +void GobEngine::errorString(const char *buf1, char *buf2) { + strcpy(buf2, buf1); +} + +int GobEngine::init(GameDetector &detector) { + debugFlag = 1; + breakSet = 0; + doRangeClamp = 1; + trySmallForBig = 0; + + checkMemFlag = 0; + videoMode = 0x13; + snd_soundPort = 1; + useMouse = 1; + soundFlags = 0; + language = 5; + + init_initGame(0); + + return 0; +} + +int GobEngine::go() { + int msec = 0; + + for (;;) { + OSystem::Event event; + while (g_system->pollEvent(event)) { + switch (event.type) { + case OSystem::EVENT_QUIT: + g_system->quit(); + break; + default: + break; + } + } + debug(0, "Main loop"); + _system->delayMillis(10); + } + + return 0; +} + +void GobEngine::shutdown() { + _system->quit(); +} + +} // End of namespace Gob diff --git a/gob/gob.h b/gob/gob.h new file mode 100644 index 0000000000..e845c8471d --- /dev/null +++ b/gob/gob.h @@ -0,0 +1,51 @@ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef __Gob_H +#define __Gob_H + +#include "common/stdafx.h" +#include "common/system.h" +#include "sound/mixer.h" +#include "common/config-manager.h" + +#include "base/engine.h" + +namespace Gob { + +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); + virtual ~GobEngine(); + + void shutdown(); + + +}; + +} // End of namespace Gob +#endif diff --git a/gob/goblin.cpp b/gob/goblin.cpp new file mode 100644 index 0000000000..c7ebd6b4f5 --- /dev/null +++ b/gob/goblin.cpp @@ -0,0 +1,3320 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/goblin.h" +#include "gob/debug.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" + +namespace Gob { + +Util_List *gob_objList; +Gob_Object *gob_goblins[4]; +int16 gob_currentGoblin; +Snd_SoundDesc *gob_soundData[16]; +int16 gob_gobStateLayer; +char gob_goesAtTarget = 0; +char gob_readyToAct = 0; +int16 gob_gobAction = 0; +Gob_Pos gob_gobPositions[3]; +int16 gob_gobDestX; +int16 gob_gobDestY; +int16 gob_pressedMapX; +int16 gob_pressedMapY; +char gob_pathExistence; + +int16 gob_itemIndInPocket = 5; +int16 gob_itemIdInPocket = 2; +char gob_itemByteFlag = 0; +int16 gob_destItemId = -1; +int16 gob_destActionItem = 0; +Gob_Object *gob_actDestItemDesc = 0; +int16 gob_forceNextState[10] = { + -1, -1, -1, -1, -1, -1, -1, 0, 0, 0 +}; + +char gob_rotStates[4][4] = { + {0, 22, 23, 24}, + {13, 2, 12, 14}, + {16, 15, 4, 17}, + {27, 25, 26, 6} +}; + +int16 gob_destItemType; +int16 gob_destItemState; +// Pointers to interpreter variables +int32 *gob_some0ValPtr; + +int32 *gob_gobRetVarPtr; +int32 *gob_curGobVarPtr; +int32 *gob_curGobXPosVarPtr; +int32 *gob_curGobYPosVarPtr; +int32 *gob_itemInPocketVarPtr; +int32 *gob_curGobStateVarPtr; +int32 *gob_curGobFrameVarPtr; +int32 *gob_curGobMultStateVarPtr; +int32 *gob_curGobNextStateVarPtr; +int32 *gob_curGobScrXVarPtr; +int32 *gob_curGobScrYVarPtr; +int32 *gob_curGobLeftVarPtr; +int32 *gob_curGobTopVarPtr; +int32 *gob_curGobRightVarPtr; +int32 *gob_curGobBottomVarPtr; +int32 *gob_curGobDoAnimVarPtr; +int32 *gob_curGobOrderVarPtr; +int32 *gob_curGobNoTickVarPtr; +int32 *gob_curGobTypeVarPtr; +int32 *gob_curGobMaxTickVarPtr; +int32 *gob_curGobTickVarPtr; +int32 *gob_curGobActStartStateVarPtr; +int32 *gob_curGobLookDirVarPtr; +int32 *gob_curGobPickableVarPtr; +int32 *gob_curGobRelaxVarPtr; +int32 *gob_curGobMaxFrameVarPtr; + +int32 *gob_destItemStateVarPtr; +int32 *gob_destItemFrameVarPtr; +int32 *gob_destItemMultStateVarPtr; +int32 *gob_destItemNextStateVarPtr; +int32 *gob_destItemScrXVarPtr; +int32 *gob_destItemScrYVarPtr; +int32 *gob_destItemLeftVarPtr; +int32 *gob_destItemTopVarPtr; +int32 *gob_destItemRightVarPtr; +int32 *gob_destItemBottomVarPtr; +int32 *gob_destItemDoAnimVarPtr; +int32 *gob_destItemOrderVarPtr; +int32 *gob_destItemNoTickVarPtr; +int32 *gob_destItemTypeVarPtr; +int32 *gob_destItemMaxTickVarPtr; +int32 *gob_destItemTickVarPtr; +int32 *gob_destItemActStartStVarPtr; +int32 *gob_destItemLookDirVarPtr; +int32 *gob_destItemPickableVarPtr; +int32 *gob_destItemRelaxVarPtr; +int32 *gob_destItemMaxFrameVarPtr; + +// +int16 gob_itemToObject[20]; +Gob_Object *gob_objects[20]; +int16 gob_objCount; +int16 gob_gobsCount; +char gob_boreCounter = 0; +int16 gob_positionedGob = 5; + +char gob_noPick = 0; + +char gob_rotateState(int16 from, int16 to) { + return gob_rotStates[from / 2][to / 2]; +} + +int16 gob_peekGoblin(Gob_Object *curGob) { + Util_ListNode *ptr; + Gob_Object *desc; + int16 index; + int16 i; + + ptr = gob_objList->pHead; + index = 0; + while (ptr != 0) { + desc = (Gob_Object *) ptr->pData; + if (desc != curGob) { + for (i = 0; i < 3; i++) { + if (desc != gob_goblins[i]) + continue; + + if (inter_mouseX < desc->right && + inter_mouseX > desc->left && + inter_mouseY < desc->bottom && + inter_mouseY > desc->top) { + index = i + 1; + } + } + } + ptr = ptr->pNext; + } + return index; +} + +void gob_initList(void) { + gob_objList = (Util_List *) malloc(sizeof(Util_List)); + gob_objList->pHead = 0; + gob_objList->pTail = 0; +} + +void gob_sortByOrder(Util_List *list) { + Util_ListNode *ptr; + Util_ListNode *ptr2; + void *tmp; + + ptr = list->pHead; + while (ptr->pNext != 0) { + for (ptr2 = ptr->pNext; ptr2 != 0; ptr2 = ptr2->pNext) { + if (((Gob_Object *) ptr->pData)->order <= + ((Gob_Object *) ptr2->pData)->order) { + if (((Gob_Object *) ptr->pData)->order != + ((Gob_Object *) ptr2->pData)->order) + continue; + + if (((Gob_Object *) ptr->pData)->bottom <= + ((Gob_Object *) ptr2->pData)->bottom) { + if (((Gob_Object *) ptr->pData)-> + bottom != + ((Gob_Object *) ptr2->pData)-> + bottom) + continue; + + if ((Gob_Object *) ptr->pData != + gob_goblins[gob_currentGoblin]) + continue; + } + } + + tmp = ptr->pData; + ptr->pData = ptr2->pData; + ptr2->pData = tmp; + } + ptr = ptr->pNext; + } +} + +void gob_playSound(Snd_SoundDesc *snd, int16 repCount, int16 freq) { + if (snd != 0) { + snd_stopSound(0); + snd_playSample(snd, repCount, freq); + } +} + +void gob_drawObjects(void) { + int16 tmp; + int16 sndItem; + int16 freq; + int16 repCount; + Util_ListNode *ptr; + Util_ListNode *ptr2; + + Gob_Object *objDesc; + Gob_Object *gobDesc2; + int16 layer; + + ptr = gob_objList->pHead; + for (ptr = gob_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 = gob_objList->pHead; ptr != 0; ptr = ptr->pNext) { + objDesc = (Gob_Object *) ptr->pData; + if (objDesc->toRedraw == 0) + continue; + + vid_drawSprite(anim_underAnimSurf, draw_backSurface, + objDesc->left, objDesc->top, objDesc->right, + objDesc->bottom, objDesc->left, objDesc->top, 0); + + draw_invalidateRect(objDesc->left, objDesc->top, + objDesc->right, objDesc->bottom); + + if (objDesc->type != 0) + continue; + + layer = + objDesc->stateMach[objDesc->state][objDesc->stateColumn]-> + layer; + scen_updateAnim(layer, objDesc->curFrame, objDesc->animation, + 0, objDesc->xPos, objDesc->yPos, 0); + + if (scen_toRedrawLeft == -12345) { + objDesc->dirtyLeft = objDesc->left; + objDesc->dirtyRight = objDesc->right; + objDesc->dirtyTop = objDesc->top; + objDesc->dirtyBottom = objDesc->bottom; + } else { + objDesc->dirtyLeft = + MIN(objDesc->left, scen_toRedrawLeft); + objDesc->dirtyRight = + MAX(objDesc->right, scen_toRedrawRight); + objDesc->dirtyTop = + MIN(objDesc->top, scen_toRedrawTop); + objDesc->dirtyBottom = + MAX(objDesc->bottom, scen_toRedrawBottom); + } + + objDesc->dirtyLeft = 0; + objDesc->dirtyRight = 319; + objDesc->dirtyTop = 0; + objDesc->dirtyBottom = 199; + } + + gob_sortByOrder(gob_objList); + for (ptr = gob_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) { + scen_updateAnim(layer, + objDesc->curFrame, + objDesc->animation, 0, + objDesc->xPos, objDesc->yPos, 0); + + } else { + scen_updateAnim(layer, + objDesc->curFrame, + objDesc->animation, 2, + objDesc->xPos, objDesc->yPos, 1); + } + if (scen_toRedrawLeft == -12345) { + objDesc->left = 0; + objDesc->top = 0; + objDesc->right = 0; + objDesc->bottom = 0; + } else { + draw_invalidateRect(scen_toRedrawLeft, + scen_toRedrawTop, + scen_toRedrawRight, + scen_toRedrawBottom); + + objDesc->left = scen_toRedrawLeft; + objDesc->top = scen_toRedrawTop; + objDesc->right = scen_toRedrawRight; + objDesc->bottom = scen_toRedrawBottom; + scen_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 = gob_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; + + scen_toRedrawLeft = gobDesc2->dirtyLeft; + scen_toRedrawRight = gobDesc2->dirtyRight; + scen_toRedrawTop = gobDesc2->dirtyTop; + scen_toRedrawBottom = gobDesc2->dirtyBottom; + + layer = + objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]->layer; + + scen_updateAnim(layer, objDesc->curFrame, + objDesc->animation, 4, objDesc->xPos, + objDesc->yPos, 1); + + scen_updateStatic(objDesc->order); + } + } + } + + for (ptr = gob_objList->pHead; ptr != 0; ptr = ptr->pNext) { + objDesc = (Gob_Object *) ptr->pData; + if (objDesc->toRedraw == 0 || objDesc->type == 1) + continue; + + tmp = + objDesc->stateMach[objDesc->state][objDesc->stateColumn]-> + unk2; + + if ((tmp >> 8) != 0) { + if (objDesc->curFrame == (tmp >> 8)) { + sndItem = + objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]->sndItem >> 8; + if (sndItem != -1) { + freq = + (objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + freq >> 8) * 100; + repCount = + (objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + repCount >> 8); + gob_playSound(gob_soundData[sndItem], + repCount, freq); + } + } + + if (objDesc->curFrame == (tmp & 0xff)) { + sndItem = + objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + sndItem & 0xff; + if (sndItem != -1) { + freq = + (objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + freq & 0xff) * 100; + repCount = + (objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + repCount & 0xff); + gob_playSound(gob_soundData[sndItem], + repCount, freq); + } + } + } else { + if (objDesc->curFrame == tmp) { + sndItem = + objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]->sndItem; + if (sndItem != -1) { + freq = + objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + freq * 100; + repCount = + objDesc->stateMach[objDesc-> + state][objDesc->stateColumn]-> + repCount; + gob_playSound(gob_soundData[sndItem], + repCount, freq); + } + } + } + } + +// scen_updateAnim(27, 0, 9, 2, 10, 10, 1); +} + +void gob_animateObjects(void) { + Util_ListNode *node; + Gob_Object *objDesc; + Scen_AnimLayer *pLayer; + int16 layer; + + for (node = gob_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 = + scen_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 = + gob_goblins[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 gob_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 = util_getRandom(30); + + layer = objDesc->stateMach[objDesc->state][0]->layer; + scen_updateAnim(layer, 0, objDesc->animation, 0, + objDesc->xPos, objDesc->yPos, 0); + + objDesc->order = scen_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; + + util_listInsertBack(gob_objList, objDesc); + } +} + +int16 gob_getObjMaxFrame(Gob_Object * objDesc) { + int16 layer; + + layer = objDesc->stateMach[objDesc->state][0]->layer; + return scen_animations[objDesc->animation].layers[layer]->framesCount - + 1; +} + +int16 gob_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 gob_setMultStates(Gob_Object * gobDesc) { + gobDesc->stateMach = gob_goblins[gobDesc->multObjIndex]->stateMach; +} + +int16 gob_nextLayer(Gob_Object *gobDesc) { + if (gobDesc->nextState == 10) + gobDesc->curLookDir = 0; + + if (gobDesc->nextState == 11) + gobDesc->curLookDir = 4; + + if (gobDesc->nextState > 39) { + gob_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 gob_showBoredom(int16 gobIndex) { + Gob_Object *gobDesc; + int16 frame; + int16 frameCount; + int16 layer; + int16 state; + int16 boreFlag; + + gobDesc = gob_goblins[gobIndex]; + layer = gobDesc->stateMach[gobDesc->state][0]->layer; + + frameCount = + scen_animations[gobDesc->animation].layers[layer]->framesCount; + state = gobDesc->state; + frame = gobDesc->curFrame; + + gobDesc->noTick = 0; + gobDesc->toRedraw = 1; + + boreFlag = 1 << util_getRandom(7); + + if (gobIndex != gob_currentGoblin && 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 + && READ_LE_UINT32(inter_variables + 0xec) == 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 gob_switchGoblin(int16 index) { + int16 next; + int16 tmp; + + debug(0, "gob_switchGoblin"); + if (READ_LE_UINT32(inter_variables + 0xec) != 0) + return; + + if (gob_goblins[gob_currentGoblin]->state <= 39 && + gob_goblins[gob_currentGoblin]->curFrame != 0) + return; + + if (index != 0 && gob_goblins[index - 1]->type != 0) + return; + + if (index == 0) + next = (gob_currentGoblin + 1) % 3; + else + next = index - 1; + + if (map_passMap[map_curGoblinY][map_curGoblinX] == 3 || + map_passMap[map_curGoblinY][map_curGoblinX] == 6) + return; + + if (gob_goblins[(gob_currentGoblin + 1) % 3]->type != 0 && + gob_goblins[(gob_currentGoblin + 2) % 3]->type != 0) + return; + + gob_gobPositions[gob_currentGoblin].x = map_curGoblinX; + gob_gobPositions[gob_currentGoblin].y = map_curGoblinY; + + gob_goblins[gob_currentGoblin]->doAnim = 1; + gob_goblins[gob_currentGoblin]->nextState = 21; + + gob_nextLayer(gob_goblins[gob_currentGoblin]); + + gob_currentGoblin = next; + if (gob_goblins[gob_currentGoblin]->type != 0) + gob_currentGoblin = (gob_currentGoblin + 1) % 3; + + gob_goblins[gob_currentGoblin]->doAnim = 0; + if (gob_goblins[gob_currentGoblin]->curLookDir == 4) + gob_goblins[gob_currentGoblin]->nextState = 18; + else + gob_goblins[gob_currentGoblin]->nextState = 19; + + gob_goblins[gob_currentGoblin]->toRedraw = 1; + gob_nextLayer(gob_goblins[gob_currentGoblin]); + + tmp = gob_gobPositions[gob_currentGoblin].x; + gob_pressedMapX = tmp; + map_destX = tmp; + gob_gobDestX = tmp; + map_curGoblinX = tmp; + + tmp = gob_gobPositions[gob_currentGoblin].y; + gob_pressedMapY = tmp; + map_destY = tmp; + gob_gobDestY = tmp; + map_curGoblinY = tmp; + + *gob_curGobVarPtr = gob_currentGoblin; + gob_pathExistence = 0; + gob_readyToAct = 0; +} + +void gob_adjustDest(int16 posX, int16 posY) { + int16 resDelta; + int16 resDeltaDir; + int16 resDeltaPix; + int16 deltaPix; + int16 i; + + if (map_passMap[gob_pressedMapY][gob_pressedMapX] == 0 && + (gob_gobAction == 0 + || map_itemsMap[gob_pressedMapY][gob_pressedMapX] == 0)) { + + resDelta = -1; + resDeltaDir = 0; + resDeltaPix = 0; + + for (i = 1; + i <= gob_pressedMapX + && map_passMap[gob_pressedMapY][gob_pressedMapX - i] == 0; + i++); + + if (i <= gob_pressedMapX) { + resDeltaPix = (i - 1) * 12 + (posX % 12) + 1; + resDelta = i; + } + + for (i = 1; + (i + gob_pressedMapX) < 26 + && map_passMap[gob_pressedMapY][gob_pressedMapX + i] == 0; + i++); + + if (gob_pressedMapX + i < 26) { + deltaPix = (i * 12) - (posX % 12); + if (resDelta == -1 || deltaPix < resDeltaPix) { + resDeltaPix = deltaPix; + resDelta = i; + resDeltaDir = 1; + } + } + + for (i = 1; + (i + gob_pressedMapY) < 28 + && map_passMap[gob_pressedMapY + i][gob_pressedMapX] == 0; + i++); + + if (gob_pressedMapY + i < 28) { + deltaPix = (i * 6) - (posY % 6); + if (resDelta == -1 || deltaPix < resDeltaPix) { + resDeltaPix = deltaPix; + resDelta = i; + resDeltaDir = 2; + } + } + + for (i = 1; + i <= gob_pressedMapY + && map_passMap[gob_pressedMapY - i][gob_pressedMapX] == 0; + i++); + + if (i <= gob_pressedMapY) { + deltaPix = (i * 6) + (posY % 6); + if (resDelta == -1 || deltaPix < resDeltaPix) { + resDeltaPix = deltaPix; + resDelta = i; + resDeltaDir = 3; + } + } + + switch (resDeltaDir) { + case 0: + gob_pressedMapX -= resDelta; + break; + + case 1: + gob_pressedMapX += resDelta; + break; + + case 2: + gob_pressedMapY += resDelta; + break; + + case 3: + gob_pressedMapY -= resDelta; + break; + } + + } +} + +void gob_adjustTarget(void) { + if (gob_gobAction == 4 + && map_itemsMap[gob_pressedMapY][gob_pressedMapX] == 0) { + + if (gob_pressedMapY > 0 + && map_itemsMap[gob_pressedMapY - 1][gob_pressedMapX] != + 0) { + gob_pressedMapY--; + } else if (gob_pressedMapX < 25 + && map_itemsMap[gob_pressedMapY][gob_pressedMapX + 1] != + 0) { + gob_pressedMapX++; + } else if (gob_pressedMapX < 25 && gob_pressedMapY > 0 + && map_itemsMap[gob_pressedMapY - 1][gob_pressedMapX + + 1] != 0) { + gob_pressedMapY--; + gob_pressedMapX++; + } + } +} + +void gob_targetDummyItem(Gob_Object *gobDesc) { + if (map_itemsMap[gob_pressedMapY][gob_pressedMapX] == 0 && + map_passMap[gob_pressedMapY][gob_pressedMapX] == 1) { + if (gobDesc->curLookDir == 0) { + map_itemPoses[0].x = gob_pressedMapX; + map_itemPoses[0].y = gob_pressedMapY; + map_itemPoses[0].orient = -4; + } else { + map_itemPoses[0].x = gob_pressedMapX; + map_itemPoses[0].y = gob_pressedMapY; + map_itemPoses[0].orient = -1; + } + } +} + +void gob_targetItem(void) { + int16 tmpX; + int16 tmpY; + int16 items; + int16 layer; + int16 tmpPosX; + int16 tmpPosY; + Gob_Object *itemDesc; + + if (gob_gobAction == 3 || gob_gobAction == 4) { + items = map_itemsMap[gob_pressedMapY][gob_pressedMapX]; + if (gob_gobAction == 4 && (items & 0xff00) != 0 && + gob_objects[gob_itemToObject[(items & 0xff00) >> 8]]-> + pickable == 1) { + gob_destItemId = (items & 0xff00) >> 8; + gob_destActionItem = (items & 0xff00) >> 8; + gob_itemByteFlag = 1; + } else if ((items & 0xff) == 0) { + gob_destItemId = (items & 0xff00) >> 8; + gob_destActionItem = (items & 0xff00) >> 8; + gob_itemByteFlag = 1; + } else if (gob_gobAction == 3 && gob_currentGoblin == 2 && + (items & 0xff00) != 0) { + gob_destItemId = (items & 0xff00) >> 8; + gob_destActionItem = (items & 0xff00) >> 8; + gob_itemByteFlag = 1; + } else { + gob_destItemId = items & 0xff; + gob_destActionItem = items & 0xff; + gob_itemByteFlag = 0; + } + + gob_pressedMapY = map_itemPoses[gob_destItemId].y; + map_destY = map_itemPoses[gob_destItemId].y; + gob_gobDestY = map_itemPoses[gob_destItemId].y; + + if (gob_gobAction == 3 || gob_destActionItem == 0) { + gob_pressedMapX = map_itemPoses[gob_destItemId].x; + map_destX = map_itemPoses[gob_destItemId].x; + gob_gobDestX = map_itemPoses[gob_destItemId].x; + } else if ((items & 0xff00) != 0) { + if (map_itemPoses[gob_destItemId].orient == 4) { + if ((map_itemsMap[gob_pressedMapY] + [gob_pressedMapX - 1] & 0xff00) == + (map_itemsMap[gob_pressedMapY] + [gob_pressedMapX] & 0xff00)) { + gob_pressedMapX--; + map_destX = gob_pressedMapX; + gob_gobDestX = gob_pressedMapX; + } + } else if (map_itemPoses[gob_destItemId].orient == 0) { + + if ((map_itemsMap[gob_pressedMapY] + [gob_pressedMapX + 1] & 0xff00) == + (map_itemsMap[gob_pressedMapY] + [gob_pressedMapX] & 0xff00)) { + gob_pressedMapX++; + map_destX = gob_pressedMapX; + gob_gobDestX = gob_pressedMapX; + } + } + + if ((map_itemsMap[gob_pressedMapY + + 1][gob_pressedMapX] & 0xff00) == + (map_itemsMap[gob_pressedMapY][gob_pressedMapX] & + 0xff00)) { + gob_pressedMapY++; + map_destY = gob_pressedMapY; + gob_gobDestY = gob_pressedMapY; + } + } else { + if (map_itemPoses[gob_destItemId].orient == 4) { + if ((map_itemsMap[gob_pressedMapY] + [gob_pressedMapX - 1]) == + (map_itemsMap[gob_pressedMapY] + [gob_pressedMapX])) { + gob_pressedMapX--; + map_destX = gob_pressedMapX; + gob_gobDestX = gob_pressedMapX; + } + } else if (map_itemPoses[gob_destItemId].orient == 0) { + + if ((map_itemsMap[gob_pressedMapY] + [gob_pressedMapX + 1]) == + (map_itemsMap[gob_pressedMapY] + [gob_pressedMapX])) { + gob_pressedMapX++; + map_destX = gob_pressedMapX; + gob_gobDestX = gob_pressedMapX; + } + } + + if ((map_itemsMap[gob_pressedMapY + + 1][gob_pressedMapX]) == + (map_itemsMap[gob_pressedMapY][gob_pressedMapX])) { + gob_pressedMapY++; + map_destY = gob_pressedMapY; + gob_gobDestY = gob_pressedMapY; + } + + } + + if (gob_gobAction == 4 && gob_destActionItem != 0 && + gob_objects[gob_itemToObject[gob_destActionItem]]-> + pickable == 1) { + + itemDesc = + gob_objects[gob_itemToObject[gob_destActionItem]]; + + itemDesc->animation = + itemDesc->stateMach[itemDesc->state][0]->animation; + layer = + itemDesc->stateMach[itemDesc->state][itemDesc-> + stateColumn]->layer; + + scen_updateAnim(layer, 0, itemDesc->animation, 0, + itemDesc->xPos, itemDesc->yPos, 0); + + tmpX = (scen_toRedrawRight + scen_toRedrawLeft) / 2; + tmpY = scen_toRedrawBottom; + + tmpPosY = tmpY / 6; + if ((tmpY % 3) < 3 && tmpPosY > 0) + tmpPosY--; + + tmpPosX = tmpX / 12; + if ((tmpX % 12) < 6 && tmpPosX > 0) + tmpPosX--; + + if (map_itemPoses[gob_destActionItem].orient == 0 || + map_itemPoses[gob_destActionItem].orient == -1) { + tmpPosX++; + } + + if (map_passMap[tmpPosY][tmpPosX] == 1) { + gob_pressedMapX = tmpPosX; + map_destX = tmpPosX; + gob_gobDestX = tmpPosX; + + gob_pressedMapY = tmpPosY; + map_destY = tmpPosY; + gob_gobDestY = tmpPosY; + } + } + } +} + +void gob_initiateMove(void) { + map_findNearestToDest(); + map_findNearestToGob(); + + map_nearestWayPoint = + map_optimizePoints(map_curGoblinX, map_curGoblinY); + + gob_pathExistence = map_checkDirectPath(map_curGoblinX, map_curGoblinY, + gob_pressedMapX, gob_pressedMapY); + + if (gob_pathExistence == 3) { + if (map_checkLongPath(map_curGoblinX, map_curGoblinY, + gob_pressedMapX, gob_pressedMapY, + map_nearestWayPoint, map_nearestDest) == 0) { + gob_pathExistence = 0; + } else { + map_destX = map_wayPoints[map_nearestWayPoint].x; + map_destY = map_wayPoints[map_nearestWayPoint].y; + } + } +} + +void gob_moveFindItem(int16 posX, int16 posY) { + int16 i; + if (gob_gobAction == 3 || gob_gobAction == 4) { + for (i = 0; i < 20; i++) { + if (gob_objects[i] == 0) + continue; + + if (gob_objects[i]->type != 0) + continue; + + if (gob_objects[i]->left > posX) + continue; + + if (gob_objects[i]->right < posX) + continue; + + if (gob_objects[i]->top > posY) + continue; + + if (gob_objects[i]->bottom < posY) + continue; + + if (gob_objects[i]->right - gob_objects[i]->left < 40) + posX = + (gob_objects[i]->left + + gob_objects[i]->right) / 2; + + if (gob_objects[i]->bottom - gob_objects[i]->top < 40) + posY = + (gob_objects[i]->top + + gob_objects[i]->bottom) / 2; + + break; + } + + gob_pressedMapX = posX / 12; + gob_pressedMapY = posY / 6; + + if (map_itemsMap[gob_pressedMapY][gob_pressedMapX] == 0 + && i < 20) { + + if (map_itemsMap[gob_pressedMapY + + 1][gob_pressedMapX] != 0) { + gob_pressedMapY++; + } else if (map_itemsMap[gob_pressedMapY + + 1][gob_pressedMapX + 1] != 0) { + gob_pressedMapX++; + gob_pressedMapY++; + } else + if (map_itemsMap[gob_pressedMapY][gob_pressedMapX + + 1] != 0) { + gob_pressedMapX++; + } else if (map_itemsMap[gob_pressedMapY - + 1][gob_pressedMapX + 1] != 0) { + gob_pressedMapX++; + gob_pressedMapY--; + } else if (map_itemsMap[gob_pressedMapY - + 1][gob_pressedMapX] != 0) { + gob_pressedMapY--; + } else if (map_itemsMap[gob_pressedMapY - + 1][gob_pressedMapX - 1] != 0) { + gob_pressedMapY--; + gob_pressedMapX--; + } else + if (map_itemsMap[gob_pressedMapY][gob_pressedMapX - + 1] != 0) { + gob_pressedMapX--; + } else if (map_itemsMap[gob_pressedMapY + + 1][gob_pressedMapX - 1] != 0) { + gob_pressedMapX--; + gob_pressedMapY++; + } + } + } else { + gob_pressedMapX = posX / 12; + gob_pressedMapY = posY / 6; + } +} + +void gob_moveCheckSelect(int16 framesCount, Gob_Object * gobDesc, int16 *pGobIndex, + int16 *nextAct) { + if (gobDesc->right > inter_mouseX && + gobDesc->left < inter_mouseX && + gobDesc->bottom > inter_mouseY && + gobDesc->bottom - 10 < inter_mouseY && gob_gobAction == 0) { + if (gobDesc->curLookDir & 4) + *nextAct = 16; + else + *nextAct = 23; + + gobDesc->curFrame = framesCount - 1; + gob_pathExistence = 0; + } else { + *pGobIndex = gob_peekGoblin(gobDesc); + + if (*pGobIndex != 0) { + gob_pathExistence = 0; + } else if (map_curGoblinX == gob_pressedMapX && + map_curGoblinY == gob_pressedMapY) { + + if (gob_gobAction != 0) + gob_readyToAct = 1; + + gob_pathExistence = 0; + } + } +} + +void gob_moveInitStep(int16 framesCount, int16 action, int16 cont, + Gob_Object *gobDesc, int16 *pGobIndex, int16 *pNextAct) { + int16 posX; + int16 posY; + + if (cont != 0 && gob_goesAtTarget == 0 && + gob_readyToAct == 0 && READ_LE_UINT32(inter_variables + 0xec) == 0 && + gobDesc->type != 1 && + gobDesc->state != 10 && gobDesc->state != 11) { + if (gobDesc->state >= 40) { + gobDesc->curFrame = framesCount - 1; + } + + gob_gobAction = action; + gob_forceNextState[0] = -1; + gob_forceNextState[1] = -1; + gob_forceNextState[2] = -1; + + if (action == 3) { + posX = inter_mouseX + 6; + posY = inter_mouseY + 7; + } else if (action == 4) { + posX = inter_mouseX + 7; + posY = inter_mouseY + 12; + } else { + posX = inter_mouseX; + posY = inter_mouseY; + } + + gob_moveFindItem(posX, posY); + gob_adjustDest(posX, posY); + gob_adjustTarget(); + + map_destX = gob_pressedMapX; + gob_gobDestX = gob_pressedMapX; + + map_destY = gob_pressedMapY; + gob_gobDestY = gob_pressedMapY; + + gob_targetDummyItem(gobDesc); + + gob_targetItem(); + gob_initiateMove(); + + gob_moveCheckSelect(framesCount, gobDesc, pGobIndex, pNextAct); + } else { + + if (gob_readyToAct != 0 && + (map_curGoblinX != gob_pressedMapX || + map_curGoblinY != gob_pressedMapY)) + gob_readyToAct = 0; + + if (gobDesc->type == 1) { + *pGobIndex = gob_peekGoblin(gobDesc); + } + } +} + +void gob_moveTreatRopeStairs(Gob_Object *gobDesc) { + if (gob_currentGoblin != 1) + return; + + if (gobDesc->nextState == 28 + && map_passMap[map_curGoblinY - 1][map_curGoblinX] == 6) { + gob_forceNextState[0] = 28; + gob_forceNextState[1] = -1; + } + + if (gobDesc->nextState == 29 + && map_passMap[map_curGoblinY + 1][map_curGoblinX] == 6) { + gob_forceNextState[0] = 29; + gob_forceNextState[1] = -1; + } + + if ((gobDesc->nextState == 28 || gobDesc->nextState == 29 + || gobDesc->nextState == 20) + && map_passMap[map_curGoblinY][map_curGoblinX] == 6) { + if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4 + || gobDesc->curLookDir == 2) + && map_passMap[map_curGoblinY - 1][map_curGoblinX] == 6) { + gob_forceNextState[0] = 28; + gob_forceNextState[1] = -1; + } else if ((gobDesc->curLookDir == 0 + || gobDesc->curLookDir == 4 + || gobDesc->curLookDir == 6) + && map_passMap[map_curGoblinY + 1][map_curGoblinX] == 6) { + gob_forceNextState[0] = 29; + gob_forceNextState[1] = -1; + } + } + + if (gobDesc->nextState == 8 + && map_passMap[map_curGoblinY - 1][map_curGoblinX] == 3) { + gob_forceNextState[0] = 8; + gob_forceNextState[1] = -1; + } + + if (gobDesc->nextState == 9 + && map_passMap[map_curGoblinY + 1][map_curGoblinX] == 3) { + gob_forceNextState[0] = 9; + gob_forceNextState[1] = -1; + } + + if (gobDesc->nextState == 20 + && map_passMap[map_curGoblinY][map_curGoblinX] == 3) { + if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4 + || gobDesc->curLookDir == 2) + && map_passMap[map_curGoblinY - 1][map_curGoblinX] == 3) { + gob_forceNextState[0] = 8; + gob_forceNextState[1] = -1; + } else if ((gobDesc->curLookDir == 0 + || gobDesc->curLookDir == 4 + || gobDesc->curLookDir == 6) + && map_passMap[map_curGoblinY + 1][map_curGoblinX] == 3) { + gob_forceNextState[0] = 9; + gob_forceNextState[1] = -1; + } + } + +} + +void gob_movePathFind(Gob_Object *gobDesc, int16 nextAct) { + if (gob_pathExistence == 1) { + map_curGoblinX = gob_gobPositions[gob_currentGoblin].x; + map_curGoblinY = gob_gobPositions[gob_currentGoblin].y; + + if (map_curGoblinX == gob_pressedMapX && + map_curGoblinY == gob_pressedMapY && gob_gobAction != 0) { + gob_readyToAct = 1; + gob_pathExistence = 0; + } + + nextAct = map_getDirection(map_curGoblinX, map_curGoblinY, + map_destX, map_destY); + + if (nextAct == 0) + gob_pathExistence = 0; + } else if (gob_pathExistence == 3) { + map_curGoblinX = gob_gobPositions[gob_currentGoblin].x; + map_curGoblinY = gob_gobPositions[gob_currentGoblin].y; + + if (map_curGoblinX == gob_gobDestX && + map_curGoblinY == gob_gobDestY) { + gob_pathExistence = 1; + map_destX = gob_pressedMapX; + map_destY = gob_pressedMapY; + } else { + + if (map_checkDirectPath(map_curGoblinX, map_curGoblinY, + gob_gobDestX, gob_gobDestY) == 1) { + map_destX = gob_gobDestX; + map_destY = gob_gobDestY; + } else if (map_curGoblinX == map_destX + && map_curGoblinY == map_destY) { + + if (map_nearestWayPoint > map_nearestDest) { + map_nearestWayPoint = + map_optimizePoints(map_curGoblinX, + map_curGoblinY); + + map_destX = + map_wayPoints[map_nearestWayPoint]. + x; + map_destY = + map_wayPoints[map_nearestWayPoint]. + y; + + if (map_nearestWayPoint > + map_nearestDest) + map_nearestWayPoint--; + } else if (map_nearestWayPoint < + map_nearestDest) { + map_nearestWayPoint = + map_optimizePoints(map_curGoblinX, + map_curGoblinY); + + map_destX = + map_wayPoints[map_nearestWayPoint]. + x; + map_destY = + map_wayPoints[map_nearestWayPoint]. + y; + + if (map_nearestWayPoint < map_nearestDest) + map_nearestWayPoint++; + } else { + if (map_checkDirectPath(map_curGoblinX, + map_curGoblinY, gob_gobDestX, + gob_gobDestY) == 3 && map_passMap[gob_pressedMapY][gob_pressedMapX] != 0) { + map_destX = map_wayPoints[map_nearestWayPoint].x; + map_destY = map_wayPoints[map_nearestWayPoint].y; + } else { + gob_pathExistence = 1; + map_destX = gob_pressedMapX; + map_destY = gob_pressedMapY; + } + } + } + nextAct = + map_getDirection(map_curGoblinX, map_curGoblinY, + map_destX, map_destY); + } + } + + if (gob_readyToAct != 0 && (gob_gobAction == 3 || gob_gobAction == 4)) + nextAct = 0x4dc8; + + switch (nextAct) { + case 0x4b00: + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 0); + break; + + case 0x4d00: + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 4); + break; + + case 16: + gobDesc->nextState = 16; + break; + + case 23: + gobDesc->nextState = 23; + break; + + case 0x4800: + + if (map_passMap[map_curGoblinY - 1][map_curGoblinX] == 6 && + gob_currentGoblin != 1) { + gob_pathExistence = 0; + break; + } + + if (map_passMap[map_curGoblinY][map_curGoblinX] == 3) { + gobDesc->nextState = 8; + break; + } + + if (map_passMap[map_curGoblinY][map_curGoblinX] == 6 && + gob_currentGoblin == 1) { + gobDesc->nextState = 28; + break; + } + + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 2); + break; + + case 0x5000: + if (map_passMap[map_curGoblinY + 1][map_curGoblinX] == 6 && + gob_currentGoblin != 1) { + gob_pathExistence = 0; + break; + } + + if (map_passMap[map_curGoblinY][map_curGoblinX] == 3) { + gobDesc->nextState = 9; + break; + } + + if (map_passMap[map_curGoblinY][map_curGoblinX] == 6 && + gob_currentGoblin == 1) { + gobDesc->nextState = 29; + break; + } + + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 6); + break; + + case 0x5100: + if (map_passMap[map_curGoblinY + 1][map_curGoblinX + 1] == 6 && + gob_currentGoblin != 1) { + gob_pathExistence = 0; + break; + } + + gobDesc->nextState = 5; + if (gobDesc->curLookDir == 4) + break; + + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 4); + break; + + case 0x4f00: + if (map_passMap[map_curGoblinY + 1][map_curGoblinX - 1] == 6 && + gob_currentGoblin != 1) { + gob_pathExistence = 0; + break; + } + + gobDesc->nextState = 7; + if (gobDesc->curLookDir == 0) + break; + + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 0); + break; + + case 0x4700: + if (map_passMap[map_curGoblinY - 1][map_curGoblinX - 1] == 6 && + gob_currentGoblin != 1) { + gob_pathExistence = 0; + break; + } + + gobDesc->nextState = 1; + if (gobDesc->curLookDir == 0) + break; + + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 0); + break; + + case 0x4900: + if (map_passMap[map_curGoblinY - 1][map_curGoblinX + 1] == 6 && + gob_currentGoblin != 1) { + gob_pathExistence = 0; + break; + } + + gobDesc->nextState = 3; + if (gobDesc->curLookDir == 4) + break; + + gobDesc->nextState = gob_rotateState(gobDesc->curLookDir, 4); + break; + + case 0x4dc8: + + if (gob_currentGoblin == 0 && gob_gobAction == 3 + && gob_itemIndInPocket == -1) { + gob_destItemId = -1; + gob_readyToAct = 0; + break; + } + + if (gob_currentGoblin == 0 && gob_gobAction == 4 && + gob_itemIndInPocket == -1 && gob_destActionItem == 0) { + gobDesc->multState = 104; + gob_destItemId = -1; + gob_readyToAct = 0; + break; + } + + if (gob_currentGoblin == 0 && gob_gobAction == 4 && + gob_itemIndInPocket == -1 && gob_destActionItem != 0 && + gob_itemToObject[gob_destActionItem] != -1 && + gob_objects[gob_itemToObject[gob_destActionItem]]-> + pickable == 0) { + gobDesc->multState = 104; + gob_destItemId = -1; + gob_readyToAct = 0; + break; + } + + switch (map_itemPoses[gob_destActionItem].orient) { + case 0: + case -4: + gobDesc->nextState = 10; + gobDesc->curLookDir = 0; + gob_destItemId = -1; + break; + + case -1: + case 4: + gobDesc->nextState = 11; + gobDesc->curLookDir = 4; + gob_destItemId = -1; + break; + } + break; + + default: + if (map_passMap[map_curGoblinY][map_curGoblinX] == 3 || + (map_passMap[map_curGoblinY][map_curGoblinX] == 6 + && gob_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 gob_moveAdvance(Gob_Object *gobDesc, int16 nextAct, int16 framesCount) { + int16 i; + int16 newX; + int16 newY; + int16 flag; + + gob_movePathFind(gobDesc, nextAct); + + gobDesc->curFrame++; + if (gobDesc->curFrame == 1) + gobDesc->actionStartState = gobDesc->state; + + if (gob_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 (gob_currentGoblin != 1) + break; + gobDesc->curLookDir = 2; + break; + + case 2: + case 8: + case 15: + case 22: + case 25: + gobDesc->curLookDir = 2; + break; + + case 29: + if (gob_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)) { + snd_speakerOn(10 * util_getRandom(3) + 50); + util_delay(5); + snd_speakerOff(); + } + + if (gob_currentGoblin == 0 + && gobDesc->stateMach == gobDesc->realStateMach + && (gobDesc->state == 10 || gobDesc->state == 11) + && gobDesc->curFrame == 9) { + snd_stopSound(0); + if (gob_itemIndInPocket != -1) { + snd_playSample(gob_soundData[14], 1, 9000); + } + + if (gob_itemIndInPocket == -1) { + snd_playSample(gob_soundData[14], 1, 5000); + } + } + + if (gob_boreCounter++ == 120) { + gob_boreCounter = 0; + for (i = 0; i < 3; i++) + gob_showBoredom(i); + } + + if (gobDesc->multState != -1 && gobDesc->curFrame == framesCount && + gobDesc->state != gobDesc->multState) { + gobDesc->nextState = gobDesc->multState; + gobDesc->multState = -1; + + newX = + scen_animations[gobDesc->animation]. + layers[gob_gobStateLayer]->animDeltaX + gobDesc->xPos; + + newY = + scen_animations[gobDesc->animation]. + layers[gob_gobStateLayer]->animDeltaX + gobDesc->yPos; + + gob_gobStateLayer = gob_nextLayer(gobDesc); + + gobDesc->xPos = newX; + gobDesc->yPos = newY; + } else { + if (gobDesc->curFrame == 3 && + gobDesc->stateMach == gobDesc->realStateMach && + (gobDesc->state < 10 || + (gob_currentGoblin == 1 && (gobDesc->state == 28 + || gobDesc->state == 29)) + )) { + flag = 0; + if (gob_forceNextState[0] != -1) { + gobDesc->nextState = gob_forceNextState[0]; + for (i = 0; i < 9; i++) + gob_forceNextState[i] = + gob_forceNextState[i + 1]; + } + + map_curGoblinX = gob_gobPositions[gob_currentGoblin].x; + map_curGoblinY = gob_gobPositions[gob_currentGoblin].y; + + if (gobDesc->nextState != gobDesc->state) { + gob_gobStateLayer = gob_nextLayer(gobDesc); + flag = 1; + } + + switch (gobDesc->state) { + case 0: + gob_gobPositions[gob_currentGoblin].x--; + break; + + case 2: + case 8: + gob_gobPositions[gob_currentGoblin].y--; + break; + + case 4: + gob_gobPositions[gob_currentGoblin].x++; + break; + + case 6: + case 9: + gob_gobPositions[gob_currentGoblin].y++; + break; + + case 1: + gob_gobPositions[gob_currentGoblin].x--; + gob_gobPositions[gob_currentGoblin].y--; + break; + + case 3: + gob_gobPositions[gob_currentGoblin].x++; + gob_gobPositions[gob_currentGoblin].y--; + break; + + case 5: + gob_gobPositions[gob_currentGoblin].x++; + gob_gobPositions[gob_currentGoblin].y++; + break; + + case 7: + gob_gobPositions[gob_currentGoblin].x--; + gob_gobPositions[gob_currentGoblin].y++; + break; + + case 38: + gob_gobPositions[gob_currentGoblin].y++; + break; + } + + if (gob_currentGoblin == 1) { + if (gobDesc->state == 28) + gob_gobPositions[1].y--; + + if (gobDesc->state == 29) + gob_gobPositions[1].y++; + } + + if (flag != 0) { + scen_updateAnim(gob_gobStateLayer, 0, + gobDesc->animation, 0, gobDesc->xPos, + gobDesc->yPos, 0); + + gobDesc->yPos = + (map_curGoblinY + 1) * 6 - + (scen_toRedrawBottom - scen_animTop); + gobDesc->xPos = + map_curGoblinX * 12 - (scen_toRedrawLeft - + scen_animLeft); + } + + if ((gobDesc->state == 10 || gobDesc->state == 11) + && gob_currentGoblin != 0) + gob_goesAtTarget = 1; + } + + if (gobDesc->curFrame != framesCount) + return; + + if (gob_forceNextState[0] != -1) { + gobDesc->nextState = gob_forceNextState[0]; + for (i = 0; i < 10; i++) + gob_forceNextState[i] = + gob_forceNextState[i + 1]; + } + + map_curGoblinX = gob_gobPositions[gob_currentGoblin].x; + map_curGoblinY = gob_gobPositions[gob_currentGoblin].y; + + gob_gobStateLayer = gob_nextLayer(gobDesc); + if (gobDesc->stateMach == gobDesc->realStateMach) { + + switch (gobDesc->nextState) { + case 0: + gob_gobPositions[gob_currentGoblin].x--; + break; + + case 2: + case 8: + gob_gobPositions[gob_currentGoblin].y--; + break; + + case 4: + gob_gobPositions[gob_currentGoblin].x++; + break; + + case 6: + case 9: + gob_gobPositions[gob_currentGoblin].y++; + break; + + case 1: + gob_gobPositions[gob_currentGoblin].x--; + gob_gobPositions[gob_currentGoblin].y--; + break; + + case 3: + gob_gobPositions[gob_currentGoblin].x++; + gob_gobPositions[gob_currentGoblin].y--; + break; + + case 5: + gob_gobPositions[gob_currentGoblin].x++; + gob_gobPositions[gob_currentGoblin].y++; + break; + + case 7: + gob_gobPositions[gob_currentGoblin].x--; + gob_gobPositions[gob_currentGoblin].y++; + break; + + case 38: + gob_gobPositions[gob_currentGoblin].y++; + break; + } + if (gob_currentGoblin == 1) { + if (gobDesc->nextState == 28) + gob_gobPositions[1].y--; + + if (gobDesc->nextState == 29) + gob_gobPositions[1].y++; + } + } + + scen_updateAnim(gob_gobStateLayer, 0, gobDesc->animation, 0, + gobDesc->xPos, gobDesc->yPos, 0); + + gobDesc->yPos = + (map_curGoblinY + 1) * 6 - (scen_toRedrawBottom - + scen_animTop); + gobDesc->xPos = + map_curGoblinX * 12 - (scen_toRedrawLeft - scen_animLeft); + + if ((gobDesc->state == 10 || gobDesc->state == 11) + && gob_currentGoblin != 0) + gob_goesAtTarget = 1; + } + return; +} + +int16 gob_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 = + scen_animations[gobDesc->animation].layers[layer]->framesCount; + + if (READ_LE_UINT32(inter_variables + 0xec) == 0 && + gobDesc->state != 30 && gobDesc->state != 31) { + gobDesc->order = (gobDesc->bottom) / 24 + 3; + } + + if (gob_positionedGob != gob_currentGoblin) { + map_curGoblinX = gob_gobPositions[gob_currentGoblin].x; + map_curGoblinY = gob_gobPositions[gob_currentGoblin].y; + } + + gob_positionedGob = gob_currentGoblin; + + gobDesc->animation = + gobDesc->stateMach[gobDesc->state][gobDesc->stateColumn]-> + animation; + + gob_gobStateLayer = + gobDesc->stateMach[gobDesc->state][gobDesc->stateColumn]->layer; + + gob_moveInitStep(framesCount, action, cont, gobDesc, &gobIndex, + &nextAct); + gob_moveTreatRopeStairs(gobDesc); + gob_moveAdvance(gobDesc, nextAct, framesCount); + + return gobIndex; +} + +void gob_freeObjects(void) { + int16 i; + int16 state; + int16 col; + + for (i = 0; i < 16; i++) { + if (gob_soundData[i] == 0) + continue; + + snd_freeSoundData(gob_soundData[i]); + gob_soundData[i] = 0; + } + + for (i = 0; i < 4; i++) { + if (gob_goblins[i] == 0) + continue; + + gob_goblins[i]->stateMach = gob_goblins[i]->realStateMach; + + for (state = 0; state < 40; state++) { + for (col = 0; col < 6; col++) { + + if (gob_goblins[i]->stateMach[state][col] != 0) { + free((char *)gob_goblins[i]-> + stateMach[state][col]); + gob_goblins[i]->stateMach[state][col] = + 0; + } + } + } + + if (i == 3) { + for (state = 40; state < 70; state++) { + if (gob_goblins[3]->stateMach[state][0] == 0) + continue; + + free((char *)gob_goblins[3]-> + stateMach[state][0]); + gob_goblins[3]->stateMach[state][0] = 0; + } + } + + free((char *)gob_goblins[i]->stateMach); + free((char *)gob_goblins[i]); + gob_goblins[i] = 0; + } + + for (i = 0; i < 20; i++) { + if (gob_objects[i] == 0) + continue; + + gob_objects[i]->stateMach = gob_objects[i]->realStateMach; + + for (state = 0; state < 40; state++) { + for (col = 0; col < 6; col++) { + if (gob_objects[i]->stateMach[state][col] == 0) + continue; + + free((char *)gob_objects[i]-> + stateMach[state][col]); + gob_objects[i]->stateMach[state][col] = 0; + } + } + + free((char *)gob_objects[i]->stateMach); + free((char *)gob_objects[i]); + gob_objects[i] = 0; + } +} + +void gob_zeroObjects(void) { + int16 i; + + for (i = 0; i < 4; i++) + gob_goblins[i] = 0; + + for (i = 0; i < 20; i++) + gob_objects[i] = 0; + + for (i = 0; i < 16; i++) + gob_soundData[i] = 0; +} + +void gob_freeAllObjects(void) { + util_deleteList(gob_objList); + gob_freeObjects(); +} + +void gob_loadObjects(char *source) { + int16 i; + + gob_zeroObjects(); + for (i = 0; i < 20; i++) + gob_itemToObject[i] = 100; + + gob_freeObjects(); + gob_initList(); + strcpy(map_sourceFile, source); + + map_sourceFile[strlen(map_sourceFile) - 4] = 0; + map_loadMapObjects(source); + + for (i = 0; i < gob_gobsCount; i++) + gob_placeObject(gob_goblins[i], 0); + + for (i = 0; i < gob_objCount; i++) { + gob_placeObject(gob_objects[i], 1); + } + + gob_initVarPointers(); + gob_actDestItemDesc = 0; +} + +void gob_saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal) { + Gob_Object *obj; + *gob_some0ValPtr = someVal; + *gob_curGobXPosVarPtr = xPos; + *gob_curGobYPosVarPtr = yPos; + *gob_itemInPocketVarPtr = gob_itemIndInPocket; + + obj = gob_goblins[gob_currentGoblin]; + + *gob_curGobStateVarPtr = obj->state; + *gob_curGobFrameVarPtr = obj->curFrame; + *gob_curGobMultStateVarPtr = obj->multState; + *gob_curGobNextStateVarPtr = obj->nextState; + *gob_curGobScrXVarPtr = obj->xPos; + *gob_curGobScrYVarPtr = obj->yPos; + *gob_curGobLeftVarPtr = obj->left; + *gob_curGobTopVarPtr = obj->top; + *gob_curGobRightVarPtr = obj->right; + *gob_curGobBottomVarPtr = obj->bottom; + *gob_curGobDoAnimVarPtr = obj->doAnim; + *gob_curGobOrderVarPtr = obj->order; + *gob_curGobNoTickVarPtr = obj->noTick; + *gob_curGobTypeVarPtr = obj->type; + *gob_curGobMaxTickVarPtr = obj->maxTick; + *gob_curGobTickVarPtr = obj->tick; + *gob_curGobActStartStateVarPtr = obj->actionStartState; + *gob_curGobLookDirVarPtr = obj->curLookDir; + *gob_curGobPickableVarPtr = obj->pickable; + *gob_curGobRelaxVarPtr = obj->relaxTime; + *gob_curGobMaxFrameVarPtr = gob_getObjMaxFrame(obj); + + if (gob_actDestItemDesc == 0) + return; + + obj = gob_actDestItemDesc; + *gob_destItemStateVarPtr = obj->state; + *gob_destItemFrameVarPtr = obj->curFrame; + *gob_destItemMultStateVarPtr = obj->multState; + *gob_destItemNextStateVarPtr = obj->nextState; + *gob_destItemScrXVarPtr = obj->xPos; + *gob_destItemScrYVarPtr = obj->yPos; + *gob_destItemLeftVarPtr = obj->left; + *gob_destItemTopVarPtr = obj->top; + *gob_destItemRightVarPtr = obj->right; + *gob_destItemBottomVarPtr = obj->bottom; + *gob_destItemDoAnimVarPtr = obj->doAnim; + *gob_destItemOrderVarPtr = obj->order; + *gob_destItemNoTickVarPtr = obj->noTick; + *gob_destItemTypeVarPtr = obj->type; + *gob_destItemMaxTickVarPtr = obj->maxTick; + *gob_destItemTickVarPtr = obj->tick; + *gob_destItemActStartStVarPtr = obj->actionStartState; + *gob_destItemLookDirVarPtr = obj->curLookDir; + *gob_destItemPickableVarPtr = obj->pickable; + *gob_destItemRelaxVarPtr = obj->relaxTime; + *gob_destItemMaxFrameVarPtr = gob_getObjMaxFrame(obj); + + gob_destItemState = obj->state; + gob_destItemType = obj->type; +} + +void gob_initVarPointers(void) { + // FIXME: All this is not endian-safe + gob_curGobStateVarPtr = (int32 *)(inter_variables + 0xf0); + gob_curGobNoTickVarPtr = (int32 *)(inter_variables + 0x120); + gob_curGobNextStateVarPtr = (int32 *)(inter_variables + 0xfc); + gob_curGobMultStateVarPtr = (int32 *)(inter_variables + 0xf8); + gob_curGobLookDirVarPtr = (int32 *)(inter_variables + 0x134); + gob_curGobPickableVarPtr = (int32 *)(inter_variables + 0x140); + gob_curGobRelaxVarPtr = (int32 *)(inter_variables + 0x144); + gob_curGobTypeVarPtr = (int32 *)(inter_variables + 0x124); + gob_curGobMaxFrameVarPtr = (int32 *)(inter_variables + 0x1b8); + gob_curGobTickVarPtr = (int32 *)(inter_variables + 0x12c); + gob_curGobFrameVarPtr = (int32 *)(inter_variables + 0xf4); + gob_curGobOrderVarPtr = (int32 *)(inter_variables + 0x11c); + gob_curGobMaxTickVarPtr = (int32 *)(inter_variables + 0x128); + gob_curGobActStartStateVarPtr = (int32 *)(inter_variables + 0x130); + gob_curGobDoAnimVarPtr = (int32 *)(inter_variables + 0x118); + gob_curGobLeftVarPtr = (int32 *)(inter_variables + 0x108); + gob_curGobRightVarPtr = (int32 *)(inter_variables + 0x110); + gob_curGobScrXVarPtr = (int32 *)(inter_variables + 0x100); + gob_curGobTopVarPtr = (int32 *)(inter_variables + 0x10c); + gob_curGobBottomVarPtr = (int32 *)(inter_variables + 0x114); + gob_curGobScrYVarPtr = (int32 *)(inter_variables + 0x104); + + gob_destItemStateVarPtr = (int32 *)(inter_variables + 0x148); + gob_destItemNoTickVarPtr = (int32 *)(inter_variables + 0x178); + gob_destItemNextStateVarPtr = (int32 *)(inter_variables + 0x154); + gob_destItemMultStateVarPtr = (int32 *)(inter_variables + 0x150); + gob_destItemLookDirVarPtr = (int32 *)(inter_variables + 0x18c); + gob_destItemPickableVarPtr = (int32 *)(inter_variables + 0x198); + gob_destItemRelaxVarPtr = (int32 *)(inter_variables + 0x19c); + gob_destItemTypeVarPtr = (int32 *)(inter_variables + 0x17c); + gob_destItemMaxFrameVarPtr = (int32 *)(inter_variables + 0x1a4); + gob_destItemTickVarPtr = (int32 *)(inter_variables + 0x184); + gob_destItemFrameVarPtr = (int32 *)(inter_variables + 0x14c); + gob_destItemOrderVarPtr = (int32 *)(inter_variables + 0x174); + gob_destItemMaxTickVarPtr = (int32 *)(inter_variables + 0x180); + gob_destItemActStartStVarPtr = (int32 *)(inter_variables + 0x188); + gob_destItemDoAnimVarPtr = (int32 *)(inter_variables + 0x170); + gob_destItemLeftVarPtr = (int32 *)(inter_variables + 0x160); + gob_destItemRightVarPtr = (int32 *)(inter_variables + 0x168); + gob_destItemScrXVarPtr = (int32 *)(inter_variables + 0x158); + gob_destItemTopVarPtr = (int32 *)(inter_variables + 0x164); + gob_destItemBottomVarPtr = (int32 *)(inter_variables + 0x16c); + gob_destItemScrYVarPtr = (int32 *)(inter_variables + 0x15c); + + gob_some0ValPtr = (int32 *)(inter_variables + 0x1ac); + gob_curGobXPosVarPtr = (int32 *)(inter_variables + 0x1b0); + gob_curGobYPosVarPtr = (int32 *)(inter_variables + 0x1b4); + gob_itemInPocketVarPtr = (int32 *)(inter_variables + 0x1c8); + gob_gobRetVarPtr = (int32 *)(inter_variables + 0xec); + gob_curGobVarPtr = (int32 *)(inter_variables + 0x1a8); + + *gob_itemInPocketVarPtr = -2; +} + +void gob_loadGobDataFromVars(void) { + Gob_Object *obj; + + gob_itemIndInPocket = *gob_itemInPocketVarPtr; + + obj = gob_goblins[gob_currentGoblin]; + + obj->state = *gob_curGobStateVarPtr; + obj->curFrame = *gob_curGobFrameVarPtr; + obj->multState = *gob_curGobMultStateVarPtr; + obj->nextState = *gob_curGobNextStateVarPtr; + obj->xPos = *gob_curGobScrXVarPtr; + obj->yPos = *gob_curGobScrYVarPtr; + obj->left = *gob_curGobLeftVarPtr; + obj->top = *gob_curGobTopVarPtr; + obj->right = *gob_curGobRightVarPtr; + obj->bottom = *gob_curGobBottomVarPtr; + obj->doAnim = *gob_curGobDoAnimVarPtr; + obj->order = *gob_curGobOrderVarPtr; + obj->noTick = *gob_curGobNoTickVarPtr; + obj->type = *gob_curGobTypeVarPtr; + obj->maxTick = *gob_curGobMaxTickVarPtr; + obj->tick = *gob_curGobTickVarPtr; + obj->actionStartState = *gob_curGobActStartStateVarPtr; + obj->curLookDir = *gob_curGobLookDirVarPtr; + obj->pickable = *gob_curGobPickableVarPtr; + obj->relaxTime = *gob_curGobRelaxVarPtr; + + if (gob_actDestItemDesc == 0) + return; + + obj = gob_actDestItemDesc; + + obj->state = *gob_destItemStateVarPtr; + obj->curFrame = *gob_destItemFrameVarPtr; + obj->multState = *gob_destItemMultStateVarPtr; + obj->nextState = *gob_destItemNextStateVarPtr; + obj->xPos = *gob_destItemScrXVarPtr; + obj->yPos = *gob_destItemScrYVarPtr; + obj->left = *gob_destItemLeftVarPtr; + obj->top = *gob_destItemTopVarPtr; + obj->right = *gob_destItemRightVarPtr; + obj->bottom = *gob_destItemBottomVarPtr; + obj->doAnim = *gob_destItemDoAnimVarPtr; + obj->order = *gob_destItemOrderVarPtr; + obj->noTick = *gob_destItemNoTickVarPtr; + obj->type = *gob_destItemTypeVarPtr; + obj->maxTick = *gob_destItemMaxTickVarPtr; + obj->tick = *gob_destItemTickVarPtr; + obj->actionStartState = *gob_destItemActStartStVarPtr; + obj->curLookDir = *gob_destItemLookDirVarPtr; + obj->pickable = *gob_destItemPickableVarPtr; + obj->relaxTime = *gob_destItemRelaxVarPtr; + + if (obj->type != gob_destItemType) + obj->toRedraw = 1; + + if (obj->state != gob_destItemState && obj->type == 0) + obj->toRedraw = 1; +} + +void gob_pickItem(int16 indexToPocket, int16 idToPocket) { + int16 x; + int16 y; + + if (gob_objects[indexToPocket]->pickable != 1) + return; + + gob_objects[indexToPocket]->type = 3; + + gob_itemIndInPocket = indexToPocket; + gob_itemIdInPocket = idToPocket; + + for (y = 0; y < 28; y++) { + for (x = 0; x < 26; x++) { + if (gob_itemByteFlag == 1) { + if (((map_itemsMap[y][x] & 0xff00) >> 8) == + idToPocket) + map_itemsMap[y][x] &= 0xff; + } else { + if ((map_itemsMap[y][x] & 0xff) == idToPocket) + map_itemsMap[y][x] &= 0xff00; + } + } + } + + if (idToPocket >= 0 && idToPocket < 20) { + map_itemPoses[gob_itemIdInPocket].x = 0; + map_itemPoses[gob_itemIdInPocket].y = 0; + map_itemPoses[gob_itemIdInPocket].orient = 0; + } +} + +void gob_placeItem(int16 indexInPocket, int16 idInPocket) { + Gob_Object *itemDesc; + int16 lookDir; + int16 xPos; + int16 yPos; + int16 layer; + + itemDesc = gob_objects[indexInPocket]; + lookDir = gob_goblins[0]->curLookDir & 4; + + xPos = gob_gobPositions[0].x; + yPos = gob_gobPositions[0].y; + + gob_itemIndInPocket = -1; + gob_itemIdInPocket = 0; + + itemDesc->pickable = 1; + itemDesc->type = 0; + itemDesc->toRedraw = 1; + itemDesc->curFrame = 0; + itemDesc->order = gob_goblins[0]->order; + itemDesc->animation = + itemDesc->stateMach[itemDesc->state][0]->animation; + layer = + itemDesc->stateMach[itemDesc->state][itemDesc->stateColumn]->layer; + + scen_updateAnim(layer, 0, itemDesc->animation, 0, + itemDesc->xPos, itemDesc->yPos, 0); + + itemDesc->yPos += + (gob_gobPositions[0].y * 6) + 5 - scen_toRedrawBottom; + + if (lookDir == 4) { + itemDesc->xPos += (gob_gobPositions[0].x * 12 + 14) + - (scen_toRedrawLeft + scen_toRedrawRight) / 2; + } else { + itemDesc->xPos += (gob_gobPositions[0].x * 12) + - (scen_toRedrawLeft + scen_toRedrawRight) / 2; + } + + if ((map_itemsMap[yPos][xPos] & 0xff00) != 0) { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff00) + idInPocket; + + if (yPos > 0) { + + map_itemsMap[yPos - 1][xPos] = + (map_itemsMap[yPos - 1][xPos] & 0xff00) + + idInPocket; + } + + if (lookDir == 4) { + if (xPos < 25) { + + map_itemsMap[yPos][xPos + 1] = + (map_itemsMap[yPos][xPos + 1] & 0xff00) + + idInPocket; + + if (yPos > 0) { + map_itemsMap[yPos - 1][xPos + 1] = + (map_itemsMap[yPos - 1][xPos + + 1] & 0xff00) + idInPocket; + } + } + } else { + if (xPos > 0) { + + map_itemsMap[yPos][xPos - 1] = + (map_itemsMap[yPos][xPos - 1] & 0xff00) + + idInPocket; + + if (yPos > 0) { + map_itemsMap[yPos - 1][xPos - 1] = + (map_itemsMap[yPos - 1][xPos - + 1] & 0xff00) + idInPocket; + } + } + } + } else { + + map_itemsMap[yPos][xPos] += (idInPocket << 8); + + if (yPos > 0) { + + map_itemsMap[yPos - 1][xPos] += (idInPocket << 8); + } + + if (lookDir == 4) { + if (xPos < 25) { + + map_itemsMap[yPos][xPos + 1] += + (idInPocket << 8); + + if (yPos > 0) { + map_itemsMap[yPos - 1][xPos + 1] += + (idInPocket << 8); + } + } + } else { + if (xPos > 0) { + + map_itemsMap[yPos][xPos - 1] += + (idInPocket << 8); + + if (yPos > 0) { + map_itemsMap[yPos - 1][xPos - 1] += + (idInPocket << 8); + } + } + } + + } + + if (idInPocket >= 0 && idInPocket < 20) { + map_itemPoses[idInPocket].x = gob_gobPositions[0].x; + map_itemPoses[idInPocket].y = gob_gobPositions[0].y; + map_itemPoses[idInPocket].orient = lookDir; + if (map_itemPoses[idInPocket].orient == 0) { +// map_itemPoses[idInPocket].x++; + if (map_passMap[map_itemPoses[idInPocket]. + y][map_itemPoses[idInPocket].x + 1] == 1) + map_itemPoses[idInPocket].x++; + } else { + if (map_passMap[map_itemPoses[idInPocket]. + y][map_itemPoses[idInPocket].x - 1] == 1) + map_itemPoses[idInPocket].x--; + } + } +} + +void gob_swapItems(int16 indexToPick, int16 idToPick) { + int16 layer; + Gob_Object *pickObj; + Gob_Object *placeObj; + int16 idToPlace; + int16 x; + int16 y; + + pickObj = gob_objects[indexToPick]; + placeObj = gob_objects[gob_itemIndInPocket]; + + idToPlace = gob_itemIdInPocket; + pickObj->type = 3; + gob_itemIndInPocket = indexToPick; + gob_itemIdInPocket = idToPick; + + if (gob_itemByteFlag == 0) { + for (y = 0; y < 28; y++) { + for (x = 0; x < 26; x++) { + if ((map_itemsMap[y][x] & 0xff) == idToPick) + map_itemsMap[y][x] = + (map_itemsMap[y][x] & 0xff00) + + idToPlace; + } + } + } else { + + for (y = 0; y < 28; y++) { + for (x = 0; x < 26; x++) { + if (((map_itemsMap[y][x] & 0xff00) >> 8) == + idToPick) + map_itemsMap[y][x] = + (map_itemsMap[y][x] & 0xff) + + (idToPlace << 8); + } + } + } + + if (idToPick >= 0 && idToPick < 20) { + map_itemPoses[idToPlace].x = + map_itemPoses[gob_itemIdInPocket].x; + map_itemPoses[idToPlace].y = + map_itemPoses[gob_itemIdInPocket].y; + map_itemPoses[idToPlace].orient = + map_itemPoses[gob_itemIdInPocket].orient; + + map_itemPoses[gob_itemIdInPocket].x = 0; + map_itemPoses[gob_itemIdInPocket].y = 0; + map_itemPoses[gob_itemIdInPocket].orient = 0; + } + + gob_itemIndInPocket = -1; + gob_itemIdInPocket = 0; + + placeObj->type = 0; + placeObj->nextState = -1; + placeObj->multState = -1; + placeObj->unk14 = 0; + placeObj->toRedraw = 1; + placeObj->curFrame = 0; + placeObj->order = gob_goblins[0]->order; + + placeObj->animation = + placeObj->stateMach[placeObj->state][0]->animation; + + layer = + placeObj->stateMach[placeObj->state][placeObj->stateColumn]->layer; + scen_updateAnim(layer, 0, placeObj->animation, 0, placeObj->xPos, + placeObj->yPos, 0); + + placeObj->yPos += + (gob_gobPositions[0].y * 6) + 5 - scen_toRedrawBottom; + + if (map_itemPoses[idToPlace].orient == 4) { + placeObj->xPos += (gob_gobPositions[0].x * 12 + 14) + - (scen_toRedrawLeft + scen_toRedrawRight) / 2; + } else { + placeObj->xPos += (gob_gobPositions[0].x * 12) + - (scen_toRedrawLeft + scen_toRedrawRight) / 2; + } +} + +void gob_treatItemPick(int16 itemId) { + int16 itemIndex; + Gob_Object *gobDesc; + + gobDesc = gob_goblins[gob_currentGoblin]; + + if (gobDesc->curFrame != 9) + return; + + if (gobDesc->stateMach != gobDesc->realStateMach) + return; + + gob_readyToAct = 0; + gob_goesAtTarget = 0; + + itemIndex = gob_itemToObject[itemId]; + if (itemId != 0 && itemIndex != -1 + && gob_objects[itemIndex]->pickable != 1) + itemIndex = -1; + + if (gob_itemIndInPocket != -1 && gob_itemIndInPocket == itemIndex) + itemIndex = -1; + + if (gob_itemIndInPocket != -1 && itemIndex != -1 + && gob_objects[itemIndex]->pickable == 1) { + gob_swapItems(itemIndex, itemId); + gob_itemIndInPocket = itemIndex; + gob_itemIdInPocket = itemId; + return; + } + + if (gob_itemIndInPocket != -1 && itemIndex == -1) { + gob_placeItem(gob_itemIndInPocket, gob_itemIdInPocket); + return; + } + + if (gob_itemIndInPocket == -1 && itemIndex != -1) { + gob_pickItem(itemIndex, itemId); + return; + } +} + +int16 gob_treatItem(int16 action) { + int16 state; + + state = gob_goblins[gob_currentGoblin]->state; + if ((state == 10 || state == 11) && + gob_goblins[gob_currentGoblin]->curFrame == 0) { + gob_readyToAct = 0; + } + + if (action == 3 && gob_currentGoblin == 0 && + (state == 10 || state == 11) && gob_goblins[0]->curFrame == 0) { + gob_saveGobDataToVars(gob_gobPositions[gob_currentGoblin].x, + gob_gobPositions[gob_currentGoblin].y, 0); + gob_goesAtTarget = 1; + return -1; + } + + if (gob_noPick == 0 && gob_currentGoblin == 0 && + (state == 10 || state == 11)) { + gob_treatItemPick(gob_destActionItem); + + gob_saveGobDataToVars(gob_gobPositions[gob_currentGoblin].x, + gob_gobPositions[gob_currentGoblin].y, 0); + return 0; + } + + if (gob_goesAtTarget == 0) { + gob_saveGobDataToVars(gob_gobPositions[gob_currentGoblin].x, + gob_gobPositions[gob_currentGoblin].y, 0); + return 0; + } else { + + if (gob_itemToObject[gob_destActionItem] != 100 && + gob_destActionItem != 0) { + + if (gob_itemToObject[gob_destActionItem] == -1) { + gob_actDestItemDesc = 0; + } else { + gob_actDestItemDesc = + gob_objects[gob_itemToObject + [gob_destActionItem]]; + } + } + + gob_goesAtTarget = 0; + gob_saveGobDataToVars(gob_gobPositions[gob_currentGoblin].x, + gob_gobPositions[gob_currentGoblin].y, 0); + return gob_destActionItem; + } +} + +void gob_interFunc(void) { + int16 cmd; + int16 extraData = 0; + Gob_Object *objDesc = NULL; + Gob_Object *gobDesc; + int16 xPos; + int16 yPos; + int16 x; + int16 y; + int16 item; + int16 val; + int16 layer; + int16 state; + int32 *retVarPtr; + + retVarPtr = (int32 *)(inter_variables + 0xec); + + cmd = inter_load16(); + inter_execPtr += 2; + if (cmd > 0 && cmd < 17) { + extraData = inter_load16(); + objDesc = gob_objects[extraData]; + extraData = inter_load16(); + } + + if (cmd > 90 && cmd < 107) { + extraData = inter_load16(); + objDesc = gob_goblins[extraData]; + extraData = inter_load16(); + cmd -= 90; + } + + if (cmd > 110 && cmd < 128) { + extraData = inter_load16(); + objDesc = gob_goblins[extraData]; + cmd -= 90; + } else if (cmd > 20 && cmd < 38) { + extraData = inter_load16(); + objDesc = gob_objects[extraData]; + } + + if (cmd < 40 && objDesc == 0) + return; + + debug(5, "cmd = %d", cmd); + switch (cmd) { + case 1: + objDesc->state = extraData; + + if (objDesc == gob_actDestItemDesc) + *gob_destItemStateVarPtr = extraData; + break; + + case 2: + objDesc->curFrame = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemFrameVarPtr = extraData; + break; + + case 3: + objDesc->nextState = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemNextStateVarPtr = extraData; + break; + + case 4: + objDesc->multState = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemMultStateVarPtr = extraData; + break; + + case 5: + objDesc->order = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemOrderVarPtr = extraData; + break; + + case 6: + objDesc->actionStartState = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemActStartStVarPtr = extraData; + break; + + case 7: + objDesc->curLookDir = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemLookDirVarPtr = extraData; + break; + + case 8: + objDesc->type = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemTypeVarPtr = extraData; + + if (extraData == 0) + objDesc->toRedraw = 1; + break; + + case 9: + objDesc->noTick = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemNoTickVarPtr = extraData; + break; + + case 10: + objDesc->pickable = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemPickableVarPtr = extraData; + break; + + case 12: + objDesc->xPos = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemScrXVarPtr = extraData; + break; + + case 13: + objDesc->yPos = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemScrYVarPtr = extraData; + break; + + case 14: + objDesc->doAnim = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemDoAnimVarPtr = extraData; + break; + + case 15: + objDesc->relaxTime = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemRelaxVarPtr = extraData; + break; + + case 16: + objDesc->maxTick = extraData; + if (objDesc == gob_actDestItemDesc) + *gob_destItemMaxTickVarPtr = extraData; + break; + + case 21: + *retVarPtr = objDesc->state; + break; + + case 22: + *retVarPtr = objDesc->curFrame; + break; + + case 23: + *retVarPtr = objDesc->nextState; + break; + + case 24: + *retVarPtr = objDesc->multState; + break; + + case 25: + *retVarPtr = objDesc->order; + break; + + case 26: + *retVarPtr = objDesc->actionStartState; + break; + + case 27: + *retVarPtr = objDesc->curLookDir; + break; + + case 28: + *retVarPtr = objDesc->type; + break; + + case 29: + *retVarPtr = objDesc->noTick; + break; + + case 30: + *retVarPtr = objDesc->pickable; + break; + + case 32: + *retVarPtr = gob_getObjMaxFrame(objDesc); + break; + + case 33: + *retVarPtr = objDesc->xPos; + break; + + case 34: + *retVarPtr = objDesc->yPos; + break; + + case 35: + *retVarPtr = objDesc->doAnim; + break; + + case 36: + *retVarPtr = objDesc->relaxTime; + break; + + case 37: + *retVarPtr = objDesc->maxTick; + break; + + case 40: + case 42: + xPos = inter_load16(); + yPos = inter_load16(); + item = inter_load16(); + + if (cmd == 42) { + xPos = READ_LE_UINT32(inter_variables + xPos * 4); + yPos = READ_LE_UINT32(inter_variables + xPos * 4); + item = READ_LE_UINT32(inter_variables + item * 4); + } + + for (y = 0; y < 28; y++) { + for (x = 0; x < 26; x++) { + if ((map_itemsMap[y][x] & 0xff) == item) { + map_itemsMap[y][x] &= 0xff00; + } else if (((map_itemsMap[y][x] & 0xff00) >> 8) + == item) { + map_itemsMap[y][x] &= 0xff; + } + } + } + + if (xPos < 25) { + if (yPos > 0) { + if ((map_itemsMap[yPos][xPos] & 0xff00) != 0 || + (map_itemsMap[yPos - 1][xPos] & 0xff00) != + 0 + || (map_itemsMap[yPos][xPos + + 1] & 0xff00) != 0 + || (map_itemsMap[yPos - 1][xPos + + 1] & 0xff00) != 0) { + + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff00) + + item; + + map_itemsMap[yPos - 1][xPos] = + (map_itemsMap[yPos - + 1][xPos] & 0xff00) + item; + + map_itemsMap[yPos][xPos + 1] = + (map_itemsMap[yPos][xPos + + 1] & 0xff00) + item; + + map_itemsMap[yPos - 1][xPos + 1] = + (map_itemsMap[yPos - 1][xPos + + 1] & 0xff00) + item; + } else { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff) + + (item << 8); + + map_itemsMap[yPos - 1][xPos] = + (map_itemsMap[yPos - + 1][xPos] & 0xff) + (item << 8); + + map_itemsMap[yPos][xPos + 1] = + (map_itemsMap[yPos][xPos + + 1] & 0xff) + (item << 8); + + map_itemsMap[yPos - 1][xPos + 1] = + (map_itemsMap[yPos - 1][xPos + + 1] & 0xff) + (item << 8); + } + } else { + if ((map_itemsMap[yPos][xPos] & 0xff00) != 0 || + (map_itemsMap[yPos][xPos + 1] & 0xff00) != + 0) { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff00) + + item; + + map_itemsMap[yPos][xPos + 1] = + (map_itemsMap[yPos][xPos + + 1] & 0xff00) + item; + } else { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff) + + (item << 8); + + map_itemsMap[yPos][xPos + 1] = + (map_itemsMap[yPos][xPos + + 1] & 0xff) + (item << 8); + } + } + } else { + if (yPos > 0) { + if ((map_itemsMap[yPos][xPos] & 0xff00) != 0 || + (map_itemsMap[yPos - 1][xPos] & 0xff00) != + 0) { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff00) + + item; + + map_itemsMap[yPos - 1][xPos] = + (map_itemsMap[yPos - + 1][xPos] & 0xff00) + item; + } else { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff) + + (item << 8); + + map_itemsMap[yPos - 1][xPos] = + (map_itemsMap[yPos - + 1][xPos] & 0xff) + (item << 8); + } + } else { + if ((map_itemsMap[yPos][xPos] & 0xff00) != 0) { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff00) + + item; + } else { + map_itemsMap[yPos][xPos] = + (map_itemsMap[yPos][xPos] & 0xff) + + (item << 8); + } + } + } + + if (item < 0 || item >= 20) + break; + + if (xPos > 1 && map_passMap[yPos][xPos - 2] == 1) { + map_itemPoses[item].x = xPos - 2; + map_itemPoses[item].y = yPos; + map_itemPoses[item].orient = 4; + break; + } + + if (xPos < 24 && map_passMap[yPos][xPos + 2] == 1) { + map_itemPoses[item].x = xPos + 2; + map_itemPoses[item].y = yPos; + map_itemPoses[item].orient = 0; + break; + } + + if (xPos < 25 && map_passMap[yPos][xPos + 1] == 1) { + map_itemPoses[item].x = xPos + 1; + map_itemPoses[item].y = yPos; + map_itemPoses[item].orient = 0; + break; + } + + if (xPos > 0 && map_passMap[yPos][xPos - 1] == 1) { + map_itemPoses[item].x = xPos - 1; + map_itemPoses[item].y = yPos; + map_itemPoses[item].orient = 4; + break; + } + break; + + case 41: + case 43: + xPos = inter_load16(); + yPos = inter_load16(); + + if (cmd == 43) { + xPos = READ_LE_UINT32(inter_variables + xPos * 4); + yPos = READ_LE_UINT32(inter_variables + xPos * 4); + } + + if ((map_itemsMap[yPos][xPos] & 0xff00) != 0) { + *retVarPtr = (map_itemsMap[yPos][xPos] & 0xff00) >> 8; + } else { + *retVarPtr = map_itemsMap[yPos][xPos]; + } + break; + + case 44: + xPos = inter_load16(); + yPos = inter_load16(); + val = inter_load16(); + map_passMap[yPos][xPos] = val; + break; + + case 50: + item = inter_load16(); + xPos = inter_load16(); + yPos = inter_load16(); + + gob_gobPositions[item].x = xPos * 2; + gob_gobPositions[item].y = yPos * 2; + + objDesc = gob_goblins[item]; + objDesc->nextState = 21; + + gob_nextLayer(objDesc); + + layer = objDesc->stateMach[objDesc->state][0]->layer; + + scen_updateAnim(layer, 0, objDesc->animation, 0, + objDesc->xPos, objDesc->yPos, 0); + + objDesc->yPos = + (gob_gobPositions[item].y * 6 + 6) - (scen_toRedrawBottom - + scen_animTop); + objDesc->xPos = + gob_gobPositions[item].x * 12 - (scen_toRedrawLeft - + scen_animLeft); + + objDesc->curFrame = 0; + objDesc->state = 21; + if (gob_currentGoblin == item) { + *gob_curGobScrXVarPtr = objDesc->xPos; + *gob_curGobScrYVarPtr = objDesc->yPos; + + *gob_curGobFrameVarPtr = 0; + *gob_curGobStateVarPtr = 18; + gob_pressedMapX = gob_gobPositions[item].x; + gob_pressedMapY = gob_gobPositions[item].y; + } + break; + + case 52: + item = inter_load16(); + *retVarPtr = gob_gobPositions[item].x >> 1; + break; + + case 53: + item = inter_load16(); + *retVarPtr = gob_gobPositions[item].y >> 1; + break; + + case 150: + item = inter_load16(); + xPos = inter_load16(); + yPos = inter_load16(); + + objDesc = gob_goblins[item]; + if (yPos == 0) { + objDesc->multState = xPos; + objDesc->nextState = xPos; + gob_nextLayer(objDesc); + + layer = objDesc->stateMach[objDesc->state][0]->layer; + + objDesc->xPos = + scen_animations[objDesc->animation].layers[layer]-> + posX; + objDesc->yPos = + scen_animations[objDesc->animation].layers[layer]-> + posY; + + *gob_curGobScrXVarPtr = objDesc->xPos; + *gob_curGobScrYVarPtr = objDesc->yPos; + *gob_curGobFrameVarPtr = 0; + *gob_curGobStateVarPtr = objDesc->state; + *gob_curGobNextStateVarPtr = objDesc->nextState; + *gob_curGobMultStateVarPtr = objDesc->multState; + *gob_curGobMaxFrameVarPtr = + gob_getObjMaxFrame(objDesc); + gob_noPick = 1; + break; + } + + objDesc->multState = 21; + objDesc->nextState = 21; + objDesc->state = 21; + gob_nextLayer(objDesc); + layer = objDesc->stateMach[objDesc->state][0]->layer; + + scen_updateAnim(layer, 0, objDesc->animation, 0, + objDesc->xPos, objDesc->yPos, 0); + + objDesc->yPos = + (yPos * 6 + 6) - (scen_toRedrawBottom - scen_animTop); + objDesc->xPos = + xPos * 12 - (scen_toRedrawLeft - scen_animLeft); + + gob_gobPositions[item].x = xPos; + gob_pressedMapX = xPos; + map_curGoblinX = xPos; + + gob_gobPositions[item].y = yPos; + gob_pressedMapX = yPos; + map_curGoblinX = yPos; + + *gob_curGobScrXVarPtr = objDesc->xPos; + *gob_curGobScrYVarPtr = objDesc->yPos; + *gob_curGobFrameVarPtr = 0; + *gob_curGobStateVarPtr = 21; + *gob_curGobNextStateVarPtr = 21; + *gob_curGobMultStateVarPtr = -1; + gob_noPick = 0; + break; + + case 250: + item = inter_load16(); + xPos = inter_load16(); + yPos = inter_load16(); + + gob_gobPositions[item].x = xPos; + gob_gobPositions[item].y = yPos; + + objDesc = gob_goblins[item]; + objDesc->nextState = 21; + gob_nextLayer(objDesc); + + layer = objDesc->stateMach[objDesc->state][0]->layer; + + scen_updateAnim(layer, 0, objDesc->animation, 0, + objDesc->xPos, objDesc->yPos, 0); + + objDesc->yPos = + (yPos * 6 + 6) - (scen_toRedrawBottom - scen_animTop); + objDesc->xPos = + xPos * 12 - (scen_toRedrawLeft - scen_animLeft); + + objDesc->curFrame = 0; + objDesc->state = 21; + + if (gob_currentGoblin == item) { + *gob_curGobScrXVarPtr = objDesc->xPos; + *gob_curGobScrYVarPtr = objDesc->yPos; + *gob_curGobFrameVarPtr = 0; + *gob_curGobStateVarPtr = 18; + + gob_pressedMapX = gob_gobPositions[item].x; + gob_pressedMapY = gob_gobPositions[item].y; + } + break; + + case 251: + item = inter_load16(); + state = inter_load16(); + + objDesc = gob_goblins[item]; + objDesc->nextState = state; + + gob_nextLayer(objDesc); + layer = objDesc->stateMach[objDesc->state][0]->layer; + + objDesc->xPos = + scen_animations[objDesc->animation].layers[layer]->posX; + objDesc->yPos = + scen_animations[objDesc->animation].layers[layer]->posY; + + if (item == gob_currentGoblin) { + *gob_curGobScrXVarPtr = objDesc->xPos; + *gob_curGobScrYVarPtr = objDesc->yPos; + *gob_curGobFrameVarPtr = 0; + *gob_curGobStateVarPtr = objDesc->state; + *gob_curGobMultStateVarPtr = objDesc->multState; + } + break; + + case 252: + item = inter_load16(); + state = inter_load16(); + objDesc = gob_objects[item]; + + objDesc->nextState = state; + + gob_nextLayer(objDesc); + layer = objDesc->stateMach[objDesc->state][0]->layer; + objDesc->xPos = + scen_animations[objDesc->animation].layers[layer]->posX; + objDesc->yPos = + scen_animations[objDesc->animation].layers[layer]->posY; + + objDesc->toRedraw = 1; + objDesc->type = 0; + if (objDesc == gob_actDestItemDesc) { + *gob_destItemScrXVarPtr = objDesc->xPos; + *gob_destItemScrYVarPtr = objDesc->yPos; + + *gob_destItemStateVarPtr = objDesc->state; + *gob_destItemNextStateVarPtr = -1; + *gob_destItemMultStateVarPtr = -1; + *gob_destItemFrameVarPtr = 0; + } + break; + + case 152: + item = inter_load16(); + val = inter_load16(); + objDesc = gob_objects[item]; + objDesc->unk14 = val; + break; + + case 200: + gob_itemIdInPocket = inter_load16(); + break; + + case 201: + gob_itemIndInPocket = inter_load16(); + break; + + case 202: + *retVarPtr = gob_itemIdInPocket; + break; + + case 203: + *retVarPtr = gob_itemIndInPocket; + break; + + case 204: + item = inter_load16(); + xPos = inter_load16(); + yPos = inter_load16(); + val = inter_load16(); + + map_itemPoses[item].x = xPos; + map_itemPoses[item].y = yPos; + map_itemPoses[item].orient = val; + break; + + case 500: + extraData = inter_load16(); + objDesc = gob_objects[extraData]; + + objDesc->relaxTime--; + if (objDesc->relaxTime < 0 && + gob_getObjMaxFrame(objDesc) == objDesc->curFrame) { + objDesc->relaxTime = util_getRandom(100) + 50; + objDesc->curFrame = 0; + objDesc->toRedraw = 1; + } + break; + + case 502: + item = inter_load16(); + *retVarPtr = gob_gobPositions[item].x; + break; + + case 503: + item = inter_load16(); + *retVarPtr = gob_gobPositions[item].y; + break; + + case 600: + gob_pathExistence = 0; + break; + + case 601: + extraData = inter_load16(); + gob_goblins[extraData]->visible = 1; + break; + + case 602: + extraData = inter_load16(); + gob_goblins[extraData]->visible = 0; + break; + + case 603: + extraData = inter_load16(); + item = inter_load16(); + + objDesc = gob_objects[extraData]; + if (gob_objIntersected(objDesc, gob_goblins[item]) != 0) + *retVarPtr = 1; + else + *retVarPtr = 0; + break; + + case 604: + extraData = inter_load16(); + item = inter_load16(); + + objDesc = gob_goblins[extraData]; + if (gob_objIntersected(objDesc, gob_goblins[item]) != 0) + *retVarPtr = 1; + else + *retVarPtr = 0; + break; + + case 605: + item = inter_load16(); + xPos = inter_load16(); + yPos = inter_load16(); + val = inter_load16(); + + map_itemPoses[item].x = xPos; + map_itemPoses[item].y = yPos; + map_itemPoses[item].orient = val; + break; + + case 1000: + extraData = inter_load16(); + if (game_extHandle >= 0) + data_closeData(game_extHandle); + + gob_loadObjects(inter_variables + extraData * 4); + game_extHandle = data_openData(game_curExtFile); + break; + + case 1001: + gob_freeAllObjects(); + break; + + case 1002: + gob_animateObjects(); + break; + + case 1003: + gob_drawObjects(); + break; + + case 1004: + map_loadMapsInitGobs(); + break; + + case 1005: + extraData = inter_load16(); + xPos = inter_load16(); + + if (READ_LE_UINT16(inter_variables + xPos * 4) == 0) { + item = + gob_doMove(gob_goblins[gob_currentGoblin], 1, + READ_LE_UINT16(inter_variables + extraData * 4)); + } else { + item = + gob_doMove(gob_goblins[gob_currentGoblin], 1, 3); + } + + if (item != 0) + gob_switchGoblin(item); + break; + + case 1006: + gob_switchGoblin(0); + break; + + case 1008: + gob_loadGobDataFromVars(); + break; + + case 1009: + extraData = inter_load16(); + cmd = inter_load16(); + xPos = inter_load16(); + + if (READ_LE_UINT16(inter_variables + xPos * 4) == 0) { + WRITE_LE_UINT32(inter_variables + cmd * 4, + gob_treatItem(READ_LE_UINT16(inter_variables + extraData * 4))); + break; + } + + WRITE_LE_UINT32(inter_variables + cmd * 4, gob_treatItem(3)); + break; + + case 1010: + gob_doMove(gob_goblins[gob_currentGoblin], 0, 0); + break; + + case 1011: + extraData = inter_load16(); + if (READ_LE_UINT32(inter_variables + extraData * 4) != 0) + gob_goesAtTarget = 1; + else + gob_goesAtTarget = 0; + break; + + case 1015: + extraData = inter_load16(); + extraData = READ_LE_UINT32(inter_variables + extraData * 4); + gob_objects[10]->xPos = extraData; + + extraData = inter_load16(); + extraData = READ_LE_UINT32(inter_variables + extraData * 4); + gob_objects[10]->yPos = extraData; + break; + + case 2005: + gobDesc = gob_goblins[0]; + if (gob_currentGoblin != 0) { + gob_goblins[gob_currentGoblin]->doAnim = 1; + gob_goblins[gob_currentGoblin]->nextState = 21; + + gob_nextLayer(gob_goblins[gob_currentGoblin]); + gob_currentGoblin = 0; + + gobDesc->doAnim = 0; + gobDesc->type = 0; + gobDesc->toRedraw = 1; + + gob_pressedMapX = gob_gobPositions[0].x; + map_destX = gob_gobPositions[0].x; + gob_gobDestX = gob_gobPositions[0].x; + + gob_pressedMapY = gob_gobPositions[0].y; + map_destY = gob_gobPositions[0].y; + gob_gobDestY = gob_gobPositions[0].y; + + *gob_curGobVarPtr = 0; + gob_pathExistence = 0; + gob_readyToAct = 0; + } + + if (gobDesc->state != 10 && gob_itemIndInPocket != -1 && + gob_getObjMaxFrame(gobDesc) == gobDesc->curFrame) { + + gobDesc->stateMach = gobDesc->realStateMach; + xPos = gob_gobPositions[0].x; + yPos = gob_gobPositions[0].y; + + gobDesc->nextState = 10; + layer = gob_nextLayer(gobDesc); + + scen_updateAnim(layer, 0, gobDesc->animation, 0, + gobDesc->xPos, gobDesc->yPos, 0); + + gobDesc->yPos = + (yPos * 6 + 6) - (scen_toRedrawBottom - + scen_animTop); + gobDesc->xPos = + xPos * 12 - (scen_toRedrawLeft - scen_animLeft); + } + + if (gobDesc->state != 10) + break; + + if (gob_itemIndInPocket == -1) + break; + + if (gobDesc->curFrame != 10) + break; + + objDesc = gob_objects[gob_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; + + scen_updateAnim(layer, 0, objDesc->animation, 0, + objDesc->xPos, objDesc->yPos, 0); + + objDesc->yPos += + (gob_gobPositions[0].y * 6 + 5) - scen_toRedrawBottom; + + if (gobDesc->curLookDir == 4) { + objDesc->xPos += gob_gobPositions[0].x * 12 + 14 + - (scen_toRedrawLeft + scen_toRedrawRight) / 2; + } else { + objDesc->xPos += gob_gobPositions[0].x * 12 + - (scen_toRedrawLeft + scen_toRedrawRight) / 2; + } + + gob_itemIndInPocket = -1; + gob_itemIdInPocket = -1; + util_beep(50); + break; + + default: + warning("gob_interFunc: Unknown command %d!", cmd); + inter_execPtr -= 2; + cmd = inter_load16(); + inter_execPtr += cmd * 2; + break; + } + return; +} + +} // End of namespace Gob diff --git a/gob/goblin.h b/gob/goblin.h new file mode 100644 index 0000000000..e0948bcf93 --- /dev/null +++ b/gob/goblin.h @@ -0,0 +1,192 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __GOBLIN_H +#define __GOBLIN_H + +#include "gob/util.h" +#include "gob/sound.h" + +namespace Gob { + +#define TYPE_USUAL 0 +#define TYPE_AMORPHOUS 1 +#define TYPE_MOBILE 3 + +#pragma START_PACK_STRUCTS +typedef 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 unk2; // +Eh +} GCC_PACK Gob_State; + +typedef struct Gob_State *Gob_PState; + +#define szGob_StateLine 24 +typedef Gob_PState Gob_StateLine[6]; + +typedef 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 Gob_Object; + +typedef struct Gob_Pos { + char x; + char y; +} GCC_PACK Gob_Pos; +#pragma END_PACK_STRUCTS + +extern Util_List *gob_objList; +extern Gob_Object *gob_goblins[4]; +extern int16 gob_currentGoblin; +extern Snd_SoundDesc *gob_soundData[16]; +extern int16 gob_gobStateLayer; +extern char gob_goesAtTarget; +extern char gob_readyToAct; +extern int16 gob_gobAction; // 0 - move, 3 - do action, 4 - pick + // goblins 0 - picker, 1 - fighter, 2 - mage +extern Gob_Pos gob_gobPositions[3]; +extern int16 gob_gobDestX; +extern int16 gob_gobDestY; +extern int16 gob_pressedMapX; +extern int16 gob_pressedMapY; +extern char gob_pathExistence; + +// Pointers to interpreter variables +extern int32 *gob_some0ValPtr; + +extern int32 *gob_gobRetVarPtr; +extern int32 *gob_curGobVarPtr; +extern int32 *gob_curGobXPosVarPtr; +extern int32 *gob_curGobYPosVarPtr; +extern int32 *gob_itemInPocketVarPtr; + +extern int32 *gob_curGobStateVarPtr; +extern int32 *gob_curGobFrameVarPtr; +extern int32 *gob_curGobMultStateVarPtr; +extern int32 *gob_curGobNextStateVarPtr; +extern int32 *gob_curGobScrXVarPtr; +extern int32 *gob_curGobScrYVarPtr; +extern int32 *gob_curGobLeftVarPtr; +extern int32 *gob_curGobTopVarPtr; +extern int32 *gob_curGobRightVarPtr; +extern int32 *gob_curGobBottomVarPtr; +extern int32 *gob_curGobDoAnimVarPtr; +extern int32 *gob_curGobOrderVarPtr; +extern int32 *gob_curGobNoTickVarPtr; +extern int32 *gob_curGobTypeVarPtr; +extern int32 *gob_curGobMaxTickVarPtr; +extern int32 *gob_curGobTickVarPtr; +extern int32 *gob_curGobActStartStateVarPtr; +extern int32 *gob_curGobLookDirVarPtr; +extern int32 *gob_curGobPickableVarPtr; +extern int32 *gob_curGobRelaxVarPtr; +extern int32 *gob_curGobMaxFrameVarPtr; + +extern int32 *gob_destItemStateVarPtr; +extern int32 *gob_destItemFrameVarPtr; +extern int32 *gob_destItemMultStateVarPtr; +extern int32 *gob_destItemNextStateVarPtr; +extern int32 *gob_destItemScrXVarPtr; +extern int32 *gob_destItemScrYVarPtr; +extern int32 *gob_destItemLeftVarPtr; +extern int32 *gob_destItemTopVarPtr; +extern int32 *gob_destItemRightVarPtr; +extern int32 *gob_destItemBottomVarPtr; +extern int32 *gob_destItemDoAnimVarPtr; +extern int32 *gob_destItemOrderVarPtr; +extern int32 *gob_destItemNoTickVarPtr; +extern int32 *gob_destItemTypeVarPtr; +extern int32 *gob_destItemMaxTickVarPtr; +extern int32 *gob_destItemTickVarPtr; +extern int32 *gob_destItemActStartStVarPtr; +extern int32 *gob_destItemLookDirVarPtr; +extern int32 *gob_destItemPickableVarPtr; +extern int32 *gob_destItemRelaxVarPtr; +extern int32 *gob_destItemMaxFrameVarPtr; + +extern int16 gob_destItemType; +extern int16 gob_destItemState; +extern int16 gob_itemToObject[20]; +extern Gob_Object *gob_objects[20]; +extern int16 gob_objCount; +extern int16 gob_gobsCount; +extern int16 gob_itemIndInPocket; +extern int16 gob_itemIdInPocket; +extern char gob_itemByteFlag; +extern int16 gob_destItemId; +extern int16 gob_destActionItem; +extern Gob_Object *gob_actDestItemDesc; +extern int16 gob_forceNextState[10]; +extern char gob_boreCounter; +extern int16 gob_positionedGob; +extern char gob_noPick; + +// Functions +char gob_rotateState(int16 from, int16 to); +void gob_playSound(Snd_SoundDesc * snd, int16 repCount, int16 freq); +void gob_drawObjects(void); +void gob_animateObjects(void); +void gob_placeObject(Gob_Object * objDesc, char animated); +int16 gob_getObjMaxFrame(Gob_Object * obj); +int16 gob_objIntersected(Gob_Object * obj1, Gob_Object * obj2); +void gob_setMultStates(Gob_Object * gobDesc); +int16 gob_nextLayer(Gob_Object * gobDesc); +void gob_showBoredom(int16 gobIndex); +void gob_switchGoblin(int16 index); +void gob_freeObjects(void); +void gob_zeroObjects(void); +void gob_freeAllObjects(void); +void gob_loadObjects(char *source); +void gob_initVarPointers(void); +void gob_saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal); +void gob_loadGobDataFromVars(void); +void gob_pickItem(int16 indexToPocket, int16 idToPocket); +void gob_placeItem(int16 indexInPocket, int16 idInPocket); +void gob_swapItems(int16 indexToPick, int16 idToPick); +void gob_treatItemPick(int16 itemId); +int16 gob_treatItem(int16 action); +void gob_interFunc(void); + +} // End of namespace Gob + +#endif /* __GOBLIN_H */ diff --git a/gob/init.cpp b/gob/init.cpp new file mode 100644 index 0000000000..0cf6ee5c11 --- /dev/null +++ b/gob/init.cpp @@ -0,0 +1,293 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/dataio.h" +#include "gob/resource.h" +#include "gob/global.h" +#include "gob/init.h" +#include "gob/video.h" +#include "gob/debug.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" + +namespace Gob { + +void game_start(void); + +extern int16 debugFlag; +extern int16 inVM; +extern int16 colorCount; + +PalDesc *init_palDesc; + +static const char *init_fontNames[] = + { "jeulet1.let", "jeulet2.let", "jeucar1.let", "jeumath.let" }; + +void init_findBestCfg(void) { + videoMode = VIDMODE_VGA; + useMouse = mousePresent; + if (presentSound & BLASTER_FLAG) + soundFlags = BLASTER_FLAG | SPEAKER_FLAG | MIDI_FLAG; + else if (presentSound & PROAUDIO_FLAG) + soundFlags = PROAUDIO_FLAG | SPEAKER_FLAG | MIDI_FLAG; + else if (presentSound & ADLIB_FLAG) + soundFlags = ADLIB_FLAG | SPEAKER_FLAG | MIDI_FLAG; + else if (presentSound & INTERSOUND_FLAG) + soundFlags = INTERSOUND_FLAG | SPEAKER_FLAG; + else if (presentSound & SPEAKER_FLAG) + soundFlags = SPEAKER_FLAG; + else + soundFlags = 0; +} + +void init_soundVideo(int32 smallHeap, int16 flag) { + if (videoMode != 0x13 && videoMode != 0) + error("init_soundVideo: Video mode 0x%x is not supported!", + videoMode); + + pFileHandler = 0; + srand(0); + + //if ((flag & 4) == 0) + // vid_findVideo(); + + mousePresent = 1; + + inVM = 0; + + presentSound = 0; // FIXME: sound is not supported yet + + sprAllocated = 0; + filesCount = 0; + timer_enableTimer(); + + // snd_setResetTimerFlag(debugFlag); // TODO + + if (videoMode == 0x13) + colorCount = 256; + fastComputer = 1; + + pPaletteDesc = &paletteStruct; + pPaletteDesc->vgaPal = vgaPalette; + pPaletteDesc->unused1 = unusedPalette1; + pPaletteDesc->unused2 = unusedPalette2; + pPrimarySurfDesc = &primarySurfDesc; + + if (videoMode != 0) + vid_initSurfDesc(videoMode, 320, 200, PRIMARY_SURFACE); + + if (soundFlags & MIDI_FLAG) { + soundFlags &= presentSound; + if (presentSound & ADLIB_FLAG) + soundFlags |= MIDI_FLAG; + } else { + soundFlags &= presentSound; + } +} + +void init_cleanup(void) { + if (debugFlag == 0) + timer_disableTimer(); + + vid_freeDriver(); + if (curPrimaryDesc != 0) { + vid_freeSurfDesc(curPrimaryDesc); + vid_freeSurfDesc(allocatedPrimary); + allocatedPrimary = 0; + curPrimaryDesc = 0; + } + pPrimarySurfDesc = 0; + if (snd_cleanupFunc != 0 && snd_playingSound != 0) { + (*snd_cleanupFunc) (0); + snd_cleanupFunc = 0; + } + snd_speakerOff(); + + data_closeDataFile(); + if (filesCount != 0) + error("init_cleanup: Error! Opened files lef: %d", filesCount); + + if (sprAllocated != 0) + error("init_cleanup: Error! Allocated sprites left: %d", + sprAllocated); + + if (allocatedBlocks[0] != 0) + error("init_cleanup: Error! Allocated blocks in heap 0 left: %d", + allocatedBlocks[0]); + + if (allocatedBlocks[1] != 0) + error("init_cleanup: Error! Allocated blocks in heap 1 left: %d", + allocatedBlocks[1]); + + snd_stopSound(0); + keyboard_release(); + //free(heapHeads); + g_system->quit(); +} + +/*static void init_hardErrHandler(void) { + hardretn(-1); +}*/ + +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*/ + + language = 5; + disableVideoCfg = 0x11; + disableMouseCfg = 0x15; + //reqRAMParag = 570; + //requiredSpace = 10; + strcpy(batFileName, "go"); + init_soundVideo(1000, 1); + language = 2; + + handle2 = data_openData("intro.stk"); + if (handle2 >= 0) { + data_closeData(handle2); + data_openDataFile("intro.stk"); + } + + util_initInput(); + + vid_setHandlers(); + vid_initPrimary(videoMode); +// harderr(&init_hardErrHandler); + mouseXShift = 1; + mouseYShift = 1; + + game_totTextData = 0; + game_totFileData = 0; + game_totResourceTable = 0; + inter_variables = 0; + init_palDesc = (PalDesc *)malloc(12); + + if (videoMode != 0x13) + error("init_initGame: Only 0x13 video mode is supported!"); + + init_palDesc->vgaPal = draw_vgaPalette; + init_palDesc->unused1 = draw_unusedPalette1; + init_palDesc->unused2 = draw_unusedPalette2; + vid_setFullPalette(init_palDesc); + + for (i = 0; i < 4; i++) + draw_fonts[i] = 0; + + handle = data_openData("intro.inf"); + + if (handle < 0) { + for (i = 0; i < 4; i++) { + handle2 = data_openData(init_fontNames[i]); + if (handle2 >= 0) { + data_closeData(handle2); + draw_fonts[i] = + util_loadFont(init_fontNames[i]); + } + } + } else { + data_closeData(handle); + + infPtr = data_getData("intro.inf"); + infBuf = infPtr; + + infEnd = infBuf + data_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 = data_openData(buffer); + if (handle2 >= 0) { + data_closeData(handle2); + draw_fonts[i] = util_loadFont(buffer); + } + + if (infPtr == infEnd) + break; + + infPtr++; + if (infPtr == infEnd) + break; + } + + free(infBuf); + } + + if (totName != 0) { + strcpy(buffer, totName); + strcat(buffer, ".tot"); + } else { + strcpy(buffer, "intro.tot"); + } + + handle = data_openData(buffer); + + if (handle >= 0) { + // Get variables count + data_seekData(handle, 0x2c, SEEK_SET); + data_readData(handle, (char *)&varsCount, 4); + varsCount = FROM_LE_32(varsCount); + data_closeData(handle); + + inter_variables = (char *)malloc(varsCount * 4); + memset(inter_variables, 0, varsCount * 4); + + strcpy(game_curTotFile, buffer); + game_start(); + + if (inter_variables != 0) + free(inter_variables); + + if (game_totFileData != 0) + free(game_totFileData); + + if (game_totTextData != 0) + free((char *)game_totTextData); + + if (game_totResourceTable != 0) + free((char *)game_totResourceTable); + } + + for (i = 0; i < 4; i++) { + if (draw_fonts[i] != 0) + util_freeFont(draw_fonts[i]); + } + + free((char *)init_palDesc); + data_closeDataFile(); + vid_initPrimary(-1); + init_cleanup(); +} + +} // End of namespace Gob diff --git a/gob/init.h b/gob/init.h new file mode 100644 index 0000000000..da5b43a3ea --- /dev/null +++ b/gob/init.h @@ -0,0 +1,20 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __INIT_H +#define __INIT_H + +namespace Gob { + +void init_findBestCfg(void); +void init_soundVideo(int32 smallHeapSize, int16 flag); + +void init_initGame(char *totFile); + +} // End of namespace Gob + +#endif diff --git a/gob/inter.cpp b/gob/inter.cpp new file mode 100644 index 0000000000..7ae38aec7b --- /dev/null +++ b/gob/inter.cpp @@ -0,0 +1,1496 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/inter.h" +#include "gob/util.h" +#include "gob/debug.h" +#include "gob/parse.h" +#include "gob/game.h" +#include "gob/draw.h" +#include "gob/mult.h" +#include "gob/goblin.h" + +namespace Gob { + +int16 inter_animPalLowIndex; +int16 inter_animPalHighIndex; +int16 inter_animPalDir; +uint32 inter_soundEndTimeKey; +int16 inter_soundStopVal; +char inter_terminate = 0; +char inter_breakFlag = 0; +int16 *inter_breakFromLevel; +int16 *inter_nestLevel; + +int16 inter_load16(void) { + int16 tmp = READ_LE_UINT16(inter_execPtr); + inter_execPtr += 2; + return tmp; +} + +void inter_setMousePos(void) { + inter_mouseX = parse_parseValExpr(); + inter_mouseY = parse_parseValExpr(); + if (useMouse != 0) + util_setMousePos(inter_mouseX, inter_mouseY); +} + +char inter_evalExpr(int16 *pRes) { + byte token; + +// + parse_printExpr(99); + + parse_parseExpr(99, &token); + if (pRes == 0) + return token; + + switch (token) { + case 20: + *pRes = inter_resVal; + break; + + case 22: + case 23: + *pRes = 0; + break; + + case 24: + *pRes = 1; + break; + } + return token; +} + +char inter_evalBoolResult() { + byte token; + + parse_printExpr(99); + + parse_parseExpr(99, &token); + if (token == 24 || (token == 20 && inter_resVal != 0)) + return 1; + else + return 0; +} + +void inter_evaluateStore(void) { + char *savedPos; + int16 token; + int16 result; + int16 varOff; + + savedPos = inter_execPtr; + varOff = parse_parseVarIndex(); + token = inter_evalExpr(&result); + switch (savedPos[0]) { + case 23: + case 26: + WRITE_LE_UINT32(inter_variables + varOff, inter_resVal); + break; + + case 25: + case 28: + if (token == 20) + *(inter_variables + varOff) = result; + else + strcpy(inter_variables + varOff, inter_resStr); + break; + + } + return; +} + +void inter_capturePush(void) { + int16 left; + int16 top; + int16 width; + int16 height; + + left = parse_parseValExpr(); + top = parse_parseValExpr(); + width = parse_parseValExpr(); + height = parse_parseValExpr(); + game_capturePush(left, top, width, height); + (*scen_pCaptureCounter)++; +} + +void inter_capturePop(void) { + if (*scen_pCaptureCounter != 0) { + (*scen_pCaptureCounter)--; + game_capturePop(1); + } +} + +void inter_printText(void) { + char buf[60]; + int16 i; + + debug(0, "inter_printText"); + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + + draw_backColor = parse_parseValExpr(); + draw_frontColor = parse_parseValExpr(); + draw_fontIndex = parse_parseValExpr(); + draw_destSurface = 21; + draw_textToPrint = buf; + draw_transparency = 0; + + if (draw_backColor >= 16) { + draw_backColor = 0; + draw_transparency = 1; + } + + do { + for (i = 0; *inter_execPtr != '.' && (byte)*inter_execPtr != 200; + i++, inter_execPtr++) { + buf[i] = *inter_execPtr; + } + + if ((byte)*inter_execPtr != 200) { + inter_execPtr++; + switch (*inter_execPtr) { + case 23: + case 26: + sprintf(buf + i, "%ld", READ_LE_UINT32(inter_variables + parse_parseVarIndex())); + break; + + case 25: + case 28: + sprintf(buf + i, "%s", inter_variables + parse_parseVarIndex()); + break; + } + inter_execPtr++; + } else { + buf[i] = 0; + } + draw_spriteOperation(DRAW_PRINTTEXT); + } while ((byte)*inter_execPtr != 200); + inter_execPtr++; +} + +void inter_animPalette(void) { + int16 i; + Color col; + + if (inter_animPalDir == 0) + return; + + vid_waitRetrace(videoMode); + + if (inter_animPalDir == -1) { + col = draw_vgaSmallPalette[inter_animPalLowIndex]; + + for (i = inter_animPalLowIndex; i < inter_animPalHighIndex; i++) + draw_vgaSmallPalette[i] = draw_vgaSmallPalette[i + 1]; + + draw_vgaSmallPalette[inter_animPalHighIndex] = col; + } else { + col = draw_vgaSmallPalette[inter_animPalHighIndex]; + for (i = inter_animPalHighIndex; i > inter_animPalLowIndex; i--) + draw_vgaSmallPalette[i] = draw_vgaSmallPalette[i - 1]; + + draw_vgaSmallPalette[inter_animPalLowIndex] = col; + } + + pPaletteDesc->vgaPal = draw_vgaSmallPalette; + vid_setFullPalette(pPaletteDesc); +} + +void inter_animPalInit(void) { + inter_animPalDir = inter_load16(); + inter_animPalLowIndex = parse_parseValExpr(); + inter_animPalHighIndex = parse_parseValExpr(); +} + +void inter_loadMult(void) { + int16 resId; + + resId = inter_load16(); + mult_loadMult(resId); +} + +void inter_playMult(void) { + int16 checkEscape; + + checkEscape = inter_load16(); + mult_playMult(READ_LE_UINT32(inter_variables + 0xe4), -1, checkEscape, 0); +} + +void inter_freeMult(void) { + inter_load16(); // unused + mult_freeMultKeys(); +} + +void inter_initCursor(void) { + int16 width; + int16 height; + int16 count; + int16 i; + + draw_cursorXDeltaVar = parse_parseVarIndex(); + draw_cursorYDeltaVar = parse_parseVarIndex(); + + width = inter_load16(); + if (width < 16) + width = 16; + + height = inter_load16(); + if (height < 16) + height = 16; + + count = inter_load16(); + if (count < 2) + count = 2; + + if (width != draw_cursorWidth || height != draw_cursorHeight || + draw_cursorSprites->width != width * count) { + + vid_freeSurfDesc(draw_cursorSprites); + vid_freeSurfDesc(draw_cursorBack); + + draw_cursorWidth = width; + draw_cursorHeight = height; + + if (count < 0x80) + draw_transparentCursor = 1; + else + draw_transparentCursor = 0; + + if (count > 0x80) + count -= 0x80; + + draw_cursorSprites = + vid_initSurfDesc(videoMode, draw_cursorWidth * count, + draw_cursorHeight, 2); + draw_spritesArray[23] = draw_cursorSprites; + + draw_cursorBack = + vid_initSurfDesc(videoMode, draw_cursorWidth, + draw_cursorHeight, 0); + for (i = 0; i < 40; i++) { + draw_cursorAnimLow[i] = -1; + draw_cursorAnimDelays[i] = 0; + draw_cursorAnimHigh[i] = 0; + } + draw_cursorAnimLow[1] = 0; + } +} + +void inter_initCursorAnim(void) { + int16 ind; + + ind = parse_parseValExpr(); + draw_cursorAnimLow[ind] = inter_load16(); + draw_cursorAnimHigh[ind] = inter_load16(); + draw_cursorAnimDelays[ind] = inter_load16(); +} + +void inter_clearCursorAnim(void) { + int16 ind; + + ind = parse_parseValExpr(); + draw_cursorAnimLow[ind] = -1; + draw_cursorAnimHigh[ind] = 0; + draw_cursorAnimDelays[ind] = 0; +} + +void inter_drawOperations(void) { + char cmd; + int16 i; + + cmd = *inter_execPtr++; + + switch (cmd) { + case 0: + inter_loadMult(); + break; + + case 1: + inter_playMult(); + break; + + case 2: + inter_freeMult(); + break; + + case 7: + inter_initCursor(); + break; + + case 8: + inter_initCursorAnim(); + break; + + case 9: + inter_clearCursorAnim(); + break; + + case 10: + draw_renderFlags = parse_parseValExpr(); + break; + + case 11: + //word_23EC_DE = parse_parseValExpr(); + break; + + case 16: + scen_loadAnim(0); + break; + + case 17: + scen_freeAnim(-1); + break; + + case 18: + scen_interUpdateAnim(); + break; + + case 20: + mult_interInitMult(); + break; + + case 21: + mult_freeMult(); + break; + + case 22: + mult_animate(); + break; + + case 23: + mult_interLoadMult(); + break; + + case 24: + scen_interStoreParams(); + break; + + case 25: + mult_interGetObjAnimSize(); + break; + + case 26: + scen_loadStatic(0); + break; + + case 27: + scen_freeStatic(-1); + break; + + case 28: + scen_interRenderStatic(); + break; + + case 29: + scen_interLoadCurLayer(); + break; + + case 48: + i = inter_load16(); + draw_fontToSprite[i].sprite = inter_load16(); + draw_fontToSprite[i].base = inter_load16(); + draw_fontToSprite[i].width = inter_load16(); + draw_fontToSprite[i].height = inter_load16(); + break; + + case 49: + i = inter_load16(); + draw_fontToSprite[i].sprite = -1; + draw_fontToSprite[i].base = -1; + draw_fontToSprite[i].width = -1; + draw_fontToSprite[i].height = -1; + break; + } +} + +void inter_getFreeMem(void) { + int16 freeVar; + int16 maxFreeVar; + + freeVar = parse_parseVarIndex(); + maxFreeVar = parse_parseVarIndex(); + + // HACK + WRITE_LE_UINT32(inter_variables + freeVar, 1000000); + WRITE_LE_UINT32(inter_variables + maxFreeVar, 1000000); +} + +void inter_manageDataFile(void) { + inter_evalExpr(0); + + if (inter_resStr[0] != 0) + data_openDataFile(inter_resStr); + else + data_closeDataFile(); +} + +void inter_writeData(void) { + int16 offset; + int16 handle; + int16 size; + int16 dataVar; + int16 retSize; + + debug(0, "inter_writeData"); + inter_evalExpr(0); + dataVar = parse_parseVarIndex(); + size = parse_parseValExpr(); + offset = parse_parseValExpr(); + + WRITE_LE_UINT32(inter_variables + 4, 1); + handle = data_openData(inter_resStr, File::kFileWriteMode); + + if (handle < 0) + return; + + if (offset < 0) { + data_seekData(handle, -offset - 1, 2); + } else { + data_seekData(handle, offset, 0); + } + + retSize = file_getHandle(handle)->write(inter_variables + dataVar, size); + + if (retSize == size) + WRITE_LE_UINT32(inter_variables + 4, 0); + + data_closeData(handle); +} + +void inter_checkData(void) { + int16 handle; + int16 varOff; + + debug(0, "data_cheackData"); + inter_evalExpr(0); + varOff = parse_parseVarIndex(); + handle = data_openData(inter_resStr); + + WRITE_LE_UINT32(inter_variables + varOff, handle); + if (handle >= 0) + data_closeData(handle); +} + +void inter_readData(void) { + int16 retSize; + int16 size; + int16 dataVar; + int16 offset; + int16 handle; + + debug(0, "inter_readData"); + inter_evalExpr(0); + dataVar = parse_parseVarIndex(); + size = parse_parseValExpr(); + offset = parse_parseValExpr(); + + if (game_extHandle >= 0) + data_closeData(game_extHandle); + + WRITE_LE_UINT32(inter_variables + 4, 1); + handle = data_openData(inter_resStr); + if (handle >= 0) { + draw_animateCursor(4); + if (offset < 0) + data_seekData(handle, -offset - 1, 2); + else + data_seekData(handle, offset, 0); + + retSize = data_readData(handle, inter_variables + dataVar, size); + data_closeData(handle); + + if (retSize == size) + WRITE_LE_UINT32(inter_variables + 4, 0); + } + + if (game_extHandle >= 0) + game_extHandle = data_openData(game_curExtFile); +} + +void inter_loadFont(void) { + int16 index; + + debug(0, "inter_loadFont"); + inter_evalExpr(0); + index = inter_load16(); + + if (draw_fonts[index] != 0) + util_freeFont(draw_fonts[index]); + + draw_animateCursor(4); + if (game_extHandle >= 0) + data_closeData(game_extHandle); + + draw_fonts[index] = util_loadFont(inter_resStr); + + if (game_extHandle >= 0) + game_extHandle = data_openData(game_curExtFile); +} + +void inter_freeFont(void) { + int16 index; + + index = inter_load16(); + if (draw_fonts[index] != 0) + util_freeFont(draw_fonts[index]); + + draw_fonts[index] = 0; +} + +void inter_prepareStr(void) { + int16 var; + + var = parse_parseVarIndex(); + util_prepareStr(inter_variables + var); +} + +void inter_insertStr(void) { + int16 pos; + int16 strVar; + + strVar = parse_parseVarIndex(); + inter_evalExpr(0); + pos = parse_parseValExpr(); + util_insertStr(inter_resStr, inter_variables + strVar, pos); +} + +void inter_cutStr(void) { + int16 var; + int16 pos; + int16 size; + + var = parse_parseVarIndex(); + pos = parse_parseValExpr(); + size = parse_parseValExpr(); + util_cutFromStr(inter_variables + var, pos, size); +} + +void inter_strstr(void) { + int16 strVar; + int16 resVar; + int16 pos; + + strVar = parse_parseVarIndex(); + inter_evalExpr(0); + resVar = parse_parseVarIndex(); + + pos = util_strstr(inter_resStr, inter_variables + strVar); + WRITE_LE_UINT32(inter_variables + resVar, pos - 1); +} + +void inter_setFrameRate(void) { + util_setFrameRate(parse_parseValExpr()); +} + +void inter_strlen(void) { + int16 len; + int16 var; + + var = parse_parseVarIndex(); + len = strlen(inter_variables + var); + var = parse_parseVarIndex(); + + WRITE_LE_UINT32(inter_variables + var, len); +} + +void inter_strToLong(void) { + char str[20]; + int16 strVar; + int16 destVar; + int32 res; + + strVar = parse_parseVarIndex(); + strcpy(str, inter_variables + strVar); + res = atol(str); + + destVar = parse_parseVarIndex(); + WRITE_LE_UINT32(inter_variables + destVar, res); +} + +void inter_invalidate(void) { + warning("inter_invalidate: 'bugged' function!"); + draw_destSurface = inter_load16(); + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + draw_spriteRight = parse_parseValExpr(); + draw_frontColor = parse_parseValExpr(); + draw_spriteOperation(DRAW_INVALIDATE); +} + +void inter_loadSpriteContent(void) { + draw_spriteLeft = inter_load16(); + draw_destSurface = inter_load16(); + draw_transparency = inter_load16(); + draw_destSpriteX = 0; + draw_destSpriteY = 0; + draw_spriteOperation(DRAW_LOADSPRITE); +} + +void inter_copySprite(void) { + draw_sourceSurface = inter_load16(); + draw_destSurface = inter_load16(); + + draw_spriteLeft = parse_parseValExpr(); + draw_spriteTop = parse_parseValExpr(); + draw_spriteRight = parse_parseValExpr(); + draw_spriteBottom = parse_parseValExpr(); + + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + + draw_transparency = inter_load16(); + draw_spriteOperation(DRAW_BLITSURF); +} + +void inter_putPixel(void) { + draw_destSurface = inter_load16(); + + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + draw_frontColor = parse_parseValExpr(); + draw_spriteOperation(DRAW_PUTPIXEL); +} + +void inter_fillRect(void) { + draw_destSurface = inter_load16(); + + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + draw_spriteRight = parse_parseValExpr(); + draw_spriteBottom = parse_parseValExpr(); + + draw_backColor = parse_parseValExpr(); + draw_spriteOperation(DRAW_FILLRECT); +} + +void inter_drawLine(void) { + draw_destSurface = inter_load16(); + + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + draw_spriteRight = parse_parseValExpr(); + draw_spriteBottom = parse_parseValExpr(); + + draw_frontColor = parse_parseValExpr(); + draw_spriteOperation(DRAW_DRAWLINE); +} + +void inter_createSprite(void) { + int16 index; + int16 height; + int16 width; + int16 flag; + + index = inter_load16(); + width = inter_load16(); + height = inter_load16(); + + flag = inter_load16(); + if (flag == 1) + draw_spritesArray[index] = vid_initSurfDesc(videoMode, width, height, 2); + else + draw_spritesArray[index] = vid_initSurfDesc(videoMode, width, height, 0); + + vid_clearSurf(draw_spritesArray[index]); +} + +void inter_freeSprite(void) { + int16 index; + + index = inter_load16(); + if (draw_spritesArray[index] == 0) + return; + + vid_freeSurfDesc(draw_spritesArray[index]); + draw_spritesArray[index] = 0; +} + +void inter_renewTimeInVars(void) { + uint32 time = g_system->getMillis(); + + time /= 1000; // convert to seconds + + // hours + WRITE_LE_UINT32(inter_variables + 0x24, time / 3600); + time %= 3600; + + // minutes + WRITE_LE_UINT32(inter_variables + 0x28, time / 60); + time %= 60; + + // seconds + WRITE_LE_UINT32(inter_variables + 0x2c, time); +} + +void inter_playComposition(void) { + static int16 inter_composition[50]; + int16 i; + int16 dataVar; + int16 freqVal; + + dataVar = parse_parseVarIndex(); + freqVal = parse_parseValExpr(); + for (i = 0; i < 50; i++) + inter_composition[i] = READ_LE_UINT32(inter_variables + dataVar + i * 4); + + snd_playComposition(game_soundSamples, inter_composition, freqVal); +} + +void inter_stopSound(void) { + snd_stopSound(parse_parseValExpr()); + inter_soundEndTimeKey = 0; +} + +void inter_playSound(void) { + int16 frequency; + int16 freq2; + int16 repCount; + int16 index; + + index = parse_parseValExpr(); + repCount = parse_parseValExpr(); + frequency = parse_parseValExpr(); + + snd_stopSound(0); + inter_soundEndTimeKey = 0; + if (game_soundSamples[index] == 0) + return; + + if (repCount < 0) { + if (soundFlags < 2) + return; + + repCount = -repCount; + inter_soundEndTimeKey = util_getTimeKey(); + + if (frequency == 0) { + freq2 = game_soundSamples[index]->frequency; + } else { + freq2 = frequency; + } + inter_soundStopVal = + (10 * (game_soundSamples[index]->size / 2)) / freq2; + inter_soundEndTimeKey += + ((game_soundSamples[index]->size * repCount - + game_soundSamples[index]->size / 2) * 1000) / freq2; + } + snd_playSample(game_soundSamples[index], repCount, frequency); +} + +void inter_loadCursor(void) { + Game_TotResItem *itemPtr; + int16 width; + int16 height; + int16 offset; + int16 elemsCount; + char *dataBuf; + int16 id; + int8 index; + + debug(0, "inter_loadCursor"); + id = inter_load16(); + index = *inter_execPtr++; + + itemPtr = &game_totResourceTable->items[id]; + offset = itemPtr->offset; + if (offset >= 0) { + dataBuf = + ((char *)game_totResourceTable) + szGame_TotResTable + + szGame_TotResItem * game_totResourceTable->itemsCount + offset; + } else { + dataBuf = game_imFileData + ((int32 *)game_imFileData)[-offset - 1]; + } + + width = itemPtr->width; + height = itemPtr->height; + + vid_fillRect(draw_cursorSprites, index * draw_cursorWidth, 0, + index * draw_cursorWidth + draw_cursorWidth - 1, + draw_cursorHeight - 1, 0); + + vid_drawPackedSprite((byte*)dataBuf, width, height, + index * draw_cursorWidth, 0, 0, draw_cursorSprites); + draw_cursorAnimLow[index] = 0; +} + +void inter_loadSpriteToPos(void) { + debug(0, "inter_loadSpriteToPos"); + draw_spriteLeft = inter_load16(); + + draw_destSpriteX = parse_parseValExpr(); + draw_destSpriteY = parse_parseValExpr(); + + draw_transparency = inter_execPtr[0]; + draw_destSurface = (inter_execPtr[0] / 2) - 1; + + if (draw_destSurface < 0) + draw_destSurface = 101; + draw_transparency &= 1; + inter_execPtr += 2; + draw_spriteOperation(DRAW_LOADSPRITE); +} + +void inter_loadTot(void) { + char buf[20]; + int8 size; + int16 i; + + debug(0, "inter_loadTot"); + if ((*inter_execPtr & 0x80) != 0) { + inter_execPtr++; + inter_evalExpr(0); + strcpy(buf, inter_resStr); + } else { + size = *inter_execPtr++; + for (i = 0; i < size; i++) + buf[i] = *inter_execPtr++; + + buf[size] = 0; + } + + strcat(buf, ".tot"); + inter_terminate = 1; + strcpy(game_totToLoad, buf); +} + +void inter_storeKey(int16 key) { + WRITE_LE_UINT32(inter_variables + 0x30, util_getTimeKey() - game_startTimeKey); + + WRITE_LE_UINT32(inter_variables + 0x08, inter_mouseX); + WRITE_LE_UINT32(inter_variables + 0x0c, inter_mouseX); + WRITE_LE_UINT32(inter_variables + 0x10, game_mouseButtons); + WRITE_LE_UINT32(inter_variables + 0x04, 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; + + debug(0, "key: %d", key); + WRITE_LE_UINT32(inter_variables, key); + + if (key != 0) + util_waitKey(); +} + +void inter_keyFunc(void) { + int16 flag; + int16 key; + + debug(0, "inter_keyFunc"); + flag = inter_load16(); + inter_animPalette(); + draw_blitInvalidated(); + + if (flag != 0) { + + if (flag != 1) { + if (flag != 2) { + util_delay(flag); + return; + } + + key = 0; + + if (pressedKeys[0x48]) + key |= 1; + + if (pressedKeys[0x50]) + key |= 2; + + if (pressedKeys[0x4d]) + key |= 4; + + if (pressedKeys[0x4b]) + key |= 8; + + if (pressedKeys[0x1c]) + key |= 0x10; + + if (pressedKeys[0x39]) + key |= 0x20; + + if (pressedKeys[1]) + key |= 0x40; + + if (pressedKeys[0x1d]) + key |= 0x80; + + if (pressedKeys[0x2a]) + key |= 0x100; + + if (pressedKeys[0x36]) + key |= 0x200; + + if (pressedKeys[0x38]) + key |= 0x400; + + if (pressedKeys[0x3b]) + key |= 0x800; + + if (pressedKeys[0x3c]) + key |= 0x1000; + + if (pressedKeys[0x3d]) + key |= 0x2000; + + if (pressedKeys[0x3e]) + key |= 0x4000; + + WRITE_LE_UINT32(inter_variables, key); + util_waitKey(); + return; + } + key = game_checkKeys(&inter_mouseX, &inter_mouseY, &game_mouseButtons, 0); + + inter_storeKey(key); + return; + } else { + key = game_checkCollisions(0, 0, 0, 0); + inter_storeKey(key); + + if (flag == 1) + return; + + 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 = parse_parseVarIndex(); + value = READ_LE_UINT32(inter_variables + value); + + do { + len = *inter_execPtr++; + + if (len == -5) + break; + + for (i = 0; i < len; i++) { + inter_evalExpr(0); + + if (inter_terminate != 0) + return; + + if (inter_resVal == value) { + found = 1; + notFound = 0; + } + } + + if (found != 0) + *ppExec = inter_execPtr; + + inter_execPtr += READ_LE_UINT16(inter_execPtr + 2) + 2; + found = 0; + } while (len != -5); + + if (len != -5) + inter_execPtr++; + + defFlag = *inter_execPtr; + defFlag >>= 4; + if (defFlag != 4) + return; + inter_execPtr++; + + if (notFound) + *ppExec = inter_execPtr; + + inter_execPtr += READ_LE_UINT16(inter_execPtr + 2) + 2; +} + +void inter_repeatUntil(void) { + char *blockPtr; + int16 size; + char flag; + + debug(0, "inter_repeatUntil"); + inter_nestLevel[0]++; + blockPtr = inter_execPtr; + + do { + inter_execPtr = blockPtr; + size = READ_LE_UINT16(inter_execPtr + 2) + 2; + + inter_funcBlock(1); + inter_execPtr = blockPtr + size + 1; + flag = inter_evalBoolResult(); + } while (flag == 0 && inter_breakFlag == 0 && inter_terminate == 0); + + inter_nestLevel[0]--; + + if (*inter_breakFromLevel > -1) { + inter_breakFlag = 0; + *inter_breakFromLevel = -1; + } +} + +void inter_whileDo(void) { + char *blockPtr; + char *savedIP; + char flag; + int16 size; + + debug(0, "inter_whileDo"); + inter_nestLevel[0]++; + do { + savedIP = inter_execPtr; + flag = inter_evalBoolResult(); + + if (inter_terminate != 0) + return; + + blockPtr = inter_execPtr; + + size = READ_LE_UINT16(inter_execPtr + 2) + 2; + + if (flag != 0) { + inter_funcBlock(1); + inter_execPtr = savedIP; + } else { + inter_execPtr += size; + } + + if (inter_breakFlag != 0 || inter_terminate != 0) { + inter_execPtr = blockPtr; + inter_execPtr += size; + break; + } + } while (flag != 0); + + inter_nestLevel[0]--; + if (*inter_breakFromLevel > -1) { + inter_breakFlag = 0; + *inter_breakFromLevel = -1; + } +} + +void inter_funcBlock(int16 retFlag) { + char cmdCount; + int16 counter; + byte cmd; + byte cmd2; + char *storedIP; + char *callAddr; + char boolRes; + + if (inter_execPtr == 0) + return; + + inter_breakFlag = 0; + inter_execPtr++; + cmdCount = *inter_execPtr++; + inter_execPtr += 2; + + if (cmdCount == 0) { + inter_execPtr = 0; + return; + } + + counter = 0; + do { + if (inter_terminate != 0) + break; + + cmd = (byte)*inter_execPtr; + if ((cmd >> 4) >= 12) { + cmd2 = 16 - (cmd >> 4); + cmd &= 0xf; + } else + cmd2 = 0; + + inter_execPtr++; + counter++; + switch (cmd2) { + case 0: + switch (cmd >> 4) { + case 0: + case 1: + storedIP = inter_execPtr; + inter_execPtr = (char *)game_totFileData + READ_LE_UINT16(inter_execPtr); + + if (counter == cmdCount && retFlag == 2) + return; + + inter_callSub(2); + inter_execPtr = storedIP + 2; + break; + + case 2: + draw_printText(); + break; + + case 3: + inter_loadCursor(); + break; + + case 5: + inter_checkSwitchTable(&callAddr); + storedIP = inter_execPtr; + inter_execPtr = callAddr; + + if (counter == cmdCount && retFlag == 2) + return; + + inter_funcBlock(0); + inter_execPtr = storedIP; + break; + + case 6: + inter_repeatUntil(); + break; + + case 7: + inter_whileDo(); + break; + + case 8: + boolRes = inter_evalBoolResult(); + if (boolRes != 0) { + if (counter == cmdCount + && retFlag == 2) + return; + + storedIP = inter_execPtr; + inter_funcBlock(0); + inter_execPtr = storedIP; + + inter_execPtr += READ_LE_UINT16(inter_execPtr + 2) + 2; + + debug(5, "cmd = %d", (int16)*inter_execPtr); + cmd = (byte)(*inter_execPtr) >> 4; + inter_execPtr++; + if (cmd != 12) + break; + + inter_execPtr += READ_LE_UINT16(inter_execPtr + 2) + 2; + } else { + inter_execPtr += READ_LE_UINT16(inter_execPtr + 2) + 2; + + debug(5, "cmd = %d", (int16)*inter_execPtr); + cmd = (byte)(*inter_execPtr) >> 4; + inter_execPtr++; + if (cmd != 12) + break; + + if (counter == cmdCount && retFlag == 2) + return; + + storedIP = inter_execPtr; + inter_funcBlock(0); + inter_execPtr = storedIP; + inter_execPtr += READ_LE_UINT16(inter_execPtr + 2) + 2; + } + break; + + case 9: + inter_evaluateStore(); + break; + + case 10: + inter_loadSpriteToPos(); + break; + } + break; + + case 1: + switch (cmd) { + case 1: + inter_printText(); + break; + + case 2: + inter_loadTot(); + break; + + case 3: + draw_interPalLoad(); + break; + + case 4: + inter_keyFunc(); + break; + + case 5: + inter_capturePush(); + break; + + case 6: + inter_capturePop(); + break; + + case 7: + inter_animPalInit(); + break; + + case 14: + inter_drawOperations(); + break; + + case 15: + cmdCount = *inter_execPtr++; + counter = 0; + break; + } + break; + + case 2: + + switch (cmd) { + case 0: + if (retFlag != 2) + inter_breakFlag = 1; + + inter_execPtr = 0; + return; + + case 1: + inter_renewTimeInVars(); + break; + + case 2: + snd_speakerOn(parse_parseValExpr()); + break; + + case 3: + snd_speakerOff(); + break; + + case 4: + inter_putPixel(); + break; + + case 5: + gob_interFunc(); + break; + + case 6: + inter_createSprite(); + break; + + case 7: + inter_freeSprite(); + break; + } + break; + + case 3: + switch (cmd) { + case 0: + if (retFlag == 1) { + inter_breakFlag = 1; + inter_execPtr = 0; + return; + } + + if (*inter_nestLevel == 0) + break; + + *inter_breakFromLevel = *inter_nestLevel; + inter_breakFlag = 1; + inter_execPtr = 0; + return; + + case 1: + inter_loadSpriteContent(); + break; + + case 2: + inter_copySprite(); + break; + + case 3: + inter_fillRect(); + break; + + case 4: + inter_drawLine(); + break; + + case 5: + inter_strToLong(); + break; + + case 6: + inter_invalidate(); + break; + + case 7: + draw_backDeltaX = parse_parseValExpr(); + draw_backDeltaY = parse_parseValExpr(); + break; + + case 8: + inter_playSound(); + break; + + case 9: + inter_stopSound(); + break; + + case 10: + game_interLoadSound(-1); + break; + + case 11: + game_freeSoundSlot(-1); + break; + + case 12: + snd_waitEndPlay(); + break; + + case 13: + inter_playComposition(); + break; + + case 14: + inter_getFreeMem(); + break; + + case 15: + inter_checkData(); + break; + } + break; + + case 4: + + switch (cmd) { + case 1: + inter_prepareStr(); + break; + + case 2: + inter_insertStr(); + break; + + case 3: + inter_cutStr(); + break; + + case 4: + inter_strstr(); + break; + + case 5: + inter_strlen(); + break; + + case 6: + inter_setMousePos(); + break; + + case 7: + inter_setFrameRate(); + break; + + case 8: + draw_blitInvalidated(); + util_waitEndFrame(); + inter_animPalette(); + inter_storeKey(game_checkKeys(&inter_mouseX, + &inter_mouseY, &game_mouseButtons, 0)); + break; + + case 9: + draw_animateCursor(1); + break; + + case 10: + draw_blitCursor(); + break; + + case 11: + inter_loadFont(); + break; + + case 12: + inter_freeFont(); + break; + + case 13: + inter_readData(); + break; + + case 14: + inter_writeData(); + break; + + case 15: + inter_manageDataFile(); + break; + } + break; + + } + + if (inter_breakFlag != 0) { + if (retFlag != 2) + break; + + if (*inter_breakFromLevel == -1) + inter_breakFlag = 0; + break; + } + } while (counter != cmdCount); + + inter_execPtr = 0; + return; +} + +void inter_initControlVars(void) { + *inter_nestLevel = 0; + *inter_breakFromLevel = -1; + + *scen_pCaptureCounter = 0; + + inter_breakFlag = 0; + inter_terminate = 0; + inter_animPalDir = 0; + inter_soundEndTimeKey = 0; +} + +void inter_callSub(int16 retFlag) { + int16 block; + while (inter_execPtr != 0 && (char *)inter_execPtr != game_totFileData) { + block = *inter_execPtr; + if (block == 1) { + inter_funcBlock(retFlag); + } else if (block == 2) { + game_collisionsBlock(); + } + } + + if ((char *)inter_execPtr == game_totFileData) + inter_terminate = 1; +} + +} // End of namespace Gob diff --git a/gob/inter.h b/gob/inter.h new file mode 100644 index 0000000000..fc31b72b2e --- /dev/null +++ b/gob/inter.h @@ -0,0 +1,85 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __INTERPRET_H +#define __INTERPRET_H + +namespace Gob { + +extern int16 inter_animPalLowIndex; +extern int16 inter_animPalHighIndex; +extern int16 inter_animPalDir; +extern uint32 inter_soundEndTimeKey; +extern int16 inter_soundStopVal; +extern char inter_terminate; +extern char inter_breakFlag; +extern int16 *inter_breakFromLevel; +extern int16 *inter_nestLevel; + +int16 inter_load16(void); +int16 inter_peek16(char *ptr); +int32 inter_peek32(char *ptr); + +void inter_setMousePos(void); +char inter_evalExpr(int16 *pRes); +char inter_evalBoolResult(void); +void inter_storeResult(void); +void inter_printText(void); +void inter_animPalette(void); +void inter_animPalInit(void); +void inter_loadMult(void); +void inter_playMult(void); +void inter_freeMult(void); +void inter_initCursor(void); +void inter_initCursorAnim(void); +void inter_clearCursorAnim(void); +void inter_drawOperations(void); +void inter_getFreeMem(void); +void inter_manageDataFile(void); +void inter_getFreeMem(void); +void inter_manageDataFile(void); +void inter_writeData(void); +void inter_checkData(void); +void inter_readData(void); +void inter_loadFont(void); +void inter_freeFont(void); +void inter_prepareStr(void); +void inter_insertStr(void); +void inter_cutStr(void); +void inter_strstr(void); +void inter_setFrameRate(void); +void inter_strlen(void); +void inter_strToLong(void); +void inter_invalidate(void); +void inter_loadSpriteContent(void); +void inter_copySprite(void); +void inter_putPixel(void); +void inter_fillRect(void); +void inter_drawLine(void); +void inter_createSprite(void); +void inter_freeSprite(void); +void inter_renewTimeInVars(void); +void inter_playComposition(void); +void inter_stopSound(void); +void inter_playSound(void); +void inter_loadCursor(void); +void inter_loadSpriteToPos(void); +void inter_funcBlock(int16 retFlag); +void inter_loadTot(void); +void inter_storeKey(int16 key); +void inter_keyFunc(void); +void inter_checkSwitchTable(char **ppExec); +void inter_repeatUntil(void); +void inter_whileDo(void); +void inter_funcBlock(int16 retFlag); +void inter_callSub(int16 retFlag); +void inter_initControlVars(void); +void inter_callSub(int16 retFlag); + +} // End of namespace Gob + +#endif diff --git a/gob/map.cpp b/gob/map.cpp new file mode 100644 index 0000000000..a9008eb7f4 --- /dev/null +++ b/gob/map.cpp @@ -0,0 +1,736 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#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/debug.h" + +namespace Gob { + +char map_passMap[28][26]; // [y][x] +int16 map_itemsMap[28][26]; // [y][x] + +Map_Point map_wayPoints[40]; +int16 map_nearestWayPoint = 0; +int16 map_nearestDest = 0; + +int16 map_curGoblinX; +int16 map_curGoblinY; +int16 map_destX; +int16 map_destY; + +Map_ItemPos map_itemPoses[40]; +char map_loadFromAvo; +char map_sourceFile[15]; +char *map_avoDataPtr; + +int16 map_getDirection(int16 x0, int16 y0, int16 x1, int16 y1) { + int16 dir; + + dir = 0; + + if (x0 == x1 && y0 == y1) + return 0; + + if (x1 < 0 || x1 > 25 || y1 < 0 || y1 > 27) + return 0; + + if (y1 > y0) + dir = 8; + else if (y1 < y0) + dir = 2; + + if (x1 > x0) + dir += 4; + else if (x1 < x0) + dir += 1; + + if (map_passMap[y0][x0] == 3 && (dir == 3 || dir == 6 || dir == 2)) { + if (map_passMap[y0 - 1][x0] != 0) + return 0x4800; + } + + if (map_passMap[y0][x0] == 3 && (dir == 9 || dir == 12 || dir == 8)) { + if (map_passMap[y0 + 1][x0] != 0) + return 0x5000; + } + + if (map_passMap[y0][x0] == 6 && (dir == 3 || dir == 6 || dir == 2)) { + if (map_passMap[y0 - 1][x0] != 0) + return 0x4800; + } + + if (map_passMap[y0][x0] == 6 && (dir == 9 || dir == 12 || dir == 8)) { + if (map_passMap[y0 + 1][x0] != 0) + return 0x5000; + } + + if (dir == 1) { + if (x0 - 1 >= 0 && map_passMap[y0][x0 - 1] != 0) + return 0x4b00; + return 0; + } + + if (dir == 4) { + if (x0 + 1 < 26 && map_passMap[y0][x0 + 1] != 0) + return 0x4d00; + return 0; + } + + if (dir == 2) { + if (y0 - 1 >= 0 && map_passMap[y0 - 1][x0] != 0) + return 0x4800; + + if (y0 - 1 >= 0 && x0 - 1 >= 0 + && map_passMap[y0 - 1][x0 - 1] != 0) + return 0x4700; + + if (y0 - 1 >= 0 && x0 + 1 < 26 + && map_passMap[y0 - 1][x0 + 1] != 0) + return 0x4900; + + return 0; + } + + if (dir == 8) { + if (y0 + 1 < 28 && map_passMap[y0 + 1][x0] != 0) + return 0x5000; + + if (y0 + 1 < 28 && x0 - 1 >= 0 + && map_passMap[y0 + 1][x0 - 1] != 0) + return 0x4f00; + + if (y0 + 1 < 28 && x0 + 1 < 26 + && map_passMap[y0 + 1][x0 + 1] != 0) + return 0x5100; + + return 0; + } + + if (dir == 6) { + if (y0 - 1 >= 0 && x0 + 1 < 26 + && map_passMap[y0 - 1][x0 + 1] != 0) + return 0x4900; + + if (y0 - 1 >= 0 && map_passMap[y0 - 1][x0] != 0) + return 0x4800; + + if (x0 + 1 < 26 && map_passMap[y0][x0 + 1] != 0) + return 0x4d00; + + return 0; + } + + if (dir == 12) { + if (x0 + 1 < 26 && y0 + 1 < 28 + && map_passMap[y0 + 1][x0 + 1] != 0) + return 0x5100; + + if (y0 + 1 < 28 && map_passMap[y0 + 1][x0] != 0) + return 0x5000; + + if (x0 + 1 < 26 && map_passMap[y0][x0 + 1] != 0) + return 0x4d00; + + return 0; + } + + if (dir == 3) { + if (x0 - 1 >= 0 && y0 - 1 >= 0 + && map_passMap[y0 - 1][x0 - 1] != 0) + return 0x4700; + + if (y0 - 1 >= 0 && map_passMap[y0 - 1][x0] != 0) + return 0x4800; + + if (x0 - 1 >= 0 && map_passMap[y0][x0 - 1] != 0) + return 0x4b00; + + return 0; + } + + if (dir == 9) { + if (x0 - 1 >= 0 && y0 + 1 < 28 + && map_passMap[y0 + 1][x0 - 1] != 0) + return 0x4f00; + + if (y0 + 1 < 28 && map_passMap[y0 + 1][x0] != 0) + return 0x5000; + + if (x0 - 1 >= 0 && map_passMap[y0][x0 - 1] != 0) + return 0x4b00; + + return 0; + } + return -1; +} + +void map_findNearestToGob(void) { + int16 length; + int16 i; + int16 tmp; + + length = 30000; + + for (i = 0; i < 40; i++) { + if (map_wayPoints[i].x < 0 || + map_wayPoints[i].x > 25 || + map_wayPoints[i].y < 0 || map_wayPoints[i].y > 27) + return; + + tmp = ABS(map_curGoblinX - map_wayPoints[i].x) + + ABS(map_curGoblinY - map_wayPoints[i].y); + + if (tmp <= length) { + map_nearestWayPoint = i; + length = tmp; + } + } +} + +void map_findNearestToDest(void) { + int16 length; + int16 tmp; + int16 i; + + length = 30000; + for (i = 0; i < 40; i++) { + if (map_wayPoints[i].x < 0 || + map_wayPoints[i].x > 25 || + map_wayPoints[i].y < 0 || map_wayPoints[i].y > 27) + return; + + tmp = ABS(map_destX - map_wayPoints[i].x) + + ABS(map_destY - map_wayPoints[i].y); + + if (tmp <= length) { + map_nearestDest = i; + length = tmp; + } + } +} + +int16 map_checkDirectPath(int16 x0, int16 y0, int16 x1, int16 y1) { + uint16 dir; + + while (1) { + dir = map_getDirection(x0, y0, x1, y1); + + if (x0 == x1 && y0 == y1) + return 1; + + if (dir == 0) + return 3; + + switch (dir) { + case 0x4700: + x0--; + y0--; + break; + + case 0x4800: + y0--; + break; + + case 0x4900: + x0++; + y0--; + break; + + case 0x4b00: + x0--; + break; + + case 0x4d00: + x0++; + break; + + case 0x4f00: + x0--; + y0++; + break; + + case 0x5000: + y0++; + break; + + case 0x5100: + 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 (map_checkDirectPath(x0, y0, x1, y1) == 1) + return 1; + + nextLink = 0; + if (i0 > i1) { + curX = map_wayPoints[i0].x; + curY = map_wayPoints[i0].y; + i0--; + } else if (i0 < i1) { + curX = map_wayPoints[i0].x; + curY = map_wayPoints[i0].y; + i0++; + } else if (i0 == i1) { + curX = map_wayPoints[i0].x; + curY = map_wayPoints[i0].y; + } + } + if (i0 == i1 && map_wayPoints[i0].x == x0 + && map_wayPoints[i0].y == y0) { + if (map_checkDirectPath(x0, y0, x1, y1) == 1) + return 1; + return 0; + } + dir = map_getDirection(x0, y0, curX, curY); + switch (dir) { + case 0: + return 0; + + case 0x4700: + x0--; + y0--; + break; + + case 0x4800: + y0--; + break; + + case 0x4900: + x0++; + y0--; + break; + + case 0x4b00: + x0--; + break; + + case 0x4d00: + x0++; + break; + + case 0x4f00: + x0--; + y0++; + break; + + case 0x5000: + y0++; + break; + + case 0x5100: + x0++; + y0++; + break; + } + } +} + +int16 map_optimizePoints(int16 xPos, int16 yPos) { + int16 i; + + if (map_nearestWayPoint < map_nearestDest) { + for (i = map_nearestWayPoint; i <= map_nearestDest; i++) { + if (map_checkDirectPath(xPos, yPos, + map_wayPoints[i].x, map_wayPoints[i].y) == 1) + map_nearestWayPoint = i; + } + } else if (map_nearestWayPoint > map_nearestDest) { + for (i = map_nearestWayPoint; i >= map_nearestDest; i--) { + if (map_checkDirectPath(xPos, yPos, + map_wayPoints[i].x, map_wayPoints[i].y) == 1) + map_nearestWayPoint = i; + } + } + return map_nearestWayPoint; +} + +void map_loadDataFromAvo(char *dest, int16 size) { + memcpy(dest, map_avoDataPtr, size); + map_avoDataPtr += size; +} + +void map_loadItemToObject(void) { + int16 flag; + int16 count; + int16 i; + + map_loadDataFromAvo((char *)&flag, 2); + flag = FROM_LE_16(flag); + if (flag == 0) + return; + + map_avoDataPtr += 1456; + map_loadDataFromAvo((char *)&count, 2); + count = FROM_LE_16(count); + for (i = 0; i < count; i++) { + map_avoDataPtr += 20; + map_loadDataFromAvo((char *)(&gob_itemToObject[i]), 2); + gob_itemToObject[i] = FROM_LE_16(gob_itemToObject[i]); + map_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; + Gob_State *pState; + char buf[128]; + char sndNames[20][14]; + char *dataBuf; + int16 x; + int16 y; + int16 count2; + int16 count3; + + strcpy(avoName, map_sourceFile); + strcat(avoName, ".avo"); + + handle = data_openData(avoName); + if (handle >= 0) { + map_loadFromAvo = 1; + data_closeData(handle); + map_avoDataPtr = data_getSmallData(avoName); + dataBuf = map_avoDataPtr; + map_loadDataFromAvo((char *)map_passMap, 28 * 26); + + for (y = 0; y < 28; y++) { + for (x = 0; x < 26; x++) { + map_loadDataFromAvo(&item, 1); + map_itemsMap[y][x] = item; + } + } + + for (i = 0; i < 40; i++) { + map_loadDataFromAvo((char *)(&map_wayPoints[i].x), 2); + map_wayPoints[i].x = FROM_LE_16(map_wayPoints[i].x); + map_loadDataFromAvo((char *)(&map_wayPoints[i].y), 2); + map_wayPoints[i].y = FROM_LE_16(map_wayPoints[i].y); + } + map_loadDataFromAvo((char *)map_itemPoses, szMap_ItemPos * 20); + } else { + map_loadFromAvo = 0; + map_avoDataPtr = data_getSmallData(avjFile); + dataBuf = map_avoDataPtr; + } + + map_avoDataPtr += 32; + map_avoDataPtr += 76; + map_avoDataPtr += 4; + map_avoDataPtr += 20; + + for (i = 0; i < 3; i++) { + map_loadDataFromAvo((char *)&tmp, 2); + tmp = FROM_LE_16(tmp); + map_avoDataPtr += tmp * 14; + } + + map_loadDataFromAvo((char *)&soundCount, 2); + soundCount = FROM_LE_16(soundCount); + savedPtr = map_avoDataPtr; + + map_avoDataPtr += 14 * soundCount; + map_avoDataPtr += 4; + map_avoDataPtr += 24; + + map_loadDataFromAvo((char *)&count2, 2); + count2 = FROM_LE_16(count2); + map_loadDataFromAvo((char *)&count3, 2); + count3 = FROM_LE_16(count3); + + savedPtr2 = map_avoDataPtr; + map_avoDataPtr += count2 * 8; + + savedPtr3 = map_avoDataPtr; + map_avoDataPtr += count3 * 8; + + map_loadDataFromAvo((char *)&gob_gobsCount, 2); + gob_gobsCount = FROM_LE_16(gob_gobsCount); + for (i = 0; i < gob_gobsCount; i++) { + gob_goblins[i] = (Gob_Object *)malloc(sizeof(Gob_Object)); + + gob_goblins[i]->xPos = READ_LE_UINT16(savedPtr2); + savedPtr2 += 2; + + gob_goblins[i]->yPos = READ_LE_UINT16(savedPtr2); + savedPtr2 += 2; + + gob_goblins[i]->order = READ_LE_UINT16(savedPtr2); + savedPtr2 += 2; + + gob_goblins[i]->state = READ_LE_UINT16(savedPtr2); + savedPtr2 += 2; + + if (i == 3) + gob_goblins[i]->stateMach = (Gob_StateLine *)malloc(sizeof(Gob_StateLine) * 70); + else + gob_goblins[i]->stateMach = (Gob_StateLine *)malloc(sizeof(Gob_StateLine) * 40); + + // FIXME: All is wrong further. We should unwind calls to map_loadDataFromAvo() + map_loadDataFromAvo((char *)gob_goblins[i]->stateMach, 40 * szGob_StateLine); + map_avoDataPtr += 160; + gob_goblins[i]->multObjIndex = *map_avoDataPtr; + map_avoDataPtr += 2; + + gob_goblins[i]->realStateMach = gob_goblins[i]->stateMach; + + for (state = 0; state < 40; state++) { + for (col = 0; col < 6; col++) { + if (gob_goblins[i]->stateMach[state][col] == 0) + continue; + + gob_goblins[i]->stateMach[state][col] = (Gob_State *)malloc(sizeof(Gob_State)); + + map_loadDataFromAvo((char *)gob_goblins[i]->stateMach[state][col], 4); + map_avoDataPtr += 8; + map_loadDataFromAvo(((char *)gob_goblins[i]->stateMach[state][col]) + 4, 4); + + map_avoDataPtr += 2; + if (READ_LE_UINT32(map_avoDataPtr) != 0) { + map_avoDataPtr += 4; + map_loadDataFromAvo((char + *)(&gob_goblins[i]-> + stateMach[state][col]-> + sndItem), 2); + } else { + map_avoDataPtr += 6; + gob_goblins[i]->stateMach[state][col]-> + sndItem = -1; + } + map_loadDataFromAvo((char *)(&gob_goblins[i]-> + stateMach[state][col]->freq), 6); + } + } + } + + pState = (Gob_State *)malloc(sizeof(Gob_State)); + gob_goblins[0]->stateMach[39][0] = pState; + pState->animation = 0; + pState->layer = 98; + pState->unk0 = 0; + pState->unk1 = 0; + pState->sndItem = -1; + + pState = (Gob_State *) malloc(sizeof(Gob_State)); + gob_goblins[1]->stateMach[39][0] = pState; + pState->animation = 0; + pState->layer = 99; + pState->unk0 = 0; + pState->unk1 = 0; + pState->sndItem = -1; + + pState = (Gob_State *) malloc(sizeof(Gob_State)); + gob_goblins[2]->stateMach[39][0] = pState; + pState->animation = 0; + pState->layer = 100; + pState->unk0 = 0; + pState->unk1 = 0; + pState->sndItem = -1; + + gob_goblins[2]->stateMach[10][0]->unk2 = 13; + gob_goblins[2]->stateMach[11][0]->unk2 = 13; + gob_goblins[2]->stateMach[28][0]->unk2 = 13; + gob_goblins[2]->stateMach[29][0]->unk2 = 13; + + gob_goblins[1]->stateMach[10][0]->unk2 = 13; + gob_goblins[1]->stateMach[11][0]->unk2 = 13; + + for (state = 40; state < 70; state++) { + pState = (Gob_State *)malloc(sizeof(Gob_State)); + gob_goblins[3]->stateMach[state][0] = pState; + gob_goblins[3]->stateMach[state][1] = 0; + + pState->animation = 9; + pState->layer = state - 40; + pState->sndItem = -1; + pState->unk2 = 0; + } + + map_loadDataFromAvo((char *)&gob_objCount, 2); + for (i = 0; i < gob_objCount; i++) { + gob_objects[i] = + (Gob_Object *) malloc(sizeof(Gob_Object)); + + gob_objects[i]->xPos = READ_LE_UINT16(savedPtr3); + savedPtr3 += 2; + + gob_objects[i]->yPos = READ_LE_UINT16(savedPtr3); + savedPtr3 += 2; + + gob_objects[i]->order = READ_LE_UINT16(savedPtr3); + savedPtr3 += 2; + + gob_objects[i]->state = READ_LE_UINT16(savedPtr3); + savedPtr3 += 2; + + gob_objects[i]->stateMach = (Gob_StateLine *)malloc(sizeof(Gob_StateLine) * 40); + + map_loadDataFromAvo((char *)gob_objects[i]->stateMach, 40 * szGob_StateLine); + map_avoDataPtr += 160; + gob_objects[i]->multObjIndex = *map_avoDataPtr; + map_avoDataPtr += 2; + + gob_objects[i]->realStateMach = gob_objects[i]->stateMach; + for (state = 0; state < 40; state++) { + for (col = 0; col < 6; col++) { + if (gob_objects[i]->stateMach[state][col] == 0) + continue; + + gob_objects[i]->stateMach[state][col] = (Gob_State *)malloc(sizeof(Gob_State)); + + map_loadDataFromAvo((char *)gob_objects[i]->stateMach[state][col], 4); + map_avoDataPtr += 8; + map_loadDataFromAvo(((char *)gob_objects[i]->stateMach[state][col]) + 4, 4); + + map_avoDataPtr += 2; + if (READ_LE_UINT32(map_avoDataPtr) != 0) { + map_avoDataPtr += 4; + map_loadDataFromAvo((char *)(&gob_objects[i]->stateMach[state][col]->sndItem), 2); + } else { + map_avoDataPtr += 6; + gob_objects[i]->stateMach[state][col]->sndItem = -1; + } + map_loadDataFromAvo((char *)(&gob_objects[i]->stateMach[state][col]->freq), 6); + } + } + + } + + gob_objects[10] = (Gob_Object *)malloc(sizeof(Gob_Object)); + memset(gob_objects[10], 0, sizeof(Gob_Object)); + + gob_objects[10]->stateMach = (Gob_StateLine *)malloc(sizeof(Gob_StateLine) * 40); + memset(gob_objects[10]->stateMach, 0, sizeof(Gob_StateLine) * 40); + + pState = (Gob_State *)malloc(sizeof(Gob_State)); + gob_objects[10]->stateMach[0][0] = pState; + + memset(pState, 0, sizeof(Gob_State)); + pState->animation = 9; + pState->layer = 27; + pState->unk0 = 0; + pState->unk1 = 0; + pState->sndItem = -1; + pState->unk2 = 0; + + gob_placeObject(gob_objects[10], 1); + + gob_objects[10]->realStateMach = gob_objects[10]->stateMach; + gob_objects[10]->type = 1; + gob_objects[10]->unk14 = 1; + + map_loadDataFromAvo((char *)&state, 2); + for (i = 0; i < state; i++) { + map_avoDataPtr += 30; + + map_loadDataFromAvo((char *)&flag, 4); + map_avoDataPtr += 56; + + if (flag != 0) + map_avoDataPtr += 30; + } + + map_loadDataFromAvo((char *)&tmp, 2); + map_avoDataPtr += 48; + map_loadItemToObject(); + map_avoDataPtr = savedPtr; + + for (i = 0; i < soundCount; i++) { + map_loadDataFromAvo(buf, 14); + strcat(buf, ".SND"); + strcpy(sndNames[i], buf); + } + + free(dataBuf); + + gob_soundData[14] = snd_loadSoundData("diamant1.snd"); + + for (i = 0; i < soundCount; i++) { + handle = data_openData(sndNames[i]); + if (handle < 0) + continue; + + data_closeData(handle); + gob_soundData[i] = snd_loadSoundData(sndNames[i]); + } +} + +void map_loadMapsInitGobs(void) { + int16 layer; + int16 i; + + if (map_loadFromAvo == 0) + error("map_load: Loading .pas/.pos files is not supported!"); + + for (i = 0; i < 3; i++) { + gob_nextLayer(gob_goblins[i]); + } + + for (i = 0; i < 3; i++) { + + layer = + gob_goblins[i]->stateMach[gob_goblins[i]->state][0]->layer; + + scen_updateAnim(layer, 0, gob_goblins[i]->animation, 0, + gob_goblins[i]->xPos, gob_goblins[i]->yPos, 0); + + gob_goblins[i]->yPos = (gob_gobPositions[i].y + 1) * 6 - + (scen_toRedrawBottom - scen_animTop); + + gob_goblins[i]->xPos = gob_gobPositions[i].x * 12 - + (scen_toRedrawLeft - scen_animLeft); + + gob_goblins[i]->order = scen_toRedrawBottom / 24 + 3; + } + + gob_currentGoblin = 0; + gob_pressedMapX = gob_gobPositions[0].x; + gob_pressedMapY = gob_gobPositions[0].y; + gob_pathExistence = 0; + + gob_goblins[0]->doAnim = 0; + gob_goblins[1]->doAnim = 1; + gob_goblins[2]->doAnim = 1; +} + +} // End of namespace Gob diff --git a/gob/map.h b/gob/map.h new file mode 100644 index 0000000000..10d335216b --- /dev/null +++ b/gob/map.h @@ -0,0 +1,57 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __MAP_H +#define __MAP_H + +namespace Gob { + +#pragma START_PACK_STRUCTS +#define szMap_Point 4 +typedef struct Map_Point { + int16 x; + int16 y; +} GCC_PACK Map_Point; + +#define szMap_ItemPos 3 +typedef struct Map_ItemPos { + char x; + char y; + char orient; // ?? +} GCC_PACK Map_ItemPos; +#pragma END_PACK_STRUCTS + +extern char map_passMap[28][26]; // [y][x] +extern int16 map_itemsMap[28][26]; // [y][x] +extern Map_Point map_wayPoints[40]; +extern int16 map_nearestWayPoint; +extern int16 map_nearestDest; + +extern int16 map_curGoblinX; +extern int16 map_curGoblinY; +extern int16 map_destX; +extern int16 map_destY; +extern char map_loadFromAvo; + +extern Map_ItemPos map_itemPoses[40]; +extern char map_sourceFile[15]; +extern char *map_avoDataPtr; + +int16 map_getDirection(int16 x0, int16 y0, int16 x1, int16 y1); +void map_findNearestToGob(void); +void map_findNearestToDest(void); +int16 map_checkDirectPath(int16 x0, int16 y0, int16 x1, int16 y1); +int16 map_checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1); +int16 map_optimizePoints(int16 xPos, int16 yPos); +void map_loadItemToObject(void); +void map_loadMapObjects(char *avjFile); +void map_loadDataFromAvo(char *dest, int16 size); +void map_loadMapsInitGobs(void); + +} // End of namespace Gob + +#endif /* __MAP_H */ diff --git a/gob/module.mk b/gob/module.mk new file mode 100644 index 0000000000..4c45beb67c --- /dev/null +++ b/gob/module.mk @@ -0,0 +1,36 @@ +MODULE := gob + +MODULE_OBJS := \ + gob/anim.o \ + gob/dataio.o \ + gob/debug.o \ + gob/draw.o \ + gob/driver_vga.o \ + gob/game.o \ + gob/global.o \ + gob/goblin.o \ + gob/init.o \ + gob/inter.o \ + gob/map.o \ + gob/mult.o \ + gob/pack.o \ + gob/palanim.o \ + gob/parse.o \ + gob/resource.o \ + gob/scenery.o \ + gob/util.o \ + gob/video.o \ + gob/sound.o \ + gob/timer.o \ + gob/gob.o + +MODULE_DIRS += \ + 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/gob/mult.cpp b/gob/mult.cpp new file mode 100644 index 0000000000..2ecb3d72ba --- /dev/null +++ b/gob/mult.cpp @@ -0,0 +1,1205 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#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/debug.h" +#include "gob/sound.h" +#include "gob/palanim.h" +#include "gob/game.h" + +namespace Gob { + +Mult_Object *mult_objects; +int16 *mult_renderData; +int16 mult_objCount; +int16 mult_frame; + +char *mult_multData; +char mult_doPalSubst; +int16 mult_counter; +int16 mult_frameRate; + +int32 *mult_animArrayX; +int32 *mult_animArrayY; + +Mult_AnimData *mult_animArrayData; + +int16 mult_index; + +// Static keys +int16 mult_staticKeysCount; +Mult_StaticKey *mult_staticKeys; +int16 mult_staticIndices[10]; + +// Anim keys +Mult_AnimKey *mult_animKeys[4]; +int16 mult_animKeysCount[4]; +int16 mult_animLayer; +int16 mult_animIndices[10]; + +// Text keys +int16 mult_textKeysCount; +Mult_TextKey *mult_textKeys; + +int16 mult_frameStart; + +// Palette keys +int16 mult_palKeyIndex; +int16 mult_palKeysCount; +Mult_PalKey *mult_palKeys; +Color *mult_oldPalette; +Color mult_palAnimPalette[256]; +int16 mult_palAnimKey; +int16 mult_palAnimIndices[4]; +int16 mult_palAnimRed[4]; +int16 mult_palAnimGreen[4]; +int16 mult_palAnimBlue[4]; + +// Palette fading +Mult_PalFadeKey *mult_palFadeKeys; +int16 mult_palFadeKeysCount; +char mult_palFadingRed; +char mult_palFadingGreen; +char mult_palFadingBlue; + +Color mult_fadePal[5][16]; + +// Sounds +int16 mult_sndKeysCount; +Mult_SndKey *mult_sndKeys; + +char mult_animDataAllocated; + +char *mult_dataPtr; +int16 mult_staticLoaded[10]; +int16 mult_animLoaded[10]; +int16 mult_sndSlotsCount; + +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 (mult_renderData == 0) + return; + + pDirtyLefts = mult_renderData; + pDirtyRights = pDirtyLefts + mult_objCount; + pDirtyTops = pDirtyRights + mult_objCount; + pDirtyBottoms = pDirtyTops + mult_objCount; + pNeedRedraw = pDirtyBottoms + mult_objCount; + pCurLefts = pNeedRedraw + mult_objCount; + pCurRights = pCurLefts + mult_objCount; + pCurTops = pCurRights + mult_objCount; + pCurBottoms = pCurTops + mult_objCount; + minOrder = 100; + maxOrder = 0; + + //Find dirty areas + for (i = 0; i < mult_objCount; i++) { + pNeedRedraw[i] = 0; + pDirtyTops[i] = 1000; + pDirtyLefts[i] = 1000; + pDirtyBottoms[i] = 1000; + pDirtyRights[i] = 1000; + pAnimData = mult_objects[i].pAnimData; + + if (pAnimData->isStatic == 0 && pAnimData->isPaused == 0 && + mult_objects[i].tick == pAnimData->maxTick) { + if (pAnimData->order < minOrder) + minOrder = pAnimData->order; + + if (pAnimData->order > maxOrder) + maxOrder = pAnimData->order; + + pNeedRedraw[i] = 1; + scen_updateAnim(pAnimData->layer, pAnimData->frame, + pAnimData->animation, 0, + *(mult_objects[i].pPosX), *(mult_objects[i].pPosY), + 0); + + if (mult_objects[i].lastLeft != -1) { + pDirtyLefts[i] = + MIN(mult_objects[i].lastLeft, + scen_toRedrawLeft); + pDirtyTops[i] = + MIN(mult_objects[i].lastTop, + scen_toRedrawTop); + pDirtyRights[i] = + MAX(mult_objects[i].lastRight, + scen_toRedrawRight); + pDirtyBottoms[i] = + MAX(mult_objects[i].lastBottom, + scen_toRedrawBottom); + } else { + pDirtyLefts[i] = scen_toRedrawLeft; + pDirtyTops[i] = scen_toRedrawTop; + pDirtyRights[i] = scen_toRedrawRight; + pDirtyBottoms[i] = scen_toRedrawBottom; + } + pCurLefts[i] = scen_toRedrawLeft; + pCurRights[i] = scen_toRedrawRight; + pCurTops[i] = scen_toRedrawTop; + pCurBottoms[i] = scen_toRedrawBottom; + } else { + if (mult_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] = mult_objects[i].lastLeft; + pDirtyLefts[i] = mult_objects[i].lastLeft; + + pCurTops[i] = mult_objects[i].lastTop; + pDirtyTops[i] = mult_objects[i].lastTop; + + pCurRights[i] = mult_objects[i].lastRight; + pDirtyRights[i] = mult_objects[i].lastRight; + + pCurBottoms[i] = mult_objects[i].lastBottom; + pDirtyBottoms[i] = mult_objects[i].lastBottom; + } + } + } + + // Find intersections + for (i = 0; i < mult_objCount; i++) { + pAnimData = mult_objects[i].pAnimData; + pAnimData->intersected = 200; + + if (pAnimData->isStatic) + continue; + + for (j = 0; j < mult_objCount; j++) { + if (i == j) + continue; + + if (mult_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 < mult_objCount; i++) { + + if (pNeedRedraw[i] == 0 || mult_objects[i].lastLeft == -1) + continue; + + draw_sourceSurface = 22; + draw_destSurface = 21; + draw_spriteLeft = pDirtyLefts[i] - anim_animAreaLeft; + draw_spriteTop = pDirtyTops[i] - anim_animAreaTop; + draw_spriteRight = pDirtyRights[i] - pDirtyLefts[i] + 1; + draw_spriteBottom = pDirtyBottoms[i] - pDirtyTops[i] + 1; + draw_destSpriteX = pDirtyLefts[i]; + draw_destSpriteY = pDirtyTops[i]; + draw_transparency = 0; + draw_spriteOperation(DRAW_BLITSURF); + mult_objects[i].lastLeft = -1; + } + + // Update view + for (order = minOrder; order <= maxOrder; order++) { + for (i = 0; i < mult_objCount; i++) { + pAnimData = mult_objects[i].pAnimData; + if (pAnimData->order != order) + continue; + + if (pNeedRedraw[i]) { + if (pAnimData->isStatic == 0) { + + scen_updateAnim(pAnimData->layer, + pAnimData->frame, + pAnimData->animation, 2, + *(mult_objects[i].pPosX), + *(mult_objects[i].pPosY), 1); + + if (scen_toRedrawLeft != -12345) { + mult_objects[i].lastLeft = + scen_toRedrawLeft; + mult_objects[i].lastTop = + scen_toRedrawTop; + mult_objects[i].lastRight = + scen_toRedrawRight; + mult_objects[i].lastBottom = + scen_toRedrawBottom; + } else { + mult_objects[i].lastLeft = -1; + } + } + scen_updateStatic(order + 1); + } else if (pAnimData->isStatic == 0) { + for (j = 0; j < mult_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; + + scen_toRedrawLeft = pDirtyLefts[j]; + scen_toRedrawRight = pDirtyRights[j]; + scen_toRedrawTop = pDirtyTops[j]; + scen_toRedrawBottom = pDirtyBottoms[j]; + + scen_updateAnim(pAnimData->layer, + pAnimData->frame, + pAnimData->animation, 4, + *(mult_objects[i].pPosX), + *(mult_objects[i].pPosY), 1); + + scen_updateStatic(order + 1); + } + } + } + } + + // Advance animations + for (i = 0; i < mult_objCount; i++) { + pAnimData = mult_objects[i].pAnimData; + if (pAnimData->isStatic || pAnimData->isPaused) + continue; + + if (mult_objects[i].tick == pAnimData->maxTick) { + mult_objects[i].tick = 0; + if (pAnimData->animType == 4) { + pAnimData->isPaused = 1; + pAnimData->frame = 0; + } else { + pAnimData->frame++; + if (pAnimData->frame >= + scen_animations[pAnimData->animation]. + layers[pAnimData->layer]->framesCount) { + switch (pAnimData->animType) { + case 0: + pAnimData->frame = 0; + break; + + case 1: + pAnimData->frame = 0; + + *(mult_objects[i].pPosX) = + *(mult_objects[i].pPosX) + + scen_animations[pAnimData->animation].layers[pAnimData->layer]->animDeltaX; + + *(mult_objects[i].pPosY) = + *(mult_objects[i].pPosY) + + scen_animations[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 { + mult_objects[i].tick++; + } + } +} + +void mult_interGetObjAnimSize(void) { + Mult_AnimData *pAnimData; + int16 objIndex; + + inter_evalExpr(&objIndex); + pAnimData = mult_objects[objIndex].pAnimData; + if (pAnimData->isStatic == 0) { + scen_updateAnim(pAnimData->layer, pAnimData->frame, + pAnimData->animation, 0, *(mult_objects[objIndex].pPosX), + *(mult_objects[objIndex].pPosY), 0); + } + WRITE_LE_UINT32(inter_variables + parse_parseVarIndex(), scen_toRedrawLeft); + WRITE_LE_UINT32(inter_variables + parse_parseVarIndex(), scen_toRedrawTop); + WRITE_LE_UINT32(inter_variables + parse_parseVarIndex(), scen_toRedrawRight); + WRITE_LE_UINT32(inter_variables + parse_parseVarIndex(), scen_toRedrawBottom); +} + +void mult_interInitMult(void) { + int16 oldAnimHeight; + int16 oldAnimWidth; + int16 oldObjCount; + int16 i; + int16 posXVar; + int16 posYVar; + int16 animDataVar; + + oldAnimWidth = anim_animAreaWidth; + oldAnimHeight = anim_animAreaHeight; + oldObjCount = mult_objCount; + + anim_animAreaLeft = inter_load16(); + anim_animAreaTop = inter_load16(); + anim_animAreaWidth = inter_load16(); + anim_animAreaHeight = inter_load16(); + mult_objCount = inter_load16(); + posXVar = parse_parseVarIndex(); + posYVar = parse_parseVarIndex(); + animDataVar = parse_parseVarIndex(); + + if (mult_objects == 0) { + mult_renderData = (int16 *)malloc(sizeof(int16) * mult_objCount * 9); + mult_objects = (Mult_Object *)malloc(sizeof(Mult_Object) * mult_objCount); + + for (i = 0; i < mult_objCount; i++) { + mult_objects[i].pPosX = (int32 *)(inter_variables + i * 4 + (posXVar / 4) * 4); + mult_objects[i].pPosY = (int32 *)(inter_variables + i * 4 + (posYVar / 4) * 4); + mult_objects[i].pAnimData = + (Mult_AnimData *) (inter_variables + animDataVar + + i * 4 * inter_animDataSize); + + mult_objects[i].pAnimData->isStatic = 1; + mult_objects[i].tick = 0; + mult_objects[i].lastLeft = -1; + mult_objects[i].lastRight = -1; + mult_objects[i].lastTop = -1; + mult_objects[i].lastBottom = -1; + } + } else if (oldObjCount != mult_objCount) { + error("mult_interInitMult: Object count changed, but storage didn't (old count = %d, new count = %d)", + oldObjCount, mult_objCount); + } + + if (anim_underAnimSurf != 0 && + (oldAnimWidth != anim_animAreaWidth + || oldAnimHeight != anim_animAreaHeight)) { + vid_freeSurfDesc(anim_underAnimSurf); + anim_underAnimSurf = 0; + } + + if (anim_underAnimSurf == 0) { + anim_underAnimSurf = vid_initSurfDesc(videoMode, + anim_animAreaWidth, anim_animAreaHeight, 0); + + draw_spritesArray[22] = anim_underAnimSurf; + } + + vid_drawSprite(draw_backSurface, anim_underAnimSurf, + anim_animAreaLeft, anim_animAreaTop, + anim_animAreaLeft + anim_animAreaWidth - 1, + anim_animAreaTop + anim_animAreaHeight - 1, 0, 0, 0); + + debug(0, "mult_interInitMult: x = %d, y = %d, w = %d, h = %d", + anim_animAreaLeft, anim_animAreaTop, anim_animAreaWidth, anim_animAreaHeight); + debug(0, " objCount = %d, animation data size = %d", mult_objCount, inter_animDataSize); +} + +void mult_freeMult(void) { + if (anim_underAnimSurf != 0) + vid_freeSurfDesc(anim_underAnimSurf); + + if (mult_objects != 0) + free((char *)mult_objects); + + if (mult_renderData != 0) + free((char *)mult_renderData); + + mult_objects = 0; + mult_renderData = 0; + anim_underAnimSurf = 0; +} + +void mult_interLoadMult(void) { + int16 val; + int16 objIndex; + int16 i; + char *multData; + + debug(0, "mult_interLoadMult: Loading..."); + + inter_evalExpr(&objIndex); + inter_evalExpr(&val); + *mult_objects[objIndex].pPosX = val; + inter_evalExpr(&val); + *mult_objects[objIndex].pPosY = val; + + multData = (char *)mult_objects[objIndex].pAnimData; + for (i = 0; i < 11; i++) { + if ((char)READ_LE_UINT16(inter_execPtr) == (char)99) { + inter_evalExpr(&val); + multData[i] = val; + } else { + inter_execPtr++; + } + } +} + +void mult_freeAll(void) { + int16 i; + + mult_freeMult(); + for (i = 0; i < 10; i++) + scen_freeAnim(i); + + for (i = 0; i < 10; i++) + scen_freeStatic(i); +} + +void mult_initAll(void) { + int16 i; + + mult_objects = 0; + anim_underAnimSurf = 0; + mult_renderData = 0; + + for (i = 0; i < 10; i++) + scen_animPictCount[i] = 0; + + for (i = 0; i < 20; i++) { + scen_spriteRefs[i] = 0; + scen_spriteResId[i] = -1; + } + + for (i = 0; i < 10; i++) + scen_staticPictCount[i] = -1; + + scen_curStaticLayer = -1; + scen_curStatic = -1; +} + +void mult_playSound(Snd_SoundDesc * soundDesc, int16 repCount, int16 freq, + int16 negFreq) { + if (soundDesc->frequency == freq) + snd_playSample(soundDesc, repCount, -negFreq); + else + snd_playSample(soundDesc, repCount, freq); +} + +char mult_drawStatics(char stop) { + if (mult_staticKeys[mult_staticKeysCount - 1].frame > mult_frame) + stop = 0; + + for (mult_counter = 0; mult_counter < mult_staticKeysCount; + mult_counter++) { + if (mult_staticKeys[mult_counter].frame != mult_frame + || mult_staticKeys[mult_counter].layer == -1) + continue; + + for (scen_curStatic = 0, scen_curStaticLayer = mult_staticKeys[mult_counter].layer; + scen_curStaticLayer >= scen_statics[mult_staticIndices[scen_curStatic]].layersCount; + scen_curStatic++) { + scen_curStaticLayer -= + scen_statics[mult_staticIndices[scen_curStatic]].layersCount; + } + + scen_curStatic = mult_staticIndices[scen_curStatic]; + scen_renderStatic(scen_curStatic, scen_curStaticLayer); + vid_drawSprite(draw_backSurface, anim_underAnimSurf, + 0, 0, 319, 199, 0, 0, 0); + } + return stop; +} + +void mult_drawAnims(void) { + Mult_AnimKey *key; + Mult_Object *animObj; + int16 i; + int16 count; + + for (mult_index = 0; mult_index < 4; mult_index++) { + for (mult_counter = 0; mult_counter < mult_animKeysCount[mult_index]; mult_counter++) { + key = &mult_animKeys[mult_index][mult_counter]; + animObj = &mult_objects[mult_index]; + if (key->frame != mult_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 = scen_animations[mult_animIndices[0]].layersCount; + i = 0; + while (animObj->pAnimData->layer >= count) { + animObj->pAnimData->layer -= count; + i++; + + count = scen_animations[mult_animIndices[i]].layersCount; + } + animObj->pAnimData->animation = mult_animIndices[i]; + } else { + animObj->pAnimData->isStatic = 1; + } + } + } +} + +void mult_drawText(char *pStop, char *pStopNoClear) { + char *savedIP; + + int16 cmd; + for (mult_index = 0; mult_index < mult_textKeysCount; mult_index++) { + if (mult_textKeys[mult_index].frame != mult_frame) + continue; + + cmd = mult_textKeys[mult_index].cmd; + if (cmd == 0) { + *pStop = 0; + } else if (cmd == 1) { + *pStopNoClear = 1; + mult_frameStart = 0; + } else if (cmd == 3) { + *pStop = 0; + savedIP = inter_execPtr; + inter_execPtr = (char *)(&mult_textKeys[mult_index].index); + inter_execPtr = savedIP; + } + } +} + +char mult_prepPalAnim(char stop) { + mult_palKeyIndex = -1; + do { + mult_palKeyIndex++; + if (mult_palKeyIndex >= mult_palKeysCount) + return stop; + } while (mult_palKeys[mult_palKeyIndex].frame != mult_frame); + + if (mult_palKeys[mult_palKeyIndex].cmd == -1) { + stop = 0; + mult_doPalSubst = 0; + pPaletteDesc->vgaPal = mult_oldPalette; + + memcpy((char *)mult_palAnimPalette, (char *)pPaletteDesc->vgaPal, 768); + + vid_setFullPalette(pPaletteDesc); + } else { + stop = 0; + mult_doPalSubst = 1; + mult_palAnimKey = mult_palKeyIndex; + + mult_palAnimIndices[0] = 0; + mult_palAnimIndices[1] = 0; + mult_palAnimIndices[2] = 0; + mult_palAnimIndices[3] = 0; + + pPaletteDesc->vgaPal = mult_palAnimPalette; + } + return stop; +} + +void mult_doPalAnim(void) { + int16 off; + int16 off2; + Color *palPtr; + Mult_PalKey *palKey; + + if (mult_doPalSubst == 0) + return; + + for (mult_index = 0; mult_index < 4; mult_index++) { + palKey = &mult_palKeys[mult_palAnimKey]; + + if ((mult_frame % palKey->rates[mult_index]) != 0) + continue; + + mult_palAnimRed[mult_index] = + pPaletteDesc->vgaPal[palKey->subst[0][mult_index] - 1].red; + mult_palAnimGreen[mult_index] = + pPaletteDesc->vgaPal[palKey->subst[0][mult_index] - 1].green; + mult_palAnimBlue[mult_index] = + pPaletteDesc->vgaPal[palKey->subst[0][mult_index] - 1].blue; + + while (1) { + off = palKey->subst[(mult_palAnimIndices[mult_index] + 1) % 16][mult_index]; + if (off == 0) { + off = palKey->subst[mult_palAnimIndices[mult_index]][mult_index] - 1; + + pPaletteDesc->vgaPal[off].red = mult_palAnimRed[mult_index]; + pPaletteDesc->vgaPal[off].green = mult_palAnimGreen[mult_index]; + pPaletteDesc->vgaPal[off].blue = mult_palAnimBlue[mult_index]; + } else { + off = palKey->subst[(mult_palAnimIndices[mult_index] + 1) % 16][mult_index] - 1; + off2 = palKey->subst[mult_palAnimIndices[mult_index]][mult_index] - 1; + + pPaletteDesc->vgaPal[off2].red = pPaletteDesc->vgaPal[off].red; + pPaletteDesc->vgaPal[off2].green = pPaletteDesc->vgaPal[off].green; + pPaletteDesc->vgaPal[off2].blue = pPaletteDesc->vgaPal[off].blue; + } + + mult_palAnimIndices[mult_index] = (mult_palAnimIndices[mult_index] + 1) % 16; + + off = palKey->subst[mult_palAnimIndices[mult_index]][mult_index]; + + if (off == 0) { + mult_palAnimIndices[mult_index] = 0; + off = palKey->subst[0][mult_index] - 1; + + mult_palAnimRed[mult_index] = pPaletteDesc->vgaPal[off].red; + mult_palAnimGreen[mult_index] = pPaletteDesc->vgaPal[off].green; + mult_palAnimBlue[mult_index] = pPaletteDesc->vgaPal[off].blue; + } + if (mult_palAnimIndices[mult_index] == 0) + break; + } + } + + if (colorCount == 256) { + vid_waitRetrace(videoMode); + + palPtr = pPaletteDesc->vgaPal; + for (mult_counter = 0; mult_counter < 16; mult_counter++) { + vid_setPalElem(mult_counter, palPtr->red, palPtr->green, palPtr->blue, 0, 0x13); + palPtr++; + } + + palPtr = pPaletteDesc->vgaPal; + for (mult_counter = 0; mult_counter < 16; mult_counter++) { + redPalette[mult_counter] = palPtr->red; + greenPalette[mult_counter] = palPtr->green; + bluePalette[mult_counter] = palPtr->blue; + palPtr++; + } + } else { + vid_setFullPalette(pPaletteDesc); + } +} + +char mult_doFadeAnim(char stop) { + Mult_PalFadeKey *fadeKey; + + for (mult_index = 0; mult_index < mult_palFadeKeysCount; mult_index++) { + fadeKey = &mult_palFadeKeys[mult_index]; + + if (fadeKey->frame != mult_frame) + continue; + + stop = 0; + if ((fadeKey->flag & 1) == 0) { + if (fadeKey->fade == 0) { + pPaletteDesc->vgaPal = mult_fadePal[fadeKey->palIndex]; + vid_setFullPalette(pPaletteDesc); + } else { + pPaletteDesc->vgaPal = mult_fadePal[fadeKey->palIndex]; + pal_fade(pPaletteDesc, fadeKey->fade, 0); + } + } else { + pPaletteDesc->vgaPal = mult_fadePal[fadeKey->palIndex]; + pal_fade(pPaletteDesc, fadeKey->fade, -1); + + mult_palFadingRed = (fadeKey->flag >> 1) & 1; + mult_palFadingGreen = (fadeKey->flag >> 2) & 1; + mult_palFadingBlue = (fadeKey->flag >> 3) & 1; + } + } + + if (mult_palFadingRed) { + mult_palFadingRed = !pal_fadeStep(1); + stop = 0; + } + if (mult_palFadingGreen) { + mult_palFadingGreen = !pal_fadeStep(2); + stop = 0; + } + if (mult_palFadingBlue) { + mult_palFadingBlue = !pal_fadeStep(3); + stop = 0; + } + return stop; +} + +char mult_doSoundAnim(char stop) { + Mult_SndKey *sndKey; + for (mult_index = 0; mult_index < mult_sndKeysCount; mult_index++) { + sndKey = &mult_sndKeys[mult_index]; + if (sndKey->frame != mult_frame) + continue; + + if (sndKey->cmd != -1) { + if (sndKey->cmd == 1) { + snd_stopSound(0); + stop = 0; + mult_playSound(game_soundSamples[sndKey->soundIndex], sndKey->repCount, + sndKey->freq, sndKey->channel); + + } else if (sndKey->cmd == 4) { + snd_stopSound(0); + stop = 0; + mult_playSound(game_soundSamples[sndKey->soundIndex], sndKey->repCount, + sndKey->freq, sndKey->channel); + } + } else { + if (snd_playingSound) + 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 (mult_multData == 0) + return; + + stopNoClear = 0; + mult_frame = startFrame; + if (endFrame == -1) + endFrame = 32767; + + if (mult_frame == -1) { + mult_doPalSubst = 0; + mult_palFadingRed = 0; + mult_palFadingGreen = 0; + mult_palFadingBlue = 0; + + mult_oldPalette = pPaletteDesc->vgaPal; + memcpy((char *)mult_palAnimPalette, (char *)pPaletteDesc->vgaPal, 768); + + if (anim_underAnimSurf == 0) { + util_setFrameRate(mult_frameRate); + anim_animAreaTop = 0; + anim_animAreaLeft = 0; + anim_animAreaWidth = 320; + anim_animAreaHeight = 200; + mult_objCount = 4; + + mult_objects = (Mult_Object *)malloc(sizeof(Mult_Object) * mult_objCount); + mult_renderData = (int16 *)malloc(sizeof(int16) * 9 * mult_objCount); + + mult_animArrayX = (int32 *)malloc(sizeof(int32) * mult_objCount); + mult_animArrayY = (int32 *)malloc(sizeof(int32) * mult_objCount); + + mult_animArrayData = (Mult_AnimData *)malloc(sizeof(Mult_AnimData) * mult_objCount); + + for (mult_counter = 0; mult_counter < mult_objCount; mult_counter++) { + multObj = &mult_objects[mult_counter]; + + multObj->pPosX = (int32 *)&mult_animArrayX[mult_counter]; + multObj->pPosY = (int32 *)&mult_animArrayY[mult_counter]; + + multObj->pAnimData = &mult_animArrayData[mult_counter]; + + animData = multObj->pAnimData; + animData->isStatic = 1; + + multObj->tick = 0; + multObj->lastLeft = -1; + multObj->lastTop = -1; + multObj->lastRight = -1; + multObj->lastBottom = -1; + } + + anim_underAnimSurf = + vid_initSurfDesc(videoMode, 320, 200, 0); + draw_spritesArray[22] = anim_underAnimSurf; + + vid_drawSprite(draw_backSurface, anim_underAnimSurf, + 0, 0, 319, 199, 0, 0, 0); + + mult_animDataAllocated = 1; + } else + mult_animDataAllocated = 0; + mult_frame = 0; + } + + do { + stop = 1; + + if (READ_LE_UINT32(inter_variables + 0xe8) == 0) { + stop = mult_drawStatics(stop); + mult_drawAnims(); + } + + mult_animate(); + if (handleMouse) { + draw_animateCursor(-1); + } else { + draw_blitInvalidated(); + } + + if (READ_LE_UINT32(inter_variables + 0xe8) == 0) { + mult_drawText(&stop, &stopNoClear); + } + + stop = mult_prepPalAnim(stop); + mult_doPalAnim(); + + stop = mult_doFadeAnim(stop); + stop = mult_doSoundAnim(stop); + + if (mult_frame >= endFrame) + stopNoClear = 1; + + if (snd_playingSound) + stop = 0; + + util_processInput(); + if (checkEscape && util_checkKey() == 0x11b) // Esc + stop = 1; + + mult_frame++; + util_waitEndFrame(); + } while (stop == 0 && stopNoClear == 0); + + if (stopNoClear == 0) { + if (mult_animDataAllocated) { + if (mult_objects) + free((char *)mult_objects); + mult_objects = 0; + + if (mult_renderData) + free((char *)mult_renderData); + mult_renderData = 0; + + if (mult_animArrayX) + free((char *)mult_animArrayX); + mult_animArrayX = 0; + + if (mult_animArrayY) + free((char *)mult_animArrayY); + mult_animArrayY = 0; + + if (mult_animArrayData) + free((char *)mult_animArrayData); + mult_animArrayData = 0; + + if (anim_underAnimSurf) + vid_freeSurfDesc(anim_underAnimSurf); + anim_underAnimSurf = 0; + + mult_animDataAllocated = 0; + } + + if (snd_playingSound != 0) + snd_stopSound(10); + + WRITE_LE_UINT32(inter_variables + 0xe4, -1); + } else { + WRITE_LE_UINT32(inter_variables + 0xe4, mult_frame - 1 - mult_frameStart); + } +} + +void mult_zeroMultData(void) { + mult_multData = 0; +} + +void mult_loadMult(int16 resId) { + char animCount; + char staticCount; + int16 palIndex; + int16 i, j; + + mult_sndSlotsCount = 0; + mult_frameStart = 0; + mult_multData = game_loadExtData(resId, 0, 0); + mult_dataPtr = mult_multData; + + staticCount = mult_dataPtr[0]; + animCount = mult_dataPtr[1]; + mult_dataPtr += 2; + staticCount++; + animCount++; + + for (i = 0; i < staticCount; i++, mult_dataPtr += 14) { + mult_staticIndices[i] = scen_loadStatic(1); + + if (mult_staticIndices[i] >= 100) { + mult_staticIndices[i] -= 100; + mult_staticLoaded[i] = 1; + } else { + mult_staticLoaded[i] = 0; + } + } + + for (i = 0; i < animCount; i++, mult_dataPtr += 14) { + mult_animIndices[i] = scen_loadAnim(1); + + if (mult_animIndices[i] >= 100) { + mult_animIndices[i] -= 100; + mult_animLoaded[i] = 1; + } else { + mult_animLoaded[i] = 0; + } + } + + mult_frameRate = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + + mult_staticKeysCount = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + + mult_staticKeys = (Mult_StaticKey *)malloc(sizeof(Mult_StaticKey) * + mult_staticKeysCount); + for (i = 0; i < mult_staticKeysCount; i++, mult_dataPtr += 4) { + mult_staticKeys[i].frame = (int16)READ_LE_UINT16(mult_dataPtr); + mult_staticKeys[i].layer = (int16)READ_LE_UINT16(mult_dataPtr + 2); + } + + for (j = 0; j < 4; j++) { + mult_animKeysCount[j] = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + + mult_animKeys[j] = (Mult_AnimKey *) malloc(sizeof(Mult_AnimKey) * mult_animKeysCount[j]); + for (i = 0; i < mult_animKeysCount[j]; i++, mult_dataPtr += 10) { + mult_animKeys[j][i].frame = (int16)READ_LE_UINT16(mult_dataPtr); + mult_animKeys[j][i].layer = (int16)READ_LE_UINT16(mult_dataPtr + 2); + mult_animKeys[j][i].posX = (int16)READ_LE_UINT16(mult_dataPtr + 4); + mult_animKeys[j][i].posY = (int16)READ_LE_UINT16(mult_dataPtr + 6); + mult_animKeys[j][i].order = (int16)READ_LE_UINT16(mult_dataPtr + 8); + } + } + + for (palIndex = 0; palIndex < 5; palIndex++) { + for (i = 0; i < 16; i++) { + mult_fadePal[palIndex][i].red = mult_dataPtr[0]; + mult_fadePal[palIndex][i].green = mult_dataPtr[1]; + mult_fadePal[palIndex][i].blue = mult_dataPtr[2]; + mult_dataPtr += 3; + } + } + + mult_palFadeKeysCount = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + mult_palFadeKeys = (Mult_PalFadeKey *)malloc(sizeof(Mult_PalFadeKey) * mult_palFadeKeysCount); + + for (i = 0; i < mult_palFadeKeysCount; i++, mult_dataPtr += 7) { + mult_palFadeKeys[i].frame = (int16)READ_LE_UINT16(mult_dataPtr); + mult_palFadeKeys[i].fade = (int16)READ_LE_UINT16(mult_dataPtr + 2); + mult_palFadeKeys[i].palIndex = (int16)READ_LE_UINT16(mult_dataPtr + 4); + mult_palFadeKeys[i].flag = *(mult_dataPtr + 6); + } + + mult_palKeysCount = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + + mult_palKeys = (Mult_PalKey *)malloc(sizeof(Mult_PalKey) * mult_palKeysCount); + for (i = 0; i < mult_palKeysCount; i++, mult_dataPtr += 80) { + mult_palKeys[i].frame = (int16)READ_LE_UINT16(mult_dataPtr); + mult_palKeys[i].cmd = (int16)READ_LE_UINT16(mult_dataPtr + 2); + mult_palKeys[i].rates[0] = (int16)READ_LE_UINT16(mult_dataPtr + 4); + mult_palKeys[i].rates[1] = (int16)READ_LE_UINT16(mult_dataPtr + 6); + mult_palKeys[i].rates[2] = (int16)READ_LE_UINT16(mult_dataPtr + 8); + mult_palKeys[i].rates[3] = (int16)READ_LE_UINT16(mult_dataPtr + 10); + mult_palKeys[i].unknown0 = (int16)READ_LE_UINT16(mult_dataPtr + 12); + mult_palKeys[i].unknown1 = (int16)READ_LE_UINT16(mult_dataPtr + 14); + memcpy(mult_palKeys[i].subst, mult_dataPtr + 16, 64); + } + + mult_textKeysCount = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + mult_textKeys = (Mult_TextKey *) malloc(sizeof(Mult_TextKey) * mult_textKeysCount); + + for (i = 0; i < mult_textKeysCount; i++, mult_dataPtr += 28) { + mult_textKeys[i].frame = (int16)READ_LE_UINT16(mult_dataPtr); + mult_textKeys[i].cmd = (int16)READ_LE_UINT16(mult_dataPtr + 2); + for (int k = 0; k < 9; ++k) + mult_textKeys[i].unknown0[k] = (int16)READ_LE_UINT16(mult_dataPtr + 4 + (k * 2)); + mult_textKeys[i].index = (int16)READ_LE_UINT16(mult_dataPtr + 22); + mult_textKeys[i].unknown1[0] = (int16)READ_LE_UINT16(mult_dataPtr + 24); + mult_textKeys[i].unknown1[1] = (int16)READ_LE_UINT16(mult_dataPtr + 26); + } + + mult_sndKeysCount = READ_LE_UINT16(mult_dataPtr); + mult_dataPtr += 2; + + mult_sndKeys = (Mult_SndKey *)malloc(sizeof(Mult_SndKey) * mult_sndKeysCount); + for (i = 0; i < mult_sndKeysCount; i++) { + mult_sndKeys[i].frame = (int16)READ_LE_UINT16(mult_dataPtr); + mult_sndKeys[i].cmd = (int16)READ_LE_UINT16(mult_dataPtr + 2); + mult_sndKeys[i].freq = (int16)READ_LE_UINT16(mult_dataPtr + 4); + mult_sndKeys[i].channel = (int16)READ_LE_UINT16(mult_dataPtr + 6); + mult_sndKeys[i].repCount = (int16)READ_LE_UINT16(mult_dataPtr + 8); + mult_sndKeys[i].resId = (int16)READ_LE_UINT16(mult_dataPtr + 10); + mult_sndKeys[i].soundIndex = (int16)READ_LE_UINT16(mult_dataPtr + 12); + + mult_sndKeys[i].soundIndex = -1; + mult_sndKeys[i].resId = -1; + mult_dataPtr += 36; + switch (mult_sndKeys[i].cmd) { + case 1: + case 4: + mult_sndKeys[i].resId = READ_LE_UINT16(inter_execPtr); + + for (j = 0; j < i; j++) { + if (mult_sndKeys[i].resId == + mult_sndKeys[j].resId) { + mult_sndKeys[i].soundIndex = + mult_sndKeys[j].soundIndex; + inter_execPtr += 2; + break; + } + } + if (i == j) { + game_interLoadSound(19 - mult_sndSlotsCount); + mult_sndKeys[i].soundIndex = + 19 - mult_sndSlotsCount; + mult_sndSlotsCount++; + } + break; + + case 3: + inter_execPtr += 6; + break; + + case 5: + inter_execPtr += mult_sndKeys[i].freq * 2; + break; + } + } +} + +void mult_freeMultKeys(void) { + char i; + char animCount; + char staticCount; + + mult_dataPtr = mult_multData; + staticCount = mult_dataPtr[0]; + animCount = mult_dataPtr[1]; + + free(mult_dataPtr); + + staticCount++; + animCount++; + for (i = 0; i < staticCount; i++) { + + if (mult_staticLoaded[i] != 0) + scen_freeStatic(mult_staticIndices[i]); + } + + for (i = 0; i < animCount; i++) { + if (mult_animLoaded[i] != 0) + scen_freeAnim(mult_animIndices[i]); + } + + free((char *)mult_staticKeys); + + for (i = 0; i < 4; i++) + free((char *)mult_animKeys[i]); + + free((char *)mult_palFadeKeys); + free((char *)mult_palKeys); + free((char *)mult_textKeys); + + for (i = 0; i < mult_sndSlotsCount; i++) { + game_freeSoundSlot(19 - i); + } + + free((char *)mult_sndKeys); + + mult_multData = 0; + + if (mult_animDataAllocated != 0) { + if (mult_objects) + free((char *)mult_objects); + mult_objects = 0; + + if (mult_renderData) + free((char *)mult_renderData); + mult_renderData = 0; + + if (mult_animArrayX) + free((char *)mult_animArrayX); + mult_animArrayX = 0; + + if (mult_animArrayY) + free((char *)mult_animArrayY); + mult_animArrayY = 0; + + if (mult_animArrayData) + free((char *)mult_animArrayData); + mult_animArrayData = 0; + + if (anim_underAnimSurf) + vid_freeSurfDesc(anim_underAnimSurf); + anim_underAnimSurf = 0; + + mult_animDataAllocated = 0; + } +} + +void mult_checkFreeMult(void) { + if (mult_multData != 0) + mult_freeMultKeys(); +} + +} // End of namespace Gob diff --git a/gob/mult.h b/gob/mult.h new file mode 100644 index 0000000000..fc375a0d16 --- /dev/null +++ b/gob/mult.h @@ -0,0 +1,185 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __MULT_H +#define __MULT_H + +#include "gob/sound.h" + +namespace Gob { + +#pragma START_PACK_STRUCTS +typedef struct Mult_AnimData { + char animation; + char layer; + char frame; + char animType; + char order; + char isPaused; + char isStatic; + char maxTick; + char unknown; + char newLayer; + char newAnimation; + byte intersected; + char newCycle; +} GCC_PACK Mult_AnimData; + +typedef struct Mult_Object { + int32 *pPosX; + int32 *pPosY; + Mult_AnimData *pAnimData; + int16 tick; + int16 lastLeft; + int16 lastRight; + int16 lastTop; + int16 lastBottom; +} Mult_Object; + +// Mult +typedef struct Mult_StaticKey { + int16 frame; + int16 layer; +} GCC_PACK Mult_StaticKey; + +typedef struct Mult_AnimKey { + int16 frame; + int16 layer; + int16 posX; + int16 posY; + int16 order; +} GCC_PACK Mult_AnimKey; + +typedef struct Mult_TextKey { + int16 frame; + int16 cmd; + int16 unknown0[9]; + int16 index; + int16 unknown1[2]; +} GCC_PACK Mult_TextKey; + +typedef struct Mult_PalKey { + int16 frame; + int16 cmd; + int16 rates[4]; + int16 unknown0; + int16 unknown1; + char subst[16][4]; +} GCC_PACK Mult_PalKey; + +typedef struct Mult_PalFadeKey { + int16 frame; + int16 fade; + int16 palIndex; + char flag; +} GCC_PACK Mult_PalFadeKey; + +typedef struct Mult_SndKey { + int16 frame; + int16 cmd; + int16 freq; + int16 channel; + int16 repCount; + int16 resId; + int16 soundIndex; +} GCC_PACK Mult_SndKey; +#pragma END_PACK_STRUCTS + +// Globals + +extern Mult_Object *mult_objects; +extern int16 *mult_renderData; +extern int16 mult_objCount; +extern SurfaceDesc *mult_underAnimSurf; + +extern char *mult_multData; +extern int16 mult_frame; +extern char mult_doPalSubst; +extern int16 mult_counter; +extern int16 mult_frameRate; + +extern int32 *mult_animArrayX; +extern int32 *mult_animArrayY; + +extern Mult_AnimData *mult_animArrayData; + +extern int16 mult_index; + +// Static keys +extern int16 mult_staticKeysCount; +extern Mult_StaticKey *mult_staticKeys; +extern int16 mult_staticIndices[10]; + +// Anim keys +extern Mult_AnimKey *mult_animKeys[4]; +extern int16 mult_animKeysCount[4]; +extern int16 mult_animLayer; +extern int16 mult_animIndices[10]; + +// Text keys +extern int16 mult_textKeysCount; +extern Mult_TextKey *mult_textKeys; + +extern int16 mult_frameStart; + +// Palette keys +extern int16 mult_palKeyIndex; +extern int16 mult_palKeysCount; +extern Mult_PalKey *mult_palKeys; +extern Color *mult_oldPalette; +extern Color mult_palAnimPalette[256]; +extern int16 mult_palAnimKey; +extern int16 mult_palAnimIndices[4]; +extern int16 mult_palAnimRed[4]; +extern int16 mult_palAnimGreen[4]; +extern int16 mult_palAnimBlue[4]; + +// Palette fading +extern Mult_PalFadeKey *mult_palFadeKeys; +extern int16 mult_palFadeKeysCount; +extern char mult_palFadingRed; +extern char mult_palFadingGreen; +extern char mult_palFadingBlue; + +extern char mult_animDataAllocated; + +extern char *mult_dataPtr; +extern int16 mult_staticLoaded[10]; +extern int16 mult_animLoaded[10]; +extern int16 mult_sndSlotsCount; + +// Sound keys +extern int16 mult_sndKeysCount; +extern Mult_SndKey *mult_sndKeys; + +void mult_playSound(Snd_SoundDesc * soundDesc, int16 repCount, int16 freq, + int16 negFreq); +void mult_zeroMultData(void); +void mult_loadMult(int16 resId); +void mult_freeMultKeys(void); +void mult_checkFreeMult(void); +void mult_playMult(int16 startFrame, int16 endFrame, char checkEscape, + char handleMouse); +void mult_animate(void); +void mult_interGetObjAnimSize(void); +void mult_interInitMult(void); +void mult_freeMult(void); +void mult_interLoadMult(void); +void mult_freeAll(void); +void mult_initAll(void); +void mult_playSound(Snd_SoundDesc * soundDesc, int16 repCount, int16 freq, + int16 negFreq); +void mult_playMult(int16 startFrame, int16 endFrame, char checkEscape, + char handleMouse); +void mult_zeroMultData(void); +void mult_loadMult(int16 resId); +void mult_freeMultKeys(void); +void mult_checkFreeMult(void); + +} // End of namespace Gob + +#endif /* __MULT_H */ diff --git a/gob/pack.cpp b/gob/pack.cpp new file mode 100644 index 0000000000..064321c5e9 --- /dev/null +++ b/gob/pack.cpp @@ -0,0 +1,94 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/pack.h" +#include "gob/debug.h" + +namespace Gob { + +int32 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 = (byte *)malloc(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) { + free(tmpBuf); + return realSize; + } + tmpBuf[tmpIndex] = tmpBuf[(off + i) % 4096]; + tmpIndex++; + tmpIndex %= 4096; + } + } + } + free(tmpBuf); + return realSize; +} + +} // End of namespace Gob diff --git a/gob/pack.h b/gob/pack.h new file mode 100644 index 0000000000..11929834fe --- /dev/null +++ b/gob/pack.h @@ -0,0 +1,18 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __UNPACKER_H +#define __UNPACKER_H + +namespace Gob { + +int32 asm_unpackData(char *source, char *dest, char *temp); +int32 unpackData(char *source, char *dest); + +} // End of namespace Gob + +#endif diff --git a/gob/palanim.cpp b/gob/palanim.cpp new file mode 100644 index 0000000000..ad4a9f3e07 --- /dev/null +++ b/gob/palanim.cpp @@ -0,0 +1,224 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/video.h" +#include "gob/util.h" +#include "gob/global.h" +#include "gob/palanim.h" +#include "gob/debug.h" + +namespace Gob { + +int16 pal_fadeValue = 1; + +char pal_toFadeRed[256]; +char pal_toFadeGreen[256]; +char pal_toFadeBlue[256]; + +char pal_fadeColor(char from, char to) { + if ((int16)from - pal_fadeValue > (int16)to) + return from - pal_fadeValue; + else if ((int16)from + pal_fadeValue < (int16)to) + return from + pal_fadeValue; + else + return to; +} + +char pal_fadeStep(int16 oper) { + char newRed; + char newGreen; + char newBlue; + char stop; + int16 i; + + if (colorCount != 256) + error("pal_fadeStep: Only 256 color mode is supported!"); + + if (oper == 0) { + stop = 1; + if (setAllPalette) { + if (inVM != 0) + error("pal_fade: inVM != 0 not supported."); + + for (i = 0; i < 256; i++) { + newRed = + pal_fadeColor(redPalette[i], + pal_toFadeRed[i]); + newGreen = + pal_fadeColor(greenPalette[i], + pal_toFadeGreen[i]); + newBlue = + pal_fadeColor(bluePalette[i], + pal_toFadeBlue[i]); + + if (redPalette[i] != newRed + || greenPalette[i] != newGreen + || bluePalette[i] != newBlue) { + + vid_setPalElem(i, newRed, newGreen, newBlue, 0, 0x13); + + redPalette[i] = newRed; + greenPalette[i] = newGreen; + bluePalette[i] = newBlue; + stop = 0; + } + } + } else { + for (i = 0; i < 16; i++) { + + vid_setPalElem(i, + pal_fadeColor(redPalette[i], + pal_toFadeRed[i]), + pal_fadeColor(greenPalette[i], + pal_toFadeGreen[i]), + pal_fadeColor(bluePalette[i], + pal_toFadeBlue[i]), -1, videoMode); + + if (redPalette[i] != pal_toFadeRed[i] || + greenPalette[i] != pal_toFadeGreen[i] || + bluePalette[i] != pal_toFadeBlue[i]) + stop = 0; + } + } + return stop; + } else if (oper == 1) { + stop = 1; + for (i = 0; i < 16; i++) { + vid_setPalElem(i, + pal_fadeColor(redPalette[i], pal_toFadeRed[i]), + greenPalette[i], bluePalette[i], -1, videoMode); + + if (redPalette[i] != pal_toFadeRed[i]) + stop = 0; + } + return stop; + } else if (oper == 2) { + stop = 1; + for (i = 0; i < 16; i++) { + vid_setPalElem(i, + redPalette[i], + pal_fadeColor(greenPalette[i], pal_toFadeGreen[i]), + bluePalette[i], -1, videoMode); + + if (greenPalette[i] != pal_toFadeGreen[i]) + stop = 0; + } + return stop; + } else if (oper == 3) { + stop = 1; + for (i = 0; i < 16; i++) { + vid_setPalElem(i, + redPalette[i], + greenPalette[i], + pal_fadeColor(bluePalette[i], pal_toFadeBlue[i]), + -1, videoMode); + + if (bluePalette[i] != pal_toFadeBlue[i]) + stop = 0; + } + return stop; + } + return 1; +} + +void pal_fade(PalDesc * palDesc, int16 fade, int16 allColors) { + char stop; + int16 i; + + if (fade < 0) + pal_fadeValue = -fade; + else + pal_fadeValue = 2; + + if (colorCount < 256) { + if (palDesc != 0) + vid_setFullPalette(palDesc); + return; + } + + if (setAllPalette == 0) { + if (palDesc == 0) { + for (i = 0; i < 16; i++) { + pal_toFadeRed[i] = 0; + pal_toFadeGreen[i] = 0; + pal_toFadeBlue[i] = 0; + } + } else { + for (i = 0; i < 16; i++) { + pal_toFadeRed[i] = palDesc->vgaPal[i].red; + pal_toFadeGreen[i] = palDesc->vgaPal[i].green; + pal_toFadeBlue[i] = palDesc->vgaPal[i].blue; + } + } + } else { + if (inVM != 0) + error("pal_fade: inVM != 0 is not supported"); + + if (palDesc == 0) { + for (i = 0; i < 256; i++) { + pal_toFadeRed[i] = 0; + pal_toFadeGreen[i] = 0; + pal_toFadeBlue[i] = 0; + } + } else { + for (i = 0; i < 256; i++) { + pal_toFadeRed[i] = palDesc->vgaPal[i].red; + pal_toFadeGreen[i] = palDesc->vgaPal[i].green; + pal_toFadeBlue[i] = palDesc->vgaPal[i].blue; + } + } + } + + if (allColors == 0) { + + do { + if (tmpPalBuffer == 0) + vid_waitRetrace(videoMode); + + stop = pal_fadeStep(0); + + if (fade > 0) + util_delay(fade); + } while (stop == 0); + + if (palDesc != 0) + vid_setFullPalette(palDesc); + else + util_clearPalette(); + } + + if (allColors == 1) { + + do { + vid_waitRetrace(videoMode); + stop = pal_fadeStep(1); + } while (stop == 0); + + do { + vid_waitRetrace(videoMode); + stop = pal_fadeStep(2); + } while (stop == 0); + + do { + vid_waitRetrace(videoMode); + stop = pal_fadeStep(3); + } while (stop == 0); + + if (palDesc != 0) + vid_setFullPalette(palDesc); + else + util_clearPalette(); + } + + if (tmpPalBuffer != 0) { + free((char *)tmpPalBuffer); + tmpPalBuffer = 0; + } +} + +} // End of namespace Gob diff --git a/gob/palanim.h b/gob/palanim.h new file mode 100644 index 0000000000..28bffc6351 --- /dev/null +++ b/gob/palanim.h @@ -0,0 +1,21 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __PALANIM_H +#define __PALANIM_H + +namespace Gob { + +extern int16 pal_fadeValue; + +char pal_fadeColor(char from, char to); +char pal_fadeStep(int16 oper); // oper == 0 - fade all colors, 1, 2, 3 - red,green, blue +void pal_fade(PalDesc * palDesc, int16 fade, int16 all); + +} // End of namespace Gob + +#endif /* __PALANIM_H */ diff --git a/gob/parse.cpp b/gob/parse.cpp new file mode 100644 index 0000000000..aef83d367d --- /dev/null +++ b/gob/parse.cpp @@ -0,0 +1,1210 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/parse.h" +#include "gob/util.h" +#include "gob/debug.h" +#include "gob/inter.h" + +namespace Gob { + +int16 parse_parseExpr(char arg_0, 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 = *inter_execPtr++; + if (operation >= 19 && operation <= 29) { + switch (operation) { + case 19: + *operPtr = 20; + *valPtr = READ_LE_UINT32(inter_execPtr); + inter_execPtr += 4; + break; + + case 20: + *operPtr = 20; + *valPtr = inter_load16(); + break; + + case 22: + *operPtr = 22; + *valPtr = (int32)inter_execPtr; + inter_execPtr += strlen(inter_execPtr) + 1; + break; + + case 23: + *operPtr = 20; + *valPtr = READ_LE_UINT32(inter_variables + inter_load16() * 4); + break; + + case 25: + *operPtr = 22; + temp = inter_load16() * 4; + *valPtr = (int32)(inter_variables + temp); + if (*inter_execPtr == 13) { + inter_execPtr++; + temp += parse_parseValExpr(); + *operPtr = 20; + *valPtr = *(inter_variables + temp); + } + break; + + case 26: + case 28: + *operPtr = operation - 6; + temp = inter_load16(); + dimCount = *inter_execPtr++; + arrDescPtr = (byte *)inter_execPtr; + inter_execPtr += dimCount; + offset = 0; + dim = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parse_parseValExpr(); + offset = offset * arrDescPtr[dim] + temp2; + } + + if (operation == 26) { + *valPtr = READ_LE_UINT32(inter_variables + temp * 4 + offset * 4); + break; + } + *valPtr = (int32)(inter_variables + temp * 4 + offset * inter_animDataSize * 4); + if (*inter_execPtr == 13) { + inter_execPtr++; + temp2 = parse_parseValExpr(); + *operPtr = 20; + *valPtr = *(inter_variables + temp * 4 + offset * 4 * inter_animDataSize + temp2); + } + break; + + case 29: + operation = *inter_execPtr++; + parse_parseExpr(10, 0); + + switch (operation) { + case 5: + inter_resVal = inter_resVal * inter_resVal; + break; + + case 0: + case 1: + case 6: + curVal = 1; + prevVal = 1; + + do { + prevPrevVal = prevVal; + prevVal = curVal; + curVal = (curVal + inter_resVal / curVal) / 2; + } while (curVal != prevVal && curVal != prevPrevVal); + inter_resVal = curVal; + break; + + case 10: + inter_resVal = util_getRandom(inter_resVal); + break; + + case 7: + if (inter_resVal < 0) + inter_resVal = -inter_resVal; + break; + } + *operPtr = 20; + *valPtr = 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 ((char *)valPtr[-2] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-2]); + valPtr[-2] = (int32)inter_resStr; + } + strcat((char *)valPtr[-2], (char *)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 == arg_0 || operation == 30 || operation == 31 || operation == 10) { + while (stkPos >= 2) { + var_1A = 0; + if (operPtr[-2] == 9 && (operation == 10 || operation == arg_0)) { + 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 != arg_0) + 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 ((char *)values[brackStart] + != inter_resStr) { + strcpy(inter_resStr, (char *)values[brackStart]); + values[brackStart] = (int32)inter_resStr; + } + strcat((char *)values[brackStart], (char *)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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + if (strcmp((char *)valPtr[-3], (char *)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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + if (strcmp((char *)valPtr[-3], (char *)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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + if (strcmp((char *)valPtr[-3], (char *)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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + if (strcmp((char *)valPtr[-3], (char *)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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + if (strcmp((char *)valPtr[-3], (char *)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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + if (strcmp((char *)valPtr[-3], (char *)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) { + parse_skipExpr(10); + operPtr[-2] = operPtr[-1]; + stkPos -= 2; + operPtr -= 2; + valPtr -= 2; + } else { + parse_skipExpr(arg_0); + } + operation = 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 != arg_0) + continue; + + if (arg_2 != 0) + *arg_2 = operStack[0]; + + switch (operStack[0]) { + case 20: + inter_resVal = values[0]; + break; + + case 22: + if ((char *)values[0] != inter_resStr) + strcpy(inter_resStr, + (char *)values[0]); + break; + + case 11: + if (arg_2 != 0) + *arg_2 ^= 1; + break; + + case 23: + case 24: + break; + + default: + inter_resVal = 0; + if (arg_2 != 0) + *arg_2 = 20; + break; + } + return 0; + } // operation == arg_0 || 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 ((char *)valPtr[-3] != inter_resStr) { + strcpy(inter_resStr, (char *)valPtr[-3]); + valPtr[-3] = (int32)inter_resStr; + } + strcat((char *)valPtr[-3], (char *)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; + } +} + +void parse_skipExpr(char arg_0) { + int16 dimCount; + char operation; + int16 num; + int16 dim; + + num = 0; + while (1) { + operation = *inter_execPtr++; + + if (operation >= 19 && operation <= 29) { + switch (operation) { + case 20: + case 23: + inter_execPtr += 2; + break; + + case 19: + inter_execPtr += 4; + break; + + case 22: + inter_execPtr += strlen(inter_execPtr) + 1; + break; + + case 25: + inter_execPtr += 2; + if (*inter_execPtr == 13) { + inter_execPtr++; + parse_skipExpr(12); + } + break; + + case 26: + case 28: + dimCount = inter_execPtr[2]; + inter_execPtr += 3 + dimCount; // ??? + for (dim = 0; dim < dimCount; dim++) + parse_skipExpr(12); + + if (operation == 28 && *inter_execPtr == 13) { + inter_execPtr++; + parse_skipExpr(12); + } + break; + + case 29: + inter_execPtr++; + parse_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 != arg_0) + continue; + + if (arg_0 != 10 || num < 0) + return; + } +} + +int16 parse_parseValExpr() { + 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; + parse_printExpr(99); + } + + stkPos = -1; + operPtr = operStack - 1; + valPtr = values - 1; + + while (1) { + stkPos++; + operPtr++; + valPtr++; + + operation = *inter_execPtr++; + if (operation >= 19 && operation <= 29) { + *operPtr = 20; + switch (operation) { + case 19: + *valPtr = READ_LE_UINT32(inter_execPtr); + inter_execPtr += 4; + break; + + case 20: + *valPtr = inter_load16(); + break; + + case 23: + *valPtr = READ_LE_UINT16(inter_variables + inter_load16() * 4); + break; + + case 25: + temp = inter_load16() * 4; + inter_execPtr++; + temp += parse_parseValExpr(); + *valPtr = *(inter_variables + temp); + break; + + case 26: + case 28: + temp = inter_load16(); + dimCount = *inter_execPtr++; + arrDesc = (byte*)inter_execPtr; + inter_execPtr += dimCount; + offset = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parse_parseValExpr(); + offset = arrDesc[dim] * offset + temp2; + } + if (operation == 26) { + *valPtr = READ_LE_UINT16(inter_variables + temp * 4 + offset * 4); + } else { + inter_execPtr++; + temp2 = parse_parseValExpr(); + *valPtr = *(inter_variables + temp * 4 + offset * 4 * inter_animDataSize + temp2); + } + break; + + case 29: + operation = *inter_execPtr++; + parse_parseExpr(10, 0); + + if (operation == 5) { + inter_resVal = inter_resVal * inter_resVal; + } else if (operation == 7) { + if (inter_resVal < 0) + inter_resVal = -inter_resVal; + } else if (operation == 10) { + inter_resVal = util_getRandom(inter_resVal); + } + *valPtr = 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) { + flag = oldflag; + return values[0]; + } + + stkPos--; + operPtr--; + valPtr--; + } +} + +int16 parse_parseVarIndex() { + int16 temp2; + char *arrDesc; + int16 dim; + int16 dimCount; + int16 operation; + int16 temp; + int16 offset; + int16 val; + + operation = *inter_execPtr++; + debug(5, "var parse = %d\n", operation); + switch (operation) { + case 23: + case 25: + temp = inter_load16() * 4; + debug(5, "oper = %d\n", (int16)*inter_execPtr); + if (operation == 25 && *inter_execPtr == 13) { + inter_execPtr++; + val = parse_parseValExpr(); + temp += val; + debug(5, "parse subscript = %d\n", val); + } + return temp; + + case 26: + case 28: + temp = inter_load16() * 4; + dimCount = *inter_execPtr++; + arrDesc = inter_execPtr; + inter_execPtr += dimCount; + offset = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parse_parseValExpr(); + offset = arrDesc[dim] * offset + temp2; + } + offset *= 4; + if (operation != 28) + return temp + offset; + + if (*inter_execPtr == 13) { + inter_execPtr++; + temp += parse_parseValExpr(); + } + return offset * inter_animDataSize + temp; + + default: + return 0; + } +} + +void parse_printExpr(char arg_0) { + int16 dimCount; + char operation; + int16 num; + int16 dim; + char *arrDesc; + char func; + char saved = 0; + static char *savedPos = 0; + + if (savedPos == 0) { + savedPos = inter_execPtr; + saved = 1; + } + + num = 0; + while (1) { + operation = *inter_execPtr++; + + if (operation >= 19 && operation <= 29) { + switch (operation) { + case 19: + debug(5, "%l", READ_LE_UINT32(inter_execPtr)); + inter_execPtr += 4; + break; + + case 20: + debug(5, "%d", inter_load16()); + break; + + case 22: + debug(5, "\42%s\42", inter_execPtr); + inter_execPtr += strlen(inter_execPtr) + 1; + break; + + case 23: + debug(5, "var_%d", inter_load16()); + break; + + case 25: + debug(5, "(&var_%d)", inter_load16()); + if (*inter_execPtr == 13) { + inter_execPtr++; + debug(5, "{"); + parse_printExpr(12); +// debug(5, "}"); + } + break; + + case 26: + case 28: + if (operation == 28) + debug(5, "(&"); + + debug(5, "var_%d[", inter_load16()); + dimCount = *inter_execPtr++; + arrDesc = inter_execPtr; + inter_execPtr += dimCount; + for (dim = 0; dim < dimCount; dim++) { + parse_printExpr(12); + debug(5, " of %d", (int16)arrDesc[dim]); + if (dim != dimCount - 1) + debug(5, ","); + } + debug(5, "]"); + if (operation == 28) + debug(5, ")"); + + if (operation == 28 && *inter_execPtr == 13) { + inter_execPtr++; + debug(5, "{"); + parse_printExpr(12); +// debug(5, "}"); + } + break; + + case 29: + func = *inter_execPtr++; + if (func == 5) + debug(5, "sqr("); + else if (func == 10) + debug(5, "rand("); + else if (func == 7) + debug(5, "abs("); + else if (func == 0 || func == 1 || func == 6) + debug(5, "sqrt("); + else + debug(5, "id("); + parse_printExpr(10); + break; + + case 12: + debug(5, "}"); + break; + + default: + debug(5, "<%d>", (int16)operation); + break; + } + continue; + } // if(operation >= 19 && operation <= 29) + switch (operation) { + case 9: + debug(5, "("); + break; + + case 11: + debug(5, "!"); + break; + + case 10: + debug(5, ")"); + break; + + case 1: + debug(5, "-"); + break; + + case 2: + debug(5, "+"); + break; + + case 3: + debug(5, "-"); + break; + + case 4: + debug(5, "|"); + break; + + case 5: + debug(5, "*"); + break; + + case 6: + debug(5, "/"); + break; + + case 7: + debug(5, "%"); + break; + + case 8: + debug(5, "&"); + break; + + case 30: + debug(5, "||"); + break; + + case 31: + debug(5, "&&"); + break; + + case 32: + debug(5, "<"); + break; + + case 33: + debug(5, "<="); + break; + + case 34: + debug(5, ">"); + break; + + case 35: + debug(5, ">="); + break; + + case 36: + debug(5, "=="); + break; + + case 37: + debug(5, "!="); + break; + + case 99: + debug(5, "\n"); + break; + + case 12: + debug(5, "}"); + break; + + default: + debug(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 == arg_0) { + if (arg_0 != 10 || num < 0) { + + if (saved != 0) { + inter_execPtr = savedPos; + savedPos = 0; + } + return; + } + } + } +} + +void parse_printVarIndex() { + char *arrDesc; + int16 dim; + int16 dimCount; + int16 operation; + int16 temp; + + char *pos = inter_execPtr; + + operation = *inter_execPtr++; + switch (operation) { + case 23: + case 25: + temp = inter_load16() * 4; + debug(5, "&var_%d", temp); + if (operation == 25 && *inter_execPtr == 13) { + inter_execPtr++; + debug(5, "+"); + parse_printExpr(99); + } + break; + + case 26: + case 28: + debug(5, "&var_%d[", inter_load16()); + dimCount = *inter_execPtr++; + arrDesc = inter_execPtr; + inter_execPtr += dimCount; + for (dim = 0; dim < dimCount; dim++) { + parse_printExpr(12); + debug(5, " of %d", (int16)arrDesc[dim]); + if (dim != dimCount - 1) + debug(5, ","); + } + debug(5, "]"); + + if (operation == 28 && *inter_execPtr == 13) { + inter_execPtr++; + debug(5, "+"); + parse_printExpr(99); + } + break; + + default: + debug(5, "var_0"); + break; + } + debug(5, "\n"); + inter_execPtr = pos; + return; +} + +} // End of namespace Gob diff --git a/gob/parse.h b/gob/parse.h new file mode 100644 index 0000000000..437f13a191 --- /dev/null +++ b/gob/parse.h @@ -0,0 +1,22 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __PARSE_H +#define __PARSE_H + +namespace Gob { + +int16 parse_parseExpr(char stopToken, byte *resultPtr); +void parse_skipExpr(char stopToken); +int16 parse_parseValExpr(void); +int16 parse_parseVarIndex(void); +void parse_printExpr(char stopToken); +void parse_printVarIndex(void); + +} // End of namespace Gob + +#endif diff --git a/gob/resource.cpp b/gob/resource.cpp new file mode 100644 index 0000000000..0db2b8d1e3 --- /dev/null +++ b/gob/resource.cpp @@ -0,0 +1,90 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/video.h" +#include "gob/resource.h" +#include "gob/debug.h" + +namespace Gob { + +char *resourceBuf = 0; + +static char *resourcePtr; + +void res_Free(void) { + if (resourceBuf != 0) { + free(resourceBuf); + resourceBuf = 0; + } +} + +void res_Init(void) { + int16 handle; + int16 fileSize; + struct stat statBuf; + handle = open("ALL.ASK", O_RDONLY); + if (handle < 0) { + error("ALL.ASK is missing."); + } + if (stat("ALL.ASK", &statBuf) == -1) + error("res_Init: Error with stat()\n"); + fileSize = statBuf.st_size; + + resourceBuf = (char *)malloc(fileSize * 4); + read(handle, resourceBuf, fileSize); + close(handle); +} + +void res_Search(char resid) { + int16 lang; + if (resourceBuf == 0) + res_Init(); + + lang = (language == 5) ? 2 : language; + + resourcePtr = resourceBuf; + while (*resourcePtr != '#') { + if (resourcePtr[0] == '@' && resourcePtr[1] == resid && + ((int16)lang + '0') == (int16)resourcePtr[2]) { + resourcePtr += 5; + return; + + } + resourcePtr++; + } + resourcePtr = resourceBuf; + while (resourcePtr[0] != '#') { + if (resourcePtr[0] == '@' && resourcePtr[1] == resid) { + resourcePtr += 5; + return; + } + resourcePtr++; + } + return; +} + +void res_Get(char *buf) { + int16 i = 0; + while (1) { + if (*resourcePtr == '\r') + resourcePtr++; + + if (*resourcePtr == '\n') { + resourcePtr++; + break; + } + + buf[i] = *resourcePtr; + i++; + resourcePtr++; + } + buf[i] = 0; +} + +} // End of namespace Gob diff --git a/gob/resource.h b/gob/resource.h new file mode 100644 index 0000000000..f59a1d8b83 --- /dev/null +++ b/gob/resource.h @@ -0,0 +1,20 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __RESOURCE_H +#define __RESOURCE_H + +namespace Gob { + +void res_Free(void); +void res_Init(void); +void res_Search(char resid); +void res_Get(char *buf); + +} // End of namespace Gob + +#endif diff --git a/gob/scenery.cpp b/gob/scenery.cpp new file mode 100644 index 0000000000..c42f3e879d --- /dev/null +++ b/gob/scenery.cpp @@ -0,0 +1,738 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/scenery.h" +#include "gob/debug.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" + +namespace Gob { + +int16 scen_spriteResId[20]; +char scen_spriteRefs[20]; + +Scen_Static scen_statics[10]; +int16 scen_staticPictCount[10]; +char scen_staticFromExt[10]; +int16 scen_staticResId[10]; +char scen_staticPictToSprite[70]; + +Scen_Animation scen_animations[10]; +int16 scen_animPictCount[10]; +char scen_animFromExt[10]; +int16 scen_animResId[10]; +char scen_animPictToSprite[70]; + +int16 scen_curStatic; +int16 scen_curStaticLayer; + +int16 scen_toRedrawLeft; +int16 scen_toRedrawRight; +int16 scen_toRedrawTop; +int16 scen_toRedrawBottom; + +int16 scen_animTop; +int16 scen_animLeft; + +int16 *scen_pCaptureCounter; + +int16 scen_loadStatic(char search) { + int16 tmp; + int16 *backsPtr; + int16 picsCount; + int16 resId; + int16 i; + int16 sceneryIndex; + char *dataPtr; + Scen_Static *ptr; + int16 offset; + int16 pictDescId; + int16 width; + int16 height; + int16 sprResId; + int16 sprIndex; + + inter_evalExpr(&sceneryIndex); + tmp = inter_load16(); + backsPtr = (int16 *)inter_execPtr; + inter_execPtr += tmp * 2; + picsCount = inter_load16(); + resId = inter_load16(); + if (search) { + for (i = 0; i < 10; i++) { + if (scen_staticPictCount[i] != -1 && scen_staticResId[i] == resId) { + inter_execPtr += 8 * scen_staticPictCount[i]; + return i; + } + + if (scen_staticPictCount[i] == -1 && i < sceneryIndex) + sceneryIndex = i; + } + } + + scen_staticPictCount[sceneryIndex] = picsCount; + scen_staticResId[sceneryIndex] = resId; + + if (resId >= 30000) { + scen_staticFromExt[sceneryIndex] = 1; + dataPtr = game_loadExtData(resId, 0, 0); + } else { + scen_staticFromExt[sceneryIndex] = 0; + dataPtr = game_loadTotResource(resId); + } + + ptr = &scen_statics[sceneryIndex]; + ptr->dataPtr = dataPtr; + + ptr->layersCount = (int16)READ_LE_UINT16(dataPtr); + dataPtr += 2; + debug("layer: %d", ptr->layersCount); + + ptr->layers = (Scen_StaticLayer **)malloc(sizeof(Scen_StaticLayer *) * ptr->layersCount); + ptr->pieces = (Scen_PieceDesc **)malloc(sizeof(Scen_PieceDesc *) * picsCount); + + for (i = 0; i < ptr->layersCount; i++) { + offset = ((int16 *)dataPtr)[i]; + ptr->layers[i] = (Scen_StaticLayer *)(dataPtr + offset - 2); + ptr->layers[i]->backResId = *backsPtr; + backsPtr++; + } + + for (i = 0; i < picsCount; i++) { + pictDescId = inter_load16(); + if (resId >= 30000) { + ptr->pieces[i] = + (Scen_PieceDesc *) game_loadExtData(pictDescId, 0, + 0); + } else { + ptr->pieces[i] = + (Scen_PieceDesc *) + game_loadTotResource(pictDescId); + } + + width = inter_load16(); + height = inter_load16(); + sprResId = inter_load16(); + for (sprIndex = 0; sprIndex < 20; sprIndex++) { + if (scen_spriteResId[sprIndex] == sprResId) + break; + } + + if (sprIndex < 20) { + scen_staticPictToSprite[7 * sceneryIndex + i] = + sprIndex; + scen_spriteRefs[sprIndex]++; + } else { + for (sprIndex = 19; draw_spritesArray[sprIndex] != 0; + sprIndex--); + + scen_staticPictToSprite[7 * sceneryIndex + i] = + sprIndex; + scen_spriteRefs[sprIndex] = 1; + scen_spriteResId[sprIndex] = sprResId; + draw_spritesArray[sprIndex] = + vid_initSurfDesc(videoMode, width, height, 2); + + vid_clearSurf(draw_spritesArray[sprIndex]); + draw_destSurface = sprIndex; + draw_spriteLeft = sprResId; + draw_transparency = 0; + draw_destSpriteX = 0; + draw_destSpriteY = 0; + draw_spriteOperation(DRAW_LOADSPRITE); + } + } + return sceneryIndex + 100; +} + +void scen_freeStatic(int16 index) { + int16 i; + int16 spr; + + if (index == -1) + inter_evalExpr(&index); + + if (scen_staticPictCount[index] == -1) + return; + + for (i = 0; i < scen_staticPictCount[index]; i++) { + if (scen_staticFromExt[index] == 1) + free((char *)scen_statics[index].pieces[i]); + + spr = scen_staticPictToSprite[index * 7 + i]; + scen_spriteRefs[spr]--; + if (scen_spriteRefs[spr] == 0) { + vid_freeSurfDesc(draw_spritesArray[spr]); + draw_spritesArray[spr] = 0; + scen_spriteResId[spr] = -1; + } + } + + free((char *)scen_statics[index].layers); + free((char *)scen_statics[index].pieces); + if (scen_staticFromExt[index] == 1) + free((char *)scen_statics[index].dataPtr); + + scen_staticFromExt[index] = 0; + scen_staticPictCount[index] = -1; +} + +void scen_renderStatic(int16 scenery, int16 layer) { + Scen_Static *ptr; + Scen_StaticLayer *layerPtr; + Scen_StaticPlane *planePtr; + int16 planeCount; + int16 order; + int16 plane; + + int16 pieceIndex; + int16 pictIndex; + + int16 left; + int16 right; + int16 top; + int16 bottom; + + ptr = &scen_statics[scenery]; + if (layer >= ptr->layersCount) + return; + + layerPtr = ptr->layers[layer]; + + draw_spriteLeft = layerPtr->backResId; + if (draw_spriteLeft != -1) { + draw_destSpriteX = 0; + draw_destSpriteY = 0; + draw_destSurface = 21; + draw_transparency = 0; + 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; + + draw_destSpriteX = planePtr->destX; + draw_destSpriteY = planePtr->destY; + left = ptr->pieces[pictIndex][pieceIndex].left; + right = ptr->pieces[pictIndex][pieceIndex].right; + top = ptr->pieces[pictIndex][pieceIndex].top; + bottom = ptr->pieces[pictIndex][pieceIndex].bottom; + + draw_sourceSurface = + scen_staticPictToSprite[scenery * 7 + pictIndex]; + draw_destSurface = 21; + draw_spriteLeft = left; + draw_spriteTop = top; + draw_spriteRight = right - left + 1; + draw_spriteBottom = bottom - top + 1; + draw_transparency = planePtr->transp ? 3 : 0; + draw_spriteOperation(DRAW_BLITSURF); + } + } +} + +void scen_interRenderStatic(void) { + int16 layer; + int16 index; + + inter_evalExpr(&index); + inter_evalExpr(&layer); + scen_renderStatic(index, layer); +} + +void scen_interLoadCurLayer(void) { + inter_evalExpr(&scen_curStatic); + inter_evalExpr(&scen_curStaticLayer); +} + +void scen_updateStatic(int16 orderFrom) { + Scen_StaticLayer *layerPtr; + Scen_PieceDesc **pictPtr; + Scen_StaticPlane *planePtr; + int16 planeCount; + int16 order; + int16 plane; + int16 pieceIndex; + int16 pictIndex; + + int16 left; + int16 right; + int16 top; + int16 bottom; + + if (scen_curStatic == -1) + return; + + if (scen_curStaticLayer >= scen_statics[scen_curStatic].layersCount) + return; + + layerPtr = scen_statics[scen_curStatic].layers[scen_curStaticLayer]; + pictPtr = scen_statics[scen_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; + draw_destSpriteX = planePtr->destX; + draw_destSpriteY = planePtr->destY; + + left = pictPtr[pictIndex][pieceIndex].left; + right = pictPtr[pictIndex][pieceIndex].right; + top = pictPtr[pictIndex][pieceIndex].top; + bottom = pictPtr[pictIndex][pieceIndex].bottom; + + if (draw_destSpriteX > scen_toRedrawRight) + continue; + + if (draw_destSpriteY > scen_toRedrawBottom) + continue; + + if (draw_destSpriteX < scen_toRedrawLeft) { + left += scen_toRedrawLeft - draw_destSpriteX; + draw_destSpriteX = scen_toRedrawLeft; + } + + if (draw_destSpriteY < scen_toRedrawTop) { + top += scen_toRedrawTop - draw_destSpriteY; + draw_destSpriteY = scen_toRedrawTop; + } + + draw_spriteLeft = left; + draw_spriteTop = top; + draw_spriteRight = right - left + 1; + draw_spriteBottom = bottom - top + 1; + + if (draw_spriteRight <= 0 || draw_spriteBottom <= 0) + continue; + + if (draw_destSpriteX + draw_spriteRight - 1 > + scen_toRedrawRight) + draw_spriteRight = + scen_toRedrawRight - draw_destSpriteX + 1; + + if (draw_destSpriteY + draw_spriteBottom - 1 > + scen_toRedrawBottom) + draw_spriteBottom = + scen_toRedrawBottom - draw_destSpriteY + 1; + + draw_sourceSurface = + scen_staticPictToSprite[scen_curStatic * 7 + + pictIndex]; + draw_destSurface = 21; + draw_transparency = planePtr->transp ? 3 : 0; + draw_spriteOperation(DRAW_BLITSURF); + } + } +} + +int16 scen_loadAnim(char search) { + int16 picsCount; + int16 resId; + int16 i; + int16 sceneryIndex; + char *dataPtr; + Scen_Animation *ptr; + int16 offset; + int16 pictDescId; + int16 width; + int16 height; + int16 sprResId; + int16 sprIndex; + + inter_evalExpr(&sceneryIndex); + picsCount = inter_load16(); + resId = inter_load16(); + + if (search) { + for (i = 0; i < 10; i++) { + if (scen_animPictCount[i] != 0 + && scen_animResId[i] == resId) { + inter_execPtr += 8 * scen_animPictCount[i]; + return i; + } + + if (scen_animPictCount[i] == 0 && i < sceneryIndex) + sceneryIndex = i; + } + } + + scen_animPictCount[sceneryIndex] = picsCount; + scen_animResId[sceneryIndex] = resId; + + if (resId >= 30000) { + scen_animFromExt[sceneryIndex] = 1; + dataPtr = game_loadExtData(resId, 0, 0); + } else { + scen_animFromExt[sceneryIndex] = 0; + dataPtr = game_loadTotResource(resId); + } + + ptr = &scen_animations[sceneryIndex]; + ptr->dataPtr = dataPtr; + + ptr->layersCount = READ_LE_UINT16(dataPtr); + dataPtr += 2; + + ptr->layers = + (Scen_AnimLayer **) malloc(sizeof(Scen_AnimLayer *) * + ptr->layersCount); + ptr->pieces = + (Scen_PieceDesc **) malloc(sizeof(Scen_PieceDesc *) * + picsCount); + + for (i = 0; i < ptr->layersCount; i++) { + offset = ((int16 *)dataPtr)[i]; + ptr->layers[i] = (Scen_AnimLayer *) (dataPtr + offset - 2); + } + + for (i = 0; i < picsCount; i++) { + pictDescId = inter_load16(); + if (resId >= 30000) { + ptr->pieces[i] = + (Scen_PieceDesc *) game_loadExtData(pictDescId, 0, + 0); + } else { + ptr->pieces[i] = + (Scen_PieceDesc *) + game_loadTotResource(pictDescId); + } + + width = inter_load16(); + height = inter_load16(); + sprResId = inter_load16(); + for (sprIndex = 0; sprIndex < 20; sprIndex++) { + if (scen_spriteResId[sprIndex] == sprResId) + break; + } + + if (sprIndex < 20) { + scen_animPictToSprite[7 * sceneryIndex + i] = sprIndex; + scen_spriteRefs[sprIndex]++; + } else { + for (sprIndex = 19; draw_spritesArray[sprIndex] != 0; + sprIndex--); + + scen_animPictToSprite[7 * sceneryIndex + i] = sprIndex; + scen_spriteRefs[sprIndex] = 1; + scen_spriteResId[sprIndex] = sprResId; + draw_spritesArray[sprIndex] = + vid_initSurfDesc(videoMode, width, height, 2); + + vid_clearSurf(draw_spritesArray[sprIndex]); + draw_destSurface = sprIndex; + draw_spriteLeft = sprResId; + draw_transparency = 0; + draw_destSpriteX = 0; + draw_destSpriteY = 0; + 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 scen_updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, + int16 drawDeltaX, int16 drawDeltaY, char doDraw) { + Scen_AnimLayer *layerPtr; + Scen_PieceDesc **pictPtr; + Scen_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 >= scen_animations[animation].layersCount) + return; + + layerPtr = scen_animations[animation].layers[layer]; + + if (frame >= layerPtr->framesCount) + return; + + if (flags & 1) // Do capture + { + scen_updateAnim(layer, frame, animation, 0, drawDeltaX, + drawDeltaY, 0); + + if (scen_toRedrawLeft == -12345) // Some magic number? + return; + + game_capturePush(scen_toRedrawLeft, scen_toRedrawTop, + scen_toRedrawRight - scen_toRedrawLeft + 1, + scen_toRedrawBottom - scen_toRedrawTop + 1); + + *scen_pCaptureCounter = *scen_pCaptureCounter + 1; + } + pictPtr = scen_animations[animation].pieces; + framePtr = layerPtr->frames; + + for (i = 0; i < frame; i++, framePtr++) { + while (framePtr->notFinal == 1) + framePtr++; + } + + if ((flags & 4) == 0) { + scen_toRedrawLeft = -12345; + } else { + scen_toRedrawLeft = + MAX(scen_toRedrawLeft, anim_animAreaLeft); + scen_toRedrawTop = + MAX(scen_toRedrawTop, anim_animAreaTop); + scen_toRedrawRight = + MIN(scen_toRedrawRight, + anim_animAreaLeft + anim_animAreaWidth - 1); + scen_toRedrawBottom = + MIN(scen_toRedrawBottom, + anim_animAreaTop + anim_animAreaHeight - 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 = pictPtr[pictIndex][pieceIndex].left; + right = pictPtr[pictIndex][pieceIndex].right; + top = pictPtr[pictIndex][pieceIndex].top; + bottom = pictPtr[pictIndex][pieceIndex].bottom; + + if (flags & 2) { + if (destX < anim_animAreaLeft) { + left += anim_animAreaLeft - destX; + destX = anim_animAreaLeft; + } + + if (left <= right + && destX + right - left >= + anim_animAreaLeft + anim_animAreaWidth) + right -= + (destX + right - left) - + (anim_animAreaLeft + anim_animAreaWidth) + + 1; + + if (destY < anim_animAreaTop) { + top += anim_animAreaTop - destY; + destY = anim_animAreaTop; + } + + if (top <= bottom + && destY + bottom - top >= + anim_animAreaTop + anim_animAreaHeight) + bottom -= + (destY + bottom - top) - + (anim_animAreaTop + anim_animAreaHeight) + + 1; + + } else if (flags & 4) { + if (destX < scen_toRedrawLeft) { + left += scen_toRedrawLeft - destX; + destX = scen_toRedrawLeft; + } + + if (left <= right + && destX + right - left > scen_toRedrawRight) + right -= + destX + right - left - scen_toRedrawRight; + + if (destY < scen_toRedrawTop) { + top += scen_toRedrawTop - destY; + destY = scen_toRedrawTop; + } + + if (top <= bottom + && destY + bottom - top > scen_toRedrawBottom) + bottom -= + destY + bottom - top - scen_toRedrawBottom; + } + + if (left > right || top > bottom) + continue; + + if (doDraw) { + draw_sourceSurface = + scen_animPictToSprite[animation * 7 + pictIndex]; + draw_destSurface = 21; + + draw_spriteLeft = left; + draw_spriteTop = top; + draw_spriteRight = right - left + 1; + draw_spriteBottom = bottom - top + 1; + draw_destSpriteX = destX; + draw_destSpriteY = destY; + draw_transparency = transp; + draw_spriteOperation(DRAW_BLITSURF); + } + + if ((flags & 4) == 0) { + if (scen_toRedrawLeft == -12345) { + scen_toRedrawLeft = destX; + scen_animLeft = destX; + scen_toRedrawTop = destY; + scen_animTop = destY; + scen_toRedrawRight = destX + right - left; + scen_toRedrawBottom = destY + bottom - top; + } else { + scen_toRedrawLeft = + MIN(scen_toRedrawLeft, destX); + scen_toRedrawTop = + MIN(scen_toRedrawTop, destY); + scen_toRedrawRight = + MAX(scen_toRedrawRight, + destX + right - left); + scen_toRedrawBottom = + MAX(scen_toRedrawBottom, + destY + bottom - top); + } + } + } while (framePtr->notFinal == 1); +} + +void scen_freeAnim(int16 animation) { + int16 i; + int16 spr; + + if (animation == -1) + inter_evalExpr(&animation); + + if (scen_animPictCount[animation] == 0) + return; + + for (i = 0; i < scen_animPictCount[animation]; i++) { + if (scen_animFromExt[animation] == 1) + free((char *)scen_animations[animation].pieces[i]); + + spr = scen_animPictToSprite[animation * 7 + i]; + scen_spriteRefs[spr]--; + if (scen_spriteRefs[spr] == 0) { + vid_freeSurfDesc(draw_spritesArray[spr]); + + draw_spritesArray[spr] = 0; + scen_spriteResId[spr] = -1; + } + } + + free((char *)scen_animations[animation].layers); + free((char *)scen_animations[animation].pieces); + if (scen_animFromExt[animation] == 1) + free(scen_animations[animation].dataPtr); + + scen_animFromExt[animation] = 0; + scen_animPictCount[animation] = 0; +} + +void scen_interUpdateAnim(void) { + int16 deltaX; + int16 deltaY; + int16 flags; + int16 frame; + int16 layer; + int16 animation; + + inter_evalExpr(&deltaX); + inter_evalExpr(&deltaY); + inter_evalExpr(&animation); + inter_evalExpr(&layer); + inter_evalExpr(&frame); + flags = inter_load16(); + scen_updateAnim(layer, frame, animation, flags, deltaX, deltaY, 1); +} + +void scen_interStoreParams(void) { + Scen_AnimLayer *layerPtr; + int16 animation; + int16 layer; + int16 var; + + log_write("scen_interStoreParams: Storing...\n"); + + inter_evalExpr(&animation); + inter_evalExpr(&layer); + layerPtr = scen_animations[animation].layers[layer]; + + var = parse_parseVarIndex(); + WRITE_LE_UINT32(inter_variables + var, layerPtr->animDeltaX); + + var = parse_parseVarIndex(); + WRITE_LE_UINT32(inter_variables + var, layerPtr->animDeltaY); + + var = parse_parseVarIndex(); + WRITE_LE_UINT32(inter_variables + var, layerPtr->unknown0); + + var = parse_parseVarIndex(); + WRITE_LE_UINT32(inter_variables + var, layerPtr->framesCount); +} + +} // End of namespace Gob diff --git a/gob/scenery.h b/gob/scenery.h new file mode 100644 index 0000000000..3d0bb2731d --- /dev/null +++ b/gob/scenery.h @@ -0,0 +1,121 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __SCENERY_H +#define __SCENERY_H + +namespace Gob { + +#pragma START_PACK_STRUCTS +typedef struct Scen_PieceDesc { + int16 left; + int16 right; + int16 top; + int16 bottom; +} GCC_PACK Scen_PieceDesc; + +typedef struct Scen_StaticPlane { + char pictIndex; + char pieceIndex; + char drawOrder; + int16 destX; + int16 destY; + char transp; +} GCC_PACK Scen_StaticPlane; + +typedef struct Scen_StaticLayer { + int16 backResId; + int16 planeCount; + Scen_StaticPlane planes[1]; +} GCC_PACK Scen_StaticLayer; + +typedef struct Scen_Static { + int16 layersCount; + Scen_StaticLayer **layers; + Scen_PieceDesc **pieces; + void *unknown; + char *dataPtr; +} GCC_PACK Scen_Static; + +// Animations + +typedef struct Scen_AnimFramePiece { + byte pictIndex; + byte pieceIndex; + char destX; + char destY; + char notFinal; +} GCC_PACK Scen_AnimFramePiece; + +typedef struct Scen_AnimLayer { + int16 unknown0; + int16 posX; + int16 posY; + int16 animDeltaX; + int16 animDeltaY; + char transp; + int16 framesCount; + Scen_AnimFramePiece frames[1]; +} GCC_PACK Scen_AnimLayer; +#pragma END_PACK_STRUCTS + +struct Scen_Animation { + int16 layersCount; + Scen_AnimLayer **layers; + Scen_PieceDesc **pieces; + void *unknowm; + char *dataPtr; +}; + +// Global variables + +extern char scen_spriteRefs[20]; +extern int16 scen_spriteResId[20]; + +extern char scen_staticPictToSprite[70]; +extern int16 scen_staticPictCount[10]; +extern Scen_Static scen_statics[10]; +extern char scen_staticFromExt[10]; +extern int16 scen_staticResId[10]; + +extern char scen_animPictToSprite[70]; +extern int16 scen_animPictCount[10]; +extern char scen_animFromExt[10]; +extern Scen_Animation scen_animations[10]; +extern int16 scen_animResId[10]; + +extern int16 scen_curStatic; +extern int16 scen_curStaticLayer; + +extern int16 scen_toRedrawLeft; +extern int16 scen_toRedrawRight; +extern int16 scen_toRedrawTop; +extern int16 scen_toRedrawBottom; + +extern int16 scen_animTop; +extern int16 scen_animLeft; + +extern int16 *scen_pCaptureCounter; + +// Functions + +int16 scen_loadStatic(char search); +void scen_freeStatic(int16 index); +void scen_renderStatic(int16 scenery, int16 layer); +void scen_interRenderStatic(void); +void scen_interLoadCurLayer(void); +void scen_updateStatic(int16 orderFrom); +int16 scen_loadAnim(char search); +void scen_updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, + int16 drawDeltaX, int16 drawDeltaY, char doDraw); +void scen_freeAnim(int16 animation); +void scen_interUpdateAnim(void); +void scen_interStoreParams(void); + +} // End of namespace Gob + +#endif /* __SCENERY_H */ diff --git a/gob/sound.cpp b/gob/sound.cpp new file mode 100644 index 0000000000..af4731ba56 --- /dev/null +++ b/gob/sound.cpp @@ -0,0 +1,44 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/debug.h" +#include "gob/sound.h" +namespace Gob { + int16 snd_checkProAudio(void) {return 0;} + int16 snd_checkAdlib(void) {return 0;} + int16 snd_checkBlaster(void) {return 0;} + void snd_setBlasterPort(int16 port) {return;} + void snd_speakerOn(int16 frequency) {return;} + void snd_speakerOff(void) {return;} + void snd_stopSound(int16 arg){return;} + void snd_setResetTimerFlag(char flag){return;} + + void snd_playSample(Snd_SoundDesc * soundDesc, int16 repCount, int16 frequency) {;} + void snd_cleanupFuncCallback() {;} + CleanupFuncPtr (snd_cleanupFunc); + //CleanupFuncPtr snd_cleanupFunc;// = &snd_cleanupFuncCallback(); + + int16 snd_soundPort; + char snd_playingSound; + + void snd_writeAdlib(int16 port, int16 data) { + return; + } + + Snd_SoundDesc *snd_loadSoundData(char *path) { + return NULL; + } +void snd_freeSoundData(Snd_SoundDesc * sndDesc) {;} +void snd_playComposition(Snd_SoundDesc ** samples, int16 *composit, int16 freqVal) {;} +void snd_waitEndPlay(void) {;} + +} // End of namespace Gob + + + diff --git a/gob/sound.h b/gob/sound.h new file mode 100644 index 0000000000..21e349ea9f --- /dev/null +++ b/gob/sound.h @@ -0,0 +1,47 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __SOUND_H +#define __SOUND_H + +namespace Gob { + +int16 snd_checkProAudio(void); +int16 snd_checkAdlib(void); +int16 snd_checkBlaster(void); +void snd_setBlasterPort(int16 port); +void snd_speakerOn(int16 frequency); +void snd_speakerOff(void); +void snd_stopSound(int16 arg); +void snd_setResetTimerFlag(char flag); + +extern int16 snd_soundPort; +extern char snd_playingSound; + +typedef void (*CleanupFuncPtr) (int16); +extern CleanupFuncPtr snd_cleanupFunc; + +void snd_writeAdlib(int16 port, int16 data); + +typedef struct Snd_SoundDesc { + char *data; + int32 size; + int16 timerTicks; + int16 inClocks; + int16 frequency; + int16 flag; +} Snd_SoundDesc; + +void snd_playSample(Snd_SoundDesc * soundDesc, int16 repCount, int16 frequency); +Snd_SoundDesc *snd_loadSoundData(char *path); +void snd_freeSoundData(Snd_SoundDesc * sndDesc); +void snd_playComposition(Snd_SoundDesc ** samples, int16 *composit, int16 freqVal); +void snd_waitEndPlay(void); + +} // End of namespace Gob + +#endif diff --git a/gob/timer.cpp b/gob/timer.cpp new file mode 100644 index 0000000000..adc5337fc4 --- /dev/null +++ b/gob/timer.cpp @@ -0,0 +1,21 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/debug.h" +#include "gob/sound.h" +namespace Gob { + +void timer_enableTimer() { + debug(0, "STUB: timer_enableTimer()"); +} + +void timer_disableTimer() { + debug(0, "STUB: timer_disableTimer()"); +} +}; diff --git a/gob/timer.h b/gob/timer.h new file mode 100644 index 0000000000..26f3b7df56 --- /dev/null +++ b/gob/timer.h @@ -0,0 +1,25 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __TIMER_H_ +#define __TIMER_H_ + +namespace Gob { + +typedef void (* TickHandler) (void); + +void timer_enableTimer(void); +void timer_disableTimer(void); +void timer_setHandler(void); +void timer_restoreHandler(void); +void timer_addTicks(int16 ticks); +void timer_setTickHandler(TickHandler handler); +int32 timer_getTicks(void); + +} // End of namespace Gob + +#endif diff --git a/gob/util.cpp b/gob/util.cpp new file mode 100644 index 0000000000..581d96c7d0 --- /dev/null +++ b/gob/util.cpp @@ -0,0 +1,465 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/timer.h" +#include "gob/util.h" +#include "gob/debug.h" +#include "gob/draw.h" +#include "gob/game.h" + +namespace Gob { + +static int16 _mouseX, _mouseY, _keyPressed, _mouseButtons; + +void util_initInput(void) { + _mouseX = _mouseY = _keyPressed = _mouseButtons = 0; +} + +void util_waitKey(void) { + while (_keyPressed) { + util_processInput(); + g_system->delayMillis(10); + } +} + +int16 util_translateKey(int16 key) { + struct keyS { + int16 from; + int16 to; + } static keys[] = { + 8, 0xe08, // Backspace + 13, 0x1C0D, // Enter + 27, 0x11b, // 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, 0x3F00, // 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; + + return key; +} + +int16 util_getKey(void) { + while (!_keyPressed) { + util_processInput(); + + if (_keyPressed) + break; + + g_system->delayMillis(10); + } + return util_translateKey(_keyPressed); +} + +int16 util_checkKey(void) { + int key = _keyPressed; + + if (_keyPressed) + _keyPressed = 0; + + return util_translateKey(key); +} + +int16 util_getRandom(int16 max) { + return ((int32)rand() * max) / (RAND_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: + _keyPressed = event.kbd.keycode; + break; + case OSystem::EVENT_KEYUP: + _keyPressed = 0; + break; + case OSystem::EVENT_QUIT: + g_system->quit(); + break; + default: + break; + } + } +} + +void util_getMouseState(int16 *pX, int16 *pY, int16 *pButtons) { + int16 x = 0; + int16 y = 0; + int16 buttons = 0; + + *pX = _mouseX; + *pY = _mouseY; + + if (pButtons != 0) + *pButtons = _mouseButtons; +// if (pX != 0) +// *pX = x >> mouseXShift; +// if (pY != 0) +// *pY = y >> mouseYShift; +} + +void util_setMousePos(int16 x, int16 y) { + g_system->warpMouse(x, y); +} + +void util_delay(uint16 msecs) { + g_system->delayMillis(msecs); +} + +void util_beep(int16 freq) { + if (soundFlags == 0) + return; + + //sound(freq); + util_delay(50); + //nosound(); +} + +uint32 util_getTimeKey(void) { + return g_system->getMillis(); +} + +void util_waitMouseUp(void) { + int16 x; + int16 y; + int16 buttons; + + do { + util_getMouseState(&x, &y, &buttons); + } while (buttons != 0); +} + +void util_waitMouseDown(void) { + int16 x; + int16 y; + int16 buttons; + + do { + util_getMouseState(&x, &y, &buttons); + } while (buttons == 0); +} + +/* NOT IMPLEMENTED */ +int16 util_calcDelayTime() { + return 0; +} + +/* NOT IMPLEMENTED */ +void util_checkJoystick() { + useJoystick = 0; +} + +void util_setFrameRate(int16 rate) { + if (rate == 0) + rate = 1; + + frameWaitTime = 1000 / rate; + startFrameTime = util_getTimeKey(); +} + +void util_waitEndFrame() { + int32 time; + + if (pPrimarySurfDesc) { + g_system->copyRectToScreen(pPrimarySurfDesc->vidPtr, 320, 0, 0, 320, 200); + g_system->updateScreen(); + } + + time = util_getTimeKey() - startFrameTime; + if (time > 1000 || time < 0) { + startFrameTime = util_getTimeKey(); + return; + } + if (timer_enabled) { + do { + time = util_getTimeKey(); + + } while (time - startFrameTime < frameWaitTime); + } else { + if (frameWaitTime - time > 0) + util_delay(frameWaitTime - time); + } + startFrameTime = util_getTimeKey(); +} + +int16 joy_getState() { + return 0; +} + +int16 joy_calibrate() { + return 0; +} + +FontDesc *util_loadFont(const char *path) { + FontDesc *fontDesc = (FontDesc *) malloc(sizeof(FontDesc)); + char *data; + + if (fontDesc == 0) + return 0; + + data = data_getData(path); + if (data == 0) { + free((char *)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(FontDesc * fontDesc) { + free(fontDesc->dataPtr - 4); + free((char *)fontDesc); +} + +void util_clearPalette(void) { + int16 i; + byte colors[768]; + + if (videoMode != 0x13) + error("util_clearPalette: Video mode 0x%x is not supported!", + videoMode); + + if (setAllPalette) { + for (i = 0; i < 768; i++) + colors[i] = 0; + g_system->setPalette(colors, 0, 256); + + return; + } + + for (i = 0; i < 16; i++) + vid_setPalElem(i, 0, 0, 0, 0, videoMode); +} + +void util_insertStr(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("util_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); +} + +int16 util_strstr(const char *str1, char *str2) { + char c; + int16 len1; + int16 i; + + log_write("util_strstr: str1 = %s, str2 = %s\n", str1, str2); + + for (i = 0, len1 = strlen(str1); strlen(str2 + i) >= len1; i++) { + c = str2[i + len1]; + str2[i + len1] = 0; + if (strcmp(str2 + i, str1) == 0) { + str2[i + len1] = c; + return i + 1; + } + str2[i + len1] = c; + } + return 0; +} + +void util_listInsertFront(Util_List * list, void *data) { + Util_ListNode *node; + + node = (Util_ListNode *) malloc(sizeof(Util_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(Util_List * list, void *data) { + Util_ListNode *node; + + if (list->pHead != 0) { + if (list->pTail == 0) { + list->pTail = list->pHead; + log_write("util_listInsertBack: Broken list!"); + } + + node = + (Util_ListNode *) malloc(sizeof(Util_ListNode)); + node->pData = data; + node->pPrev = list->pTail; + node->pNext = 0; + list->pTail->pNext = node; + list->pTail = node; + } else { + util_listInsertFront(list, data); + } +} + +void util_listDropFront(Util_List * list) { + if (list->pHead->pNext == 0) { + free((char *)(list->pHead)); + list->pHead = 0; + list->pTail = 0; + } else { + list->pHead = list->pHead->pNext; + free((char *)(list->pHead->pPrev)); + list->pHead->pPrev = 0; + } +} + +void util_deleteList(Util_List * list) { + while (list->pHead != 0) { + util_listDropFront(list); + } + + free((char *)list); +} + +char *util_str1 = + " ' + - :0123456789: <=> abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz "; +char *util_str2 = + " ueaaaaceeeiii ooouu aioun "; +char *util_str3 = " "; + +void util_prepareStr(char *str) { + int16 i; + int16 j; + char buf[300]; + + strcpy(buf, util_str1); + strcat(buf, util_str2); + strcat(buf, util_str3); + + for (i = 0; i < strlen(str); i++) + str[i] = buf[str[i] - 32]; + + while (str[0] == ' ') + util_cutFromStr(str, 0, 1); + + while (strlen(str) > 0 && str[strlen(str) - 1] == ' ') + util_cutFromStr(str, strlen(str) - 1, 1); + + i = util_strstr(" ", str); + + while (1) { + if (i == 0) + return; + + if (str[i] == ' ') { + util_cutFromStr(str, i - 1, 1); + continue; + } + + j = util_strstr(" ", str + i); + if (j != 0) + i += j; + else + i = 0; + } +} + +void util_waitMouseRelease(char drawMouse) { + int16 buttons; + int16 mouseX; + int16 mouseY; + + do { + game_checkKeys(&mouseX, &mouseY, &buttons, drawMouse); + if (drawMouse != 0) + draw_animateCursor(2); + } while (buttons != 0); +} + +void keyboard_release(void) {;} +} // End of namespace Gob diff --git a/gob/util.h b/gob/util.h new file mode 100644 index 0000000000..95bf935d3e --- /dev/null +++ b/gob/util.h @@ -0,0 +1,68 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __UTIL_H +#define __UTIL_H + +#include "gob/video.h" + +namespace Gob { + +struct Util_ListNode; +typedef struct Util_ListNode { + void *pData; + struct Util_ListNode *pNext; + struct Util_ListNode *pPrev; +} Util_ListNode; + +typedef struct Util_List { + Util_ListNode *pHead; + Util_ListNode *pTail; +} Util_List; + +void util_initInput(void); +void util_processInput(void); +void util_waitKey(void); +int16 util_getKey(void); +int16 util_checkKey(void); +int16 util_getRandom(int16 max); +void util_getMouseState(int16 *pX, int16 *pY, int16 *pButtons); +void util_setMousePos(int16 x, int16 y); +void util_delay(uint16 msecs); +void util_beep(int16 freq); +uint32 util_getTimeKey(void); +void util_waitMouseUp(void); +void util_waitMouseDown(void); + +void keyboard_init(void); +void keyboard_release(void); + +void util_clearPalette(void); + +void asm_setPaletteBlock(char *tmpPalBuffer, int16 start, int16 end); + +void vid_waitRetrace(int16 mode); + +FontDesc *util_loadFont(const char *path); +void util_freeFont(FontDesc * fontDesc); +void util_clearPalette(void); +void util_insertStr(char *str1, char *str2, int16 pos); +void util_cutFromStr(char *str, int16 from, int16 cutlen); +int16 util_strstr(const char *str1, char *str2); +void util_waitEndFrame(void); +void util_setFrameRate(int16 rate); + +void util_listInsertBack(Util_List * list, void *data); +void util_listInsertFront(Util_List * list, void *data); +void util_listDropFront(Util_List * list); +void util_deleteList(Util_List * list); +void util_prepareStr(char *str); +void util_waitMouseRelease(char drawMouse); + +} // End of namespace Gob + +#endif diff --git a/gob/video.cpp b/gob/video.cpp new file mode 100644 index 0000000000..62d8174ac2 --- /dev/null +++ b/gob/video.cpp @@ -0,0 +1,547 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#include "gob/gob.h" +#include "gob/global.h" +#include "gob/video.h" +#include "gob/debug.h" +#include "gob/dataio.h" + +#include "gob/driver_vga.h" + +namespace Gob { + +VideoDriver *_videoDriver; + + +/* NOT IMPLEMENTED */ + +//XXX: Use this function to update the screen for now. +// This should be moved to a better location later on. +void vid_waitRetrace(int16) { + if (pPrimarySurfDesc) { + g_system->copyRectToScreen(pPrimarySurfDesc->vidPtr, 320, 0, 0, 320, 200); + g_system->updateScreen(); + } +} + +char vid_initDriver(int16 vidMode) { + warning("STUB: vid_initDriver"); + + // FIXME: Finish all this stuff :) + g_system->initSize(320, 200); + + _videoDriver = new VGAVideoDriver(); + + return 1; +} + +void vid_freeDriver() { + delete _videoDriver; + warning("STUB: vid_freeDriver"); +} + +int32 vid_getRectSize(int16 width, int16 height, int16 flag, int16 mode) { + int32 size; + + if ((mode & 0x7f) != 0x13) + log_write + ("vid_getRectSize: Warning! Video mode %d is not fully supported!\n", + 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; +} + +SurfaceDesc *vid_initSurfDesc(int16 vidMode, int16 width, int16 height, int16 flags) { + char flagsAnd2; + byte *vidMem; + int32 sprSize; + int16 someFlags = 1; + SurfaceDesc *descPtr; + + debug(0, "stub: vid_initSurfDesc()"); + + if (flags != PRIMARY_SURFACE) + sprAllocated++; + + if (flags & RETURN_PRIMARY) + return pPrimarySurfDesc; + + if (vidMode != 0x13) + error("vid_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) { + vidMem = 0; + primaryWidth = width; + mouseMaxCol = width; + primaryHeight = height; + mouseMaxRow = height; + sprSize = 0; + + } else { + vidMem = 0; + sprSize = vid_getRectSize(width, height, flagsAnd2, vidMode); + if (flagsAnd2) + someFlags += 0x80; + } + if (flags & PRIMARY_SURFACE) { + descPtr = pPrimarySurfDesc; + vidMem = (byte *)malloc(320 * 200); + } else { + if (flags & DISABLE_SPR_ALLOC) + descPtr = (SurfaceDesc *)malloc(sizeof(SurfaceDesc)); + else + descPtr = (SurfaceDesc *)malloc(sizeof(SurfaceDesc) + sprSize); + } + if (descPtr == 0) + return 0; + + descPtr->width = width; + descPtr->height = height; + descPtr->flag = someFlags; + descPtr->vidMode = vidMode; + if (vidMem == 0) + vidMem = ((byte *)descPtr) + sizeof(SurfaceDesc); + descPtr->vidPtr = vidMem; + + descPtr->reserved1 = 0; + descPtr->reserved2 = 0; + return descPtr; +} + +void vid_freeSurfDesc(SurfaceDesc * surfDesc) { + sprAllocated--; + if (surfDesc != pPrimarySurfDesc) + free((char *)surfDesc); + else + free(surfDesc->vidPtr); +} + +int16 vid_clampValue(int16 val, int16 max) { + if (val >= max) + val = max - 1; + + if (val < 0) + val = 0; + + return val; +} + +void vid_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 (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 = vid_clampValue(right, source->width); + bottom = vid_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; + } + +// pDrawSprite(source, dest, left, top, right, bottom, x, y, transp); + _videoDriver->drawSprite(source, dest, left, top, right, bottom, x, y, transp); +} + +void vid_fillRect(SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, + int16 color) { + int16 temp; + + if (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 = vid_clampValue(left, dest->width); + top = vid_clampValue(top, dest->height); + right = vid_clampValue(right, dest->width); + bottom = vid_clampValue(bottom, dest->height); + } + +// pFillRect(dest, left, top, right, bottom, color); + _videoDriver->fillRect(dest, left, top, right, bottom, color); +} + +void vid_drawLine(SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, int16 y1, int16 color) { + if (x0 == x1 || y0 == y1) { + vid_fillRect(dest, x0, y0, x1, y1, color); + return; + } + +// pDrawLine(dest, x0, y0, x1, y1, color); + _videoDriver->drawLine(dest, x0, y0, x1, y1, color); +} + +void vid_putPixel(int16 x, int16 y, int16 color, SurfaceDesc *dest) { + if (x < 0 || y < 0 || x >= dest->width || y >= dest->height) + return; + +// pPutPixel(x, y, color, dest); + _videoDriver->putPixel(x, y, color, dest); +} + +void vid_drawLetter(char item, int16 x, int16 y, FontDesc *fontDesc, int16 color1, + int16 color2, int16 transp, SurfaceDesc * dest) { + +// pDrawLetter(item, x, y, fontDesc, color1, color2, transp, dest); + _videoDriver->drawLetter(item, x, y, fontDesc, color1, color2, transp, dest); +} + +void vid_clearSurf(SurfaceDesc *dest) { + vid_fillRect(dest, 0, 0, dest->width - 1, dest->height - 1, 0); +} + +void vid_drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y, + int16 transp, SurfaceDesc *dest) { + + if (vid_spriteUncompressor(sprBuf, width, height, x, y, transp, dest)) + return; + + if ((dest->vidMode & 0x7f) != 0x13) + error("vid_drawPackedSprite: Vide mode 0x%x is not fully supported!", + dest->vidMode & 0x7f); + +// pDrawPackedSprite(sprBuf, width, height, x, y, transp, dest); + _videoDriver->drawPackedSprite(sprBuf, width, height, x, y, transp, dest); +} + +void vid_setPalElem(int16 index, char red, char green, char blue, int16 unused, + int16 vidMode) { + byte pal[4]; + + redPalette[index] = red; + greenPalette[index] = green; + bluePalette[index] = blue; + + if (vidMode != 0x13) + error("vid_setPalElem: Video mode 0x%x is not supported!", + vidMode); + + pal[0] = red << 2; + pal[1] = green << 2; + pal[2] = blue << 2; + pal[3] = 0; + g_system->setPalette(pal, index, 1); +} + +void vid_setPalette(PalDesc *palDesc) { + int16 i; + byte pal[1024]; + int16 numcolors; + + if (videoMode != 0x13) + error("vid_setPalette: Video mode 0x%x is not supported!", + videoMode); + + if (setAllPalette) + numcolors = 256; + else + numcolors = 16; + + for (i = 0; i < numcolors; i++) { + pal[i * 4 + 0] = palDesc->vgaPal[i].red << 2; + pal[i * 4 + 1] = palDesc->vgaPal[i].green << 2; + pal[i * 4 + 2] = palDesc->vgaPal[i].blue << 2; + pal[i * 4 + 3] = 0; + } + + g_system->setPalette(pal, 0, numcolors); +} + +void vid_setFullPalette(PalDesc *palDesc) { + Color *colors; + int16 i; + byte pal[1024]; + + if (setAllPalette) { + colors = palDesc->vgaPal; + for (i = 0; i < 256; i++) { + redPalette[i] = colors[i].red; + greenPalette[i] = colors[i].green; + bluePalette[i] = colors[i].blue; + } + + for (i = 0; i < 256; i++) { + pal[i * 4 + 0] = colors[i].red << 2; + pal[i * 4 + 1] = colors[i].green << 2; + pal[i * 4 + 2] = colors[i].blue << 2; + pal[i * 4 + 3] = 0; + } + g_system->setPalette(pal, 0, 256); + } else { + vid_setPalette(palDesc); + } +} + +void vid_initPrimary(int16 mode) { + int16 old; + if (curPrimaryDesc) { + vid_freeSurfDesc(curPrimaryDesc); + vid_freeSurfDesc(allocatedPrimary); + + curPrimaryDesc = 0; + allocatedPrimary = 0; + } + if (mode != 0x13 && mode != 3 && mode != -1) + error("vid_initPrimary: Video mode 0x%x is not supported!", + mode); + + if (videoMode != 0x13) + error("vid_initPrimary: Video mode 0x%x is not supported!", + mode); + + old = oldMode; + if (mode == -1) + mode = 3; + + oldMode = mode; + if (mode != 3) + vid_initDriver(mode); + + needDriverInit = 1; + + if (mode != 3) { + vid_initSurfDesc(mode, 320, 200, PRIMARY_SURFACE); + + if (dontSetPalette) + return; + + vid_setFullPalette(pPaletteDesc); + } +} + +char vid_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; + + warning("vid_spriteUncompressor called"); + + if ((destDesc->vidMode & 0x7f) != 0x13) + error("vid_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; + vid_drawSprite(&sourceDesc, destDesc, 0, 0, srcWidth - 1, + srcHeight - 1, x, y, transp); + return 1; + } else { + memBuffer = (byte *)malloc(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) { + free(memBuffer); + return 1; + } + } + sourceLeft--; + if (sourceLeft == 0) { + free(memBuffer); + return 1; + } + memBuffer[bufPos] = temp; + bufPos++; + bufPos %= 4096; + } + } + } + } + free(memBuffer); + return 1; +} + +void vid_setHandlers() { + //pDrawPacked = &vid_spriteUncompressor; + pFileHandler = 0; + setAllPalette = 1; +} + +} // End of namespace Gob diff --git a/gob/video.h b/gob/video.h new file mode 100644 index 0000000000..130e0c8b5f --- /dev/null +++ b/gob/video.h @@ -0,0 +1,125 @@ +/* +** Gobliiins 1 +** Original game by CoktelVision +** +** Reverse engineered by Ivan Dubrov <WFrag@yandex.ru> +** +*/ +#ifndef __VIDEO_H +#define __VIDEO_H + +namespace Gob { + +#include "stdafx.h" +#include "common/util.h" + +#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 + + +typedef struct SurfaceDesc_t { + int16 width; + int16 height; + char reserved1; + char flag; + int16 vidMode; + byte *vidPtr; + int16 reserved2; +} SurfaceDesc; + +typedef struct FontDesc_t { + char *dataPtr; + char itemWidth; + char itemHeight; + char startItem; + char endItem; + char itemSize; + char bitWidth; + void *extraData; +} FontDesc; + + +class VideoDriver { +public: + VideoDriver() {} + virtual ~VideoDriver() {} + virtual void drawSprite(SurfaceDesc *source, SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp) = 0; + virtual void fillRect(SurfaceDesc *dest, int16 left, int16 top, int16 right, int16 bottom, byte color) = 0; + virtual void putPixel(int16 x, int16 y, byte color, SurfaceDesc *dest) = 0; + virtual void drawLetter(char item, int16 x, int16 y, FontDesc *fontDesc, byte color1, byte color2, byte transp, SurfaceDesc *dest) = 0; + virtual void drawLine(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, SurfaceDesc *dest) = 0; +}; + + +typedef void (*FillRectFunc) (SurfaceDesc * desc, int16 left, int16 top, int16 right, + int16 bottom, int16 color); +typedef void (*DrawSpriteFunc) (SurfaceDesc * source, SurfaceDesc * dest, + int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp); +typedef void (*PutPixelFunc) (int16 x, int16 y, int16 color, SurfaceDesc * desc); +typedef void (*XorRectFunc) (SurfaceDesc * desc, int16 left, int16 top, int16 right, + int16 bottom); +typedef void (*SetXorValFunc) (int16 val); +typedef void (*DrawLineFunc) (SurfaceDesc * desc, int16 x0, int16 y0, int16 x1, + int16 y1, int16 color); +typedef void (*DrawLetterFunc) (char item, int16 x, int16 y, FontDesc * fontDesc, + int16 color1, int16 color2, int16 transp, SurfaceDesc * dest); +typedef char (*DrawPackedSpriteFunc) (byte *sprBuf, int16 width, int16 height, + int16 x, int16 y, int16 transp, SurfaceDesc * dest); + +#define GDR_VERSION 4 + +#define SET_SEG(ptr,seg) (((unsigned*)(ptr))[1] = (seg)) + + +#define PRIMARY_SURFACE 0x80 +#define RETURN_PRIMARY 0x01 +#define DISABLE_SPR_ALLOC 0x20 + +typedef struct Color { + byte red; + byte green; + byte blue; +} Color; + +typedef struct PalDesc { + Color *vgaPal; + int16 *unused1; + int16 *unused2; +} PalDesc; + +char vid_initDriver(int16 vidMode); +void vid_freeDriver(void); +int32 vid_getRectSize(int16 width, int16 height, int16 flag, int16 mode); +SurfaceDesc *vid_initSurfDesc(int16 vidMode, int16 width, int16 height, int16 flags); +void vid_freeSurfDesc(SurfaceDesc * surfDesc); +int16 vid_clampValue(int16 val, int16 max); +void vid_drawSprite(SurfaceDesc * source, SurfaceDesc * dest, int16 left, + int16 top, int16 right, int16 bottom, int16 x, int16 y, int16 transp); +void vid_fillRect(SurfaceDesc * dest, int16 left, int16 top, int16 right, int16 bottom, + int16 color); +void vid_drawLine(SurfaceDesc * dest, int16 x0, int16 y0, int16 x1, int16 y1, + int16 color); +void vid_putPixel(int16 x, int16 y, int16 color, SurfaceDesc * dest); +void vid_drawLetter(char item, int16 x, int16 y, FontDesc * fontDesc, int16 color1, + int16 color2, int16 transp, SurfaceDesc * dest); +void vid_clearSurf(SurfaceDesc * dest); +void vid_drawPackedSprite(byte *sprBuf, int16 width, int16 height, int16 x, int16 y, + int16 transp, SurfaceDesc * dest); +void vid_setPalElem(int16 index, char red, char green, char blue, int16 unused, + int16 vidMode); +void vid_setPalette(PalDesc * palDesc); +void vid_setFullPalette(PalDesc * palDesc); +void vid_initPrimary(int16 mode); +char vid_spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight, int16 x, + int16 y, int16 transp, SurfaceDesc * destDesc); +void vid_setHandlers(void); + +} // End of namespace Gob + +#endif |