[Scummvm-cvs-logs] SF.net SVN: scummvm: [31444] scummvm/trunk/engines/cine

sev at users.sourceforge.net sev at users.sourceforge.net
Mon Apr 7 22:24:40 CEST 2008


Revision: 31444
          http://scummvm.svn.sourceforge.net/scummvm/?rev=31444&view=rev
Author:   sev
Date:     2008-04-07 13:24:40 -0700 (Mon, 07 Apr 2008)

Log Message:
-----------
Patch #1913862: "CinE Script system"

Modified Paths:
--------------
    scummvm/trunk/engines/cine/anim.cpp
    scummvm/trunk/engines/cine/anim.h
    scummvm/trunk/engines/cine/bg.cpp
    scummvm/trunk/engines/cine/bg.h
    scummvm/trunk/engines/cine/bg_list.cpp
    scummvm/trunk/engines/cine/bg_list.h
    scummvm/trunk/engines/cine/cine.cpp
    scummvm/trunk/engines/cine/gfx.cpp
    scummvm/trunk/engines/cine/gfx.h
    scummvm/trunk/engines/cine/main_loop.cpp
    scummvm/trunk/engines/cine/object.cpp
    scummvm/trunk/engines/cine/object.h
    scummvm/trunk/engines/cine/part.cpp
    scummvm/trunk/engines/cine/part.h
    scummvm/trunk/engines/cine/prc.cpp
    scummvm/trunk/engines/cine/prc.h
    scummvm/trunk/engines/cine/rel.cpp
    scummvm/trunk/engines/cine/rel.h
    scummvm/trunk/engines/cine/script.cpp
    scummvm/trunk/engines/cine/script.h
    scummvm/trunk/engines/cine/sound.cpp
    scummvm/trunk/engines/cine/texte.cpp
    scummvm/trunk/engines/cine/various.cpp

Added Paths:
-----------
    scummvm/trunk/engines/cine/xref.txt

Modified: scummvm/trunk/engines/cine/anim.cpp
===================================================================
--- scummvm/trunk/engines/cine/anim.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/anim.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -23,6 +23,9 @@
  *
  */
 
+/*! \file
+ * \todo Make resource manager class and make load* functions its members
+ */
 
 #include "common/endian.h"
 #include "common/stream.h"
@@ -46,11 +49,9 @@
 	uint16 field_E;
 };
 
-static uint16 animDataCount = 0;
+AnimData animDataTable[NUM_MAX_ANIMDATA];
 
-AnimHeaderStruct animHeader;
-
-static const AnimDataEntry animData[] = {
+static const AnimDataEntry transparencyData[] = {
 	{"ALPHA", 0xF},
 	{"TITRE2", 0xF},
 	{"ET", 0xC},
@@ -184,135 +185,250 @@
 	{"FIN", 0x9},
 };
 
-static void freeAnimData(byte idx) {
-	assert(idx < NUM_MAX_ANIMDATA);
-	if (animDataTable[idx].ptr1) {
-		free(animDataTable[idx].ptr1);
-		free(animDataTable[idx].ptr2);
-		memset(&animDataTable[idx], 0, sizeof(AnimData));
-		animDataTable[idx].fileIdx = -1;
-		animDataTable[idx].frameIdx = -1;
-		if (animDataCount > 0)
-			animDataCount--;
-	}
-}
+void convertMask(byte *dest, const byte *source, int16 width, int16 height);
+void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency);
+void convert8BBP(byte *dest, const byte *source, int16 width, int16 height);
+void convert8BBP2(byte *dest, byte *source, int16 width, int16 height);
 
