aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.common6
-rw-r--r--NEWS1
-rw-r--r--base/plugins.cpp4
-rw-r--r--base/plugins.h1
-rwxr-xr-xconfigure13
-rw-r--r--gob/anim.cpp20
-rw-r--r--gob/anim.h21
-rw-r--r--gob/dataio.cpp356
-rw-r--r--gob/dataio.h46
-rw-r--r--gob/debug.cpp171
-rw-r--r--gob/debug.h27
-rw-r--r--gob/draw.cpp908
-rw-r--r--gob/draw.h111
-rw-r--r--gob/driver_vga.cpp59
-rw-r--r--gob/driver_vga.h22
-rw-r--r--gob/game.cpp1909
-rw-r--r--gob/game.h151
-rw-r--r--gob/global.cpp175
-rw-r--r--gob/global.h191
-rw-r--r--gob/gob.cpp130
-rw-r--r--gob/gob.h51
-rw-r--r--gob/goblin.cpp3320
-rw-r--r--gob/goblin.h192
-rw-r--r--gob/init.cpp293
-rw-r--r--gob/init.h20
-rw-r--r--gob/inter.cpp1496
-rw-r--r--gob/inter.h85
-rw-r--r--gob/map.cpp736
-rw-r--r--gob/map.h57
-rw-r--r--gob/module.mk36
-rw-r--r--gob/mult.cpp1205
-rw-r--r--gob/mult.h185
-rw-r--r--gob/pack.cpp94
-rw-r--r--gob/pack.h18
-rw-r--r--gob/palanim.cpp224
-rw-r--r--gob/palanim.h21
-rw-r--r--gob/parse.cpp1210
-rw-r--r--gob/parse.h22
-rw-r--r--gob/resource.cpp90
-rw-r--r--gob/resource.h20
-rw-r--r--gob/scenery.cpp738
-rw-r--r--gob/scenery.h121
-rw-r--r--gob/sound.cpp44
-rw-r--r--gob/sound.h47
-rw-r--r--gob/timer.cpp21
-rw-r--r--gob/timer.h25
-rw-r--r--gob/util.cpp465
-rw-r--r--gob/util.h68
-rw-r--r--gob/video.cpp547
-rw-r--r--gob/video.h125
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 \
diff --git a/NEWS b/NEWS
index 0461816e7c..79f90a9fb5 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/configure b/configure
index 7815c51598..e85ab85865 100755
--- a/configure
+++ b/configure
@@ -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