Index: engines/cine/script_fw.cpp
===================================================================
--- engines/cine/script_fw.cpp	(revision 31445)
+++ engines/cine/script_fw.cpp	(working copy)
@@ -24,7 +24,7 @@
  */
 
 /*! \file
- * Script interpreter file
+ * Future Wars script interpreter file
  */
 
 #include "common/endian.h"
@@ -38,6 +38,8 @@
 
 namespace Cine {
 
+ScriptVars globalVars(NUM_MAX_VAR);
+
 uint16 compareVars(int16 a, int16 b);
 void palRotate(byte a, byte b, byte c);
 void removeSeq(uint16 param1, uint16 param2, uint16 param3);
@@ -161,7 +163,7 @@
 	{ &FWScript::o1_declareFunctionName, "s" },
 	{ &FWScript::o1_freePartRange, "bb" },
 	{ &FWScript::o1_unloadAllMasks, "" },
-	// 5C */
+	/* 5C */
 	{ 0, 0 },
 	{ 0, 0 },
 	{ 0, 0 },
@@ -204,224 +206,6 @@
 };
 const unsigned int FWScript::_numOpcodes = ARRAYSIZE(FWScript::_opcodeTable);
 
-
-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);
-
 FWScriptInfo *scriptInfo; ///< Script factory
 RawScriptArray scriptTable; ///< Table of script bytecode
 
@@ -898,33 +682,6 @@
 	fHandle.writeUint16BE(_index);
 }
 
-/*! \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) {}
-
-/*! \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) {}
-
-/*! \brief Copy constructor
- */
-OSScript::OSScript(const OSScript &src) : FWScript(src, new OSScriptInfo) {}
-
-/*! \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
  */
@@ -1003,84 +760,6 @@
 	return tmp;
 }
 