-void freeAnimDataRange(byte startIdx, byte numIdx) {
-	for (byte i = 0; i < numIdx; i++) {
-		freeAnimData(i + startIdx);
-	}
-}
+AnimData::AnimData() : _width(0), _height(0), _bpp(0), _var1(0), _data(NULL),
+	_mask(NULL), _fileIdx(-1), _frameIdx(-1), _realWidth(0), _size(0) {
 
-void freeAnimDataTable() {
-	freeAnimDataRange(0, NUM_MAX_ANIMDATA);
+	memset(_name, 0, 10);
 }
 
-static byte getAnimTransparentColor(const char *animName) {
-	char name[15];
+/*! \brief Copy constructor
+ */
+AnimData::AnimData(const AnimData &src) : _width(src._width),
+	_height(src._height), _bpp(src._bpp), _var1(src._var1),
+	_data(NULL), _mask(NULL), _fileIdx(src._fileIdx),
+	_frameIdx(src._frameIdx), _realWidth(src._realWidth), _size(src._size) {
 
-	removeExtention(name, animName);
+	if (src._data) {
+		_data = new byte[_size];
+		assert(_data);
+		memcpy(_data, src._data, _size*sizeof(byte));
+	}
 
-	for (int i = 0; i < ARRAYSIZE(animData); i++) {
-		if (!strcmp(name, animData[i].name)) {
-			return animData[i].color;
-		}
+	if(src._mask) {
+		_mask = new byte[_size];
+		assert(_mask);
+		memcpy(_mask, src._mask, _size*sizeof(byte));
 	}
-	return 0;
+
+	memset(_name, 0, 10);
+	strcpy(_name, src._name);
 }
 
-int16 allocFrame(uint16 width, uint16 height, int8 isMask) {
-	uint16 i;
-	uint32 frameSize;
+/*! \brief Destructor
+ */
+AnimData::~AnimData() {
+	clear();
+}
 
-	for (i = 0; i < NUM_MAX_ANIMDATA; i++) {
-		if (!animDataTable[i].ptr1)
-			break;
-	}
+/*! \brief Assingment operator
+ */
+AnimData &AnimData::operator=(const AnimData &src) {
+	AnimData tmp = src;
+	byte *ptr;
 
-	if (i == NUM_MAX_ANIMDATA)
-		return -1;
+	_width = tmp._width;
+	_height = tmp._height;
+	_bpp = tmp._bpp;
+	_var1 = tmp._var1;
 
-	if (!isMask) {		// sprite + generated mask
-		frameSize = width * height;
+	ptr = _data;
+	_data = tmp._data;
+	tmp._data = ptr;
 
-		animDataTable[i].ptr1 = (byte *)malloc(frameSize);
-		animDataTable[i].ptr2 = (byte *)malloc(frameSize);
-	} else {
-		// mask
-		frameSize = width * height * 8;
+	ptr = _mask;
+	_mask = tmp._mask;
+	tmp._mask = ptr;
 
-		animDataTable[i].ptr1 = (byte *)malloc(frameSize);
-		animDataTable[i].ptr2 = NULL;
-	}
+	_fileIdx = tmp._fileIdx;
+	_frameIdx = tmp._frameIdx;
+	memset(_name, 0, 10);
+	strcpy(_name, tmp._name);
+	_realWidth = tmp._realWidth;
+	_size = tmp._size;
 
-	animDataTable[i].width = width;
-	animDataTable[i].var1 = width >> 3;
-	animDataTable[i].bpp = 4;
-	animDataTable[i].height = height;
+	return *this;
+}
 
-	animDataTable[i].fileIdx = -1;
-	animDataTable[i].frameIdx = -1;
+byte AnimData::getColor(int x, int y) {
+	assert(_data);
+	assert(x >= 0 && x < _realWidth && y >= 0 && y <= _height);
+	assert(x + y * _realWidth < _size);
 
-	animDataCount++;
-
-	return i;
+	return _data[x + y * _realWidth];
 }
 
-int16 reserveFrame(uint16 width, uint16 height, uint16 type, int16 idx) {
-	uint16 i;
-	uint32 frameSize;
+/*! \brief Load and decode image frame
+ * \param d Encoded image data
+ * \param type Encoding type
+ * \param w Image width
+ * \param h Image height
+ * \param file Data file index in bundle
+ * \param frame Image frame index
+ * \param n Part name
+ * \param transparent Transparent color (for ANIM_MASKSPRITE)
+ */
+void AnimData::load(byte *d, int type, uint16 w, uint16 h, int16 file,
+	int16 frame, const char *n, byte transparent) {
 
-	if (idx >= 0) {
-		i = (uint16) idx;
-	} else {
-		for (i = 0; i < NUM_MAX_ANIMDATA; i++) {
-			if (!animDataTable[i].ptr1)
-				break;
-		}
+	assert(d);
 
-		if (i == NUM_MAX_ANIMDATA)
-			return -1;
+	if (_data) {
+		clear();
 	}
 
-	frameSize = width * height;
+	_width = w * 2;
+	_height = h;
+	_var1 = _width >> 3;
+	_data = NULL;
+	_mask = NULL;
+	_fileIdx = file;
+	_frameIdx = frame;
+	memset(_name, 0, 10);
+	strcpy(_name, n);
+	_realWidth = w;
 
-	if (type == 4) {		// 256 color sprites
-		frameSize *= 2;
-		type = 8;
-		width *= 2;
-	}
+	switch (type) {
+	case ANIM_RAW:
+		_width = w;
+		_var1 = w >> 3;
+		_bpp = 4;
+		_size = w * h;
+		_data = new byte[_size];
+		assert(_data);
+		memcpy(_data, d, _size*sizeof(byte));
+		break;
 
-	if (type == 5) {
-		frameSize += 16;
-	}
+	case ANIM_MASK:
+		_bpp = 1;
+		_size = w * h * 8;
+		_data = new byte[_size];
+		_realWidth = w * 8;
+		assert(_data);
+		convertMask(_data, d, w, h);
+		break;
 
-	frameSize *= 2;
+	case ANIM_SPRITE:
+		_bpp = 4;
+		_size = w * h * 2;
+		_data = new byte[_size];
+		_realWidth = w * 2;
+		assert(_data);
+		gfxConvertSpriteToRaw(_data, d, w, h);
+		break;
 
-	animDataTable[i].ptr1 = (byte *)malloc(frameSize);
+	case ANIM_MASKSPRITE:
+		_bpp = 4;
+		_size = w * h * 2;
+		_data = new byte[_size];
+		_mask = new byte[_size];
+		_realWidth = w * 2;
+		assert(_data && _mask);
+		gfxConvertSpriteToRaw(_data, d, w, h);
+		generateMask(_data, _mask, _size, transparent);
+		break;
 
-	assert(animDataTable[i].ptr1);
+	case ANIM_PALSPRITE:
+		_bpp = 5;
+		_size = w * h * 2;
+		_data = new byte[_size];
+		_realWidth = w * 2;
+		assert(_data);
+		convert8BBP(_data, d, w, h);
+		break;
 
-	animDataTable[i].width = width;
+	case ANIM_FULLSPRITE:
+		_bpp = 8;
+		_var1 = _width >> 4;
+		_size = w * h;
+		_data = new byte[_size];
+		assert(_data);
+		convert8BBP2(_data, d, w, h);
+		break;
 
-	if (type == 5) {
-		animDataTable[i].var1 = width / 8;
-	} else {
-		animDataTable[i].var1 = width / 16;
+	default:
+		error("AnimData::load: unknown image type");
 	}
+}
 
-	animDataTable[i].bpp = type;
+/*! \brief Reset image
+ */
+void AnimData::clear() {
+	delete[] _data;
+	delete [] _mask;
 
-	animDataTable[i].height = height;
+	_width = 0;
+	_height = 0;
+	_bpp = 0;
+	_var1 = 0;
+	_data = NULL;
+	_mask = NULL;
+	_fileIdx = -1;
+	_frameIdx = -1;
+	memset(_name, 0, 10);
+	_size = 0;
+}
 
-	animDataTable[i].fileIdx = -1;
-	animDataTable[i].frameIdx = -1;
+/*! \brief Write image identifiers to savefile
+ * \param fHandle Savefile open for writing
+ */
+void AnimData::save(Common::OutSaveFile &fHandle) const {
+	fHandle.writeUint16BE(_width);
+	fHandle.writeUint16BE(_var1);
+	fHandle.writeUint16BE(_bpp);
+	fHandle.writeUint16BE(_height);
+	// Just because I write pointers to a file doesn't mean
+	// anyone should actually read those values back!
+	fHandle.writeUint32BE((uint32)_data);
+	fHandle.writeUint32BE((uint32)_mask);
+	fHandle.writeUint16BE(_fileIdx);
+	fHandle.writeUint16BE(_frameIdx);
+	fHandle.write(_name, 10);
+}
 
-	animDataCount++;
+/*! \brief Clear part of animDataTable
+ * \param startIdx First image frame to be cleared
+ * \param numIdx Number of image frames to be cleared
+ */
+void freeAnimDataRange(byte startIdx, byte numIdx) {
+	for (byte i = 0; i < numIdx; i++) {
+		animDataTable[startIdx + i].clear();
+	}
+}
 
-	return i;
+/*! \brief Clear whole animDataTable
+ */
+void freeAnimDataTable() {
+	freeAnimDataRange(0, NUM_MAX_ANIMDATA);
 }
 
-void generateMask(byte * sprite, byte * mask, uint16 size, byte transparency) {
+/*! \brief Find transparent color index for image
+ * \brief animName Image file name
+ */
+static byte getAnimTransparentColor(const char *animName) {
+	char name[15];
+
+	removeExtention(name, animName);
+
+	for (int i = 0; i < ARRAYSIZE(transparencyData); i++) {
+		if (!strcmp(name, transparencyData[i].name)) {
+			return transparencyData[i].color;
+		}
+	}
+	return 0;
+}
+
+/*! \brief Generate mask for image
+ * \param[in] sprite Image data
+ * \param[out] mask Image mask
+ * \param size Image data length
+ * \param transparency Transparent color index
+ */
+void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency) {
 	for (uint16 i = 0; i < size; i++) {
 		if (*(sprite++) != transparency) {
 			*(mask++) = 0;
@@ -322,7 +438,13 @@
 	}
 }
 
-void convertMask(byte * dest, byte * source, int16 width, int16 height) {
+/*! \brief Decode 1bpp mask
+ * \param[out] dest Decoded mask
+ * \param[in] source Encoded mask
+ * \param width Mask width
+ * \param height Mask height
+ */
+void convertMask(byte *dest, const byte *source, int16 width, int16 height) {
 	int16 i, j;
 	byte maskEntry;
 
@@ -335,7 +457,13 @@
 	}
 }
 
-void convert4BBP(byte * dest, byte * source, int16 width, int16 height) {
+/*! \brief Decode 4bpp sprite
+ * \param[out] dest Decoded image
+ * \param[in] source Encoded image
+ * \param width Image width
+ * \param height Image height
+ */
+void convert4BBP(byte *dest, const byte *source, int16 width, int16 height) {
 	byte maskEntry;
 
 	for (int16 i = 0; i < width * height; i++) {
@@ -345,7 +473,11 @@
 	}
 }
 
-void loadAnimHeader(Common::MemoryReadStream readS) {
+/*! \brief Read image header
+ * \param[out] animHeader Image header reference
+ * \param readS Input stream open for reading
+ */
+void loadAnimHeader(AnimHeaderStruct &animHeader, Common::MemoryReadStream readS) {
 	animHeader.field_0 = readS.readByte();
 	animHeader.field_1 = readS.readByte();
 	animHeader.field_2 = readS.readByte();
@@ -366,115 +498,109 @@
 	animHeader.field_14 = readS.readUint16BE();
 }
 
+/*! \brief Find next empty space animDataTable
+ * \param start First index to check
+ */
+int emptyAnimSpace(int start = 0) {
+	for (; start < NUM_MAX_ANIMDATA; start++) {
+		if (!animDataTable[start].data()) {
+			return start;
+		}
+	}
+
+	return -1;
+}
+
+/*! \brief Load SPL data into animDataTable
+ * \param resourceName SPL filename
+ * \param idx Target index in animDataTable
+ */
 void loadSpl(const char *resourceName, int16 idx) {
 	int16 foundFileIdx = findFileInBundle(resourceName);
-	int16 entry;
+	int entry;
+
+	if (foundFileIdx < 0) {
+		return;
+	}
+
 	byte *dataPtr = readBundleFile(foundFileIdx);
 
-	if (idx >= 0) {
-		entry = reserveFrame((uint16) partBuffer[foundFileIdx].unpackedSize, 1, 0, idx);
-		memcpy(animDataTable[entry].ptr1, dataPtr, partBuffer[foundFileIdx].unpackedSize);
-	} else {
-		entry = allocFrame((uint16) partBuffer[foundFileIdx].unpackedSize, 1, -1);
-		assert(entry != -1);
-		memcpy(animDataTable[entry].ptr1, dataPtr, (uint16) partBuffer[foundFileIdx].unpackedSize);
+	entry = idx < 0 ? emptyAnimSpace() : idx;
+	assert(entry >= 0);
+	animDataTable[entry].load(dataPtr, ANIM_RAW, partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName);
 
-		animDataTable[entry].fileIdx = foundFileIdx;
-		animDataTable[entry].frameIdx = 0;
-		strcpy(animDataTable[entry].name, currentPartName);
-	}
-
 	free(dataPtr);
 }
 
+/*! \brief Load 1bpp mask
+ * \param resourceName Mask filename
+ */
 void loadMsk(const char *resourceName) {
 	int16 foundFileIdx = findFileInBundle(resourceName);
-	int16 entry;
+	int entry = 0;
 	byte *dataPtr = readBundleFile(foundFileIdx);
 	byte *ptr;
+	AnimHeaderStruct animHeader;
 
 	Common::MemoryReadStream readS(dataPtr, 0x16);
-	loadAnimHeader(readS);
+	loadAnimHeader(animHeader, readS);
 	ptr = dataPtr + 0x16;
 
-	for (int16 i = 0; i < animHeader.numFrames; i++) {
-		entry = allocFrame(animHeader.frameWidth * 2, animHeader.frameHeight, 1);
-
-		assert(entry != -1);
-
-		convertMask(animDataTable[entry].ptr1, ptr, animHeader.frameWidth, animHeader.frameHeight);
+	for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
+		entry = emptyAnimSpace(entry);
+		assert(entry >= 0);
+		animDataTable[entry].load(ptr, ANIM_MASK, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName);
 		ptr += animHeader.frameWidth * animHeader.frameHeight;
-
-		animDataTable[entry].fileIdx = foundFileIdx;
-		animDataTable[entry].frameIdx = i;
-		strcpy(animDataTable[entry].name, currentPartName);
 	}
 
 	free(dataPtr);
 }
 
+/*! \brief Load animation
+ * \param resourceName Animation filename
+ */
 void loadAni(const char *resourceName) {
 	int16 foundFileIdx = findFileInBundle(resourceName);
-	int16 entry;
+	int entry = 0;
 	byte *dataPtr = readBundleFile(foundFileIdx);
-	byte *ptr, *animPtr;
+	byte *ptr;
 	byte transparentColor;
-	uint32 fullSize;
+	AnimHeaderStruct animHeader;
 
 	Common::MemoryReadStream readS(dataPtr, 0x16);
-	loadAnimHeader(readS);
+	loadAnimHeader(animHeader, readS);
 	ptr = dataPtr + 0x16;
 
 	transparentColor = getAnimTransparentColor(resourceName);
 
-	fullSize = animHeader.frameWidth * animHeader.frameHeight;
+	for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
+		entry = emptyAnimSpace(entry);
+		assert(entry >= 0);
 
-	for (int16 i = 0; i < animHeader.numFrames; i++) {
-		entry = allocFrame(animHeader.frameWidth * 2, animHeader.frameHeight, 0);
-
-		assert(entry != -1);
-
 		// special case transparency handling
 		if (!strcmp(resourceName, "L2202.ANI")) {
-			if (i < 2) {
-				transparentColor = 0;
-			} else {
-				transparentColor = 7;
-			}
+			transparentColor = i < 2 ? 0 : 7;
+		} else if (!strcmp(resourceName, "L4601.ANI")) {
+			transparentColor = i < 1 ? 0xE : 0;
 		}
 
-		if (!strcmp(resourceName, "L4601.ANI")) {
-			if (i < 1) {
-				transparentColor = 0xE;
-			} else {
-				transparentColor = 0;
-			}
-		}
-
-		animPtr = (byte *)malloc(fullSize);
-
-		memcpy(animPtr, ptr, fullSize);
-		ptr += fullSize;
-
-		gfxConvertSpriteToRaw(animDataTable[entry].ptr1, animPtr, animHeader.frameWidth, animHeader.frameHeight);
-
-		generateMask(animDataTable[entry].ptr1, animDataTable[entry].ptr2, animHeader.frameWidth * 2 * animHeader.frameHeight, transparentColor);
-
-		free(animPtr);
-
-		animDataTable[entry].fileIdx = foundFileIdx;
-		animDataTable[entry].frameIdx = i;
-		strcpy(animDataTable[entry].name, currentPartName);
+		animDataTable[entry].load(ptr, ANIM_MASKSPRITE, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName, transparentColor);
+		ptr += animHeader.frameWidth * animHeader.frameHeight;
 	}
 
 	free(dataPtr);
 }
 
-void convert8BBP(byte * dest, byte * source, int16 width, int16 height) {
-	byte table[16];
+/*! \brief Decode 16 color image with palette
+ * \param[out] dest Decoded image
+ * \param[in] source Encoded image
+ * \param width Image width
+ * \param height Image height
+ */
+void convert8BBP(byte *dest, const byte *source, int16 width, int16 height) {
+	const byte *table = source;
 	byte color;
 
-	memcpy(table, source, 16);
 	source += 16;
 
 	for (uint16 i = 0; i < width * height; i++) {
@@ -485,16 +611,24 @@
 	}
 }
 
-void convert8BBP2(byte * dest, byte * source, int16 width, int16 height) {
-	uint16 i, j, k, m;
+/*! \brief Decode 8bit image
+ * \param[out] dest Decoded image
+ * \param[in] source Encoded image
+ * \param width Image width
+ * \param height Image height
+ * \attention Data in source are destroyed during decoding
+ */
+void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
+	uint16 i, j;
+	int k, m;
 	byte color;
 
 	for (j = 0; j < (width * height) / 16; j++) {
 		// m = 0: even bits, m = 1: odd bits
-		for (m = 0; m < 2; m++) {
+		for (m = 0; m <= 1; m++) {
 			for (i = 0; i < 8; i++) {
 				color = 0;
-				for (k = 14 + m; k >= 0 + m; k = k - 2) {
+				for (k = 14 + m; k >= 0; k -= 2) {
 					color |= ((*(source + k) & 0x080) >> 7);
 					*(source + k) <<= 1;
 					if (k > 0 + m)
@@ -508,14 +642,17 @@
 	}	// end j
 }
 
+/*! \brief Load image set
+ * \param resourceName Image set filename
+ * \param idx Target index in animDataTable
+ */
 void loadSet(const char *resourceName, int16 idx) {
 	AnimHeader2Struct header2;
-	uint32 fullSize;
 	uint16 numSpriteInAnim;
 	int16 foundFileIdx = findFileInBundle(resourceName);
-	int16 entry, typeParam;
+	int16 entry = idx >= 0 ? idx : 0;
 	byte *ptr, *startOfDataPtr, *dataPtr, *origDataPtr;
-	byte table[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+	int type;
 
 	origDataPtr = dataPtr = readBundleFile(foundFileIdx);
 	assert(!memcmp(dataPtr, "SET", 3));
@@ -526,9 +663,7 @@
 
 	startOfDataPtr = ptr + numSpriteInAnim * 0x10;
 
-	for (int16 i = 0; i < numSpriteInAnim; i++) {
-		typeParam = 0;
-
+	for (int16 i = 0; i < numSpriteInAnim; i++, entry++) {
 		Common::MemoryReadStream readS(ptr, 0x10);
 
 		header2.field_0 = readS.readUint32BE();
@@ -541,56 +676,37 @@
 
 		ptr += 0x10;
 
-		fullSize = header2.width * header2.height;
+		entry = idx < 0 ? emptyAnimSpace(entry) : idx + i;
+		assert(entry >= 0);
 
-		if (header2.type == 5) {
-			fullSize += 16;
-		}
-
-		if (header2.type == 4) {
-			header2.type = 5;
-			typeParam = 1;
-		}
-
-		if (idx >= 0)
-			entry = reserveFrame(header2.width * 2, header2.height, header2.type, idx + i);
-		else
-			entry = reserveFrame(header2.width * 2, header2.height, header2.type, -1);
-
-		assert(entry != -1);
-
 		dataPtr = startOfDataPtr + header2.field_0;
 
-		if (typeParam) {
-			memcpy(animDataTable[entry].ptr1, table, 0x10);
-			gfxConvertSpriteToRaw(animDataTable[entry].ptr1, dataPtr, header2.width, header2.height);
-			//memcpy(animDataTable[entry].ptr1 + 0x10, dataPtr, fullSize);
+		if (header2.type == 1) {
+			type = ANIM_MASK;
+		} else if (header2.type == 4) {
+			type = ANIM_SPRITE;
+		} else if (header2.type == 5) {
+			type = ANIM_PALSPRITE;
 		} else {
-			if (header2.type == 1) {
-				convert4BBP(animDataTable[entry].ptr1, dataPtr, header2.width, header2.height);
-			} else if (header2.type == 5) {
-				convert8BBP(animDataTable[entry].ptr1, dataPtr, header2.width, header2.height);
-			} else if (header2.type == 4) {
-				error("loadSet: header2.type == 4");
-			} else {
-				convert8BBP2(animDataTable[entry].ptr1, dataPtr, header2.width, header2.height);
-			}
+			type = ANIM_FULLSPRITE;
 		}
 
-		animDataTable[entry].fileIdx = foundFileIdx;
-		animDataTable[entry].frameIdx = i;
-		strcpy(animDataTable[entry].name, currentPartName);
+		animDataTable[entry].load(dataPtr, type, header2.width, header2.height, foundFileIdx, i, currentPartName);
 	}
 
 	free(origDataPtr);
 }
 
+/*! \brief Load SEQ data into animDataTable
+ * \param resourceName SEQ data filename
+ * \param idx Target index in animDataTable
+ */
 void loadSeq(const char *resourceName, int16 idx) {
 	int16 foundFileIdx = findFileInBundle(resourceName);
 	byte *dataPtr = readBundleFile(foundFileIdx);
-	int16 entry = reserveFrame((uint16) partBuffer[foundFileIdx].unpackedSize, 1, 0, idx);
+	int entry = idx < 0 ? emptyAnimSpace() : idx;
 
-	memcpy(animDataTable[entry].ptr1, dataPtr + 0x16, (uint16) partBuffer[foundFileIdx].unpackedSize - 0x16);
+	animDataTable[entry].load(dataPtr+0x16, ANIM_RAW, partBuffer[foundFileIdx].unpackedSize-0x16, 1, foundFileIdx, 0, currentPartName);
 	free(dataPtr);
 }
 
@@ -624,6 +740,8 @@
 	error("loadResource: Cannot determine type for '%s'", resourceName);
 }
 
+/*! \todo There seems to be some additional resource file that is not loaded
+ */
 void loadAbs(const char *resourceName, uint16 idx) {
 	/* byte isMask = 0; */
 	/* byte isSpl = 0; */
@@ -632,6 +750,7 @@
 		loadSet(resourceName, idx);
 		return;
 	} else if (strstr(resourceName, ".H32")) {
+		warning("Ignoring file %s (load at %d)", resourceName, idx);
 		return;
 	} else if (strstr(resourceName, ".SEQ")) {
 		loadSeq(resourceName, idx);
@@ -640,116 +759,108 @@
 		loadSpl(resourceName, idx);
 		return;
 	} else if (strstr(resourceName, ".AMI")) {
+		warning("Ignoring file %s (load at %d)", resourceName, idx);
 		return;
 	} else if (strstr(resourceName, ".ANI")) {
+		warning("Ignoring file %s (load at %d)", resourceName, idx);
 		return;
 	}
 
 	error("loadAbs: Cannot determine type for '%s'", resourceName);
 }
 
-void loadResourcesFromSave() {
-	int16 currentAnim, foundFileIdx, fullSize, entry, i;
+/*! \brief Load animDataTable from save
+ * \param fHandle Savefile open for reading
+ * \param broken Broken/correct file format switch
+ * \todo Add Operation Stealth savefile support
+ *
+ * Unlike the old code, this one actually rebuilds the table one frame
+ * at a time.
+ */
+void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken) {
+	int16 currentAnim, foundFileIdx;
 	int8 isMask = 0, isSpl = 0;
-	byte *dataPtr, *ptr, *animPtr;
-	char animName[256], part[256];
+	byte *dataPtr, *ptr;
+	char *animName, part[256];
 	byte transparentColor;
 	AnimData *currentPtr;
+	AnimHeaderStruct animHeader;
 
+	uint16 width, height, bpp, var1;
+	int16  frame;
+	char name[10];
+	int type;
+
 	strcpy(part, currentPartName);
 
 	for (currentAnim = 0; currentAnim < NUM_MAX_ANIMDATA; currentAnim++) {
 		currentPtr = &animDataTable[currentAnim];
-		if (currentPtr->refresh && currentPtr->fileIdx != -1) {
-			if (strcmp(currentPartName, currentPtr->name)) {
-				closePart();
-				loadPart(currentPtr->name);
-			}
 
-			foundFileIdx = currentPtr->fileIdx;
+		width = fHandle.readUint16BE();
+		var1 = fHandle.readUint16BE();
+		bpp = fHandle.readUint16BE();
+		height = fHandle.readUint16BE();
 
-			strcpy(animName, partBuffer[foundFileIdx].partName);
-			ptr = dataPtr = readBundleFile(foundFileIdx);
-
-			isSpl  = (strstr(animName, ".SPL")) ? 1 : 0;
-			isMask = (strstr(animName, ".MSK")) ? 1 : 0;
-
-			if (isSpl) {
-				animHeader.frameWidth = (uint16) partBuffer[foundFileIdx].unpackedSize;
-				animHeader.frameHeight = 1;
-				animHeader.numFrames = 1;
-				isMask = -1;
-			} else {
-				Common::MemoryReadStream readS(ptr, 0x22);
-
-				loadAnimHeader(readS);
-
-				ptr += 0x16;
+		if (!broken) {
+			if (!fHandle.readUint32BE()) {
+				fHandle.skip(18);
+				continue;
 			}
+			fHandle.readUint32BE();
+		}
 
-			{
-				fullSize = animHeader.frameWidth * animHeader.frameHeight;
+		foundFileIdx = fHandle.readSint16BE();
+		frame = fHandle.readSint16BE();
+		fHandle.read(name, 10);
 
-				loadRelatedPalette(animName);
+		if (foundFileIdx < 0 || (broken && !fHandle.readByte())) {
+			continue;
+		}
 
-				transparentColor = getAnimTransparentColor(animName);
+		if (strcmp(currentPartName, name)) {
+			closePart();
+			loadPart(name);
+		}
 
-				for (i = 0; i < animHeader.numFrames; i++) { // load all the frames
-					// special case transparency handling
-					if (!strcmp(animName, "L2202.ANI")) {
-						if (i < 2) {
-							transparentColor = 0;
-						} else {
-							transparentColor = 7;
-						}
-					}
+		animName = partBuffer[foundFileIdx].partName;
+		ptr = dataPtr = readBundleFile(foundFileIdx);
 
-					if (!strcmp(animName, "L4601.ANI")) {
-						if (i < 1) {
-							transparentColor = 0xE;
-						} else {
-							transparentColor = 0;
-						}
-					}
+		isSpl  = (strstr(animName, ".SPL")) ? 1 : 0;
+		isMask = (strstr(animName, ".MSK")) ? 1 : 0;
 
-					currentPtr[i].ptr1 = NULL;
-					entry = allocFrame(animHeader.frameWidth * 2, animHeader.frameHeight, isMask);
+		if (isSpl) {
+			width = (uint16) partBuffer[foundFileIdx].unpackedSize;
+			height = 1;
+			frame = 0;
+			type = ANIM_RAW;
+		} else {
+			Common::MemoryReadStream readS(ptr, 0x16);
+			loadAnimHeader(animHeader, readS);
+			ptr += 0x16;
 
-					currentPtr->fileIdx = foundFileIdx;
+			width = animHeader.frameWidth;
+			height = animHeader.frameHeight;
 
-					assert(entry != -1);
+			if (isMask) {
+				type = ANIM_MASK;
+			} else {
+				type = ANIM_MASKSPRITE;
 
-					if (isSpl) {
-						memcpy(animDataTable[entry].ptr1, ptr, fullSize);
-						ptr += fullSize;
-					} else {
-						if (!isMask) {
-							animPtr = (byte *)malloc(fullSize);
-							memcpy(animPtr, ptr, fullSize);
-							ptr += fullSize;
+				loadRelatedPalette(animName);
+				transparentColor = getAnimTransparentColor(animName);
 
-							gfxConvertSpriteToRaw(animDataTable[entry].ptr1, animPtr,
-										animHeader.frameWidth, animHeader.frameHeight);
-							generateMask(animDataTable[entry].ptr1, animDataTable[entry].ptr2,
-										animHeader.frameWidth * 2 *animHeader.frameHeight, transparentColor);
-
-							free(animPtr);
-						} else {
-							convertMask(animDataTable[entry].ptr1, ptr, animHeader.frameWidth,
-										animHeader.frameHeight);
-							ptr += fullSize;
-						}
-					}
-
-					//animDataTable[entry].fileIdx = foundFileIdx; // Only when reading from bundles
-
-					animDataTable[entry].frameIdx = i;
-					strcpy(animDataTable[entry].name, currentPartName);
+				// special case transparency handling
+				if (!strcmp(animName, "L2202.ANI")) {
+					transparentColor = (frame < 2) ? 0 : 7;
+				} else if (!strcmp(animName, "L4601.ANI")) {
+					transparentColor = (frame < 1) ? 0xE : 0;
 				}
 			}
+		}
 
-			free(dataPtr);
-		}
+		ptr += frame * width * height;
+		currentPtr->load(ptr, type, width, height, foundFileIdx, frame, name, transparentColor);
+		free(dataPtr);
 	}
 
 	loadPart(part);

Modified: scummvm/trunk/engines/cine/anim.h
===================================================================
--- scummvm/trunk/engines/cine/anim.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/anim.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -54,11 +54,54 @@
 	byte color;
 };
 
+#define ANIM_RAW 0 // memcpy
+#define ANIM_MASK 1 // convertMask
+#define ANIM_SPRITE 2 // gfxConvertSpriteToRaw
+#define ANIM_MASKSPRITE 3 // gfxConvertSpriteToRaw + generateMask
+#define ANIM_PALSPRITE 5 // convert8BBP
+#define ANIM_FULLSPRITE 8 // convert8BBP2
+
+class AnimData {
+private:
+	byte *_data; ///< Image data
+	byte *_mask; ///< Image mask (may be NULL)
+	int16 _fileIdx; ///< Source file index in bundle
+	int16 _frameIdx; ///< Frame number in animation
+	char _name[10]; ///< Part filename
+	int _size; ///< _data/_mask size, internal only
+
+public:
+	uint16 _width; ///< Image width (ussually twice the real size)
+	uint16 _height; ///< Image height
+	uint16 _bpp; ///< Bit depth/type information
+	uint16 _var1; ///< Something related to width
+	int _realWidth; ///< Real image width in bytes
+
+	AnimData();
+	AnimData(const AnimData &src);
+	~AnimData();
+
+	AnimData &operator=(const AnimData &src);
+
+	const byte *data() const { return _data; } ///< Image data
+	const byte *mask() const { return _mask; } ///< Image mask (may be NULL)
+	byte getColor(int x, int y);
+
+	void load(byte *d, int type, uint16 w, uint16 h, int16 file, int16 frame, const char *n, byte transparent = 0);
+	void clear();
+
+	void save(Common::OutSaveFile &fHandle) const;
+};
+
+#define NUM_MAX_ANIMDATA 255
+
+extern AnimData animDataTable[NUM_MAX_ANIMDATA];
+
 void freeAnimDataTable(void);
 void freeAnimDataRange(byte startIdx, byte numIdx);
 void loadResource(const char *animName);
 void loadAbs(const char *resourceName, uint16 idx);
-void loadResourcesFromSave();
+void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken);
 
 } // End of namespace Cine
 

Modified: scummvm/trunk/engines/cine/bg.cpp
===================================================================
--- scummvm/trunk/engines/cine/bg.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/bg.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -29,6 +29,7 @@
 
 #include "cine/cine.h"
 #include "cine/various.h"
+#include "cine/bg.h"
 
 namespace Cine {
 
@@ -36,10 +37,6 @@
 byte *additionalBgTable[9];
 byte currentAdditionalBgIdx = 0, currentAdditionalBgIdx2 = 0;
 
-void loadCtHigh(byte * currentPtr) {
-	memcpy(page3Raw, currentPtr, 320 * 200);
-}
-
 byte loadCt(const char *ctName) {
 	uint16 header[32];
 	byte *ptr, *dataPtr;
@@ -52,10 +49,17 @@
 	if (g_cine->getGameType() == Cine::GType_OS) {
 		uint16 bpp = READ_BE_UINT16(ptr); ptr += 2;
 		if (bpp == 8) {
+			ctColorMode = 1;
+			memcpy(newPalette, ptr, 256*3);
 			ptr += 3 * 256;
-			loadCtHigh(ptr);
+			memcpy(page3Raw, ptr, 320 * 200);
 		} else {
-			ptr += 32;
+			ctColorMode = 0;
+			for (int i = 0; i < 16; i++) {
+				tempPalette[i] = READ_BE_UINT16(ptr);
+				ptr += 2;
+			}
+
 			gfxResetRawPage(page3Raw);
 			gfxConvertSpriteToRaw(page3Raw, ptr, 160, 200);
 		}
@@ -78,12 +82,14 @@
 }
 
 void loadBgHigh(const char *currentPtr) {
-	memcpy(palette256, currentPtr, 256 * 3);
+	memcpy(newPalette, currentPtr, 256 * 3);
 	currentPtr += 256 * 3;
 
 	memcpy(page2Raw, currentPtr, 320 * 200);
 
-	colorMode256 = 1;
+	newColorMode = 2;
+	bgColorMode = 1;
+
 }
 
 byte loadBg(const char *bgName) {
@@ -99,7 +105,8 @@
 	if (bpp == 8) {
 		loadBgHigh((const char *)ptr);
 	} else {
-		colorMode256 = 0;
+		newColorMode = 1;
+		bgColorMode = 0;
 
 		for (int i = 0; i < 16; i++) {
 			tempPalette[i] = READ_BE_UINT16(ptr);
@@ -127,12 +134,22 @@
 
 	additionalBgTable[bgIdx] = (byte *) malloc(320 * 200);
 
+	debug("addBackground %d", bgIdx);
+
 	uint16 bpp = READ_BE_UINT16(ptr); ptr += 2;
+
 	if (bpp == 8) {
+		bgColorMode = 1;
+		memcpy(newPalette, ptr, 256*3);
 		ptr += 3 * 256;
 		memcpy(additionalBgTable[bgIdx], ptr, 320 * 200);
 	} else {
-		ptr += 32;
+		bgColorMode = 0;
+		for (int i = 0; i < 16; i++) {
+			tempPalette[i] = READ_BE_UINT16(ptr);
+			ptr += 2;
+		}
+
 		gfxConvertSpriteToRaw(additionalBgTable[bgIdx], ptr, 160, 200);
 	}
 	free(dataPtr);

Modified: scummvm/trunk/engines/cine/bg.h
===================================================================
--- scummvm/trunk/engines/cine/bg.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/bg.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -27,10 +27,17 @@
 #define CINE_BG_H
 
 namespace Cine {
+struct bgData {
+	byte *data;
+	byte colorMode;
+	byte *highPalette;
+	uint16 *lowPalette;
+};
 
 byte loadBg(const char *bgName);
 byte loadCt(const char *bgName);
 
+//extern bgData additionalBgTable[9];
 extern byte *additionalBgTable[9];
 extern byte currentAdditionalBgIdx;
 extern byte currentAdditionalBgIdx2;

Modified: scummvm/trunk/engines/cine/bg_list.cpp
===================================================================
--- scummvm/trunk/engines/cine/bg_list.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/bg_list.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -36,129 +36,116 @@
 namespace Cine {
 
 uint32 var8;
-BGIncrustList *bgIncrustList;
+Common::List<BGIncrust> bgIncrustList;
 
+/*! \brief Add masked sprite to the background
+ * \param objIdx Sprite description
+ * \param addList Add sprite to incrust list if true
+ * \todo Fix incrust objects on CT background. Always drawing incrust elements
+ * on CT background breaks game zones
+ */
 void addToBGList(int16 objIdx, bool addList) {
 	int16 x = objectTable[objIdx].x;
 	int16 y = objectTable[objIdx].y;
-	int16 width = animDataTable[objectTable[objIdx].frame].var1;
-	int16 height = animDataTable[objectTable[objIdx].frame].height;
+	int16 width = animDataTable[objectTable[objIdx].frame]._var1;
+	int16 height = animDataTable[objectTable[objIdx].frame]._height;
+	const byte *data = animDataTable[objectTable[objIdx].frame].data();
+	const byte *mask = animDataTable[objectTable[objIdx].frame].mask();
 //	int16 part = objectTable[objIdx].part;
 
+	// Operation Stealth may switch among multiple backgrounds
 	if (g_cine->getGameType() == GType_OS) {
-		drawSpriteRaw2(animDataTable[objectTable[objIdx].frame].ptr1, objectTable[objIdx].part, width, height, page2Raw, x, y);
+		for (int i = 0; i < 8; i++) {
+			if (additionalBgTable[i]) {
+				drawSpriteRaw2(data, objectTable[objIdx].part, width, height, additionalBgTable[i], x, y);
+			}
+		}
 	} else {
-		drawSpriteRaw(animDataTable[objectTable[objIdx].frame].ptr1, animDataTable[objectTable[objIdx].frame].ptr2, width, height, page2Raw, x, y);
+		drawSpriteRaw(data, mask, width, height, page2Raw, x, y);
 	}
 
 	if (addList)
 		createBgIncrustListElement(objIdx, 0);
 }
 
+/*! \brief Add filled sprite to the background
+ * \param objIdx Sprite description
+ * \param addList Add sprite to incrust list if true
+ * \todo Fix incrust objects on CT background. Always drawing incrust elements
+ * on CT background breaks game zones
+ */
 void addSpriteFilledToBGList(int16 objIdx, bool addList) {
 	int16 x = objectTable[objIdx].x;
 	int16 y = objectTable[objIdx].y;
-	int16 width = animDataTable[objectTable[objIdx].frame].width;
-	int16 height = animDataTable[objectTable[objIdx].frame].height;
+	int16 width = animDataTable[objectTable[objIdx].frame]._width;
+	int16 height = animDataTable[objectTable[objIdx].frame]._height;
+	const byte *data = animDataTable[objectTable[objIdx].frame].data();
 
-	if (animDataTable[objectTable[objIdx].frame].ptr1) {
-		gfxFillSprite(animDataTable[objectTable[objIdx].frame].ptr1, width / 2, height, page2Raw, x, y);
+	if (data) {
+		// Operation Stealth may switch among multiple backgrounds
+		if (g_cine->getGameType() == GType_OS) {
+			for (int i = 0; i < 8; i++) {
+				if (additionalBgTable[i]) {
+					gfxFillSprite(data, width / 2, height, additionalBgTable[i], x, y);
+				}
+			}
+		} else {
+			gfxFillSprite(data, width / 2, height, page2Raw, x, y);
+		}
 	}
 
 	if (addList)
 		createBgIncrustListElement(objIdx, 1);
 }
 
+/*! \brief Add new element to incrust list
+ * \param objIdx Element description
+ * \param param Type of element
+ */
 void createBgIncrustListElement(int16 objIdx, int16 param) {
-	BGIncrustList *bgIncrustPtr = bgIncrustList;
-	BGIncrustList *bgIncrustPtrP = 0;
+	BGIncrust tmp;
 
-	// Find first empty element
-	while (bgIncrustPtr) {
-		bgIncrustPtrP = bgIncrustPtr;
-		bgIncrustPtr = bgIncrustPtr->next;
-	}
+	tmp.objIdx = objIdx;
+	tmp.param = param;
+	tmp.x = objectTable[objIdx].x;
+	tmp.y = objectTable[objIdx].y;
+	tmp.frame = objectTable[objIdx].frame;
+	tmp.part = objectTable[objIdx].part;
 
-	bgIncrustPtr = new BGIncrustList;
-	if (bgIncrustPtrP)
-		bgIncrustPtrP->next = bgIncrustPtr;
-	else
-		bgIncrustList = bgIncrustPtr;
-
-	bgIncrustPtr->next = 0;
-
-	bgIncrustPtr->objIdx = objIdx;
-	bgIncrustPtr->param = param;
-    bgIncrustPtr->x = objectTable[objIdx].x;
-    bgIncrustPtr->y = objectTable[objIdx].y;
-    bgIncrustPtr->frame = objectTable[objIdx].frame;
-    bgIncrustPtr->part = objectTable[objIdx].part;
+	bgIncrustList.push_back(tmp);
 }
 
-void freeBgIncrustList(void) {
-	BGIncrustList *bgIncrustPtr = bgIncrustList;
-	BGIncrustList *bgIncrustPtrN;
-
-	while (bgIncrustPtr) {
-		bgIncrustPtrN = bgIncrustPtr->next;
-		delete bgIncrustPtr;
-		bgIncrustPtr = bgIncrustPtrN;
-	}
-
-	resetBgIncrustList();
-}
-
+/*! \brief Reset var8 (probably something related to bgIncrustList
+ */
 void resetBgIncrustList(void) {
-	bgIncrustList = NULL;
 	var8 = 0;
 }
 
-void loadBgIncrustFromSave(Common::InSaveFile *fHandle) {
-	BGIncrustList *bgIncrustPtr = bgIncrustList;
-	BGIncrustList *bgIncrustPtrP = 0;
+/*! \brief Restore incrust list from savefile
+ * \param fHandle Savefile open for reading
+ */
+void loadBgIncrustFromSave(Common::InSaveFile &fHandle) {
+	BGIncrust tmp;
+	int size = fHandle.readSint16BE();
 
-	// Find first empty element
-	while (bgIncrustPtr) {
-		bgIncrustPtrP = bgIncrustPtr;
-		bgIncrustPtr = bgIncrustPtr->next;
-	}
+	for (int i = 0; i < size; i++) {
+		fHandle.readUint32BE();
+		fHandle.readUint32BE();
 
-	bgIncrustPtr = new BGIncrustList;
-	if (bgIncrustPtrP)
-		bgIncrustPtrP->next = bgIncrustPtr;
-	else
-		bgIncrustList = bgIncrustPtr;
+		tmp.objIdx = fHandle.readUint16BE();
+		tmp.param = fHandle.readUint16BE();
+		tmp.x = fHandle.readUint16BE();
+		tmp.y = fHandle.readUint16BE();
+		tmp.frame = fHandle.readUint16BE();
+		tmp.part = fHandle.readUint16BE();
+	
+		bgIncrustList.push_back(tmp);
 
-	bgIncrustPtr->next = 0;
-
-	fHandle->readUint32BE();
-	fHandle->readUint32BE();
-
-	bgIncrustPtr->objIdx = fHandle->readUint16BE();
-	bgIncrustPtr->param = fHandle->readUint16BE();
-    bgIncrustPtr->x = fHandle->readUint16BE();
-    bgIncrustPtr->y = fHandle->readUint16BE();
-    bgIncrustPtr->frame = fHandle->readUint16BE();
-    bgIncrustPtr->part = fHandle->readUint16BE();
-}
-
-void reincrustAllBg(void) {
-	BGIncrustList *bgIncrustPtr = bgIncrustList;
-
-	while (bgIncrustPtr) {
-#if 0
-		objectTable[bgIncrustPtr->objIdx].x = bgIncrustPtr->x;
-		objectTable[bgIncrustPtr->objIdx].y = bgIncrustPtr->y;
-		objectTable[bgIncrustPtr->objIdx].frame = bgIncrustPtr->frame;
-		objectTable[bgIncrustPtr->objIdx].part = bgIncrustPtr->part;
-#endif
-		if (bgIncrustPtr->param == 0) {
-			addToBGList(bgIncrustPtr->objIdx, false);
+		if (tmp.param == 0) {
+			addToBGList(tmp.objIdx, false);
 		} else {
-			addSpriteFilledToBGList(bgIncrustPtr->objIdx, false);
+			addSpriteFilledToBGList(tmp.objIdx, false);
 		}
-
-		bgIncrustPtr = bgIncrustPtr->next;
 	}
 }
 

Modified: scummvm/trunk/engines/cine/bg_list.h
===================================================================
--- scummvm/trunk/engines/cine/bg_list.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/bg_list.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -29,11 +29,11 @@
 
 #include "common/scummsys.h"
 #include "common/savefile.h"
+#include "common/list.h"
 
 namespace Cine {
 
-struct BGIncrustList {
-	struct BGIncrustList *next;
+struct BGIncrust {
 	byte *unkPtr;
 	int16 objIdx;
 	int16 param;
@@ -43,17 +43,15 @@
 	int16 part;
 };
 
-extern BGIncrustList *bgIncrustList;
+extern Common::List<BGIncrust> bgIncrustList;
 extern uint32 var8;
 
 void addToBGList(int16 objIdx, bool addList = true);
 void addSpriteFilledToBGList(int16 idx, bool addList = true);
 
 void createBgIncrustListElement(int16 objIdx, int16 param);
-void freeBgIncrustList(void);
 void resetBgIncrustList(void);
-void loadBgIncrustFromSave(Common::InSaveFile *fHandle);
-void reincrustAllBg(void);
+void loadBgIncrustFromSave(Common::InSaveFile &fHandle);
 
 } // End of namespace Cine
 

Modified: scummvm/trunk/engines/cine/cine.cpp
===================================================================
--- scummvm/trunk/engines/cine/cine.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/cine.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -111,8 +111,6 @@
 
 	partBuffer = (PartBuffer *)malloc(NUM_MAX_PARTDATA * sizeof(PartBuffer));
 
-	animDataTable = (AnimData *)malloc(NUM_MAX_ANIMDATA * sizeof(AnimData));
-
 	if (g_cine->getGameType() == Cine::GType_OS) {
 		readVolCnf();
 	}
@@ -124,30 +122,24 @@
 		loadErrmessDat("errmess.dat");
 	}
 
+	// in case ScummVM engines can be restarted in the future
+	scriptTable.clear();
+	relTable.clear();
+	objectScripts.clear();
+	globalScripts.clear();
+	bgIncrustList.clear();
+	freeAnimDataTable();
+
 	memset(objectTable, 0, sizeof(objectTable));
-	memset(scriptTable, 0, sizeof(scriptTable));
 	memset(messageTable, 0, sizeof(messageTable));
-	memset(relTable, 0, sizeof(relTable));
 
-	for (int i = 0; i < NUM_MAX_ANIMDATA; i++) {
-		animDataTable[i].ptr1 = animDataTable[i].ptr2 = NULL;
-	}
-
 	overlayHead.next = overlayHead.previous = NULL;
 
 	var8 = 0;
-	bgIncrustList = NULL;
+//	bgIncrustList = NULL;
 
-	objScriptList.next = NULL;
-	objScriptList.scriptPtr = NULL;
-
-	globalScriptsHead.next = NULL;
-	globalScriptsHead.scriptPtr = NULL;
-
 	var2 = var3 = var4 = var5 = 0;
 
-	freePrcLinkedList();
-
 	_preLoad = false;
 	if (ConfMan.hasKey("save_slot")) {
 		char saveNameBuffer[256];

Modified: scummvm/trunk/engines/cine/gfx.cpp
===================================================================
--- scummvm/trunk/engines/cine/gfx.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/gfx.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -37,6 +37,10 @@
 uint16 c_palette[256];
 byte colorMode256 = 0;
 byte palette256[256 * 3];
+byte newPalette[256 * 3];
+byte newColorMode = 0;
+byte ctColorMode = 0;
+byte bgColorMode = 0;
 
 byte *screenBuffer;
 byte *page1Raw;
@@ -157,7 +161,7 @@
 	//gfxFlipPage(page2);
 }
 
-void gfxFillSprite(byte *spritePtr, uint16 width, uint16 height, byte *page, int16 x, int16 y, uint8 fillColor) {
+void gfxFillSprite(const byte *spritePtr, uint16 width, uint16 height, byte *page, int16 x, int16 y, uint8 fillColor) {
 	int16 i, j;
 
 	for (i = 0; i < height; i++) {
@@ -180,7 +184,7 @@
 	}
 }
 
-void gfxDrawMaskedSprite(byte *spritePtr, byte *maskPtr, uint16 width, uint16 height, byte *page, int16 x, int16 y) {
+void gfxDrawMaskedSprite(const byte *spritePtr, const byte *maskPtr, uint16 width, uint16 height, byte *page, int16 x, int16 y) {
 	int16 i, j;
 
 	for (i = 0; i < height; i++) {
@@ -198,7 +202,7 @@
 	}
 }
 
-void gfxUpdateSpriteMask(byte *spritePtr, byte *spriteMskPtr, int16 width, int16 height, byte *maskPtr,
+void gfxUpdateSpriteMask(const byte *spritePtr, const byte *spriteMskPtr, int16 width, int16 height, const byte *maskPtr,
 	int16 maskWidth, int16 maskHeight, byte *bufferSprPtr, byte *bufferMskPtr, int16 xs, int16 ys, int16 xm, int16 ym, byte maskIdx) {
 	int16 i, j, d, spritePitch, maskPitch;
 
@@ -299,8 +303,8 @@
 	}
 }
 
-int16 gfxGetBit(int16 x, int16 y, byte *ptr, int16 width) {
-	byte *ptrToData = (ptr) + y * width + x;
+int16 gfxGetBit(int16 x, int16 y, const byte *ptr, int16 width) {
+	const byte *ptrToData = (ptr) + y * width + x;
 
 	if (x > width) {
 		return 0;
@@ -379,7 +383,7 @@
 	g_system->copyRectToScreen(screenBuffer, 320, 0, 0, 320, 200);
 }
 
-void drawSpriteRaw(byte *spritePtr, byte *maskPtr, int16 width, int16 height,
+void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int16 height,
 				   byte *page, int16 x, int16 y) {
 	int16 i, j;
 
@@ -406,7 +410,7 @@
 	}
 }
 
-void drawSpriteRaw2(byte *spritePtr, byte transColor, int16 width, int16 height,
+void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height,
 					byte *page, int16 x, int16 y) {
 	int16 i, j;
 
@@ -425,11 +429,84 @@
 	}
 }
 
+void maskBgOverlay(const byte *bgPtr, const byte *maskPtr, int16 width, int16 height,
+				   byte *page, int16 x, int16 y) {
+	int16 i, j;
+
+	for (i = 0; i < height; i++) {
+		byte *destPtr = page + x + y * 320;
+		const byte *srcPtr = bgPtr + x + y * 320;
+		destPtr += i * 320;
+		srcPtr += i * 320;
+
+		for (j = 0; j < width * 8; j++) {
+			if ((!maskPtr || !(*maskPtr)) && (x + j >= 0
+					&& x + j < 320 && i + y >= 0 && i + y < 200)) {
+				*destPtr = *srcPtr;
+			}
+
+			destPtr++;
+			srcPtr++;
+			maskPtr++;
+		}
+	}
+}
+
+/*! \todo Fix rendering to prevent fadein artifacts
+ */
+void fadeFromBlack() {
+	int i, j;
+	int r, g, b, tr, tg, tb;
+	if (newColorMode == 2) {
+		colorMode256 = 1;
+		memset(palette256, 0, 256*3);
+	} else if (newColorMode == 1) {
+		colorMode256 = 0;
+		memset(c_palette, 0, 16 * sizeof(uint16));
+	}
+
+	for (i = 0; i < 8; i++ ) {
+		gfxFlipRawPage(page1Raw);
+		g_system->updateScreen();
+		g_system->delayMillis(50);
+
+		if (colorMode256) {
+			for (j = 0; j < 256*3; j++) {
+				r = palette256[j] + (newPalette[j] + 7) / 8;
+				palette256[j] = CLIP(r, 0, (int)newPalette[j]);
+			}
+		} else {
+			for (j = 0; j < 16; j++) {
+				r = c_palette[j] & 0xf;
+				g = (c_palette[j] & 0xf0) >> 4;
+				b = (c_palette[j] & 0xf00) >> 8;
+
+				tr = tempPalette[j] & 0xf;
+				tg = (tempPalette[j] & 0xf0) >> 4;
+				tb = (tempPalette[j] & 0xf00) >> 8;
+
+				r = CLIP(r + (tr + 7) / 8, 0, tr);
+				g = CLIP(g + (tg + 7) / 8, 0, tg);
+				b = CLIP(b + (tb + 7) / 8, 0, tb);
+
+				c_palette[j] = r | (g << 4) | (b << 8);
+			}
+
+		}
+	}
+
+	if (colorMode256) {
+		memcpy(palette256, newPalette, 256*3);
+	} else {
+		memcpy(c_palette, tempPalette, sizeof(uint16) * 16);
+	}
+}
+
 void fadeToBlack() {
 	for (int i = 0; i < 8; i++) {
 		if (colorMode256) {
-			for (int j = 0; j < 256; j++) {
-				palette256[j] = transformColor(palette256[j], -1, -1, -1);
+			for (int j = 0; j < 256*3; j++) {
+				palette256[j] = CLIP(palette256[j] - 32, 0, 255);
 			}
 		} else {
 			for (int j = 0; j < 16; j++) {
@@ -449,7 +526,17 @@
 void flip(void) {
 	blitRawScreen(page1Raw);
 	if (fadeRequired) {
-		memcpy(c_palette, tempPalette, sizeof(uint16) * 16);
+		if (newColorMode == 3) {
+			newColorMode = ctColorMode + 1;
+		}
+
+		if (newColorMode == 2) {
+			colorMode256 = 1;
+			memcpy(palette256, newPalette, 256*3);
+		} else {
+			colorMode256 = 0;
+			memcpy(c_palette, tempPalette, sizeof(uint16) * 16);
+		}
 		fadeRequired = false;
 	}
 }

Modified: scummvm/trunk/engines/cine/gfx.h
===================================================================
--- scummvm/trunk/engines/cine/gfx.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/gfx.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -37,6 +37,10 @@
 extern uint16 c_palette[256];
 extern byte colorMode256;
 extern byte palette256[256 * 3];
+extern byte newPalette[256 * 3];
+extern byte newColorMode;
+extern byte ctColorMode;
+extern byte bgColorMode;
 
 void gfxInit();
 void gfxDestroy();
@@ -46,10 +50,10 @@
 void transformPaletteRange(byte startColor, byte numColor, int8 r, int8 g, int8 b);
 void gfxFlipPage(void);
 
-void gfxDrawMaskedSprite(byte *ptr, byte *msk, uint16 width, uint16 height, byte *page, int16 x, int16 y);
-void gfxFillSprite(byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy, uint8 fillColor = 0);
+void gfxDrawMaskedSprite(const byte *ptr, const byte *msk, uint16 width, uint16 height, byte *page, int16 x, int16 y);
+void gfxFillSprite(const byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy, uint8 fillColor = 0);
 
-void gfxUpdateSpriteMask(byte *spritePtr, byte *spriteMskPtr, int16 width, int16 height, byte *maskPtr,
+void gfxUpdateSpriteMask(const byte *spritePtr, const byte *spriteMskPtr, int16 width, int16 height, const byte *maskPtr,
     int16 maskWidth, int16 maskHeight, byte *bufferSprPtr, byte *bufferMskPtr, int16 xs, int16 ys, int16 xm, int16 ym, byte maskIdx);
 
 void gfxDrawLine(int16 x1, int16 y1, int16 x2, int16 y2, byte color, byte *page);
@@ -57,19 +61,23 @@
 
 void gfxResetPage(byte *pagePtr);
 
-int16 gfxGetBit(int16 x, int16 y, byte *ptr, int16 width);
+int16 gfxGetBit(int16 x, int16 y, const byte *ptr, int16 width);
+byte gfxGetColor(int16 x, int16 y, const byte *ptr, int16 width);
 
 void gfxResetRawPage(byte *pageRaw);
 void gfxConvertSpriteToRaw(byte *dst, const byte *src, uint16 w, uint16 h);
 void gfxCopyRawPage(byte *source, byte * dest);
 void gfxFlipRawPage(byte *frontBuffer);
-void drawSpriteRaw(byte *spritePtr, byte *maskPtr, int16 width, int16 height, byte *page, int16 x, int16 y);
+void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int16 height, byte *page, int16 x, int16 y);
 void gfxDrawPlainBoxRaw(int16 x1, int16 y1, int16 x2, int16 y2, byte color, byte *page);
-void drawSpriteRaw2(byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y);
+void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y);
+void maskBgOverlay(const byte *spritePtr, const byte *maskPtr, int16 width, int16 height, byte *page, int16 x, int16 y);
 
+void fadeFromBlack(void);
 void fadeToBlack(void);
 
-void gfxDrawMaskedSprite(byte *param1, byte *param2, byte *param3, byte *param4, int16 param5);
+// wtf?!
+//void gfxDrawMaskedSprite(byte *param1, byte *param2, byte *param3, byte *param4, int16 param5);
 void gfxWaitVBL(void);
 void gfxRedrawMouseCursor(void);
 

Modified: scummvm/trunk/engines/cine/main_loop.cpp
===================================================================
--- scummvm/trunk/engines/cine/main_loop.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/main_loop.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -189,11 +189,8 @@
 	quitFlag = 0;
 
 	if (_preLoad == false) {
-		freeAnimDataTable();
 		resetMessageHead();
 		resetSeqList();
-		resetglobalScriptsHead();
-		resetObjectScriptHead();
 		resetBgIncrustList();
 
 		setTextWindow(0, 0, 20, 200);
@@ -318,14 +315,10 @@
 
 	hideMouse();
 	g_sound->stopMusic();
-	freeAnimDataTable();
 	unloadAllMasks();
-	freePrcLinkedList();
-	releaseObjectScripts();
 	// if (g_cine->getGameType() == Cine::GType_OS) {
 	//	freeUnkList();
 	// }
-	freeBgIncrustList();
 	closePart();
 }
 

Modified: scummvm/trunk/engines/cine/object.cpp
===================================================================
--- scummvm/trunk/engines/cine/object.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/object.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -231,7 +231,9 @@
 		objectTable[objIdx].frame = newValue;
 		break;
 	case 4:
-		if (newValue == -1) {
+		// is it really in Future Wars? it breaks the newspaper machine
+		// on the airport in Operation Stealth
+		if (newValue == -1 && g_cine->getGameType() != Cine::GType_OS) {
 			objectTable[objIdx].costume = globalVars[0];
 		} else {
 			objectTable[objIdx].costume = newValue;
@@ -243,8 +245,8 @@
 	}
 }
 
-byte compareObjectParam(byte objIdx, byte type, int16 value) {
-	byte compareResult = 0;
+uint16 compareObjectParam(byte objIdx, byte type, int16 value) {
+	uint16 compareResult = 0;
 	int16 objectParam = getObjectParam(objIdx, type);
 
 	if (objectParam > value) {

Modified: scummvm/trunk/engines/cine/object.h
===================================================================
--- scummvm/trunk/engines/cine/object.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/object.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -74,7 +74,7 @@
 
 void addObjectParam(byte objIdx, byte paramIdx, int16 newValue);
 void subObjectParam(byte objIdx, byte paramIdx, int16 newValue);
-byte compareObjectParam(byte objIdx, byte param1, int16 param2);
+uint16 compareObjectParam(byte objIdx, byte param1, int16 param2);
 
 } // End of namespace Cine
 

Modified: scummvm/trunk/engines/cine/part.cpp
===================================================================
--- scummvm/trunk/engines/cine/part.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/part.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -33,7 +33,6 @@
 
 uint16 numElementInPart;
 
-AnimData *animDataTable;
 PartBuffer *partBuffer;
 
 void loadPart(const char *partName) {

Modified: scummvm/trunk/engines/cine/part.h
===================================================================
--- scummvm/trunk/engines/cine/part.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/part.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -35,26 +35,8 @@
 	uint32 unpackedSize;
 };
 
-struct AnimData {
-	uint16 width;
-	uint16 var1;
-	uint16 bpp;
-	uint16 height;
-
-	byte *ptr1;
-	byte *ptr2;
-	int16 fileIdx;
-	int16 frameIdx;
-	char name[10];
-
-	// Not part of the data, but used when saving/restoring it.
-	bool refresh;
-};
-
 #define NUM_MAX_PARTDATA 255
-#define NUM_MAX_ANIMDATA 255
 
-extern AnimData *animDataTable;
 extern PartBuffer *partBuffer;
 
 void loadPart(const char *partName);

Modified: scummvm/trunk/engines/cine/prc.cpp
===================================================================
--- scummvm/trunk/engines/cine/prc.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/prc.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -33,34 +33,14 @@
 
 namespace Cine {
 
-prcLinkedListStruct globalScriptsHead;
-prcLinkedListStruct objScriptList;
+ScriptList globalScripts;
+ScriptList objectScripts;
 
 //char currentPrcName[20];
 
-void resetglobalScriptsHead(void) {
-	globalScriptsHead.next = NULL;
-	globalScriptsHead.scriptIdx = -1;
-}
-
-void freePrcLinkedList(void) {
-	prcLinkedListStruct *currentHead = globalScriptsHead.next;
-
-	while (currentHead) {
-		prcLinkedListStruct *temp;
-
-		assert(currentHead);
-
-		temp = currentHead->next;
-
-		delete currentHead;
-
-		currentHead = temp;
-	}
-
-	resetglobalScriptsHead();
-}
-
+/*! \todo Is script size of 0 valid?
+ * \todo Fix script dump code
+ */
 void loadPrc(const char *pPrcName) {
 	byte i;
 	uint16 numScripts;
@@ -68,14 +48,8 @@
 
 	assert(pPrcName);
 
-	for (i = 0; i < NUM_MAX_SCRIPT; i++) {
-		if (scriptTable[i].ptr) {
-			assert(scriptTable[i].ptr);
-			free(scriptTable[i].ptr);
-			scriptTable[i].ptr = NULL;
-			scriptTable[i].size = 0;
-		}
-	}
+	globalScripts.clear();
+	scriptTable.clear();
 
 	// This is copy protection. Used to hang the machine
 	if (!scumm_stricmp(pPrcName, "L201.ANI")) {
@@ -100,17 +74,18 @@
 	assert(numScripts <= NUM_MAX_SCRIPT);
 
 	for (i = 0; i < numScripts; i++) {
-		scriptTable[i].size = READ_BE_UINT16(scriptPtr); scriptPtr += 2;
+		RawScriptPtr tmp(new RawScript(READ_BE_UINT16(scriptPtr)));
+		scriptPtr += 2;
+		assert(tmp);
+		scriptTable.push_back(tmp);
 	}
 
 	for (i = 0; i < numScripts; i++) {
-		uint16 size = scriptTable[i].size;
+		uint16 size = scriptTable[i]->_size;
+		// TODO: delete the test?
 		if (size) {
-			scriptTable[i].ptr = (byte *) malloc(size);
-			assert(scriptTable[i].ptr);
-			memcpy(scriptTable[i].ptr, scriptPtr, size);
+			scriptTable[i]->setData(*scriptInfo, scriptPtr);
 			scriptPtr += size;
-			computeScriptStack(scriptTable[i].ptr, scriptTable[i].stack, size);
 		}
 	}
 

Modified: scummvm/trunk/engines/cine/prc.h
===================================================================
--- scummvm/trunk/engines/cine/prc.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/prc.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -28,21 +28,9 @@
 
 namespace Cine {
 
-struct prcLinkedListStruct {
-	struct prcLinkedListStruct *next;
-	int16 stack[SCRIPT_STACK_SIZE];
-	ScriptVars localVars;
-	uint16 compareResult;
-	uint16 scriptPosition;
-	byte *scriptPtr;
-	int16 scriptIdx;
-};
+extern ScriptList globalScripts;
+extern ScriptList objectScripts;
 
-extern prcLinkedListStruct globalScriptsHead;
-extern prcLinkedListStruct objScriptList;
-
-void resetglobalScriptsHead(void);
-void freePrcLinkedList(void);
 void loadPrc(const char *pPrcName);
 
 } // End of namespace Cine

Modified: scummvm/trunk/engines/cine/rel.cpp
===================================================================
--- scummvm/trunk/engines/cine/rel.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/rel.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -31,45 +31,21 @@
 
 namespace Cine {
 
-RelObjectScript relTable[NUM_MAX_REL];
+RawObjectScriptArray relTable; ///< Object script bytecode table
 
-void resetObjectScriptHead(void) {
-	objScriptList.next = NULL;
-	objScriptList.scriptIdx = -1;
-}
-
-void releaseObjectScripts(void) {
-	prcLinkedListStruct *currentHead = objScriptList.next;
-
-	while (currentHead) {
-		prcLinkedListStruct *temp;
-
-		assert(currentHead);
-
-		temp = currentHead->next;
-
-		delete currentHead;
-
-		currentHead = temp;
-	}
-
-	resetObjectScriptHead();
-}
-
+/*! \todo Is script size of 0 valid?
+ * \todo Fix script dump code
+ */
 void loadRel(char *pRelName) {
 	uint16 numEntry;
 	uint16 i;
+	uint16 size, p1, p2, p3;
 	byte *ptr, *dataPtr;
 
 	checkDataDisk(-1);
 
-	for (i = 0; i < NUM_MAX_REL; i++) {
-		if (relTable[i].data) {
-			free(relTable[i].data);
-			relTable[i].data = NULL;
-			relTable[i].size = 0;
-		}
-	}
+	objectScripts.clear();
+	relTable.clear();
 
 	ptr = dataPtr = readBundleFile(findFileInBundle(pRelName));
 
@@ -77,24 +53,22 @@
 
 	numEntry = READ_BE_UINT16(ptr); ptr += 2;
 
-	assert(numEntry <= NUM_MAX_REL);
-
 	for (i = 0; i < numEntry; i++) {
-		relTable[i].size = READ_BE_UINT16(ptr); ptr += 2;
-		relTable[i].obj1Param1 = READ_BE_UINT16(ptr); ptr += 2;
-		relTable[i].obj1Param2 = READ_BE_UINT16(ptr); ptr += 2;
-		relTable[i].obj2Param = READ_BE_UINT16(ptr); ptr += 2;
-		relTable[i].runCount = 0;
+		size = READ_BE_UINT16(ptr); ptr += 2;
+		p1 = READ_BE_UINT16(ptr); ptr += 2;
+		p2 = READ_BE_UINT16(ptr); ptr += 2;
+		p3 = READ_BE_UINT16(ptr); ptr += 2;
+		RawObjectScriptPtr tmp(new RawObjectScript(size, p1, p2, p3));
+		assert(tmp);
+		relTable.push_back(tmp);
 	}
 
 	for (i = 0; i < numEntry; i++) {
-		if (relTable[i].size) {
-			relTable[i].data = (byte *)malloc(relTable[i].size);
-
-			assert(relTable[i].data);
-
-			memcpy(relTable[i].data, ptr, relTable[i].size);
-			ptr += relTable[i].size;
+		size = relTable[i]->_size;
+		// TODO: delete the test?
+		if (size) {
+			relTable[i]->setData(*scriptInfo, ptr);
+			ptr += size;
 		}
 	}
 

Modified: scummvm/trunk/engines/cine/rel.h
===================================================================
--- scummvm/trunk/engines/cine/rel.h	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/rel.h	2008-04-07 20:24:40 UTC (rev 31444)
@@ -26,24 +26,11 @@
 #ifndef CINE_REL_H
 #define CINE_REL_H
 
+#include "cine/script.h"
 namespace Cine {
 
-struct RelObjectScript {
-	byte *data;
-	uint16 size;
-	uint16 obj1Param1;
-	uint16 obj1Param2;
-	uint16 obj2Param;
-	uint16 runCount;
-};
+extern RawObjectScriptArray relTable;
 
-#define NUM_MAX_REL 255
-
-extern RelObjectScript relTable[NUM_MAX_REL];
-
-void releaseObjectScripts(void);
-void resetObjectScriptHead(void);
-
 void loadRel(char *pRelName);
 
 } // End of namespace Cine

Modified: scummvm/trunk/engines/cine/script.cpp
===================================================================
--- scummvm/trunk/engines/cine/script.cpp	2008-04-07 17:56:04 UTC (rev 31443)
+++ scummvm/trunk/engines/cine/script.cpp	2008-04-07 20:24:40 UTC (rev 31444)
@@ -23,6 +23,9 @@
  *
  */
 
+/*! \file
+ * Script interpreter file
+ */
 
 #include "common/endian.h"
 
@@ -31,435 +34,423 @@
 #include "cine/object.h"
 #include "cine/sound.h"
 #include "cine/various.h"
+#include "cine/script.h"
 
 namespace Cine {
 
-prcLinkedListStruct *_currentScriptElement;
-byte *_currentScriptPtr;
-uint16 _currentScriptParams;
-uint16 _currentPosition;
-uint16 _currentLine;
-uint16 _closeScript;
+uint16 compareVars(int16 a, int16 b);
+void palRotate(byte a, byte b, byte c);
+void removeSeq(uint16 param1, uint16 param2, uint16 param3);
+uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3);
+void addGfxElementA0(int16 param1, int16 param2);
+void removeGfxElementA0(int16 idx, int16 param);
 
-struct Opcode {
-	void (*proc)();
-	const char *args;
+const Opcode FWScript::_opcodeTable[] = {
+	/* 00 */
+	{ &FWScript::o1_modifyObjectParam, "bbw" },
+	{ &FWScript::o1_getObjectParam, "bbb" },
+	{ &FWScript::o1_addObjectParam, "bbw" },
+	{ &FWScript::o1_subObjectParam, "bbw" },
+	/* 04 */
+	{ &FWScript::o1_add2ObjectParam, "bbw" },
+	{ &FWScript::o1_sub2ObjectParam, "bbw" },
+	{ &FWScript::o1_compareObjectParam, "bbw" },
+	{ &FWScript::o1_setupObject, "bwwww" },
+	/* 08 */
+	{ &FWScript::o1_checkCollision, "bwwww" },
+	{ &FWScript::o1_loadVar, "bc" },
+	{ &FWScript::o1_addVar, "bc" },
+	{ &FWScript::o1_subVar, "bc" },
+	/* 0C */
+	{ &FWScript::o1_mulVar, "bc" },
+	{ &FWScript::o1_divVar, "bc" },
+	{ &FWScript::o1_compareVar, "bc" },
+	{ &FWScript::o1_modifyObjectParam2, "bbb" },
+	/* 10 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_loadMask0, "b" },
+	/* 14 */
+	{ &FWScript::o1_unloadMask0, "b" },
+	{ &FWScript::o1_addToBgList, "b" },
+	{ &FWScript::o1_loadMask1, "b" },
+	{ &FWScript::o1_unloadMask1, "b" },
+	/* 18 */
+	{ &FWScript::o1_loadMask4, "b" },
+	{ &FWScript::o1_unloadMask4, "b" },
+	{ &FWScript::o1_addSpriteFilledToBgList, "b" },
+	{ &FWScript::o1_op1B, "" },
+	/* 1C */
+	{ 0, 0 },
+	{ &FWScript::o1_label, "l" },
+	{ &FWScript::o1_goto, "b" },
+	{ &FWScript::o1_gotoIfSup, "b" },
+	/* 20 */
+	{ &FWScript::o1_gotoIfSupEqu, "b" },
+	{ &FWScript::o1_gotoIfInf, "b" },
+	{ &FWScript::o1_gotoIfInfEqu, "b" },
+	{ &FWScript::o1_gotoIfEqu, "b" },
+	/* 24 */
+	{ &FWScript::o1_gotoIfDiff, "b" },
+	{ &FWScript::o1_removeLabel, "b" },
+	{ &FWScript::o1_loop, "bb" },
+	{ 0, 0 },
+	/* 28 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 2C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 30 */
+	{ 0, 0 },
+	{ &FWScript::o1_startGlobalScript, "b" },
+	{ &FWScript::o1_endGlobalScript, "b" },
+	{ 0, 0 },
+	/* 34 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 38 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_loadAnim, "s" },
+	/* 3C */
+	{ &FWScript::o1_loadBg, "s" },
+	{ &FWScript::o1_loadCt, "s" },
+	{ 0, 0 },
+	{ &FWScript::o1_loadPart, "s" },
+	/* 40 */
+	{ &FWScript::o1_closePart, "" },
+	{ &FWScript::o1_loadNewPrcName, "bs" },
+	{ &FWScript::o1_requestCheckPendingDataLoad, "" },
+	{ 0, 0 },
+	/* 44 */
+	{ 0, 0 },
+	{ &FWScript::o1_blitAndFade, "" },
+	{ &FWScript::o1_fadeToBlack, "" },
+	{ &FWScript::o1_transformPaletteRange, "bbwww" },
+	/* 48 */
+	{ 0, 0 },
+	{ &FWScript::o1_setDefaultMenuColor2, "b" },
+	{ &FWScript::o1_palRotate, "bbb" },
+	{ 0, 0 },
+	/* 4C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_break, "" },
+	/* 50 */
+	{ &FWScript::o1_endScript, "x" },
+	{ &FWScript::o1_message, "bwwww" },
+	{ &FWScript::o1_loadGlobalVar, "bc" },
+	{ &FWScript::o1_compareGlobalVar, "bc" },
+	/* 54 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 58 */
+	{ 0, 0 },
+	{ &FWScript::o1_declareFunctionName, "s" },
+	{ &FWScript::o1_freePartRange, "bb" },
+	{ &FWScript::o1_unloadAllMasks, "" },
+	// 5C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 60 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_setScreenDimensions, "wwww" },
+	/* 64 */
+	{ &FWScript::o1_displayBackground, "" },
+	{ &FWScript::o1_initializeZoneData, "" },
+	{ &FWScript::o1_setZoneDataEntry, "bw" },
+	{ &FWScript::o1_getZoneDataEntry, "bb" },
+	/* 68 */
+	{ &FWScript::o1_setDefaultMenuColor, "b" },
+	{ &FWScript::o1_allowPlayerInput, "" },
+	{ &FWScript::o1_disallowPlayerInput, "" },
+	{ &FWScript::o1_changeDataDisk, "b" },
+	/* 6C */
+	{ 0, 0 },
+	{ &FWScript::o1_loadMusic, "s" },
+	{ &FWScript::o1_playMusic, "" },
+	{ &FWScript::o1_fadeOutMusic, "" },
+	/* 70 */
+	{ &FWScript::o1_stopSample, "" },
+	{ &FWScript::o1_op71, "bw" },
+	{ &FWScript::o1_op72, "wbw" },
+	{ &FWScript::o1_op73, "wbw" },
+	/* 74 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_playSample, "bbwbww" },
+	/* 78 */
+	{ &FWScript::o1_playSample, "bbwbww" },
+	{ &FWScript::o1_disableSystemMenu, "b" },
+	{ &FWScript::o1_loadMask5, "b" },
+	{ &FWScript::o1_unloadMask5, "b" }
 };
+const unsigned int FWScript::_numOpcodes = ARRAYSIZE(FWScript::_opcodeTable);
 
-const Opcode *_opcodeTable;
-int _numOpcodes;
 
-void setupOpcodes() {
-	static const Opcode opcodeTableFW[] = {
-		/* 00 */
-		{ o1_modifyObjectParam, "bbw" },
-		{ o1_getObjectParam, "bbb" },
-		{ o1_addObjectParam, "bbw" },
-		{ o1_subObjectParam, "bbw" },
-		/* 04 */
-		{ o1_add2ObjectParam, "bbw" },
-		{ o1_sub2ObjectParam, "bbw" },
-		{ o1_compareObjectParam, "bbw" },
-		{ o1_setupObject, "bwwww" },
-		/* 08 */
-		{ o1_checkCollision, "bwwww" },
-		{ o1_loadVar, "bc" },
-		{ o1_addVar, "bc" },
-		{ o1_subVar, "bc" },
-		/* 0C */
-		{ o1_mulVar, "bc" },
-		{ o1_divVar, "bc" },
-		{ o1_compareVar, "bc" },
-		{ o1_modifyObjectParam2, "bbb" },
-		/* 10 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_loadMask0, "b" },
-		/* 14 */
-		{ o1_unloadMask0, "b" },
-		{ o1_addToBgList, "b" },
-		{ o1_loadMask1, "b" },
-		{ o1_unloadMask1, "b" },
-		/* 18 */
-		{ o1_loadMask4, "b" },
-		{ o1_unloadMask4, "b" },
-		{ o1_addSpriteFilledToBgList, "b" },
-		{ o1_op1B, "" },
-		/* 1C */
-		{ 0, 0 },
-		{ o1_label, "l" },
-		{ o1_goto, "b" },
-		{ o1_gotoIfSup, "b" },
-		/* 20 */
-		{ o1_gotoIfSupEqu, "b" },
-		{ o1_gotoIfInf, "b" },
-		{ o1_gotoIfInfEqu, "b" },
-		{ o1_gotoIfEqu, "b" },
-		/* 24 */
-		{ o1_gotoIfDiff, "b" },
-		{ o1_removeLabel, "b" },
-		{ o1_loop, "bb" },
-		{ 0, 0 },
-		/* 28 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 2C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 30 */
-		{ 0, 0 },
-		{ o1_startGlobalScript, "b" },
-		{ o1_endGlobalScript, "b" },
-		{ 0, 0 },
-		/* 34 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 38 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_loadAnim, "s" },
-		/* 3C */
-		{ o1_loadBg, "s" },
-		{ o1_loadCt, "s" },
-		{ 0, 0 },
-		{ o1_loadPart, "s" },
-		/* 40 */
-		{ o1_closePart, "" },
-		{ o1_loadNewPrcName, "bs" },
-		{ o1_requestCheckPendingDataLoad, "" },
-		{ 0, 0 },
-		/* 44 */
-		{ 0, 0 },
-		{ o1_blitAndFade, "" },
-		{ o1_fadeToBlack, "" },
-		{ o1_transformPaletteRange, "bbwww" },
-		/* 48 */
-		{ 0, 0 },
-		{ o1_setDefaultMenuColor2, "b" },
-		{ o1_palRotate, "bbb" },
-		{ 0, 0 },
-		/* 4C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_break, "" },
-		/* 50 */
-		{ o1_endScript, "x" },
-		{ o1_message, "bwwww" },
-		{ o1_loadGlobalVar, "bc" },
-		{ o1_compareGlobalVar, "bc" },
-		/* 54 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 58 */
-		{ 0, 0 },
-		{ o1_declareFunctionName, "s" },
-		{ o1_freePartRange, "bb" },
-		{ o1_unloadAllMasks, "" },
-		// 5C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 60 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_setScreenDimensions, "wwww" },
-		/* 64 */
-		{ o1_displayBackground, "" },
-		{ o1_initializeZoneData, "" },
-		{ o1_setZoneDataEntry, "bw" },
-		{ o1_getZoneDataEntry, "bb" },
-		/* 68 */
-		{ o1_setDefaultMenuColor, "b" },
-		{ o1_allowPlayerInput, "" },
-		{ o1_disallowPlayerInput, "" },
-		{ o1_changeDataDisk, "b" },
-		/* 6C */
-		{ 0, 0 },
-		{ o1_loadMusic, "s" },
-		{ o1_playMusic, "" },
-		{ o1_fadeOutMusic, "" },
-		/* 70 */
-		{ o1_stopSample, "" },
-		{ o1_op71, "bw" },
-		{ o1_op72, "wbw" },
-		{ o1_op73, "wbw" },
-		/* 74 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_playSample, "bbwbww" },
-		/* 78 */
-		{ o1_playSample, "bbwbww" },
-		{ o1_disableSystemMenu, "b" },
-		{ o1_loadMask5, "b" },
-		{ o1_unloadMask5, "b" }
-	};
+const Opcode OSScript::_opcodeTable[] = {
+	/* 00 */
+	{ &FWScript::o1_modifyObjectParam, "bbw" },
+	{ &FWScript::o1_getObjectParam, "bbb" },
+	{ &FWScript::o1_addObjectParam, "bbw" },
+	{ &FWScript::o1_subObjectParam, "bbw" },
+	/* 04 */
+	{ &FWScript::o1_add2ObjectParam, "bbw" },
+	{ &FWScript::o1_sub2ObjectParam, "bbw" },
+	{ &FWScript::o1_compareObjectParam, "bbw" },
+	{ &FWScript::o1_setupObject, "bwwww" },
+	/* 08 */
+	{ &FWScript::o1_checkCollision, "bwwww" },
+	{ &FWScript::o1_loadVar, "bc" },
+	{ &FWScript::o1_addVar, "bc" },
+	{ &FWScript::o1_subVar, "bc" },
+	/* 0C */
+	{ &FWScript::o1_mulVar, "bc" },
+	{ &FWScript::o1_divVar, "bc" },
+	{ &FWScript::o1_compareVar, "bc" },
+	{ &FWScript::o1_modifyObjectParam2, "bbb" },
+	/* 10 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_loadMask0, "b" },
+	/* 14 */
+	{ &FWScript::o1_unloadMask0, "b" },
+	{ &FWScript::o1_addToBgList, "b" },
+	{ &FWScript::o1_loadMask1, "b" },
+	{ &FWScript::o1_unloadMask1, "b" },
+	/* 18 */
+	{ &FWScript::o1_loadMask4, "b" },
+	{ &FWScript::o1_unloadMask4, "b" },
+	{ &FWScript::o1_addSpriteFilledToBgList, "b" },
+	{ &FWScript::o1_op1B, "" },
+	/* 1C */
+	{ 0, 0 },
+	{ &FWScript::o1_label, "l" },
+	{ &FWScript::o1_goto, "b" },
+	{ &FWScript::o1_gotoIfSup, "b" },
+	/* 20 */
+	{ &FWScript::o1_gotoIfSupEqu, "b" },
+	{ &FWScript::o1_gotoIfInf, "b" },
+	{ &FWScript::o1_gotoIfInfEqu, "b" },
+	{ &FWScript::o1_gotoIfEqu, "b" },
+	/* 24 */
+	{ &FWScript::o1_gotoIfDiff, "b" },
+	{ &FWScript::o1_removeLabel, "b" },
+	{ &FWScript::o1_loop, "bb" },
+	{ 0, 0 },
+	/* 28 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 2C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 30 */
+	{ 0, 0 },
+	{ &FWScript::o1_startGlobalScript, "b" },
+	{ &FWScript::o1_endGlobalScript, "b" },
+	{ 0, 0 },
+	/* 34 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 38 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_loadAnim, "s" },
+	/* 3C */
+	{ &FWScript::o1_loadBg, "s" },
+	{ &FWScript::o1_loadCt, "s" },
+	{ 0, 0 },
+	{ &FWScript::o2_loadPart, "s" },
+	/* 40 */
+	{ 0, 0 }, /* o1_closePart, triggered by some scripts (STARTA.PRC 4 for ex.) */
+	{ &FWScript::o1_loadNewPrcName, "bs" },
+	{ &FWScript::o1_requestCheckPendingDataLoad, "" },
+	{ 0, 0 },
+	/* 44 */
+	{ 0, 0 },
+	{ &FWScript::o1_blitAndFade, "" },
+	{ &FWScript::o1_fadeToBlack, "" },
+	{ &FWScript::o1_transformPaletteRange, "bbwww" },
+	/* 48 */
+	{ 0, 0 },
+	{ &FWScript::o1_setDefaultMenuColor2, "b" },
+	{ &FWScript::o1_palRotate, "bbb" },
+	{ 0, 0 },
+	/* 4C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_break, "" },
+	/* 50 */
+	{ &FWScript::o1_endScript, "x" },
+	{ &FWScript::o1_message, "bwwww" },
+	{ &FWScript::o1_loadGlobalVar, "bc" },
+	{ &FWScript::o1_compareGlobalVar, "bc" },
+	/* 54 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 58 */
+	{ 0, 0 },
+	{ &FWScript::o1_declareFunctionName, "s" },
+	{ &FWScript::o1_freePartRange, "bb" },
+	{ &FWScript::o1_unloadAllMasks, "" },
+	// 5C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 60 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o1_setScreenDimensions, "wwww" },
+	/* 64 */
+	{ &FWScript::o1_displayBackground, "" },
+	{ &FWScript::o1_initializeZoneData, "" },
+	{ &FWScript::o1_setZoneDataEntry, "bw" },
+	{ &FWScript::o1_getZoneDataEntry, "bb" },
+	/* 68 */
+	{ &FWScript::o1_setDefaultMenuColor, "b" },
+	{ &FWScript::o1_allowPlayerInput, "" },
+	{ &FWScript::o1_disallowPlayerInput, "" },
+	{ &FWScript::o1_changeDataDisk, "b" },
+	/* 6C */
+	{ 0, 0 },
+	{ &FWScript::o1_loadMusic, "s" },
+	{ &FWScript::o1_playMusic, "" },
+	{ &FWScript::o1_fadeOutMusic, "" },
+	/* 70 */
+	{ &FWScript::o1_stopSample, "" },
+	{ &FWScript::o1_op71, "bw" },
+	{ &FWScript::o1_op72, "wbw" },
+	{ &FWScript::o1_op72, "wbw" },
+	/* 74 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o2_playSample, "bbwbww" },
+	/* 78 */
+	{ &FWScript::o2_playSampleAlt, "bbwbww" },
+	{ &FWScript::o1_disableSystemMenu, "b" },
+	{ &FWScript::o1_loadMask5, "b" },
+	{ &FWScript::o1_unloadMask5, "b" },
+	/* 7C */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o2_addSeqListElement, "bbbbwww" },
+	/* 80 */
+	{ &FWScript::o2_removeSeq, "bb" },
+	{ &FWScript::o2_op81, "" },
+	{ &FWScript::o2_op82, "bbw" },
+	{ &FWScript::o2_isSeqRunning, "bb" },
+	/* 84 */
+	{ &FWScript::o2_gotoIfSupNearest, "b" },
+	{ &FWScript::o2_gotoIfSupEquNearest, "b" },
+	{ &FWScript::o2_gotoIfInfNearest, "b" },
+	{ &FWScript::o2_gotoIfInfEquNearest, "b" },
+	/* 88 */
+	{ &FWScript::o2_gotoIfEquNearest, "b" },
+	{ &FWScript::o2_gotoIfDiffNearest, "b" },
+	{ 0, 0 },
+	{ &FWScript::o2_startObjectScript, "b" },
+	/* 8C */
+	{ &FWScript::o2_stopObjectScript, "b" },
+	{ &FWScript::o2_op8D, "wwwwwwww" },
+	{ &FWScript::o2_addBackground, "bs" },
+	{ &FWScript::o2_removeBackground, "b" },
+	/* 90 */
+	{ &FWScript::o2_loadAbs, "bs" },
+	{ &FWScript::o2_loadBg, "b" },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 94 */
+	{ 0, 0 },
+	{ &FWScript::o1_changeDataDisk, "b" },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* 98 */
+	{ 0, 0 },
+	{ 0, 0 },
+	{ &FWScript::o2_wasZoneChecked, "" },
+	{ &FWScript::o2_op9B, "wwwwwwww" },
+	/* 9C */
+	{ &FWScript::o2_op9C, "wwww" },
+	{ &FWScript::o2_useBgScroll, "b" },
+	{ &FWScript::o2_setAdditionalBgVScroll, "c" },
+	{ &FWScript::o2_op9F, "ww" },
+	/* A0 */
+	{ &FWScript::o2_addGfxElementA0, "ww" },
+	{ &FWScript::o2_removeGfxElementA0, "ww" },
+	{ &FWScript::o2_opA2, "ww" },
+	{ &FWScript::o2_opA3, "ww" },
+	/* A4 */
+	{ &FWScript::o2_loadMask22, "b" },
+	{ &FWScript::o2_unloadMask22, "b" },
+	{ 0, 0 },
+	{ 0, 0 },
+	/* A8 */
+	{ 0, 0 },
+	{ &FWScript::o1_changeDataDisk, "b" }
+};
+const unsigned int OSScript::_numOpcodes = ARRAYSIZE(OSScript::_opcodeTable);
 
-	// TODO: We need to verify the Operation Stealth opcodes.
+FWScriptInfo *scriptInfo; ///< Script factory
+RawScriptArray scriptTable; ///< Table of script bytecode
 
-	static const Opcode opcodeTableOS[] = {
-		/* 00 */
-		{ o1_modifyObjectParam, "bbw" },
-		{ o1_getObjectParam, "bbb" },
-		{ o1_addObjectParam, "bbw" },
-		{ o1_subObjectParam, "bbw" },
-		/* 04 */
-		{ o1_add2ObjectParam, "bbw" },
-		{ o1_sub2ObjectParam, "bbw" },
-		{ o1_compareObjectParam, "bbw" },
-		{ o1_setupObject, "bwwww" },
-		/* 08 */
-		{ o1_checkCollision, "bwwww" },
-		{ o1_loadVar, "bc" },
-		{ o1_addVar, "bc" },
-		{ o1_subVar, "bc" },
-		/* 0C */
-		{ o1_mulVar, "bc" },
-		{ o1_divVar, "bc" },
-		{ o1_compareVar, "bc" },
-		{ o1_modifyObjectParam2, "bbb" },
-		/* 10 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_loadMask0, "b" },
-		/* 14 */
-		{ o1_unloadMask0, "b" },
-		{ o1_addToBgList, "b" },
-		{ o1_loadMask1, "b" },
-		{ o1_unloadMask1, "b" },
-		/* 18 */
-		{ o1_loadMask4, "b" },
-		{ o1_unloadMask4, "b" },
-		{ o1_addSpriteFilledToBgList, "b" },
-		{ o1_op1B, "" },
-		/* 1C */
-		{ 0, 0 },
-		{ o1_label, "l" },
-		{ o1_goto, "b" },
-		{ o1_gotoIfSup, "b" },
-		/* 20 */
-		{ o1_gotoIfSupEqu, "b" },
-		{ o1_gotoIfInf, "b" },
-		{ o1_gotoIfInfEqu, "b" },
-		{ o1_gotoIfEqu, "b" },
-		/* 24 */
-		{ o1_gotoIfDiff, "b" },
-		{ o1_removeLabel, "b" },
-		{ o1_loop, "bb" },
-		{ 0, 0 },
-		/* 28 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 2C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 30 */
-		{ 0, 0 },
-		{ o1_startGlobalScript, "b" },
-		{ o1_endGlobalScript, "b" },
-		{ 0, 0 },
-		/* 34 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 38 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_loadAnim, "s" },
-		/* 3C */
-		{ o1_loadBg, "s" },
-		{ o1_loadCt, "s" },
-		{ 0, 0 },
-		{ o2_loadPart, "s" },
-		/* 40 */
-		{ 0, 0 }, /* o1_closePart, triggered by some scripts (STARTA.PRC 4 for ex.) */
-		{ o1_loadNewPrcName, "bs" },
-		{ o1_requestCheckPendingDataLoad, "" },
-		{ 0, 0 },
-		/* 44 */
-		{ 0, 0 },
-		{ o1_blitAndFade, "" },
-		{ o1_fadeToBlack, "" },
-		{ o1_transformPaletteRange, "bbwww" },
-		/* 48 */
-		{ 0, 0 },
-		{ o1_setDefaultMenuColor2, "b" },
-		{ o1_palRotate, "bbb" },
-		{ 0, 0 },
-		/* 4C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_break, "" },
-		/* 50 */
-		{ o1_endScript, "x" },
-		{ o1_message, "bwwww" },
-		{ o1_loadGlobalVar, "bc" },
-		{ o1_compareGlobalVar, "bc" },
-		/* 54 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 58 */
-		{ 0, 0 },
-		{ o1_declareFunctionName, "s" },
-		{ o1_freePartRange, "bb" },
-		{ o1_unloadAllMasks, "" },
-		// 5C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 60 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o1_setScreenDimensions, "wwww" },
-		/* 64 */
-		{ o1_displayBackground, "" },
-		{ o1_initializeZoneData, "" },
-		{ o1_setZoneDataEntry, "bw" },
-		{ o1_getZoneDataEntry, "bb" },
-		/* 68 */
-		{ o1_setDefaultMenuColor, "b" },
-		{ o1_allowPlayerInput, "" },
-		{ o1_disallowPlayerInput, "" },
-		{ o1_changeDataDisk, "b" },
-		/* 6C */
-		{ 0, 0 },
-		{ o1_loadMusic, "s" },
-		{ o1_playMusic, "" },
-		{ o1_fadeOutMusic, "" },
-		/* 70 */
-		{ o1_stopSample, "" },
-		{ o1_op71, "bw" },
-		{ o1_op72, "wbw" },
-		{ o1_op72, "wbw" },
-		/* 74 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o2_playSample, "bbwbww" },
-		/* 78 */
-		{ o2_playSampleAlt, "bbwbww" },
-		{ o1_disableSystemMenu, "b" },
-		{ o1_loadMask5, "b" },
-		{ o1_unloadMask5, "b" },
-		/* 7C */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o2_addSeqListElement, "bbbbwww" },
-		/* 80 */
-		{ o2_removeSeq, "bb" },
-		{ o2_op81, "" },
-		{ o2_op82, "bbw" },
-		{ o2_isSeqRunning, "bb" },
-		/* 84 */
-		{ o2_gotoIfSupNearest, "b" },
-		{ o2_gotoIfSupEquNearest, "b" },
-		{ o2_gotoIfInfNearest, "b" },
-		{ o2_gotoIfInfEquNearest, "b" },
-		/* 88 */
-		{ o2_gotoIfEquNearest, "b" },
-		{ o2_gotoIfDiffNearest, "b" },
-		{ 0, 0 },
-		{ o2_startObjectScript, "b" },
-		/* 8C */
-		{ o2_stopObjectScript, "b" },
-		{ o2_op8D, "wwwwwwww" },
-		{ o2_addBackground, "bs" },
-		{ o2_removeBackground, "b" },
-		/* 90 */
-		{ o2_loadAbs, "bs" },
-		{ o2_loadBg, "b" },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 94 */
-		{ 0, 0 },
-		{ o1_changeDataDisk, "b" },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* 98 */
-		{ 0, 0 },
-		{ 0, 0 },
-		{ o2_wasZoneChecked, "" },
-		{ o2_op9B, "wwwwwwww" },
-		/* 9C */
-		{ o2_op9C, "wwww" },
-		{ o2_useBgScroll, "b" },
-		{ o2_setAdditionalBgVScroll, "c" },
-		{ o2_op9F, "ww" },
-		/* A0 */
-		{ o2_addGfxElementA0, "ww" },
-		{ o2_opA1, "ww" },
-		{ o2_opA2, "ww" },
-		{ o2_opA3, "ww" },
-		/* A4 */
-		{ o2_loadMask22, "b" },
-		{ o2_unloadMask22, "b" },
-		{ 0, 0 },
-		{ 0, 0 },
-		/* A8 */
-		{ 0, 0 },
-		{ o1_changeDataDisk, "b" }
-	};
-
+/*! \todo: replace with script subsystem
+ */
+void setupOpcodes() {
+	static FWScriptInfo fw;
+	static OSScriptInfo os;
 	if (g_cine->getGameType() == Cine::GType_FW) {
-		_opcodeTable = opcodeTableFW;
-		_numOpcodes = ARRAYSIZE(opcodeTableFW);
+		scriptInfo = &fw;
 	} else {
-		_opcodeTable = opcodeTableOS;
-		_numOpcodes = ARRAYSIZE(opcodeTableOS);
+		scriptInfo = &os;
 	}
 }
 
-byte getNextByte() {
-	byte val = *(_currentScriptPtr + _currentPosition);
-	_currentPosition++;
-	return val;
-}
-
-uint16 getNextWord() {
-	uint16 val = READ_BE_UINT16(_currentScriptPtr + _currentPosition);
-	_currentPosition += 2;
-	return val;
-}
-
-const char *getNextString() {
-	const char *val = (const char *)(_currentScriptPtr + _currentPosition);
-	_currentPosition += strlen(val) + 1;
-	return val;
-}
-
-// empty array
+/*! \brief Allocate empty array
+ * \param len Size of array
+ *
+ * Explicit to prevent var=0 instead of var[i]=0 typos.
+ */
 ScriptVars::ScriptVars(unsigned int len) : _size(len), _vars(new int16[len]) {
 	assert(_vars);
 	reset();
 }
 
-// read game save, for later use
+/*! \brief Allocate array and read contents from savefile
+ * \param fHandle Savefile open for reading
+ * \param len Size of array
+ */
 ScriptVars::ScriptVars(Common::InSaveFile &fHandle, unsigned int len)
 	: _size(len), _vars(new int16[len]) {
 
@@ -468,16 +459,21 @@
 	load(fHandle);
 }
 
-// copy constructor
+/*! \brief Copy constructor
+ */
 ScriptVars::ScriptVars(const ScriptVars &src) : _size(src._size), _vars(new int16[_size]) {
 	assert(_vars);
 	memcpy(_vars, src._vars, _size * sizeof(int16));
 }
 
+/*! \brief Destructor
+ */
 ScriptVars::~ScriptVars(void) {
 	delete[] _vars;
 }
 
+/*! \brief Assignment operator
+ */
 ScriptVars &ScriptVars::operator=(const ScriptVars &src) {
 	ScriptVars tmp(src);
 	int16 *tmpvars = _vars;
@@ -489,462 +485,708 @@
 	return *this;
 }
 
-// array access
+/*! \brief Direct array item access
+ * \param idx Item index
+ * \return Reference to item
+ */
 int16 &ScriptVars::operator[](unsigned int idx) {
-	debugN(5, "assert(%d < %d)", idx, _size);
+	debug(6, "assert(%d < %d)", idx, _size);
 	assert(idx < _size);
 	return _vars[idx];
 }
 
+/*! \brief Direct read-only array item access
+ * \param idx Item index
+ * \return Copy of item
+ */
 int16 ScriptVars::operator[](unsigned int idx) const {
-	debugN(5, "assert(%d < %d)\n", idx, _size);
+	debug(6, "assert(%d < %d)", idx, _size);
 	assert(idx < _size);
 	return _vars[idx];
 }
 
-// dump to savefile
-void ScriptVars::save(Common::OutSaveFile &fHandle) {
+/*! \brief Savefile writer
+ * \param fHandle Savefile open for writing
+ */
+void ScriptVars::save(Common::OutSaveFile &fHandle) const {
 	save(fHandle, _size);
 }
 
-// globalVars[255] is not written to savefiles...
-void ScriptVars::save(Common::OutSaveFile &fHandle, unsigned int len) {
-	debugN(5, "assert(%d <= %d)\n", len, _size);
+/*! \brief Savefile writer with data length limit
+ * \param fHandle Savefile open for writing
+ * \param len Length of data to be written (len <= _size)
+ */
+void ScriptVars::save(Common::OutSaveFile &fHandle, unsigned int len) const {
+	debug(6, "assert(%d <= %d)", len, _size);
 	assert(len <= _size);
 	for (unsigned int i = 0; i < len; i++) {
 		fHandle.writeUint16BE(_vars[i]);
 	}
 }
 
-// read from savefile
+/*! \brief Restore array from savefile
+ * \param fHandle Savefile open for reading
+ */
 void ScriptVars::load(Common::InSaveFile &fHandle) {
 	load(fHandle, _size);
 }
 
+/*! \brief Restore part of array from savefile
+ * \param fHandle Savefile open for reading
+ * \param len Length of data to be read
+ */
 void ScriptVars::load(Common::InSaveFile &fHandle, unsigned int len) {
-	debugN(5, "assert(%d <= %d)\n", len, _size);
+	debug(6, "assert(%d <= %d)", len, _size);
 	assert(len <= _size);
 	for (unsigned int i = 0; i < len; i++) {
 		_vars[i] = fHandle.readUint16BE();
 	}
 }
 
+/*! \brief Reset all values to 0
+ */
 void ScriptVars::reset(void) {
 	memset( _vars, 0, _size * sizeof(int16));
 }
 
-void addGfxElementA0(int16 param1, int16 param2) {
-	overlayHeadElement *currentHead = &overlayHead;
-	overlayHeadElement *tempHead = currentHead;
-	overlayHeadElement *newElement;
+/*! \brief Constructor for partial loading
+ * \param s Size of bytecode which will be added later
+ *
+ * This constructor _MUST_ be followed by setdata() method call before the
+ * instance can be used. It leaves the instance in partially invalid state.
+ */
+RawScript::RawScript(uint16 s) : _size(s), _data(NULL),
+	_labels(SCRIPT_STACK_SIZE) { }
 
-	currentHead = tempHead->next;
+/*! \brief Complete constructor
+ * \param data Script bytecode
+ * \param s Bytecode length
+ */
+RawScript::RawScript(const FWScriptInfo &info, const byte *data, uint16 s) :
+	_size(s), _data(NULL), _labels(SCRIPT_STACK_SIZE) {
 
-	while (currentHead) {
-		if (objectTable[currentHead->objIdx].mask == objectTable[param1].mask) {
-			if (currentHead->type == 2 || currentHead->objIdx == 3) {
-				break;
-			}
-		}
+	setData(info, data);
+}
 
-		tempHead = currentHead;
-		currentHead = currentHead->next;
-	}
+/*! \brief Copy constructor
+ */
+RawScript::RawScript(const RawScript &src) : _size(src._size),
+	_data(new byte[_size+1]), _labels(src._labels) {
 
-	if (currentHead && currentHead->objIdx == param1 && currentHead->type == 20 && currentHead->x == param2)
-		return;
-
-	newElement = new overlayHeadElement;
-
-	newElement->next = tempHead->next;
-	tempHead->next = newElement;
-
-	newElement->objIdx = param1;
-	newElement->type = 20;
-
-	newElement->x = param2;
-	newElement->y = 0;
-	newElement->width = 0;
-	newElement->color = 0;
-
-	if (!currentHead)
-		currentHead = &overlayHead;
-
-	newElement->previous = currentHead->previous;
-
-	currentHead->previous = newElement;
+	assert(_data);
+	memcpy(_data, src._data, _size+1);
 }
 
-void removeSeq(uint16 param1, uint16 param2, uint16 param3) {
-	SeqListElement *currentHead = &seqList;
-	SeqListElement *tempHead = currentHead;
-
-	while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
-
-	if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) {
-		currentHead->var4 = -1;
-	}
+/*! \brief Destructor
+ */
+RawScript::~RawScript(void) {
+	delete[] _data;
 }
 
-uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) {
-	SeqListElement *currentHead = &seqList;
-	SeqListElement *tempHead = currentHead;
+/*! \brief Assignment operator
+ */
+RawScript &RawScript::operator=(const RawScript &src) {
+	assert(src._data);
+	byte *tmp = new byte[src._size+1];
 
-	while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
+	assert(tmp);
+	_labels = src._labels;
+	_size = src._size;
 
-	if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) {
-		return 1;
-	}
+	delete[] _data;
+	_data = tmp;
+	memcpy(_data, src._data, _size);
+	_data[_size] = 0;
 
-	return 0;
+	return *this;
 }
 
-ScriptStruct scriptTable[NUM_MAX_SCRIPT];
+/*! \brief Get the next label in bytecode
+ * \param info Script info instance
+ * \param offset Starting offset
+ * \return Index of the next label in bytecode or _size on end of bytecode
+ *
+ * computeScriptStackSub replacement
+ */
+int RawScript::getNextLabel(const FWScriptInfo &info, int offset) const {
+	assert(_data);
+	int pos = offset;
 
-void stopGlobalScript(uint16 scriptIdx) {
-	prcLinkedListStruct *currentHead = &globalScriptsHead;
-	prcLinkedListStruct *tempHead = currentHead;
+	assert(pos >= 0);
 
-	currentHead = tempHead->next;
+	while (pos < _size) {
+		uint8 opcode = _data[pos++];
+		const char *ptr = info.opcodeInfo(opcode);
 
-	while (currentHead && (currentHead->scriptIdx != scriptIdx)) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
-
-	if (!currentHead) {
-		return;
-	}
-
-	if (currentHead->scriptIdx != scriptIdx) {
-		return;
-	}
-
-	currentHead->scriptIdx = -1;
-}
-
-uint16 computeScriptStackSub(bool computeAllLabels, byte *scriptPtr, int16 *stackPtr, uint16 scriptSize, byte labelIndex, uint16 startOffset) {
-	uint16 position;
-
-	if (computeAllLabels) {
-		for (int i = 0; i < SCRIPT_STACK_SIZE; i++) {
-			stackPtr[i] = -1;
-		}
-		position = 0;
-	} else {
-		position = startOffset;
-	}
-	while (position < scriptSize) {
-		uint8 opcode = scriptPtr[position];
-		position++;
-		if (opcode == 0 || opcode > _numOpcodes) {
+		if (!ptr) {
 			continue;
 		}
-		if (!_opcodeTable[opcode - 1].args) {
-			warning("Undefined opcode 0x%02X in computeScriptStackSub", opcode - 1);
-			continue;
-		}
-		for (const char *p = _opcodeTable[opcode - 1].args; *p; ++p) {
-			switch (*p) {
+
+		for (; *ptr; ++ptr) {
+			switch (*ptr) {
 			case 'b': // byte
-				position++;
+				pos++;
 				break;
 			case 'w': // word
-				position += 2;
+				pos += 2;
 				break;
 			case 'c': { // byte != 0 ? byte : word
-					uint8 test = scriptPtr[position];
-					position++;
+					uint8 test = _data[pos];
+					pos++;
 					if (test) {
-						position++;
+						pos++;
 					} else {
-						position += 2;
+						pos += 2;
 					}
 				}
 				break;
-			case 'l': { // label
-					uint8 index = scriptPtr[position];
-					position++;
-					if (computeAllLabels) {
-						stackPtr[index] = position;
-					} else {
-						if (labelIndex == index) {
-							return position;
-						}
-					}
-				}
-				break;
+			case 'l': // label
+				return pos;
 			case 's': // string
-				while (scriptPtr[position++] != 0);
+				while (_data[pos++] != 0);
 				break;
 			case 'x': // exit script
-				return position;
+				return -pos-1;
 			}
 		}
 	}
-	return position;
+	return _size;
 }
 
-void computeScriptStack(byte *scriptPtr, int16 *stackPtr, uint16 scriptSize) {
-	computeScriptStackSub(true, scriptPtr, stackPtr, scriptSize, 0, 0);
-}
+/*! \brief Calculate initial script labels
+ * \param info Script info instance
+ *
+ * computeScriptStack replacement
+ */
+void RawScript::computeLabels(const FWScriptInfo &info) {
+	assert(_data);
+	int pos = 0;
+	int i;
 
-uint16 computeScriptStackFromScript(byte *scriptPtr, uint16 currentPosition, uint16 labelIdx, uint16 scriptSize) {
-	return computeScriptStackSub(false, scriptPtr, (int16 *)&dummyU16, (uint16)scriptSize, labelIdx, currentPosition);
+	// reset labels
+	for (i = 0; i < SCRIPT_STACK_SIZE; i++) {
+		_labels[i] = -1;
+	}
+
+	// parse bytecode
+	while ((pos = getNextLabel(info, pos)) >= 0) {
+		i = _data[pos];
+		_labels[i] = ++pos;
+	}
 }
 
-void palRotate(byte a, byte b, byte c) {
-	if (c == 1) {
-		uint16 currentColor = c_palette[b];
+/*! \brief find the next label from current position
+ * \param info Script info instance
+ * \param index Label index to look for
+ * \param offset Current position in script
+ * \return Position of next instruction following the label
+ *
+ * computeScriptStackFromScript replacement
+ */
+uint16 RawScript::getLabel(const FWScriptInfo &info, byte index, uint16 offset)
+	const {
 
-		for (int16 i = b; i > a; i--) {
-			c_palette[i] = c_palette[i - 1];
+	assert(_data);
+	int pos = offset;
+
+	while ((pos = getNextLabel(info, pos)) >= 0) {
+		if (_data[pos++] == index) {
+			return pos;
 		}
+	}
 
-		c_palette[a] = currentColor;
-	}
+	return -pos - 1;
 }
 
-void addScriptToList0(uint16 idx) {
-	uint16 i;
-	prcLinkedListStruct *pNewElement;
-	prcLinkedListStruct *currentHead = &globalScriptsHead;
-	prcLinkedListStruct *tempHead = currentHead;
+/*! \brief Copy bytecode and calculate labels
+ * \param data Bytecode to copy, must be _size long
+ */
+void RawScript::setData(const FWScriptInfo &info, const byte *data) {
+	assert(!_data); // this function should be called only once per instance
+	_data = new byte[_size+1];
 
-	assert(idx <= NUM_MAX_SCRIPT);
+	assert(data && _data);
+	memcpy(_data, data, _size * sizeof(byte));
+	_data[_size] = 0;
 
-	currentHead = tempHead->next;
+	computeLabels(info);
+}
 
-	while (currentHead) {
-		tempHead = currentHead;
+/*! \brief Initial script labels
+ * \return Precalculated script labels
+ */
+const ScriptVars &RawScript::labels(void) const {
+	assert(_data);
+	return _labels;
+}
 
-		assert(tempHead);
+/*! \brief One byte of bytecode
+ * \param pos Index in bytecode
+ * \return Byte from bytecode
+ */
+byte RawScript::getByte(unsigned int pos) const {
+	assert(_data && pos < _size);
 
-		currentHead = tempHead->next;
-	}
+	return _data[pos];
+}
 
-	pNewElement = new prcLinkedListStruct;
+/*! \brief One word of bytecode
+ * \param pos Index of the first byte in bytecode
+ * \return Word of bytecode
+ */
+uint16 RawScript::getWord(unsigned int pos) const {
+	assert(_data && pos+1 < _size);
 
-	assert(pNewElement);
+	return READ_BE_UINT16(_data + pos);
+}
 
-	pNewElement->next = tempHead->next;
-	tempHead->next = pNewElement;
+/*! \brief String in bytecode
+ * \param pos Index of the first char in string
+ * \return Pointer to part of bytecode
+ */
+const char *RawScript::getString(unsigned int pos) const {
+	assert(_data && pos < _size);
 
-	// copy the stack into the script instance
-	for (i = 0; i < SCRIPT_STACK_SIZE; i++) {
-		pNewElement->stack[i] = scriptTable[idx].stack[i];
-	}
+	return (const char*)(_data+pos);
+}
 
-	pNewElement->compareResult = 0;
-	pNewElement->scriptPosition = 0;
+/*! \brief Constructor for partial loading
+ * \param size Size of bytecode which will be added later
+ * \param p1 First object script parameter
+ * \param p2 Second object script parameter
+ * \param p3 Third object script parameter
+ *
+ * This constructor _MUST_ be followed by setdata() method call before the
+ * instance can be used. It leaves the instance in partially invalid state.
+ */
+RawObjectScript::RawObjectScript(uint16 s, uint16 p1, uint16 p2, uint16 p3)
+	: RawScript(s), _runCount(0), _param1(p1), _param2(p2), _param3(p3)
+{ }
 
-	pNewElement->scriptPtr = scriptTable[idx].ptr;
-	pNewElement->scriptIdx = idx;
+/*! \brief Complete constructor
+ * \param data Script bytecode
+ * \param s Bytecode length
+ * \param p1 First object script parameter
+ * \param p2 Second object script parameter
+ * \param p3 Third object script parameter
+ */
+RawObjectScript::RawObjectScript(const FWScriptInfo &info, const byte *data,
+	uint16 s, uint16 p1, uint16 p2, uint16 p3) : RawScript(info, data, s),
+	_runCount(0), _param1(p1), _param2(p2), _param3(p3) { }
+
+/*! \brief Contructor for global scripts
+ * \param script Script bytecode reference
+ * \param idx Script bytecode index
+ */
+FWScript::FWScript(const RawScript &script, int16 idx) : _script(script),
+	_pos(0), _line(0), _compare(0), _index(idx),
+	_labels(script.labels()), _localVars(LOCAL_VARS_SIZE),
+	_globalVars(globalVars), _info(new FWScriptInfo) { }
+
+/*! \brief Copy constructor
+ */
+FWScript::FWScript(const FWScript &src) : _script(src._script), _pos(src._pos),
+	_line(src._line), _compare(src._compare), _index(src._index),
+	_labels(src._labels), _localVars(src._localVars),
+	_globalVars(src._globalVars), _info(new FWScriptInfo) { }
+
+/*! \brief Contructor for global scripts in derived classes
+ * \param script Script bytecode reference
+ * \param idx Script bytecode index
+ */
+FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info) :
+	_script(script), _pos(0), _line(0), _compare(0), _index(idx),
+	_labels(script.labels()), _localVars(LOCAL_VARS_SIZE),
+	_globalVars(globalVars), _info(info) { }
+
+/*! \brief Constructor for object scripts in derived classes
+ * \param script Script bytecode reference
+ * \param idx Script bytecode index
+ */
+FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info) :
+	_script(script), _pos(0), _line(0), _compare(0), _index(idx),
+	_labels(script.labels()), _localVars(LOCAL_VARS_SIZE),
+	_globalVars(globalVars), _info(info) {
+
+	_localVars[0] = script.run();
 }
 
-int16 endScript0(uint16 scriptIdx) {
-	prcLinkedListStruct *currentHead = &globalScriptsHead;
-	prcLinkedListStruct *tempHead = currentHead;
+/*! \brief Copy constructor for derived classes
+ */
+FWScript::FWScript(const FWScript &src, FWScriptInfo *info) :
+	_script(src._script), _pos(src._pos), _line(src._line),
+	_compare(src._compare), _index(src._index), _labels(src._labels),
+	_localVars(src._localVars), _globalVars(src._globalVars), _info(info) { }
 
-	//assert(scriptIdx <= NUM_MAX_SCRIPT);
+FWScript::~FWScript(void) {
+	delete _info;
+}
 
-	currentHead = tempHead->next;
+/*! \brief Read next byte from bytecode
+ * \return Byte from bytecode
+ */
+byte FWScript::getNextByte() {
+	byte val = _script.getByte(_pos);
+	_pos++;
+	return val;
+}
 
-	while (currentHead && currentHead->scriptIdx != scriptIdx) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
+/*! \brief Read next word from bytecode
+ * \return Word from bytecode
+ */
+uint16 FWScript::getNextWord() {
+	uint16 val = _script.getWord(_pos);
+	_pos += 2;
+	return val;
+}
 
-	if (!currentHead) {
-		return -1;
-	}
+/*! \brief Read next string from bytecode
+ * \return Pointer to string
+ */
+const char *FWScript::getNextString() {
+	const char *val = _script.getString(_pos);
+	_pos += strlen(val) + 1;
+	return val;
+}
 
-	if (currentHead->scriptIdx != scriptIdx) {
-		return -1;
+/*! \brief Restore script state from savefile
+ * \param labels Restored script labels
+ * \param local Restored local script variables
+ * \param compare Restored last comparison result
+ * \param pos Restored script position
+ */
+void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) {
+	assert(pos < _script._size);
+	_labels = labels;
+	_localVars = local;
+	_compare = compare;
+	_pos = _line = pos;
+}
+
+/*! \brief Execute script
+ * \return <0 on script termination, >0 on script pause
+ *
+ * executeScript replacement.
+ * Instruction handler must return 0 if the script should continue or
+ * nonzero with the same meaning as return value of this function
+ */
+int FWScript::execute() {
+	int ret = 0;
+
+	while (!ret) {
+		_line = _pos;
+		byte opcode = getNextByte();
+		opFunc handler = _info->opcodeHandler(opcode);
+
+		if (handler) {
+			ret = (this->*handler)();
+		}
 	}
 
-	currentHead->scriptIdx = -1;
+	return ret;
+}
 
-	return 0;
+/*! \brief Save script to savefile
+ * \param fHandle Savefile handle
+ */
+void FWScript::save(Common::OutSaveFile &fHandle) const {
+	_labels.save(fHandle);
+	_localVars.save(fHandle);
+	fHandle.writeUint16BE(_compare);
+	fHandle.writeUint16BE(_pos);
+	// data order sucks...
+	fHandle.writeUint16BE(_index);
 }
 
-int16 endScript1(uint16 scriptIdx) {
-	prcLinkedListStruct *currentHead = &objScriptList;
-	prcLinkedListStruct *tempHead = currentHead;
+/*! \brief Contructor for global scripts
+ * \param script Script bytecode reference
+ * \param idx Script bytecode index
+ */
+OSScript::OSScript(const RawScript &script, int16 idx) :
+	FWScript(script, idx, new OSScriptInfo) {}
 
-	currentHead = tempHead->next;
+/*! \brief Constructor for object scripts
+ * \param script Script bytecode reference
+ * \param idx Script bytecode index
+ */
+OSScript::OSScript(RawObjectScript &script, int16 idx) :
+	FWScript(script, idx, new OSScriptInfo) {}
 
-	while (currentHead && currentHead->scriptIdx != scriptIdx) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
+/*! \brief Copy constructor
+ */
+OSScript::OSScript(const OSScript &src) : FWScript(src, new OSScriptInfo) {}
 
-	if (!currentHead) {
-		return -1;
+/*! \brief Restore script state from savefile
+ * \param labels Restored script labels
+ * \param local Restored local script variables
+ * \param compare Restored last comparison result
+ * \param pos Restored script position
+ */
+void OSScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) {
+	FWScript::load(labels, local, compare, pos);
+}
+/*! \brief Get opcode info string
+ * \param opcode Opcode to look for in opcode table
+ */
+const char *FWScriptInfo::opcodeInfo(byte opcode) const {
+	if (opcode == 0 || opcode > FWScript::_numOpcodes) {
+		return NULL;
 	}
 
-	if (currentHead->scriptIdx != scriptIdx) {
-		return -1;
+	if (!FWScript::_opcodeTable[opcode - 1].args) {
+		warning("Undefined opcode 0x%02X in FWScriptInfo::opcodeInfo", opcode - 1);
+		return NULL;
 	}
 
-	currentHead->scriptIdx = -1;
-
-	return 0;
+	return FWScript::_opcodeTable[opcode - 1].args;
 }
 
-int16 getZoneFromPosition(byte *page, int16 x, int16 y, int16 width) {
-	byte *ptr = page + (y * width) + x / 2;
-	byte zoneVar;
+/*! \brief Get opcode handler pointer
+ * \param opcode Opcode to look for in opcode table
+ */
+opFunc FWScriptInfo::opcodeHandler(byte opcode) const {
+	if (opcode == 0 || opcode > FWScript::_numOpcodes) {
+		return NULL;
+	}
 
-	if (!(x % 2)) {
-		zoneVar = (*(ptr) >> 4) & 0xF;
-	} else {
-		zoneVar = (*(ptr)) & 0xF;
+	if (!FWScript::_opcodeTable[opcode - 1].proc) {
+		warning("Undefined opcode 0x%02X in FWScriptInfo::opcodeHandler", opcode - 1);
+		return NULL;
 	}
 
-	return zoneVar;
+	return FWScript::_opcodeTable[opcode - 1].proc;
 }
 
-int16 getZoneFromPositionRaw(byte *page, int16 x, int16 y, int16 width) {
-	byte *ptr = page + (y * width) + x;
-	byte zoneVar;
+/*! \brief Create new FWScript instance
+ * \param script Script bytecode
+ * \param index Bytecode index
+ */
+FWScript *FWScriptInfo::create(const RawScript &script, int16 index) const {
+	return new FWScript(script, index);
+}
 
-	zoneVar = (*(ptr)) & 0xF;
+/*! \brief Create new FWScript instance
+ * \param script Object script bytecode
+ * \param index Bytecode index
+ */
+FWScript *FWScriptInfo::create(const RawObjectScript &script, int16 index) const {
+	return new FWScript(script, index);
+}
 
-	return zoneVar;
+/*! \brief Load saved FWScript instance
+ * \param script Script bytecode
+ * \param index Bytecode index
+ * \param local Local variables
+ * \param labels Script labels
+ * \param compare Last compare result
+ * \param pos Position in script
+ */
+FWScript *FWScriptInfo::create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const {
+	FWScript *tmp = new FWScript(script, index);
+	assert(tmp);
+	tmp->load(labels, local, compare, pos);
+	return tmp;
 }
 
-int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx) {
-	int16 lx = objectTable[objIdx].x + x;
-	int16 ly = objectTable[objIdx].y + y;
-	int16 idx;
+/*! \brief Load saved FWScript instance
+ * \param script Object script bytecode
+ * \param index Bytecode index
+ * \param local Local variables
+ * \param labels Script labels
+ * \param compare Last compare result
+ * \param pos Position in script
+ */
+FWScript *FWScriptInfo::create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const {
+	FWScript *tmp = new FWScript(script, index);
+	assert(tmp);
+	tmp->load(labels, local, compare, pos);
+	return tmp;
+}
 
-	for (int16 i = 0; i < numZones; i++) {
-		idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320);
+/*! \brief Get opcode info string
+ * \param opcode Opcode to look for in opcode table
+ */
+const char *OSScriptInfo::opcodeInfo(byte opcode) const {
+	if (opcode == 0 || opcode > OSScript::_numOpcodes) {
+		return NULL;
+	}
 
-		assert(idx >= 0 && idx <= NUM_MAX_ZONE);
-
-		if (zoneData[idx] == zoneIdx) {
-			return 1;
-		}
+	if (!OSScript::_opcodeTable[opcode - 1].args) {
+		warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeInfo", opcode - 1);
+		return NULL;
 	}
 
-	return 0;
+	return OSScript::_opcodeTable[opcode - 1].args;
 }
 
-uint16 compareVars(int16 a, int16 b) {
-	uint16 flag = 0;
+/*! \brief Get opcode handler pointer
+ * \param opcode Opcode to look for in opcode table
+ */
+opFunc OSScriptInfo::opcodeHandler(byte opcode) const {
+	if (opcode == 0 || opcode > OSScript::_numOpcodes) {
+		return NULL;
+	}
 
-	if (a == b) {
-		flag |= kCmpEQ;
-	} else if (a > b) {
-		flag |= kCmpGT;
-	} else if (a < b) {
-		flag |= kCmpLT;
+	if (!OSScript::_opcodeTable[opcode - 1].proc) {
+		warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeHandler", opcode - 1);
+		return NULL;
 	}
 
-	return flag;
+	return OSScript::_opcodeTable[opcode - 1].proc;
 }
 
+/*! \brief Create new OSScript instance
+ * \param script Script bytecode
+ * \param index Bytecode index
+ */
+FWScript *OSScriptInfo::create(const RawScript &script, int16 index) const {
+	return new OSScript(script, index);
+}
+
+/*! \brief Create new OSScript instance
+ * \param script Object script bytecode
+ * \param index Bytecode index
+ */
+FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index) const {
+	return new OSScript(script, index);
+}
+
+/*! \brief Load saved OSScript instance
+ * \param script Script bytecode
+ * \param index Bytecode index
+ * \param local Local variables
+ * \param labels Script labels
+ * \param compare Last compare result
+ * \param pos Position in script
+ */
+FWScript *OSScriptInfo::create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const {
+	OSScript *tmp = new OSScript(script, index);
+	assert(tmp);
+	tmp->load(labels, local, compare, pos);
+	return tmp;
+}
+
+/*! \brief Load saved OSScript instance
+ * \param script Object script bytecode
+ * \param index Bytecode index
+ * \param local Local variables
+ * \param labels Script labels
+ * \param compare Last compare result
+ * \param pos Position in script
+ */
+FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const {
+	OSScript *tmp = new OSScript(script, index);
+	assert(tmp);
+	tmp->load(labels, local, compare, pos);
+	return tmp;
+}
+
 // ------------------------------------------------------------------------
 // FUTURE WARS opcodes
 // ------------------------------------------------------------------------
 
-void o1_modifyObjectParam() {
+int FWScript::o1_modifyObjectParam() {
 	byte objIdx = getNextByte();
 	byte paramIdx = getNextByte();
 	int16 newValue = getNextWord();
 
-	debugC(5, kCineDebugScript, "Line: %d: modifyObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _currentLine, objIdx, paramIdx, newValue);
+	debugC(5, kCineDebugScript, "Line: %d: modifyObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue);
 
 	modifyObjectParam(objIdx, paramIdx, newValue);
+	return 0;
 }
 
-void o1_getObjectParam() {
+int FWScript::o1_getObjectParam() {
 	byte objIdx = getNextByte();
 	byte paramIdx = getNextByte();
 	byte newValue = getNextByte();
 
-	debugC(5, kCineDebugScript, "Line: %d: getObjectParam(objIdx:%d,paramIdx:%d,var:%d)", _currentLine, objIdx, paramIdx, newValue);
+	debugC(5, kCineDebugScript, "Line: %d: getObjectParam(objIdx:%d,paramIdx:%d,var:%d)", _line, objIdx, paramIdx, newValue);
 
-	_currentScriptElement->localVars[newValue] = getObjectParam(objIdx, paramIdx);
+	_localVars[newValue] = getObjectParam(objIdx, paramIdx);
+	return 0;
 }
 
-void o1_addObjectParam() {

@@ Diff output truncated at 100000 characters. @@

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list