Initial checking of Gob engine

svn-id: r17388
This commit is contained in:
Eugene Sandulenko 2005-04-05 15:07:40 +00:00
parent b399a052f1
commit 1758c5b211
50 changed files with 15896 additions and 2 deletions

View file

@ -81,6 +81,12 @@ else
MODULES += kyra MODULES += kyra
endif endif
ifdef DISABLE_GOB
DEFINES += -DDISABLE_GOB
else
MODULES += gob
endif
# After the game specific modules follow the shared modules # After the game specific modules follow the shared modules
MODULES += \ MODULES += \
gui \ gui \

1
NEWS
View file

@ -5,6 +5,7 @@ For a more comprehensive changelog for the latest experimental CVS code, see:
New Games: New Games:
- Added SAGA engine (for the games and "I Have No Mouth and I Must Scream" - Added SAGA engine (for the games and "I Have No Mouth and I Must Scream"
and "Inherit the Earth"). and "Inherit the Earth").
- Added Gob engine (for Goblins series)
General: General:
- Reworked cursor handling in SDL backend. Now cursors can have their own - Reworked cursor handling in SDL backend. Now cursors can have their own

View file

@ -278,9 +278,11 @@ void PluginManager::loadPlugins() {
#ifndef DISABLE_KYRA #ifndef DISABLE_KYRA
LINK_PLUGIN(KYRA) LINK_PLUGIN(KYRA)
#endif #endif
#ifndef DISABLE_GOB
LINK_PLUGIN(GOB)
#endif
#endif #endif
} }
void PluginManager::unloadPlugins() { void PluginManager::unloadPlugins() {

View file

@ -155,5 +155,4 @@ public:
DetectedGameList detectGames(const FSList &fslist) const; DetectedGameList detectGames(const FSList &fslist) const;
}; };
#endif #endif

13
configure vendored
View file

@ -30,6 +30,7 @@ _build_sword2=yes
_build_queen=yes _build_queen=yes
_build_kyra=no _build_kyra=no
_build_saga=yes _build_saga=yes
_build_gob=no
_need_memalign=no _need_memalign=no
_build_plugins=no _build_plugins=no
_nasm=auto _nasm=auto
@ -268,6 +269,7 @@ Optional Features:
--disable-queen don't build the Flight of the Amazon Queen engine --disable-queen don't build the Flight of the Amazon Queen engine
--disable-saga don't build the SAGA engine --disable-saga don't build the SAGA engine
--enable-kyra build the Legend of Kyrandia 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 --enable-plugins build engines as loadable modules instead of
static linking them static linking them
--disable-mt32emu don't enable the integrated MT-32 emulator --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-queen) _build_queen=no ;;
--disable-saga) _build_saga=no ;; --disable-saga) _build_saga=no ;;
--enable-kyra) _build_kyra=yes ;; --enable-kyra) _build_kyra=yes ;;
--enable-gob) _build_gob=yes ;;
--enable-alsa) _alsa=yes ;; --enable-alsa) _alsa=yes ;;
--disable-alsa) _alsa=no ;; --disable-alsa) _alsa=no ;;
--enable-vorbis) _vorbis=yes ;; --enable-vorbis) _vorbis=yes ;;
@ -581,6 +584,12 @@ else
_mak_saga='# DISABLE_SAGA = 1' _mak_saga='# DISABLE_SAGA = 1'
fi fi
if test "$_build_gob" = no ; then
_mak_gob='DISABLE_GOB = 1'
else
_mak_gob='# DISABLE_GOB = 1'
fi
if test -n "$_host"; then if test -n "$_host"; then
# Cross-compiling mode - add your target here if needed # Cross-compiling mode - add your target here if needed
case "$_host" in case "$_host" in
@ -1041,6 +1050,9 @@ fi
if test "$_build_kyra" = yes ; then if test "$_build_kyra" = yes ; then
echo " Legend of Kyrandia" echo " Legend of Kyrandia"
fi fi
if test "$_build_gob" = yes ; then
echo " Gobli*ns"
fi
echo echo
@ -1166,6 +1178,7 @@ $_mak_sword2
$_mak_queen $_mak_queen
$_mak_kyra $_mak_kyra
$_mak_saga $_mak_saga
$_mak_gob
$_mak_mt32emu $_mak_mt32emu
INCLUDES += $INCLUDES INCLUDES += $INCLUDES

20
gob/anim.cpp Normal file
View file

@ -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

21
gob/anim.h Normal file
View file

@ -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

356
gob/dataio.cpp Normal file
View file

@ -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

46
gob/dataio.h Normal file
View file

@ -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

171
gob/debug.cpp Normal file
View file

@ -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

27
gob/debug.h Normal file
View file

@ -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

908
gob/draw.cpp Normal file
View file

@ -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

111
gob/draw.h Normal file
View file

@ -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 */

59
gob/driver_vga.cpp Normal file
View file

@ -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;
}
}

22
gob/driver_vga.h Normal file
View file

@ -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

1909
gob/game.cpp Normal file

File diff suppressed because it is too large Load diff

151
gob/game.h Normal file
View file

@ -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

175
gob/global.cpp Normal file
View file

@ -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

191
gob/global.h Normal file
View file

@ -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

130
gob/gob.cpp Normal file
View file

@ -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

51
gob/gob.h Normal file
View file

@ -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

3320
gob/goblin.cpp Normal file

File diff suppressed because it is too large Load diff

192
gob/goblin.h Normal file
View file

@ -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 */

293
gob/init.cpp Normal file
View file

@ -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

20
gob/init.h Normal file
View file

@ -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

1496
gob/inter.cpp Normal file

File diff suppressed because it is too large Load diff

85
gob/inter.h Normal file
View file

@ -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

736
gob/map.cpp Normal file
View file

@ -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

57
gob/map.h Normal file
View file

@ -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 */

36
gob/module.mk Normal file
View file

@ -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

1205
gob/mult.cpp Normal file

File diff suppressed because it is too large Load diff

185
gob/mult.h Normal file
View file

@ -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 */

94
gob/pack.cpp Normal file
View file

@ -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

18
gob/pack.h Normal file
View file

@ -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

224
gob/palanim.cpp Normal file
View file

@ -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

21
gob/palanim.h Normal file
View file

@ -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 */

1210
gob/parse.cpp Normal file

File diff suppressed because it is too large Load diff

22
gob/parse.h Normal file
View file

@ -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

90
gob/resource.cpp Normal file
View file

@ -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

20
gob/resource.h Normal file
View file

@ -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

738
gob/scenery.cpp Normal file
View file

@ -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

121
gob/scenery.h Normal file
View file

@ -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 */

44
gob/sound.cpp Normal file
View file

@ -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

47
gob/sound.h Normal file
View file

@ -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

21
gob/timer.cpp Normal file
View file

@ -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()");
}
};

25
gob/timer.h Normal file
View file

@ -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

465
gob/util.cpp Normal file
View file

@ -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

68
gob/util.h Normal file
View file

@ -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

547
gob/video.cpp Normal file
View file

@ -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

125
gob/video.h Normal file
View file

@ -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