-/*! \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;
-	}
-
-	if (!OSScript::_opcodeTable[opcode - 1].args) {
-		warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeInfo", opcode - 1);
-		return NULL;
-	}
-
-	return OSScript::_opcodeTable[opcode - 1].args;
-}
-
-/*! \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 (!OSScript::_opcodeTable[opcode - 1].proc) {
-		warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeHandler", opcode - 1);
-		return NULL;
-	}
-
-	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
 // ------------------------------------------------------------------------
@@ -1375,7 +1054,7 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: addSpriteOverlay(%d)", _line, param);
-	loadOverlayElement(param, 0);
+	addOverlay(param, 0);
 	return 0;
 }
 
@@ -1383,8 +1062,9 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: removeSpriteOverlay(%d)", _line, param);
-	freeOverlay(param, 0);
+	removeOverlay(param, 0);
 	return 0;
+	return 0;
 }
 
 int FWScript::o1_addToBgList() {
@@ -1399,7 +1079,7 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: addOverlay1(%d)", _line, param);
-	loadOverlayElement(param, 1);
+	addOverlay(param, 1);
 	return 0;
 }
 
@@ -1407,7 +1087,7 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: removeOverlay1(%d)", _line, param);
-	freeOverlay(param, 1);
+	removeOverlay(param, 1);
 	return 0;
 }
 
@@ -1415,7 +1095,7 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: addOverlayType4(%d)", _line, param);
-	loadOverlayElement(param, 4);
+	addOverlay(param, 4);
 	return 0;
 }
 
@@ -1423,7 +1103,7 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: removeSpriteOverlay4(%d)", _line, param);
-	freeOverlay(param, 4);
+	removeOverlay(param, 4);
 	return 0;
 }
 
@@ -1825,7 +1505,7 @@
 
 int FWScript::o1_unloadAllMasks() {
 	debugC(5, kCineDebugScript, "Line: %d: unloadAllMasks()", _line);
-	unloadAllMasks();
+	overlayList.clear();
 	return 0;
 }
 
@@ -2034,7 +1714,7 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: addOverlay5(%d)", _line, param);
-	loadOverlayElement(param, 5);
+	addOverlay(param, 5);
 	return 0;
 }
 
@@ -2042,534 +1722,12 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: freeOverlay5(%d)", _line, param);
-	freeOverlay(param, 5);
+	removeOverlay(param, 5);
 	return 0;
 }
 
-// ------------------------------------------------------------------------
-// OPERATION STEALTH opcodes
-// ------------------------------------------------------------------------
-
-int FWScript::o2_loadPart() {
-	const char *param = getNextString();
-
-	debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _line, param);
-	return 0;
-}
-
-int FWScript::o2_playSample() {
-	if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) {
-		// no-op in these versions
-		getNextByte();
-		getNextByte();
-		getNextWord();
-		getNextByte();
-		getNextWord();
-		getNextWord();
-		return 0;
-	}
-	return o1_playSample();
-}
-
-int FWScript::o2_playSampleAlt() {
-	byte num = getNextByte();
-	byte channel = getNextByte();
-	uint16 frequency = getNextWord();
-	getNextByte();
-	getNextWord();
-	uint16 size = getNextWord();
-
-	if (size == 0xFFFF) {
-		size = animDataTable[num]._width * animDataTable[num]._height;
-	}
-	if (animDataTable[num].data()) {
-		if (g_cine->getPlatform() == Common::kPlatformPC) {
-			// if speaker output is available, play sound on it
-			// if it's another device, don't play anything
-			// TODO: implement this, it's used in the introduction for example
-			// on each letter displayed
-		} else {
-			g_sound->playSound(channel, frequency, animDataTable[num].data(), size, 0, 0, 63, 0);
-		}
-	}
-	return 0;
-}
-
-int FWScript::o2_addSeqListElement() {
-	byte param1 = getNextByte();
-	byte param2 = getNextByte();
-	byte param3 = getNextByte();
-	byte param4 = getNextByte();
-	uint16 param5 = getNextWord();
-	uint16 param6 = getNextWord();
-	uint16 param7 = getNextWord();
-
-	debugC(5, kCineDebugScript, "Line: %d: addSeqListElement(%d,%d,%d,%d,%d,%d,%d)", _line, param1, param2, param3, param4, param5, param6, param7);
-	addSeqListElement(param1, 0, param2, param3, param4, param5, param6, 0, param7);
-	return 0;
-}
-
-int FWScript::o2_removeSeq() {
-	byte a = getNextByte();
-	byte b = getNextByte();
-
-	debugC(5, kCineDebugScript, "Line: %d: removeSeq(%d,%d) -> TODO", _line, a, b);
-	removeSeq(a, 0, b);
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op81() {
-	warning("STUB: o2_op81()");
-	// freeUnkList();
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op82() {
-	byte a = getNextByte();
-	byte b = getNextByte();
-	uint16 c = getNextWord();
-	warning("STUB: o2_op82(%x, %x, %x)", a, b, c);
-	return 0;
-}
-
-int FWScript::o2_isSeqRunning() {
-	byte a = getNextByte();
-	byte b = getNextByte();
-
-	debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b);
-
-	if (isSeqRunning(a, 0, b)) {
-		_compare = 1;
-	} else {
-		_compare = 0;
-	}
-	return 0;
-}
-
-/*! \todo The assert may produce false positives and requires testing
- */
-int FWScript::o2_gotoIfSupNearest() {
-	byte labelIdx = getNextByte();
-
-	if (_compare == kCmpGT) {
-		assert(_labels[labelIdx] != -1);
-
-		debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (true)", _line, labelIdx);
-		_pos = _script.getLabel(*_info, labelIdx, _pos);
-	} else {
-		debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (false)", _line, labelIdx);
-	}
-	return 0;
-}
-
-/*! \todo The assert may produce false positives and requires testing
- */
-int FWScript::o2_gotoIfSupEquNearest() {
-	byte labelIdx = getNextByte();
-
-	if (_compare & (kCmpGT | kCmpEQ)) {
-		assert(_labels[labelIdx] != -1);
-
-		debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (true)", _line, labelIdx);
-		_pos = _script.getLabel(*_info, labelIdx, _pos);
-	} else {
-		debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (false)", _line, labelIdx);
-	}
-	return 0;
-}
-
-/*! \todo The assert may produce false positives and requires testing
- */
-int FWScript::o2_gotoIfInfNearest() {
-	byte labelIdx = getNextByte();
-
-	if (_compare == kCmpLT) {
-		assert(_labels[labelIdx] != -1);
-
-		debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (true)", _line, labelIdx);
-		_pos = _script.getLabel(*_info, labelIdx, _pos);
-	} else {
-		debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (false)", _line, labelIdx);
-	}
-	return 0;
-}
-
-/*! \todo The assert may produce false positives and requires testing
- */
-int FWScript::o2_gotoIfInfEquNearest() {
-	byte labelIdx = getNextByte();
-
-	if (_compare & (kCmpLT | kCmpEQ)) {
-		assert(_labels[labelIdx] != -1);
-
-		debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (true)", _line, labelIdx);
-		_pos = _script.getLabel(*_info, labelIdx, _pos);
-	} else {
-		debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (false)", _line, labelIdx);
-	}
-	return 0;
-}
-
-/*! \todo The assert may produce false positives and requires testing
- */
-int FWScript::o2_gotoIfEquNearest() {
-	byte labelIdx = getNextByte();
-
-	if (_compare == kCmpEQ) {
-		assert(_labels[labelIdx] != -1);
-
-		debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (true)", _line, labelIdx);
-		_pos = _script.getLabel(*_info, labelIdx, _pos);
-	} else {
-		debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (false)", _line, labelIdx);
-	}
-	return 0;
-}
-
-/*! \todo The assert may produce false positives and requires testing
- */
-int FWScript::o2_gotoIfDiffNearest() {
-	byte labelIdx = getNextByte();
-
-	if (_compare != kCmpEQ) {
-		assert(_labels[labelIdx] != -1);
-
-		debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (true)", _line, labelIdx);
-		_pos = _script.getLabel(*_info, labelIdx, _pos);
-	} else {
-		debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (false)", _line, labelIdx);
-	}
-	return 0;
-}
-
-int FWScript::o2_startObjectScript() {
-	byte param = getNextByte();
-
-	debugC(5, kCineDebugScript, "Line: %d: startObjectScript(%d)", _line, param);
-	runObjectScript(param);
-	return 0;
-}
-
-int FWScript::o2_stopObjectScript() {
-	byte param = getNextByte();
-
-	debugC(5, kCineDebugScript, "Line: %d: stopObjectScript(%d)", _line, param);
-	ScriptList::iterator it = objectScripts.begin();
-
-	for (; it != objectScripts.end(); ++it) {
-		if ((*it)->_index == param) {
-			(*it)->_index = -1;
-		}
-	}
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op8D() {
-	uint16 a = getNextWord();
-	uint16 b = getNextWord();
-	uint16 c = getNextWord();
-	uint16 d = getNextWord();
-	uint16 e = getNextWord();
-	uint16 f = getNextWord();
-	uint16 g = getNextWord();
-	uint16 h = getNextWord();
-	warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h);
-	// _currentScriptElement->compareResult = ...
-	return 0;
-}
-
-int FWScript::o2_addBackground() {
-	byte param1 = getNextByte();
-	const char *param2 = getNextString();
-
-	debugC(5, kCineDebugScript, "Line: %d: addBackground(%s,%d)", _line, param2, param1);
-	addBackground(param2, param1);
-	return 0;
-}
-
-int FWScript::o2_removeBackground() {
-	byte param = getNextByte();
-
-	assert(param);
-
-	debugC(5, kCineDebugScript, "Line: %d: removeBackground(%d)", _line, param);
-
-	if (additionalBgTable[param]) {
-		free(additionalBgTable[param]);
-		additionalBgTable[param] = NULL;
-	}
-
-	if (currentAdditionalBgIdx == param) {
-		currentAdditionalBgIdx = 0;
-	}
-
-	if (currentAdditionalBgIdx2 == param) {
-		currentAdditionalBgIdx2 = 0;
-	}
-
-	strcpy(currentBgName[param], "");
-	return 0;
-}
-
-int FWScript::o2_loadAbs() {
-	byte param1 = getNextByte();
-	const char *param2 = getNextString();
-
-	debugC(5, kCineDebugScript, "Line: %d: loadABS(%d,%s)", _line, param1, param2);
-	loadAbs(param2, param1);
-	return 0;
-}
-
-int FWScript::o2_loadBg() {
-	byte param = getNextByte();
-
-	assert(param <= 8);
-
-	debugC(5, kCineDebugScript, "Line: %d: useBg(%d)", _line, param);
-
-	if (additionalBgTable[param]) {
-		currentAdditionalBgIdx = param;
-		if (param == 8) {
-			newColorMode = 3;
-		} else {
-			newColorMode = bgColorMode + 1;
-		}
-		//if (_screenNeedFadeOut == 0) {
-		//	adBgVar1 = 1;
-		//}
-		fadeRequired = true;
-	}
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_wasZoneChecked() {
-	warning("STUB: o2_wasZoneChecked()");
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op9B() {
-	uint16 a = getNextWord();
-	uint16 b = getNextWord();
-	uint16 c = getNextWord();
-	uint16 d = getNextWord();
-	uint16 e = getNextWord();
-	uint16 f = getNextWord();
-	uint16 g = getNextWord();
-	uint16 h = getNextWord();
-	warning("STUB: o2_op9B(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h);
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op9C() {
-	uint16 a = getNextWord();
-	uint16 b = getNextWord();
-	uint16 c = getNextWord();
-	uint16 d = getNextWord();
-	warning("STUB: o2_op9C(%x, %x, %x, %x)", a, b, c, d);
-	return 0;
-}
-
-int FWScript::o2_useBgScroll() {
-	byte param = getNextByte();
-
-	assert(param <= 8);
-
-	debugC(5, kCineDebugScript, "Line: %d: useBgScroll(%d)", _line, param);
-
-	if (additionalBgTable[param]) {
-		currentAdditionalBgIdx2 = param;
-	}
-	return 0;
-}
-
-int FWScript::o2_setAdditionalBgVScroll() {
-	byte param1 = getNextByte();
-
-	if (param1) {
-		byte param2 = getNextByte();
-
-		debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = var[%d]", _line, param2);
-		additionalBgVScroll = _localVars[param2];
-	} else {
-		uint16 param2 = getNextWord();
-
-		debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = %d", _line, param2);
-		additionalBgVScroll = param2;
-	}
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op9F() {
-	warning("o2_op9F()");
-	getNextWord();
-	getNextWord();
-	return 0;
-}
-
-int FWScript::o2_addGfxElementA0() {
-	uint16 param1 = getNextWord();
-	uint16 param2 = getNextWord();
-
-	debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2);
-	addGfxElementA0(param1, param2);
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_removeGfxElementA0() {
-	uint16 idx = getNextWord();
-	uint16 param = getNextWord();
-	warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param);
-	removeGfxElementA0(idx, param);
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_opA2() {
-	uint16 a = getNextWord();
-	uint16 b = getNextWord();
-	warning("STUB: o2_opA2(%x, %x)", a, b);
-	// addGfxElementA2();
-	return 0;
-}
-
-/*! \todo Implement this instruction
- */
-int FWScript::o2_opA3() {
-	uint16 a = getNextWord();
-	uint16 b = getNextWord();
-	warning("STUB: o2_opA3(%x, %x)", a, b);
-	// removeGfxElementA2();
-	return 0;
-}
-
-int FWScript::o2_loadMask22() {
-	byte param = getNextByte();
-
-	debugC(5, kCineDebugScript, "Line: %d: addOverlay22(%d)", _line, param);
-	loadOverlayElement(param, 22);
-	return 0;
-}
-
-int FWScript::o2_unloadMask22() {
-	byte param = getNextByte();
-
-	debugC(5, kCineDebugScript, "Line: %d: removeOverlay22(%d)", _line, param);
-	freeOverlay(param, 22);
-	return 0;
-}
-
 //-----------------------------------------------------------------------
 
-void addGfxElementA0(int16 param1, int16 param2) {
-	overlayHeadElement *currentHead = &overlayHead;
-	overlayHeadElement *tempHead = currentHead;
-	overlayHeadElement *newElement;
-
-	currentHead = tempHead->next;
-
-	while (currentHead) {
-		if (objectTable[currentHead->objIdx].mask == objectTable[param1].mask) {
-			if (currentHead->type == 2 || currentHead->objIdx == 3) {
-				break;
-			}
-		}
-
-		tempHead = currentHead;
-		currentHead = currentHead->next;
-	}
-
-	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;
-}
-
-/*! \todo Check that it works
- */
-void removeGfxElementA0(int16 idx, int16 param) {
-	overlayHeadElement *parent = &overlayHead;
-	overlayHeadElement *head = overlayHead.next;
-	overlayHeadElement *tmp;
-
-	while (head) {
-		if (head->objIdx == idx && head->x == param) {
-			parent->next = head->next;
-			tmp = head->next ? head->next : &overlayHead;
-			tmp->previous = parent;
-			delete head;
-			return;
-		}
-
-		parent = head;
-		head = head->next;
-	}
-}
-
-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;
-	}
-}
-
-uint16 isSeqRunning(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) {
-		return 1;
-	}
-
-	return 0;
-}
-
 void palRotate(byte a, byte b, byte c) {
 	if (c == 1) {
 		uint16 currentColor = c_palette[b];
Index: engines/cine/script.h
===================================================================
--- engines/cine/script.h	(revision 31445)
+++ engines/cine/script.h	(working copy)
@@ -358,6 +358,7 @@
 
 extern RawScriptArray scriptTable;
 extern FWScriptInfo *scriptInfo;
+extern ScriptVars globalVars;
 
 void setupOpcodes();
 
Index: engines/cine/module.mk
===================================================================
--- engines/cine/module.mk	(revision 31445)
+++ engines/cine/module.mk	(working copy)
@@ -14,7 +14,8 @@
 	part.o \
 	prc.o \
 	rel.o \
-	script.o \
+	script_fw.o \
+	script_os.o \
 	sound.o \
 	texte.o \
 	unpack.o \
Index: engines/cine/object.h
===================================================================
--- engines/cine/object.h	(revision 31445)
+++ engines/cine/object.h	(working copy)
@@ -40,9 +40,7 @@
 	uint16 part;
 };
 
-struct overlayHeadElement {
-	struct overlayHeadElement *next;
-	struct overlayHeadElement *previous;
+struct overlay {
 	uint16 objIdx;
 	uint16 type;
 	int16 x;
@@ -55,22 +53,19 @@
 #define NUM_MAX_VAR 256
 
 extern objectStruct objectTable[NUM_MAX_OBJECT];
-extern ScriptVars globalVars;
 
-extern overlayHeadElement overlayHead;
+extern Common::List<overlay> overlayList;
 
-void unloadAllMasks(void);
-void resetMessageHead(void);
-
 void loadObject(char *pObjectName);
 void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4);
 void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue);
 
-void loadOverlayElement(uint16 objIdx, uint16 param);
-int8 removeOverlayElement(uint16 objIdx, uint16 param);
+void addOverlay(uint16 objIdx, uint16 param);
+int removeOverlay(uint16 objIdx, uint16 param);
+void addGfxElementA0(int16 objIdx, int16 param);
+void removeGfxElementA0(int16 objIdx, int16 param);
 
 int16 getObjectParam(uint16 objIdx, uint16 paramIdx);
-int16 freeOverlay(uint16 objIdx, uint16 param);
 
 void addObjectParam(byte objIdx, byte paramIdx, int16 newValue);
 void subObjectParam(byte objIdx, byte paramIdx, int16 newValue);
Index: engines/cine/bg_list.cpp
===================================================================
--- engines/cine/bg_list.cpp	(revision 31445)
+++ engines/cine/bg_list.cpp	(working copy)
@@ -77,7 +77,7 @@
 void addSpriteFilledToBGList(int16 objIdx, bool addList) {
 	int16 x = objectTable[objIdx].x;
 	int16 y = objectTable[objIdx].y;
-	int16 width = animDataTable[objectTable[objIdx].frame]._width;
+	int16 width = animDataTable[objectTable[objIdx].frame]._realWidth;
 	int16 height = animDataTable[objectTable[objIdx].frame]._height;
 	const byte *data = animDataTable[objectTable[objIdx].frame].data();
 
@@ -86,11 +86,11 @@
 		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);
+					gfxFillSprite(data, width, height, additionalBgTable[i], x, y);
 				}
 			}
 		} else {
-			gfxFillSprite(data, width / 2, height, page2Raw, x, y);
+			gfxFillSprite(data, width, height, page2Raw, x, y);
 		}
 	}
 
