[Scummvm-cvs-logs] CVS: scummvm/gob anim.cpp,NONE,1.1 anim.h,NONE,1.1 dataio.cpp,NONE,1.1 dataio.h,NONE,1.1 debug.cpp,NONE,1.1 debug.h,NONE,1.1 draw.cpp,NONE,1.1 draw.h,NONE,1.1 driver_vga.cpp,NONE,1.1 driver_vga.h,NONE,1.1 game.cpp,NONE,1.1 game.h,NONE,1.1 global.cpp,NONE,1.1 global.h,NONE,1.1 gob.cpp,NONE,1.1 gob.h,NONE,1.1 goblin.cpp,NONE,1.1 goblin.h,NONE,1.1 init.cpp,NONE,1.1 init.h,NONE,1.1 inter.cpp,NONE,1.1 inter.h,NONE,1.1 map.cpp,NONE,1.1 map.h,NONE,1.1 module.mk,NONE,1.1 mult.cpp,NONE,1.1 mult.h,NONE,1.1 pack.cpp,NONE,1.1 pack.h,NONE,1.1 palanim.cpp,NONE,1.1 palanim.h,NONE,1.1 parse.cpp,NONE,1.1 parse.h,NONE,1.1 resource.cpp,NONE,1.1 resource.h,NONE,1.1 scenery.cpp,NONE,1.1 scenery.h,NONE,1.1 sound.cpp,NONE,1.1 sound.h,NONE,1.1 timer.cpp,NONE,1.1 timer.h,NONE,1.1 util.cpp,NONE,1.1 util.h,NONE,1.1 video.cpp,NONE,1.1 video.h,NONE,1.1

Eugene Sandulenko sev at users.sourceforge.net
Tue Apr 5 08:08:08 CEST 2005


Update of /cvsroot/scummvm/scummvm/gob
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25761/gob

Added Files:
	anim.cpp anim.h dataio.cpp dataio.h debug.cpp debug.h draw.cpp 
	draw.h driver_vga.cpp driver_vga.h game.cpp game.h global.cpp 
	global.h gob.cpp gob.h goblin.cpp goblin.h init.cpp init.h 
	inter.cpp inter.h map.cpp map.h module.mk mult.cpp mult.h 
	pack.cpp pack.h palanim.cpp palanim.h parse.cpp parse.h 
	resource.cpp resource.h scenery.cpp scenery.h sound.cpp 
	sound.h timer.cpp timer.h util.cpp util.h video.cpp video.h 
Log Message:
Initial checking of Gob engine


--- NEW FILE: anim.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: anim.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: dataio.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: dataio.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: debug.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: debug.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: draw.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: draw.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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 */

--- NEW FILE: driver_vga.cpp ---
#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;
}

}


--- NEW FILE: driver_vga.h ---
#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

--- NEW FILE: game.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at yandex.ru>
**
*/
#include "gob/gob.h"
#include "gob/global.h"
#include "gob/game.h"
#include "gob/video.h"
#include "gob/dataio.h"
#include "gob/pack.h"
#include "gob/debug.h"
#include "gob/inter.h"
#include "gob/parse.h"
#include "gob/draw.h"
#include "gob/mult.h"
#include "gob/util.h"
[...1870 lines suppressed...]

	inter_nestLevel = oldNestLevel;
	inter_breakFromLevel = oldBreakFrom;
	scen_pCaptureCounter = oldCaptureCounter;
	inter_execPtr = savedIP;
}

void game_start(void) {
	game_collisionAreas = (Game_Collision *)malloc(250 * sizeof(Game_Collision));
	game_prepareStart();
	game_playTot(0);

	free((char *)game_collisionAreas);

	vid_freeSurfDesc(draw_cursorSprites);
	vid_freeSurfDesc(draw_cursorBack);
	vid_freeSurfDesc(draw_backSurface);
}

} // End of namespace Gob

--- NEW FILE: game.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: global.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: global.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: gob.cpp ---
/* 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: /cvsroot/scummvm/scummvm/gob/gob.cpp,v 1.1 2005/04/05 15:07:39 sev Exp $
 *
 */
#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

--- NEW FILE: gob.h ---
/* 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: /cvsroot/scummvm/scummvm/gob/gob.h,v 1.1 2005/04/05 15:07:39 sev Exp $
 *
 */

#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

