/* 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. * */ /** \file * Operation Stealth script interpreter file */ #include "common/endian.h" #include "common/textconsole.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 = 0; unsigned int OSScript::_numOpcodes = 0; void OSScript::setupTable() { static const Opcode opcodeTable[] = { /* 00 */ { &FWScript::o1_modifyObjectParam, "bbw" }, { &FWScript::o1_getObjectParam, "bbb" }, { &FWScript::o1_addObjectParam, "bbw" }, { &FWScript::o1_subObjectParam, "bbw" }, /* 04 */ { &FWScript::o1_mulObjectParam, "bbw" }, { &FWScript::o1_divObjectParam, "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, "" }, /* TODO: Name this opcode properly. */ /* 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::o2_loadCt, "s" }, { 0, 0 }, { &FWScript::o2_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_setDefaultMenuBgColor, "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_setPlayerCommandPosY, "b" }, { &FWScript::o1_allowPlayerInput, "" }, { &FWScript::o1_disallowPlayerInput, "" }, { &FWScript::o1_changeDataDisk, "b" }, /* Same as opcodes 0x95 and 0xA9. */ /* 6C */ { 0, 0 }, { &FWScript::o1_loadMusic, "s" }, { &FWScript::o1_playMusic, "" }, { &FWScript::o1_fadeOutMusic, "" }, /* 70 */ { &FWScript::o1_stopSample, "" }, { &FWScript::o1_op71, "bw" }, /* TODO: Name this opcode properly. */ { &FWScript::o1_op72, "wbw" }, /* Same as opcode 0x73. TODO: Name this opcode properly. */ { &FWScript::o1_op72, "wbw" }, /* Same as opcode 0x72. */ /* 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" }, /* Last opcode used by Future Wars. */ /* 7C */ { 0, 0 }, { 0, 0 }, { 0, 0 }, { &FWScript::o2_addSeqListElement, "bbbbwww" }, /* 80 */ { &FWScript::o2_removeSeq, "bb" }, { &FWScript::o2_op81, "" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_modifySeqListElement, "bbwwb" }, { &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" }, /* TODO: Name this opcode properly. */ { &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" }, /* Same as opcodes 0x6B and 0xA9. */ { 0, 0 }, { 0, 0 }, /* 98 */ { 0, 0 }, { 0, 0 }, { &FWScript::o2_wasZoneChecked, "b" }, { &FWScript::o2_op9B, "wwwwwwww" }, /* TODO: Name this opcode properly. */ /* 9C */ { &FWScript::o2_op9C, "wwww" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_useBgScroll, "b" }, { &FWScript::o2_setAdditionalBgVScroll, "c" }, { &FWScript::o2_op9F, "ww" }, /* TODO: Name this opcode properly. */ /* A0 */ { &FWScript::o2_addGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_removeGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_addGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_removeGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */ /* A4 */ { &FWScript::o2_loadMask22, "b" }, /* TODO: Name this opcode properly. */ { &FWScript::o2_unloadMask22, "b" }, /* TODO: Name this opcode properly. */ { 0, 0 }, { 0, 0 }, /* A8 */ { 0, 0 }, { &FWScript::o1_changeDataDisk, "b" } /* Same as opcodes 0x6B and 0x95. */ }; OSScript::_opcodeTable = (const Opcode *)opcodeTable; OSScript::_numOpcodes = ARRAYSIZE(opcodeTable); } /** * 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) {} /** * 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) {} /** * Copy constructor */ OSScript::OSScript(const OSScript &src) : FWScript(src, new OSScriptInfo) {} /** * 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); } /** * 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; } /** * 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; } /** * 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); } /** * 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); } /** * 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; } /** * 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 // ------------------------------------------------------------------------ /** Load collision table data */ int FWScript::o2_loadCt() { const char *param = getNextString(); debugC(5, kCineDebugScript, "Line: %d: loadCt(\"%s\")", _line, param); loadCtOS(param); return 0; } 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 = g_cine->_animDataTable[num]._width * g_cine->_animDataTable[num]._height; } if (g_cine->_animDataTable[num].data()) { if (g_cine->getPlatform() == Common::kPlatformDOS) { // 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, g_cine->_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 * @note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op81() { warning("STUB: o2_op81()"); // freeUnkList(); return 0; } int FWScript::o2_modifySeqListElement() { byte a = getNextByte(); byte b = getNextByte(); uint16 c = getNextWord(); uint16 d = getNextWord(); byte e = getNextByte(); debugC(5, kCineDebugScript, "Line: %d: o2_modifySeqListElement(%d,%d,%d,%d,%d)", _line, a, b, c, d, e); modifySeqListElement(a, 0, b, c, d, e); return 0; } /** * @todo Check whether this opcode's name is backwards (i.e. should it be o2_isSeqNotRunning?) */ int FWScript::o2_isSeqRunning() { byte a = getNextByte(); byte b = getNextByte(); debugC(5, kCineDebugScript, "Line: %d: o2_isSeqRunning(%d,%d)", _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 = g_cine->_objectScripts.begin(); for (; it != g_cine->_objectScripts.end(); ++it) { if ((*it)->_index == param) { (*it)->_index = -1; } } return 0; } int FWScript::o2_op8D() { uint16 objIdx1 = getNextWord(); uint16 xAdd1 = getNextWord(); uint16 yAdd1 = getNextWord(); uint16 maskAdd1 = getNextWord(); uint16 objIdx2 = getNextWord(); uint16 xAdd2 = getNextWord(); uint16 yAdd2 = getNextWord(); uint16 maskAdd2 = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: o2_op8D(%d, %d, %d, %d, %d, %d, %d, %d)", _line, objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2); _compare = compareObjectParamRanges(objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2); 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); renderer->removeBg(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); // Load the resource to an absolute position if (loadResource(param2, param1) == -1) { // Check if the loading failed // WORKAROUND: In the 256 color PC version of Operation Stealth when // walking out of the airport in Santa Paragua to the street the // player character should be seen as a grey silhuette while walking // behind the glass. But actually the player character is completely // invisible when walking behind the glass because the animation files // used are wrongly loaded. In AIRPORT.PRC's 6th script there are // calls loadAbs("JOHN01.ANI", 73) and loadAbs("JOHN02.ANI", 37) to // load the animations involved but no such files are found with the // game. Corresponding SET-files are found though. As it worked and // looked fine when I tried loading them instead of the missing ANI // files I'm doing so here. NOTE: At least the German Amiga version // of Operation Stealth seems to have all the files involved // (JOHN01.ANI, JOHN02.ANI, JOHN01.SET and JOHN02.SET). if (scumm_stricmp(param2, "JOHN01.ANI") == 0 && param1 == 73) { loadResource("JOHN01.SET", param1); } else if (scumm_stricmp(param2, "JOHN02.ANI") == 0 && param1 == 37) { loadResource("JOHN02.SET", param1); } } return 0; } int FWScript::o2_loadBg() { byte param = getNextByte(); assert(param < 9); debugC(5, kCineDebugScript, "Line: %d: useBg(%d)", _line, param); renderer->selectBg(param); return 0; } int FWScript::o2_wasZoneChecked() { byte param = getNextByte(); _compare = (param < NUM_MAX_ZONE && g_cine->_zoneQuery[param]) ? 1 : 0; debugC(5, kCineDebugScript, "Line: %d: o2_wasZoneChecked(%d)", _line, param); return 0; } /** * @todo Implement this instruction * @note According to the scripts' opcode usage comparison this opcode isn't used at all. */ 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 * @note According to the scripts' opcode usage comparison this opcode isn't used at all. */ 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 < 9); debugC(5, kCineDebugScript, "Line: %d: useBgScroll(%d)", _line, param); renderer->selectScrollBg(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); renderer->setScroll(_localVars[param2]); } else { uint16 param2 = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = %d", _line, param2); renderer->setScroll(param2); } return 0; } /** * @todo Implement this instruction * @note According to the scripts' opcode usage comparison this opcode isn't used at all. */ int FWScript::o2_op9F() { warning("o2_op9F()"); getNextWord(); getNextWord(); return 0; } int FWScript::o2_addGfxElementType20() { uint16 param1 = getNextWord(); uint16 param2 = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType20(%d,%d)", _line, param1, param2); addGfxElement(param1, param2, 20); return 0; } int FWScript::o2_removeGfxElementType20() { uint16 idx = getNextWord(); uint16 param = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType20(%d,%d)", _line, idx, param); removeGfxElement(idx, param, 20); return 0; } int FWScript::o2_addGfxElementType21() { uint16 a = getNextWord(); uint16 b = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType21(%d,%d)", _line, a, b); addGfxElement(a, b, 21); return 0; } int FWScript::o2_removeGfxElementType21() { uint16 a = getNextWord(); uint16 b = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType21(%d,%d)", _line, a, b); removeGfxElement(a, b, 21); 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