Index: engines/cine/anim.cpp
===================================================================
--- engines/cine/anim.cpp	(revision 31445)
+++ engines/cine/anim.cpp	(working copy)
@@ -186,7 +186,6 @@
 };
 
 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);
 
Index: engines/cine/msg.cpp
===================================================================
--- engines/cine/msg.cpp	(revision 31445)
+++ engines/cine/msg.cpp	(working copy)
@@ -31,47 +31,34 @@
 
 namespace Cine {
 
-uint16 messageCount;
+Common::StringList messageTable;
 
 void loadMsg(char *pMsgName) {
-	uint16 i;
+	int i, count, len;
 	byte *ptr, *dataPtr;
+	const char *messagePtr;
 
 	checkDataDisk(-1);
 
-	messageCount = 0;
+	messageTable.clear();
 
-	for (i = 0; i < NUM_MAX_MESSAGE; i++) {
-		messageTable[i].len = 0;
-		if (messageTable[i].ptr) {
-			free(messageTable[i].ptr);
-			messageTable[i].ptr = NULL;
-		}
-	}
-
 	ptr = dataPtr = readBundleFile(findFileInBundle(pMsgName));
 
 	setMouseCursor(MOUSE_CURSOR_DISK);
 
-	messageCount = READ_BE_UINT16(ptr); ptr += 2;
+	count = READ_BE_UINT16(ptr);
+	ptr += 2;
 
-	assert(messageCount <= NUM_MAX_MESSAGE);
+	messagePtr = (const char*)(ptr + 2 * count);
 
-	for (i = 0; i < messageCount; i++) {
-		messageTable[i].len = READ_BE_UINT16(ptr); ptr += 2;
+	for (i = 0; i < count; i++) {
+		len = READ_BE_UINT16(ptr);
+		ptr += 2;
+		
+		messageTable.push_back(messagePtr);
+		messagePtr += len;
 	}
 
-	for (i = 0; i < messageCount; i++) {
-		if (messageTable[i].len) {
-			messageTable[i].ptr = (byte *) malloc(messageTable[i].len);
-
-			assert(messageTable[i].ptr);
-
-			memcpy(messageTable[i].ptr, ptr, messageTable[i].len);
-			ptr += messageTable[i].len;
-		}
-	}
-
 	free(dataPtr);
 }
 
Index: engines/cine/various.cpp
===================================================================
--- engines/cine/various.cpp	(revision 31445)
+++ engines/cine/various.cpp	(working copy)
@@ -44,7 +44,7 @@
 int16 commandVar1;
 int16 commandVar2;
 
-Message messageTable[NUM_MAX_MESSAGE];
+//Message messageTable[NUM_MAX_MESSAGE];
 
 uint16 var2;
 uint16 var3;
@@ -130,32 +130,16 @@
 	objectScripts.push_back(tmp);
 }
 
+/*! \brief Add action result message to overlay list
+ * \param cmd Message description
+ * \todo Why are x, y, width and color left uninitialized?
+ */
 void addPlayerCommandMessage(int16 cmd) {
-	overlayHeadElement *currentHeadPtr = overlayHead.next;
-	overlayHeadElement *tempHead = &overlayHead;
-	overlayHeadElement *pNewElement;
+	overlay tmp;
+	tmp.objIdx = cmd;
+	tmp.type = 3;
 
-	while (currentHeadPtr) {
-		tempHead = currentHeadPtr;
-		currentHeadPtr = tempHead->next;
-	}
-
-	pNewElement = new overlayHeadElement;
-
-	assert(pNewElement);
-
-	pNewElement->next = tempHead->next;
-	tempHead->next = pNewElement;
-
-	pNewElement->objIdx = cmd;
-	pNewElement->type = 3;
-
-	if (!currentHeadPtr) {
-		currentHeadPtr = &overlayHead;
-	}
-
-	pNewElement->previous = currentHeadPtr->previous;
-	currentHeadPtr->previous = pNewElement;
+	overlayList.push_back(tmp);
 }
 
 int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSelectedObject) {
@@ -180,55 +164,64 @@
 	return found;
 }
 
+/*! \brief Find index of the object under cursor
+ * \param x Mouse cursor coordinate
+ * \param y Mouse cursor coordinate
+ * \todo Fix displaced type 1 objects
+ */
 int16 getObjectUnderCursor(uint16 x, uint16 y) {
-	overlayHeadElement *currentHead = overlayHead.previous;
+	Common::List<overlay>::iterator it;
 
 	int16 objX, objY, frame, part, threshold, height, xdif, ydif;
 	int width;
 
-	while (currentHead) {
-		if (currentHead->type < 2) {
-			if (objectTable[currentHead->objIdx].name[0]) {
-				objX = objectTable[currentHead->objIdx].x;
-				objY = objectTable[currentHead->objIdx].y;
+	// reverse_iterator would be nice
+	for (it = overlayList.reverse_begin(); it != overlayList.end(); --it) {
+		if (it->type >= 2 || !objectTable[it->objIdx].name[0]) {
+			continue;
+		}
 
-				frame = ABS((int16)(objectTable[currentHead->objIdx].frame));
+		objX = objectTable[it->objIdx].x;
+		objY = objectTable[it->objIdx].y;
 
-				part = objectTable[currentHead->objIdx].part;
+		frame = ABS((int16)(objectTable[it->objIdx].frame));
+		part = objectTable[it->objIdx].part;
 
-				if (currentHead->type == 0) {
-					threshold = animDataTable[frame]._var1;
-				} else {
-					threshold = animDataTable[frame]._width / 2;
-				}
+		if (it->type == 0) {
+			threshold = animDataTable[frame]._var1;
+		} else {
+			threshold = animDataTable[frame]._width / 2;
+		}
 
-				height = animDataTable[frame]._height;
-				width = animDataTable[frame]._realWidth;
+		height = animDataTable[frame]._height;
+		width = animDataTable[frame]._realWidth;
 
-				xdif = x - objX;
-				ydif = y - objY;
+		xdif = x - objX;
+		ydif = y - objY;
 
-				if ((xdif >= 0) && ((threshold << 4) > xdif) && (ydif > 0) && (ydif < height)) {
-					if (animDataTable[frame].data()) {
-						if (g_cine->getGameType() == Cine::GType_OS) {
-							if(xdif < width && (currentHead->type == 1 || animDataTable[frame].getColor(xdif, ydif) != objectTable[currentHead->objIdx].part)) {
-								return currentHead->objIdx;
-							}
-						} else if (currentHead->type == 0)	{ // use generated mask
-							if (gfxGetBit(x - objX, y - objY, animDataTable[frame].mask(), animDataTable[frame]._width)) {
-								return currentHead->objIdx;
-							}
-						} else if (currentHead->type == 1) { // is mask
-							if (gfxGetBit(x - objX, y - objY, animDataTable[frame].data(), animDataTable[frame]._width * 4)) {
-								return currentHead->objIdx;
-							}
-						}
-					}
-				}
-			}
+		if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif < 0) || (ydif >= height) || !animDataTable[frame].data()) {
+			continue;
 		}
 
-		currentHead = currentHead->previous;
+		if (g_cine->getGameType() == Cine::GType_OS) {
+			if (xdif >= width) {
+				continue;
+			}
+
+			if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != part) {
+				return it->objIdx;
+			} else if (it->type == 1 && gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) {
+				return it->objIdx;
+			}
+		} else if (it->type == 0)	{ // use generated mask
+			if (gfxGetBit(xdif, ydif, animDataTable[frame].mask(), animDataTable[frame]._width)) {
+				return it->objIdx;
+			}
+		} else if (it->type == 1) { // is mask
+			if (gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) {
+				return it->objIdx;
+			}
+		}
 	}
 
 	return -1;
@@ -285,38 +278,23 @@
 	}
 }
 