--- NEW FILE: goblin.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at yandex.ru>
**
*/
#include "gob/gob.h"
#include "gob/goblin.h"
#include "gob/debug.h"
#include "gob/inter.h"
#include "gob/global.h"
#include "gob/draw.h"
#include "gob/video.h"
#include "gob/anim.h"
#include "gob/scenery.h"
#include "gob/map.h"
#include "gob/sound.h"
#include "gob/game.h"
[...3281 lines suppressed...]
			objDesc->xPos += gob_gobPositions[0].x * 12
			    - (scen_toRedrawLeft + scen_toRedrawRight) / 2;
		}

		gob_itemIndInPocket = -1;
		gob_itemIdInPocket = -1;
		util_beep(50);
		break;

	default:
		warning("gob_interFunc: Unknown command %d!", cmd);
		inter_execPtr -= 2;
		cmd = inter_load16();
		inter_execPtr += cmd * 2;
		break;
	}
	return;
}

} // End of namespace Gob

--- NEW FILE: goblin.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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 */

--- NEW FILE: init.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: init.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: inter.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at yandex.ru>
**
*/
#include "gob/gob.h"
#include "gob/global.h"
#include "gob/inter.h"
#include "gob/util.h"
#include "gob/debug.h"
#include "gob/parse.h"
#include "gob/game.h"
#include "gob/draw.h"
#include "gob/mult.h"
#include "gob/goblin.h"

namespace Gob {
[...1457 lines suppressed...]
	inter_animPalDir = 0;
	inter_soundEndTimeKey = 0;
}

void inter_callSub(int16 retFlag) {
	int16 block;
	while (inter_execPtr != 0 && (char *)inter_execPtr != game_totFileData) {
		block = *inter_execPtr;
		if (block == 1) {
			inter_funcBlock(retFlag);
		} else if (block == 2) {
			game_collisionsBlock();
		}
	}

	if ((char *)inter_execPtr == game_totFileData)
		inter_terminate = 1;
}

} // End of namespace Gob

--- NEW FILE: inter.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: map.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: map.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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 */

--- NEW FILE: module.mk ---
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

--- NEW FILE: mult.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at yandex.ru>
**
*/
#include "gob/gob.h"
#include "gob/video.h"
#include "gob/anim.h"
#include "gob/draw.h"
#include "gob/scenery.h"
#include "gob/mult.h"
#include "gob/util.h"
#include "gob/inter.h"
#include "gob/parse.h"
#include "gob/global.h"
#include "gob/debug.h"
#include "gob/sound.h"
[...1166 lines suppressed...]
		mult_animArrayY = 0;

		if (mult_animArrayData)
			free((char *)mult_animArrayData);
		mult_animArrayData = 0;

		if (anim_underAnimSurf)
			vid_freeSurfDesc(anim_underAnimSurf);
		anim_underAnimSurf = 0;

		mult_animDataAllocated = 0;
	}
}

void mult_checkFreeMult(void) {
	if (mult_multData != 0)
		mult_freeMultKeys();
}

}				// End of namespace Gob

--- NEW FILE: mult.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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 */

--- NEW FILE: pack.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: pack.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: palanim.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: palanim.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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 */

--- NEW FILE: parse.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at yandex.ru>
**
*/
#include "gob/gob.h"
#include "gob/global.h"
#include "gob/parse.h"
#include "gob/util.h"
#include "gob/debug.h"
#include "gob/inter.h"

namespace Gob {

int16 parse_parseExpr(char arg_0, byte *arg_2) {
	int32 values[20];
	byte operStack[20];
[...1171 lines suppressed...]
		}
		debug(5, "]");

		if (operation == 28 && *inter_execPtr == 13) {
			inter_execPtr++;
			debug(5, "+");
			parse_printExpr(99);
		}
		break;

	default:
		debug(5, "var_0");
		break;
	}
	debug(5, "\n");
	inter_execPtr = pos;
	return;
}

} // End of namespace Gob

--- NEW FILE: parse.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: resource.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: resource.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: scenery.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: scenery.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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 */

--- NEW FILE: sound.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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




--- NEW FILE: sound.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: timer.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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()");
}
};

--- NEW FILE: timer.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: util.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: util.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: video.cpp ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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

--- NEW FILE: video.h ---
/*
** Gobliiins 1
** Original game by CoktelVision
**
** Reverse engineered by Ivan Dubrov <WFrag at 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





More information about the Scummvm-git-logs mailing list