-void loadOverlayFromSave(Common::InSaveFile *fHandle) {
-	overlayHeadElement *newElement;
-	overlayHeadElement *currentHead = &overlayHead;
-	overlayHeadElement *tempHead = currentHead;
+/*! \brief Restore overlay sprites from savefile
+ * \param fHandle Savefile open for reading
+ */
+void loadOverlayFromSave(Common::InSaveFile &fHandle) {
+	overlay tmp;
 
-	currentHead = tempHead->next;
+	fHandle.readUint32BE();
+	fHandle.readUint32BE();
 
-	while (currentHead) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
+	tmp.objIdx = fHandle.readUint16BE();
+	tmp.type = fHandle.readUint16BE();
+	tmp.x = fHandle.readSint16BE();
+	tmp.y = fHandle.readSint16BE();
+	tmp.width = fHandle.readSint16BE();
+	tmp.color = fHandle.readSint16BE();
 
-	newElement = new overlayHeadElement;
-
-	fHandle->readUint32BE();
-	fHandle->readUint32BE();
-
-	newElement->objIdx = fHandle->readUint16BE();
-	newElement->type = fHandle->readUint16BE();
-	newElement->x = fHandle->readSint16BE();
-	newElement->y = fHandle->readSint16BE();
-	newElement->width = fHandle->readSint16BE();
-	newElement->color = fHandle->readSint16BE();
-
-	newElement->next = tempHead->next;
-	tempHead->next = newElement;
-
-	if (!currentHead)
-		currentHead = &overlayHead;
-
-	newElement->previous = currentHead->previous;
-	currentHead->previous = newElement;
+	overlayList.push_back(tmp);
 }
 
 /*! \brief Savefile format tester
@@ -433,7 +411,7 @@
 
 	g_sound->stopMusic();
 	freeAnimDataTable();
-	unloadAllMasks();
+	overlayList.clear();
 	// if (g_cine->getGameType() == Cine::GType_OS) {
 	//	freeUnkList();
 	// }
@@ -444,16 +422,8 @@
 	globalScripts.clear();
 	relTable.clear();
 	scriptTable.clear();
+	messageTable.clear();
 
-	for (i = 0; i < NUM_MAX_MESSAGE; i++) {
-		messageTable[i].len = 0;
-
-		if (messageTable[i].ptr) {
-			free(messageTable[i].ptr);
-			messageTable[i].ptr = NULL;
-		}
-	}
-
 	for (i = 0; i < NUM_MAX_OBJECT; i++) {
 		objectTable[i].part = 0;
 		objectTable[i].name[0] = 0;
@@ -599,7 +569,7 @@
 
 	size = fHandle->readSint16BE();
 	for (i = 0; i < size; i++) {
-		loadOverlayFromSave(fHandle);
+		loadOverlayFromSave(*fHandle);
 	}
 
 	loadBgIncrustFromSave(*fHandle);
@@ -722,30 +692,19 @@
 	}
 
 	{
-		int16 numScript = 0;
-		overlayHeadElement *currentHead = overlayHead.next;
+		Common::List<overlay>::iterator it;
 
-		while (currentHead) {
-			numScript++;
-			currentHead = currentHead->next;
-		}
+		fHandle->writeUint16BE(overlayList.size());
 
-		fHandle->writeUint16BE(numScript);
-
-		// actual save
-		currentHead = overlayHead.next;
-
-		while (currentHead) {
+		for (it = overlayList.begin(); it != overlayList.end(); ++it) {
 			fHandle->writeUint32BE(0);
 			fHandle->writeUint32BE(0);
-			fHandle->writeUint16BE(currentHead->objIdx);
-			fHandle->writeUint16BE(currentHead->type);
-			fHandle->writeSint16BE(currentHead->x);
-			fHandle->writeSint16BE(currentHead->y);
-			fHandle->writeSint16BE(currentHead->width);
-			fHandle->writeSint16BE(currentHead->color);
-
-			currentHead = currentHead->next;
+			fHandle->writeUint16BE(it->objIdx);
+			fHandle->writeUint16BE(it->type);
+			fHandle->writeSint16BE(it->x);
+			fHandle->writeSint16BE(it->y);
+			fHandle->writeSint16BE(it->width);
+			fHandle->writeSint16BE(it->color);
 		}
 	}
 
@@ -762,31 +721,7 @@
 		fHandle->writeUint16BE(it->frame);
 		fHandle->writeUint16BE(it->part);
 	}
-/*
-	int numBgIncrustList = 0;
-	BGIncrustList *bgIncrustPtr = bgIncrustList;
 
-	while (bgIncrustPtr) {
-		numBgIncrustList++;
-		bgIncrustPtr = bgIncrustPtr->next;
-	}
-
-	fHandle->writeUint16BE(numBgIncrustList);
-	bgIncrustPtr = bgIncrustList;
-	while (bgIncrustPtr) {
-		fHandle->writeUint32BE(0); // next
-		fHandle->writeUint32BE(0); // unkPtr
-		fHandle->writeUint16BE(bgIncrustPtr->objIdx);
-		fHandle->writeUint16BE(bgIncrustPtr->param);
-		fHandle->writeUint16BE(bgIncrustPtr->x);
-		fHandle->writeUint16BE(bgIncrustPtr->y);
-		fHandle->writeUint16BE(bgIncrustPtr->frame);
-		fHandle->writeUint16BE(bgIncrustPtr->part);
-
-		bgIncrustPtr = bgIncrustPtr->next;
-	}
-*/
-
 	delete fHandle;
 
 	setMouseCursor(MOUSE_CURSOR_NORMAL);
@@ -1682,52 +1617,40 @@
 	return var_5E;
 }
 
-void drawSprite(overlayHeadElement *currentOverlay, const byte *spritePtr,
-				const byte *maskPtr, uint16 width, uint16 height, byte *page, int16 x, int16 y) {
-	byte *ptr = NULL;
+void drawSprite(Common::List<overlay>::iterator it, const byte *spritePtr, const byte *maskPtr, uint16 width, uint16 height, byte *page, int16 x, int16 y) {
 	byte *msk = NULL;
-	byte i = 0;
-	uint16 si = 0;
-	overlayHeadElement *pCurrentOverlay = currentOverlay;
 	int16 maskX, maskY, maskWidth, maskHeight;
 	uint16 maskSpriteIdx;
 
+	msk = (byte *)malloc(width * height);
+
 	if (g_cine->getGameType() == Cine::GType_OS) {
-		drawSpriteRaw2(spritePtr, objectTable[currentOverlay->objIdx].part, width, height, page, x, y);
-		return;
+		generateMask(spritePtr, msk, width * height, objectTable[it->objIdx].part);
+	} else {
+		memcpy(msk, maskPtr, width * height);
 	}
 
-	while (pCurrentOverlay) {
-		if (pCurrentOverlay->type == 5) {
-			if (!si) {
-				ptr = (byte *)malloc(width * 8 * height);
-				msk = (byte *)malloc(width * 8 * height);
-				si = 1;
-			}
+	for (++it; it != overlayList.end(); ++it) {
+		if (it->type != 5) {
+			continue;
+		}
 
-			maskX = objectTable[pCurrentOverlay->objIdx].x;
-			maskY = objectTable[pCurrentOverlay->objIdx].y;
+		maskX = objectTable[it->objIdx].x;
+		maskY = objectTable[it->objIdx].y;
 
-			maskSpriteIdx = objectTable[pCurrentOverlay->objIdx].frame;
+		maskSpriteIdx = ABS((int16)(objectTable[it->objIdx].frame));
 
-			maskWidth = animDataTable[maskSpriteIdx]._width / 2;
-			maskHeight = animDataTable[maskSpriteIdx]._height;
-			gfxUpdateSpriteMask(spritePtr, maskPtr, width, height, animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, ptr, msk, x, y, maskX, maskY, i++);
+		maskWidth = animDataTable[maskSpriteIdx]._realWidth;
+		maskHeight = animDataTable[maskSpriteIdx]._height;
+		gfxUpdateSpriteMask(msk, x, y, width, height, animDataTable[maskSpriteIdx].data(), maskX, maskY, maskWidth, maskHeight);
+
 #ifdef DEBUG_SPRITE_MASK
-			gfxFillSprite(animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, page, maskX, maskY, 1);
+		gfxFillSprite(animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, page, maskX, maskY, 1);
 #endif
-		}
-
-		pCurrentOverlay = pCurrentOverlay->next;
 	}
 
-	if (si) {
-		gfxDrawMaskedSprite(ptr, msk, width, height, page, x, y);
-		free(ptr);
-		free(msk);
-	} else {
-		gfxDrawMaskedSprite(spritePtr, maskPtr, width, height, page, x, y);
-	}
+	gfxDrawMaskedSprite(spritePtr, msk, width, height, page, x, y);
+	free(msk);
 }
 
 int16 additionalBgVScroll = 0;
@@ -1824,18 +1747,15 @@
 }
 
 void drawDialogueMessage(byte msgIdx, int16 x, int16 y, int16 width, int16 color) {
-	const char *messagePtr = (const char *)messageTable[msgIdx].ptr;
-
-	if (!messagePtr) {
-		freeOverlay(msgIdx, 2);
+	if (msgIdx >= messageTable.size()) {
+		removeOverlay(msgIdx, 2);
 		return;
 	}
 
-	_messageLen += strlen(messagePtr);
+	_messageLen += messageTable[msgIdx].size();
+	drawMessage(messageTable[msgIdx].c_str(), x, y, width, color);
 
-	drawMessage(messagePtr, x, y, width, color);
-
-	freeOverlay(msgIdx, 2);
+	removeOverlay(msgIdx, 2);
 }
 
 void drawFailureMessage(byte cmd) {
@@ -1857,161 +1777,129 @@
 
 	drawMessage(messagePtr, x, y, width, color);
 
-	freeOverlay(cmd, 3);
+	removeOverlay(cmd, 3);
 }
 
-/*! \todo Fix Operation Stealth logo in intro (the green text after the plane
- * takes off). Each letter should slowly grow top-down, it has something to
- * do with object 10 (some mask or something)
- */
 void drawOverlays(void) {
-	uint16 partVar1, partVar2;
+	uint16 width, height;
 	AnimData *pPart;
-	overlayHeadElement *currentOverlay, *nextOverlay;
 	int16 x, y;
 	objectStruct *objPtr;
 	byte messageIdx;
-	int16 part;
+	Common::List<overlay>::iterator it;
 
 	backupOverlayPage();
 
 	_messageLen = 0;
 
-	currentOverlay = (&overlayHead)->next;
+	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+		switch (it->type) {
+		case 0: // sprite
+			assert(it->objIdx < NUM_MAX_OBJECT);
 
-	while (currentOverlay) {
-		nextOverlay = currentOverlay->next;
+			objPtr = &objectTable[it->objIdx];
+			x = objPtr->x;
+			y = objPtr->y;
 
-		switch (currentOverlay->type) {
-		case 0:	// sprite
-			{
-				assert(currentOverlay->objIdx <= NUM_MAX_OBJECT);
+			if (objPtr->frame < 0) {
+				continue;
+			}
 
-				objPtr = &objectTable[currentOverlay->objIdx];
+			pPart = &animDataTable[objPtr->frame];
+			width = pPart->_realWidth;
+			height = pPart->_height;
 
-				x = objPtr->x;
-				y = objPtr->y;
+			if (!pPart->data()) {
+				continue;
+			}
 
-				if (objPtr->frame >= 0) {
-					if (g_cine->getGameType() == Cine::GType_OS) {
-						pPart = &animDataTable[objPtr->frame];
+			// drawSprite ignores masks of Operation Stealth sprites
+			drawSprite(it, pPart->data(), pPart->mask(), width, height, page1Raw, x, y);
+			break;
 
-						partVar1 = pPart->_var1;
-						partVar2 = pPart->_height;
+		case 2:	// text
+			// gfxWaitVSync();
+			// hideMouse();
 
-						if (pPart->data()) {
-							// NOTE: is the mask supposed to be in data()? Shouldn't that be mask(), like below?
-							// OS sprites don't use masks, see drawSprite() -- next_ghost
-							drawSprite(currentOverlay, pPart->data(), pPart->data(), partVar1, partVar2, page1Raw, x, y);
-						}
-					} else {
-						part = objPtr->part;
+			messageIdx = it->objIdx;
+			x = it->x;
+			y = it->y;
+			width = it->width;
+			height = it->color;
 
-						assert(part >= 0 && part <= NUM_MAX_ANIMDATA);
+			blitRawScreen(page1Raw);
 
-						pPart = &animDataTable[objPtr->frame];
+			drawDialogueMessage(messageIdx, x, y, width, height);
 
-						partVar1 = pPart->_var1;
-						partVar2 = pPart->_height;
+			// blitScreen(page0, NULL);
+			// gfxRedrawMouseCursor();
 
-						if (pPart->data()) {
-							drawSprite(currentOverlay, pPart->data(), pPart->mask(), partVar1, partVar2, page1Raw, x, y);
-						}
-					}
-				}
-				break;
-			}
-		case 2:	// text
-			{
-				// gfxWaitVSync();
-				// hideMouse();
+			waitForPlayerClick = 1;
 
-				messageIdx = currentOverlay->objIdx;
-				x = currentOverlay->x;
-				y = currentOverlay->y;
-				partVar1 = currentOverlay->width;
-				partVar2 = currentOverlay->color;
+			break;
 
-				blitRawScreen(page1Raw);
+		case 3:
+			// gfxWaitSync()
+			// hideMouse();
 
-				drawDialogueMessage(messageIdx, x, y, partVar1, partVar2);
+			blitRawScreen(page1Raw);
 
-				// blitScreen(page0, NULL);
-				// gfxRedrawMouseCursor();
+			drawFailureMessage(it->objIdx);
 
-				waitForPlayerClick = 1;
+			// blitScreen(page0, NULL);
+			// gfxRedrawMouseCursor();
 
-				break;
-			}
-		case 3:
-			{
-				// gfxWaitSync()
-				// hideMouse();
+			waitForPlayerClick = 1;
 
-				blitRawScreen(page1Raw);
+			break;
 
-				drawFailureMessage(currentOverlay->objIdx);
+		case 4:
+			assert(it->objIdx < NUM_MAX_OBJECT);
 
-				// blitScreen(page0, NULL);
-				// gfxRedrawMouseCursor();
+			objPtr = &objectTable[it->objIdx];
+			x = objPtr->x;
+			y = objPtr->y;
 
-				waitForPlayerClick = 1;
-
-				break;
+			if (objPtr->frame < 0) {
+				continue;
 			}
-		case 4:
-			{
-				assert(currentOverlay->objIdx <= NUM_MAX_OBJECT);
 
-				objPtr = &objectTable[currentOverlay->objIdx];
+			assert(objPtr->frame < NUM_MAX_ANIMDATA);
 
-				x = objPtr->x;
-				y = objPtr->y;
+			pPart = &animDataTable[objPtr->frame];
 
+			width = pPart->_realWidth;
+			height = pPart->_height;
 
-				if (objPtr->frame >= 0) {
-					part = objPtr->part;
+			if (!pPart->data()) {
+				continue;
+			}
 
-					assert(part >= 0 && part <= NUM_MAX_ANIMDATA);
+			gfxFillSprite(pPart->data(), width, height, page1Raw, x, y);
+			break;
 
-					pPart = &animDataTable[objPtr->frame];
+		case 20:
+			assert(it->objIdx < NUM_MAX_OBJECT);
 
-					partVar1 = pPart->_width / 2;
-					partVar2 = pPart->_height;
+			objPtr = &objectTable[it->objIdx];
+			x = objPtr->x;
+			y = objPtr->y;
+			var5 = it->x;
 
-					if (pPart->data()) {
-						gfxFillSprite(pPart->data(), partVar1, partVar2, page1Raw, x, y);
-					}
-				}
-				break;
+			if (objPtr->frame < 0 || var5 > 8 || !additionalBgTable[var5] || animDataTable[objPtr->frame]._bpp != 1) {
+				continue;
 			}
-		case 20:
-			{
-				assert(currentOverlay->objIdx <= NUM_MAX_OBJECT);
 
-				objPtr = &objectTable[currentOverlay->objIdx];
+			width = animDataTable[objPtr->frame]._realWidth;
+			height = animDataTable[objPtr->frame]._height;
 
-				x = objPtr->x;
-				y = objPtr->y;
-
-				var5 = currentOverlay->x;
-
-				if (objPtr->frame >= 0 && var5 <= 8 && additionalBgTable[var5] && animDataTable[objPtr->frame]._bpp == 1) {
-					int16 x2;
-					int16 y2;
-
-					x2 = animDataTable[objPtr->frame]._width / 2;
-					y2 = animDataTable[objPtr->frame]._height;
-
-					if (animDataTable[objPtr->frame].data()) {
-						maskBgOverlay(additionalBgTable[var5], animDataTable[objPtr->frame].data(), x2, y2, page1Raw, x, y);
-					}
-				}
-				break;
+			if (!animDataTable[objPtr->frame].data()) {
+				continue;
 			}
-		}
 
-		currentOverlay = nextOverlay;
+			maskBgOverlay(additionalBgTable[var5], animDataTable[objPtr->frame].data(), width, height, page1Raw, x, y);
+			break;
+		}
 	}
 }
 
@@ -2040,8 +1928,7 @@
 	}
 
 	if (newObjectName[0] != 0) {
-		unloadAllMasks();
-		resetMessageHead();
+		overlayList.clear();
 
 		loadObject(newObjectName);
 
@@ -2071,40 +1958,50 @@
 }
 
 void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5) {
-	overlayHeadElement *currentHead = &overlayHead;
-	overlayHeadElement *tempHead = currentHead;
-	overlayHeadElement *newElement;
+	overlay tmp;
 
-	currentHead = tempHead->next;
+	tmp.objIdx = param1;
+	tmp.type = 2;
+	tmp.x = param2;
+	tmp.y = param3;
+	tmp.width = param4;
+	tmp.color = param5;
 
-	while (currentHead) {
+	overlayList.push_back(tmp);
+}
+
+SeqListElement seqList;
+
+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;
 	}
 
-	newElement = new overlayHeadElement;
+	if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) {
+		currentHead->var4 = -1;
+	}
+}
 
-	newElement->next = tempHead->next;
-	tempHead->next = newElement;
+uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) {
+	SeqListElement *currentHead = &seqList;
+	SeqListElement *tempHead = currentHead;
 
-	newElement->objIdx = param1;
-	newElement->type = 2;
+	while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) {
+		tempHead = currentHead;
+		currentHead = tempHead->next;
+	}
 
-	newElement->x = param2;
-	newElement->y = param3;
-	newElement->width = param4;
-	newElement->color = param5;
+	if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) {
+		return 1;
+	}
 
-	if (!currentHead)
-		currentHead = &overlayHead;
-
-	newElement->previous = currentHead->previous;
-
-	currentHead->previous = newElement;
+	return 0;
 }
 
-SeqListElement seqList;
-
 void addSeqListElement(int16 param0, int16 param1, int16 param2, int16 param3, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) {
 	SeqListElement *currentHead = &seqList;
 	SeqListElement *tempHead = currentHead;
Index: engines/cine/gfx.h
===================================================================
--- engines/cine/gfx.h	(revision 31445)
+++ engines/cine/gfx.h	(working copy)
@@ -53,8 +53,7 @@
 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(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 gfxUpdateSpriteMask(byte *destMask, int16 x, int16 y, int16 width, int16 height, const byte *maskPtr, int16 xm, int16 ym, int16 maskWidth, int16 maskHeight);
 
 void gfxDrawLine(int16 x1, int16 y1, int16 x2, int16 y2, byte color, byte *page);
 void gfxDrawPlainBox(int16 x1, int16 y1, int16 x2, int16 y2, byte color);
Index: engines/cine/xref.txt
===================================================================
--- engines/cine/xref.txt	(revision 31445)
+++ engines/cine/xref.txt	(working copy)
@@ -144,3 +144,10 @@
 reincrustAllBg() - removed (obsoleted by new loadResourcesFromSave() and
 	loadBgIncrustFromSave() implementation)
 freeBgIncrustList() - removed (obsoleted by Common::List::clear())
+
+object.cpp
+unloadAllMasks() - removed (obsoleted by Common::List::clear())
+resetMessageHead() - removed (obsoleted by Common::List)
+freeOverlay() - removed (duplicate of removeOverlay)
+removeOverlayElement() - renamed to removeOverlay
+loadOverlayElement() - renamed to addOverlay
Index: engines/cine/script_os.cpp
===================================================================
--- engines/cine/script_os.cpp	(revision 0)
+++ engines/cine/script_os.cpp	(revision 0)
@@ -0,0 +1,793 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/cine/script.cpp $
+ * $Id: script.cpp 31444 2008-04-07 20:24:40Z sev $
+ *
+ */
+
+/*! \file
+ * Operation Stealth script interpreter file
+ */
+
+#include "common/endian.h"
+
+#include "cine/cine.h"
+#include "cine/bg_list.h"
+#include "cine/object.h"
+#include "cine/sound.h"
+#include "cine/various.h"
+#include "cine/script.h"
+
+namespace Cine {
+
+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);
+
+/*! \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) {}
+
+/*! \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) {}
+
+/*! \brief Copy constructor
+ */
+OSScript::OSScript(const OSScript &src) : FWScript(src, new OSScriptInfo) {}
+
+/*! \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 *OSScriptInfo::opcodeInfo(byte opcode) const {
+	if (opcode == 0 || opcode > OSScript::_numOpcodes) {
+		return NULL;
+	}
+
+	if (!OSScript::_opcodeTable[opcode - 1].args) {
+		warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeInfo", opcode - 1);
+		return NULL;
+	}
+
+	return OSScript::_opcodeTable[opcode - 1].args;
+}
+
+/*! \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 (!OSScript::_opcodeTable[opcode - 1].proc) {
+		warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeHandler", opcode - 1);
+		return NULL;
+	}
+
+	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;
+}
+
+// ------------------------------------------------------------------------
+// OPERATION STEALTH opcodes
+// ------------------------------------------------------------------------
+
+int FWScript::o2_loadPart() {
+	const char *param = getNextString();
+
+	debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _line, param);
+	return 0;
+}
+
+int FWScript::o2_playSample() {
+	if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) {
+		// no-op in these versions
+		getNextByte();
+		getNextByte();
+		getNextWord();
+		getNextByte();
+		getNextWord();
+		getNextWord();
+		return 0;
+	}
+	return o1_playSample();
+}
+
+int FWScript::o2_playSampleAlt() {
+	byte num = getNextByte();
+	byte channel = getNextByte();
+	uint16 frequency = getNextWord();
+	getNextByte();
+	getNextWord();
+	uint16 size = getNextWord();
+
+	if (size == 0xFFFF) {
+		size = animDataTable[num]._width * animDataTable[num]._height;
+	}
+	if (animDataTable[num].data()) {
+		if (g_cine->getPlatform() == Common::kPlatformPC) {
+			// if speaker output is available, play sound on it
+			// if it's another device, don't play anything
+			// TODO: implement this, it's used in the introduction for example
+			// on each letter displayed
+		} else {
+			g_sound->playSound(channel, frequency, animDataTable[num].data(), size, 0, 0, 63, 0);
+		}
+	}
+	return 0;
+}
+
+int FWScript::o2_addSeqListElement() {
+	byte param1 = getNextByte();
+	byte param2 = getNextByte();
+	byte param3 = getNextByte();
+	byte param4 = getNextByte();
+	uint16 param5 = getNextWord();
+	uint16 param6 = getNextWord();
+	uint16 param7 = getNextWord();
+
+	debugC(5, kCineDebugScript, "Line: %d: addSeqListElement(%d,%d,%d,%d,%d,%d,%d)", _line, param1, param2, param3, param4, param5, param6, param7);
+	addSeqListElement(param1, 0, param2, param3, param4, param5, param6, 0, param7);
+	return 0;
+}
+
+int FWScript::o2_removeSeq() {
+	byte a = getNextByte();
+	byte b = getNextByte();
+
+	debugC(5, kCineDebugScript, "Line: %d: removeSeq(%d,%d) -> TODO", _line, a, b);
+	removeSeq(a, 0, b);
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_op81() {
+	warning("STUB: o2_op81()");
+	// freeUnkList();
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_op82() {
+	byte a = getNextByte();
+	byte b = getNextByte();
+	uint16 c = getNextWord();
+	warning("STUB: o2_op82(%x, %x, %x)", a, b, c);
+	return 0;
+}
+
+int FWScript::o2_isSeqRunning() {
+	byte a = getNextByte();
+	byte b = getNextByte();
+
+	debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b);
+
+	if (isSeqRunning(a, 0, b)) {
+		_compare = 1;
+	} else {
+		_compare = 0;
+	}
+	return 0;
+}
+
+/*! \todo The assert may produce false positives and requires testing
+ */
+int FWScript::o2_gotoIfSupNearest() {
+	byte labelIdx = getNextByte();
+
+	if (_compare == kCmpGT) {
+		assert(_labels[labelIdx] != -1);
+
+		debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (true)", _line, labelIdx);
+		_pos = _script.getLabel(*_info, labelIdx, _pos);
+	} else {
+		debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (false)", _line, labelIdx);
+	}
+	return 0;
+}
+
+/*! \todo The assert may produce false positives and requires testing
+ */
+int FWScript::o2_gotoIfSupEquNearest() {
+	byte labelIdx = getNextByte();
+
+	if (_compare & (kCmpGT | kCmpEQ)) {
+		assert(_labels[labelIdx] != -1);
+
+		debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (true)", _line, labelIdx);
+		_pos = _script.getLabel(*_info, labelIdx, _pos);
+	} else {
+		debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (false)", _line, labelIdx);
+	}
+	return 0;
+}
+
+/*! \todo The assert may produce false positives and requires testing
+ */
+int FWScript::o2_gotoIfInfNearest() {
+	byte labelIdx = getNextByte();
+
+	if (_compare == kCmpLT) {
+		assert(_labels[labelIdx] != -1);
+
+		debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (true)", _line, labelIdx);
+		_pos = _script.getLabel(*_info, labelIdx, _pos);
+	} else {
+		debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (false)", _line, labelIdx);
+	}
+	return 0;
+}
+
+/*! \todo The assert may produce false positives and requires testing
+ */
+int FWScript::o2_gotoIfInfEquNearest() {
+	byte labelIdx = getNextByte();
+
+	if (_compare & (kCmpLT | kCmpEQ)) {
+		assert(_labels[labelIdx] != -1);
+
+		debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (true)", _line, labelIdx);
+		_pos = _script.getLabel(*_info, labelIdx, _pos);
+	} else {
+		debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (false)", _line, labelIdx);
+	}
+	return 0;
+}
+
+/*! \todo The assert may produce false positives and requires testing
+ */
+int FWScript::o2_gotoIfEquNearest() {
+	byte labelIdx = getNextByte();
+
+	if (_compare == kCmpEQ) {
+		assert(_labels[labelIdx] != -1);
+
+		debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (true)", _line, labelIdx);
+		_pos = _script.getLabel(*_info, labelIdx, _pos);
+	} else {
+		debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (false)", _line, labelIdx);
+	}
+	return 0;
+}
+
+/*! \todo The assert may produce false positives and requires testing
+ */
+int FWScript::o2_gotoIfDiffNearest() {
+	byte labelIdx = getNextByte();
+
+	if (_compare != kCmpEQ) {
+		assert(_labels[labelIdx] != -1);
+
+		debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (true)", _line, labelIdx);
+		_pos = _script.getLabel(*_info, labelIdx, _pos);
+	} else {
+		debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (false)", _line, labelIdx);
+	}
+	return 0;
+}
+
+int FWScript::o2_startObjectScript() {
+	byte param = getNextByte();
+
+	debugC(5, kCineDebugScript, "Line: %d: startObjectScript(%d)", _line, param);
+	runObjectScript(param);
+	return 0;
+}
+
+int FWScript::o2_stopObjectScript() {
+	byte param = getNextByte();
+
+	debugC(5, kCineDebugScript, "Line: %d: stopObjectScript(%d)", _line, param);
+	ScriptList::iterator it = objectScripts.begin();
+
+	for (; it != objectScripts.end(); ++it) {
+		if ((*it)->_index == param) {
+			(*it)->_index = -1;
+		}
+	}
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_op8D() {
+	uint16 a = getNextWord();
+	uint16 b = getNextWord();
+	uint16 c = getNextWord();
+	uint16 d = getNextWord();
+	uint16 e = getNextWord();
+	uint16 f = getNextWord();
+	uint16 g = getNextWord();
+	uint16 h = getNextWord();
+	warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h);
+	// _currentScriptElement->compareResult = ...
+	return 0;
+}
+
+int FWScript::o2_addBackground() {
+	byte param1 = getNextByte();
+	const char *param2 = getNextString();
+
+	debugC(5, kCineDebugScript, "Line: %d: addBackground(%s,%d)", _line, param2, param1);
+	addBackground(param2, param1);
+	return 0;
+}
+
+int FWScript::o2_removeBackground() {
+	byte param = getNextByte();
+
+	assert(param);
+
+	debugC(5, kCineDebugScript, "Line: %d: removeBackground(%d)", _line, param);
+
+	if (additionalBgTable[param]) {
+		free(additionalBgTable[param]);
+		additionalBgTable[param] = NULL;
+	}
+
+	if (currentAdditionalBgIdx == param) {
+		currentAdditionalBgIdx = 0;
+	}
+
+	if (currentAdditionalBgIdx2 == param) {
+		currentAdditionalBgIdx2 = 0;
+	}
+
+	strcpy(currentBgName[param], "");
+	return 0;
+}
+
+int FWScript::o2_loadAbs() {
+	byte param1 = getNextByte();
+	const char *param2 = getNextString();
+
+	debugC(5, kCineDebugScript, "Line: %d: loadABS(%d,%s)", _line, param1, param2);
+	loadAbs(param2, param1);
+	return 0;
+}
+
+int FWScript::o2_loadBg() {
+	byte param = getNextByte();
+
+	assert(param <= 8);
+
+	debugC(5, kCineDebugScript, "Line: %d: useBg(%d)", _line, param);
+
+	if (additionalBgTable[param]) {
+		currentAdditionalBgIdx = param;
+		if (param == 8) {
+			newColorMode = 3;
+		} else {
+			newColorMode = bgColorMode + 1;
+		}
+		//if (_screenNeedFadeOut == 0) {
+		//	adBgVar1 = 1;
+		//}
+		fadeRequired = true;
+	}
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_wasZoneChecked() {
+	warning("STUB: o2_wasZoneChecked()");
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_op9B() {
+	uint16 a = getNextWord();
+	uint16 b = getNextWord();
+	uint16 c = getNextWord();
+	uint16 d = getNextWord();
+	uint16 e = getNextWord();
+	uint16 f = getNextWord();
+	uint16 g = getNextWord();
+	uint16 h = getNextWord();
+	warning("STUB: o2_op9B(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h);
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_op9C() {
+	uint16 a = getNextWord();
+	uint16 b = getNextWord();
+	uint16 c = getNextWord();
+	uint16 d = getNextWord();
+	warning("STUB: o2_op9C(%x, %x, %x, %x)", a, b, c, d);
+	return 0;
+}
+
+int FWScript::o2_useBgScroll() {
+	byte param = getNextByte();
+
+	assert(param <= 8);
+
+	debugC(5, kCineDebugScript, "Line: %d: useBgScroll(%d)", _line, param);
+
+	if (additionalBgTable[param]) {
+		currentAdditionalBgIdx2 = param;
+	}
+	return 0;
+}
+
+int FWScript::o2_setAdditionalBgVScroll() {
+	byte param1 = getNextByte();
+
+	if (param1) {
+		byte param2 = getNextByte();
+
+		debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = var[%d]", _line, param2);
+		additionalBgVScroll = _localVars[param2];
+	} else {
+		uint16 param2 = getNextWord();
+
+		debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = %d", _line, param2);
+		additionalBgVScroll = param2;
+	}
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_op9F() {
+	warning("o2_op9F()");
+	getNextWord();
+	getNextWord();
+	return 0;
+}
+
+int FWScript::o2_addGfxElementA0() {
+	uint16 param1 = getNextWord();
+	uint16 param2 = getNextWord();
+
+	debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2);
+	addGfxElementA0(param1, param2);
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_removeGfxElementA0() {
+	uint16 idx = getNextWord();
+	uint16 param = getNextWord();
+	warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param);
+	removeGfxElementA0(idx, param);
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_opA2() {
+	uint16 a = getNextWord();
+	uint16 b = getNextWord();
+	warning("STUB: o2_opA2(%x, %x)", a, b);
+	// addGfxElementA2();
+	return 0;
+}
+
+/*! \todo Implement this instruction
+ */
+int FWScript::o2_opA3() {
+	uint16 a = getNextWord();
+	uint16 b = getNextWord();
+	warning("STUB: o2_opA3(%x, %x)", a, b);
+	// removeGfxElementA2();
+	return 0;
+}
+
+int FWScript::o2_loadMask22() {
+	byte param = getNextByte();
+
+	debugC(5, kCineDebugScript, "Line: %d: addOverlay22(%d)", _line, param);
+	addOverlay(param, 22);
+	return 0;
+}
+
+int FWScript::o2_unloadMask22() {
+	byte param = getNextByte();
+
+	debugC(5, kCineDebugScript, "Line: %d: removeOverlay22(%d)", _line, param);
+	removeOverlay(param, 22);
+	return 0;
+}
+
+} // End of namespace Cine
Index: engines/cine/object.cpp
===================================================================
--- engines/cine/object.cpp	(revision 31445)
+++ engines/cine/object.cpp	(working copy)
@@ -36,28 +36,8 @@
 namespace Cine {
 
 objectStruct objectTable[NUM_MAX_OBJECT];
-ScriptVars globalVars(NUM_MAX_VAR);
-overlayHeadElement overlayHead;
+Common::List<overlay> overlayList;
 
-void unloadAllMasks(void) {
-	overlayHeadElement *current = overlayHead.next;
-
-	while (current) {
-		overlayHeadElement *next = current->next;
-
-		delete current;
-
-		current = next;
-	}
-
-	resetMessageHead();
-}
-
-void resetMessageHead(void) {
-	overlayHead.next = NULL;
-	overlayHead.previous = NULL;
-}
-
 void loadObject(char *pObjectName) {
 	uint16 numEntry;
 	uint16 entrySize;
@@ -100,92 +80,88 @@
 	free(dataPtr);
 }
 
-int8 removeOverlayElement(uint16 objIdx, uint16 param) {
-	overlayHeadElement *currentHeadPtr = &overlayHead;
-	overlayHeadElement *tempHead = currentHeadPtr;
-	overlayHeadElement *tempPtr2;
+/*! \brief Remove overlay sprite from the list
+ * \param objIdx Remove overlay associated with this object
+ * \param param Remove overlay of this type
+ */
+int removeOverlay(uint16 objIdx, uint16 param) {
+	Common::List<overlay>::iterator it;
 
-	currentHeadPtr = tempHead->next;
-
-	while (currentHeadPtr && (currentHeadPtr->objIdx != objIdx || currentHeadPtr->type != param)) {
-		tempHead = currentHeadPtr;
-		currentHeadPtr = tempHead->next;
+	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+		if (it->objIdx == objIdx && it->type == param) {
+			overlayList.erase(it);
+			return 1;
+		}
 	}
 
-	if (!currentHeadPtr || currentHeadPtr->objIdx != objIdx || currentHeadPtr->type != param) {
-		return -1;
-	}
+	return 0;
+}
 
-	tempHead->next = tempPtr2 = currentHeadPtr->next;
+/*! \brief Add new overlay sprite to the list
+ * \param objIdx Associate the overlay with this object
+ * \param param Type of new overlay
+ * \todo Why are x, y, width and color left uninitialized?
+ */
+void addOverlay(uint16 objIdx, uint16 param) {
+	Common::List<overlay>::iterator it;
+	overlay tmp;
 
-	if (!tempPtr2) {
-		tempPtr2 = &overlayHead;
+	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+		if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask) {
+			break;
+		}
 	}
 
-	tempPtr2->previous = currentHeadPtr->previous;
+	tmp.objIdx = objIdx;
+	tmp.type = param;
 
-	delete currentHeadPtr;
-
-	return 0;
+	overlayList.insert(it, tmp);
 }
 
-int16 freeOverlay(uint16 objIdx, uint16 param) {
-	overlayHeadElement *currentHeadPtr = overlayHead.next;
-	overlayHeadElement *previousPtr = &overlayHead;
-	overlayHeadElement *tempPtr2;
+/*! \brief Add new background mask overlay
+ * \param objIdx Associate the overlay with this object
+ * \param param source background index
+ */
+void addGfxElementA0(int16 objIdx, int16 param) {
+	Common::List<overlay>::iterator it;
+	overlay tmp;
 
-	while (currentHeadPtr && ((currentHeadPtr->objIdx != objIdx) || (currentHeadPtr->type != param))) {
-		previousPtr = currentHeadPtr;
-		currentHeadPtr = previousPtr->next;
+	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+		// wtf?!
+		if (objectTable[it->objIdx].mask == objectTable[objIdx].mask &&
+			(it->type == 2 || it->type == 3)) {
+			break;
+		}
 	}
 
-	if (!currentHeadPtr || !((currentHeadPtr->objIdx == objIdx) && (currentHeadPtr->type == param))) {
-		return -1;
+	if (it != overlayList.end() && it->objIdx == objIdx && it->type == 20 && it->x == param) {
+		return;
 	}
 
-	previousPtr->next = tempPtr2 = currentHeadPtr->next;
+	tmp.objIdx = objIdx;
+	tmp.type = 20;
+	tmp.x = param;
+	tmp.y = 0;
+	tmp.width = 0;
+	tmp.color = 0;
 
-	if (!tempPtr2) {
-		tempPtr2 = &overlayHead;
-	}
-
-	tempPtr2->previous = currentHeadPtr->previous;
-
-	delete currentHeadPtr;
-	return 0;
+	overlayList.insert(it, tmp);
 }
 
-void loadOverlayElement(uint16 objIdx, uint16 param) {
-	overlayHeadElement *currentHeadPtr = &overlayHead;
-	overlayHeadElement *pNewElement;
+/*! \brief Remove background mask overlay
+ * \param objIdx Remove overlay associated with this object
+ * \param param Remove overlay using this background
+ * \todo Check that it works
+ */
+void removeGfxElementA0(int16 objIdx, int16 param) {
+	Common::List<overlay>::iterator it;
 
-	uint16 si = objectTable[objIdx].mask;
-
-	overlayHeadElement *tempHead = currentHeadPtr;
-
-	currentHeadPtr = tempHead->next;
-
-	while (currentHeadPtr && (objectTable[currentHeadPtr->objIdx].mask < si)) {
-		tempHead = currentHeadPtr;
-		currentHeadPtr = tempHead->next;
+	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+		if (it->objIdx == objIdx && it->type == 20 && it->x == param) {
+			overlayList.erase(it);
+			return;
+		}
 	}
-
-	pNewElement = new overlayHeadElement;
-
-	assert(pNewElement);
-
-	pNewElement->next = tempHead->next;
-	tempHead->next = pNewElement;
-
-	pNewElement->objIdx = objIdx;
-	pNewElement->type = param;
-
-	if (!currentHeadPtr) {
-		currentHeadPtr = &overlayHead;
-	}
-
-	pNewElement->previous = currentHeadPtr->previous;
-	currentHeadPtr->previous = pNewElement;
 }
 
 void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4) {
@@ -194,8 +170,8 @@
 	objectTable[objIdx].mask = param3;
 	objectTable[objIdx].frame = param4;
 
-	if (!removeOverlayElement(objIdx, 0)) {
-		loadOverlayElement(objIdx, 0);
+	if (removeOverlay(objIdx, 0)) {
+		addOverlay(objIdx, 0);
 	}
 }
 
@@ -223,8 +199,8 @@
 	case 2:
 		objectTable[objIdx].mask = newValue;
 
-		if (!removeOverlayElement(objIdx, 0)) {
-			loadOverlayElement(objIdx, 0);
+		if (removeOverlay(objIdx, 0)) {
+			addOverlay(objIdx, 0);
 		}
 		break;
 	case 3:
Index: engines/cine/main_loop.cpp
===================================================================
--- engines/cine/main_loop.cpp	(revision 31445)
+++ engines/cine/main_loop.cpp	(working copy)
@@ -189,7 +189,6 @@
 	quitFlag = 0;
 
 	if (_preLoad == false) {
-		resetMessageHead();
 		resetSeqList();
 		resetBgIncrustList();
 
@@ -315,7 +314,6 @@
 
 	hideMouse();
 	g_sound->stopMusic();
-	unloadAllMasks();
 	// if (g_cine->getGameType() == Cine::GType_OS) {
 	//	freeUnkList();
 	// }
Index: engines/cine/cine.cpp
===================================================================
--- engines/cine/cine.cpp	(revision 31445)
+++ engines/cine/cine.cpp	(working copy)
@@ -129,14 +129,12 @@
 	globalScripts.clear();
 	bgIncrustList.clear();
 	freeAnimDataTable();
+	overlayList.clear();
+	messageTable.clear();
 
 	memset(objectTable, 0, sizeof(objectTable));
-	memset(messageTable, 0, sizeof(messageTable));
 
-	overlayHead.next = overlayHead.previous = NULL;
-
 	var8 = 0;
-//	bgIncrustList = NULL;
 
 	var2 = var3 = var4 = var5 = 0;
 
Index: engines/cine/gfx.cpp
===================================================================
--- engines/cine/gfx.cpp	(revision 31445)
+++ engines/cine/gfx.cpp	(working copy)
@@ -25,6 +25,7 @@
 
 #include "cine/cine.h"
 #include "cine/bg.h"
+#include "cine/bg_list.h"
 #include "cine/various.h"
 
 #include "common/endian.h"
@@ -168,7 +169,7 @@
 		byte *destPtr = page + x + y * 320;
 		destPtr += i * 320;
 
-		for (j = 0; j < width * 8; j++) {
+		for (j = 0; j < width; j++) {
 			if (x + j >= 0 && x + j < 320 && i + y >= 0
 			    && i + y < 200) {
 				if (!*(spritePtr++)) {
@@ -191,7 +192,7 @@
 		byte *destPtr = page + x + y * 320;
 		destPtr += i * 320;
 
-		for (j = 0; j < width * 8; j++) {
+		for (j = 0; j < width; j++) {
 			if (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200 && *maskPtr == 0) {
 				*destPtr = *spritePtr;
 			}
@@ -202,62 +203,83 @@
 	}
 }
 
-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 gfxUpdateSpriteMask(byte *destMask, int16 x, int16 y, int16 width, int16 height, const byte *srcMask, int16 xm, int16 ym, int16 maskWidth, int16 maskHeight) {
 	int16 i, j, d, spritePitch, maskPitch;
 
-	width *= 8;
-	maskWidth *= 8;
-
 	spritePitch = width;
 	maskPitch = maskWidth;
 
-	if (maskIdx == 0) {
-		memcpy(bufferSprPtr, spritePtr, spritePitch * height);
-		memcpy(bufferMskPtr, spriteMskPtr, spritePitch * height);
+	// crop update area to overlapping parts of masks
+	if (y > ym) {
+		d = y - ym;
+		srcMask += d * maskPitch;
+		maskHeight -= d;
+	} else if (y < ym) {
+		d = ym - y;
+		destMask += d * spritePitch;
+		height -= d;
 	}
 
-	if (ys > ym) {
-		d = ys - ym;
-		maskPtr += d * maskPitch;
-		maskHeight -= d;
-	}
-	if (maskHeight <= 0) {
-		return;
-	}
-	if (xs > xm) {
-		d = xs - xm;
-		maskPtr += d;
+	if (x > xm) {
+		d = x - xm;
+		srcMask += d;
 		maskWidth -= d;
+	} else if (x < xm) {
+		d = xm - x;
+		destMask += d;
+		width -= d;
 	}
-	if (maskWidth <= 0) {
-		return;
+
+	// update mask
+	for (j = 0; j < MIN(maskHeight, height); ++j) {
+		for (i = 0; i < MIN(maskWidth, width); ++i) {
+			destMask[i] |= srcMask[i] ^ 1;
+		}
+		destMask += spritePitch;
+		srcMask += maskPitch;
 	}
-	if (ys < ym) {
-		d = ym - ys;
-		spriteMskPtr += d * spritePitch;
-		bufferMskPtr += d * spritePitch;
+}
+
+void gfxUpdateIncrustMask(byte *destMask, int16 x, int16 y, int16 width, int16 height, const byte *srcMask, int16 xm, int16 ym, int16 maskWidth, int16 maskHeight) {
+	int16 i, j, d, spritePitch, maskPitch;
+
+	spritePitch = width;
+	maskPitch = maskWidth;
+
+	// crop update area to overlapping parts of masks
+	if (y > ym) {
+		d = y - ym;
+		srcMask += d * maskPitch;
+		maskHeight -= d;
+	} else if (y < ym) {
+		d = ym - y > height ? height : ym - y;
+		memset(destMask, 1, d * spritePitch);
+		destMask += d * spritePitch;
 		height -= d;
 	}
-	if (height <= 0) {
-		return;
+
+	if (x > xm) {
+		d = x - xm;
+		xm = x;
+		srcMask += d;
+		maskWidth -= d;
 	}
-	if (xs < xm) {
-		d = xm - xs;
-		spriteMskPtr += d;
-		bufferMskPtr += d;
-		width -= d;
-	}
-	if (width <= 0) {
-		return;
-	}
+
+	d = xm - x;
+	maskWidth += d;
+
+	// update mask
 	for (j = 0; j < MIN(maskHeight, height); ++j) {
-		for (i = 0; i < MIN(maskWidth, width); ++i) {
-			bufferMskPtr[i] |= maskPtr[i] ^ 1;
+		for (i = 0; i < width; ++i) {
+			destMask[i] |= i < d || i >= maskWidth ? 1 : srcMask[i - d];
 		}
-		bufferMskPtr += spritePitch;
-		maskPtr += maskPitch;
+		destMask += spritePitch;
+		srcMask += maskPitch;
 	}
+
+	if (j < height) {
+		memset(destMask, 1, (height - j) * spritePitch);
+	}
 }
 
 void gfxDrawLine(int16 x1, int16 y1, int16 x2, int16 y2, byte color, byte *page) {
@@ -431,15 +453,19 @@
 
 void maskBgOverlay(const byte *bgPtr, const byte *maskPtr, int16 width, int16 height,
 				   byte *page, int16 x, int16 y) {
-	int16 i, j;
+	int16 i, j, tmpWidth, tmpHeight;
+	Common::List<BGIncrust>::iterator it;
+	byte *mask;
+	const byte *backup = maskPtr;
 
+	// background pass
 	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++) {
+		for (j = 0; j < width; j++) {
 			if ((!maskPtr || !(*maskPtr)) && (x + j >= 0
 					&& x + j < 320 && i + y >= 0 && i + y < 200)) {
 				*destPtr = *srcPtr;
@@ -450,6 +476,27 @@
 			maskPtr++;
 		}
 	}
+
+	maskPtr = backup;
+
+	// incrust pass
+	for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) {
+		tmpWidth = animDataTable[it->frame]._realWidth;
+		tmpHeight = animDataTable[it->frame]._height;
+		mask = (byte*)malloc(tmpWidth * tmpHeight);
+
+		if (it->param == 0) {
+			generateMask(animDataTable[it->frame].data(), mask, tmpWidth * tmpHeight, it->part);
+			gfxUpdateIncrustMask(mask, it->x, it->y, tmpWidth, tmpHeight, maskPtr, x, y, width, height);
+			gfxDrawMaskedSprite(animDataTable[it->frame].data(), mask, tmpWidth, tmpHeight, page, it->x, it->y);
+		} else {
+			memcpy(mask, animDataTable[it->frame].data(), tmpWidth * tmpHeight);
+			gfxUpdateIncrustMask(mask, it->x, it->y, tmpWidth, tmpHeight, maskPtr, x, y, width, height);
+			gfxFillSprite(mask, tmpWidth, tmpHeight, page, it->x, it->y);
+		}
+
+		free(mask);
+	}
 }
 
 /*! \todo Fix rendering to prevent fadein artifacts
Index: engines/cine/bg.cpp
===================================================================
--- engines/cine/bg.cpp	(revision 31445)
+++ engines/cine/bg.cpp	(working copy)
@@ -50,7 +50,7 @@
 		uint16 bpp = READ_BE_UINT16(ptr); ptr += 2;
 		if (bpp == 8) {
 			ctColorMode = 1;
-			memcpy(newPalette, ptr, 256*3);
+			memcpy(newPalette, ptr, 256 * 3);
 			ptr += 3 * 256;
 			memcpy(page3Raw, ptr, 320 * 200);
 		} else {
@@ -134,13 +134,11 @@
 
 	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);
+		memcpy(newPalette, ptr, 256 * 3);
 		ptr += 3 * 256;
 		memcpy(additionalBgTable[bgIdx], ptr, 320 * 200);
 	} else {
Index: engines/cine/anim.h
===================================================================
--- engines/cine/anim.h	(revision 31445)
+++ engines/cine/anim.h	(working copy)
@@ -102,6 +102,7 @@
 void loadResource(const char *animName);
 void loadAbs(const char *resourceName, uint16 idx);
 void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken);
+void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency);
 
 } // End of namespace Cine
 
Index: engines/cine/msg.h
===================================================================
--- engines/cine/msg.h	(revision 31445)
+++ engines/cine/msg.h	(working copy)
@@ -26,8 +26,14 @@
 #ifndef CINE_MSG_H
 #define CINE_MSG_H
 
+#include "common/str.h"
+
 namespace Cine {
 
+#define NUM_MAX_MESSAGE 255
+
+extern Common::StringList messageTable;
+
 void loadMsg(char *pMsgName);
 
 } // End of namespace Cine
Index: engines/cine/various.h
===================================================================
--- engines/cine/various.h	(revision 31445)
+++ engines/cine/various.h	(working copy)
@@ -42,15 +42,6 @@
 extern bool disableSystemMenu;
 extern bool inMenu;
 
-struct Message {
-	byte *ptr;
-	uint16 len;
-};
-
-#define NUM_MAX_MESSAGE 255
-
-extern Message messageTable[NUM_MAX_MESSAGE];
-
 struct SeqListElement {
 	struct SeqListElement *next;
 	int16 var4;
@@ -149,6 +140,8 @@
 
 extern int16 additionalBgVScroll;
 
+void removeSeq(uint16 param1, uint16 param2, uint16 param3);
+uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3);
 void addSeqListElement(int16 param0, int16 param1, int16 param2, int16 param3, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8);
 void resetSeqList();
 void processSeqList(void);
