/* 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. * */ // Item script opcodes for Simon1/Simon2 #include "common/debug-channels.h" #include "common/endian.h" #include "common/system.h" #include "common/textconsole.h" #include "agos/agos.h" #include "agos/intern.h" namespace AGOS { void AGOSEngine::setupOpcodes() { error("setupOpcodes: Unknown game"); } void AGOSEngine::setScriptCondition(bool cond) { _runScriptCondition[_recursionDepth] = cond; } bool AGOSEngine::getScriptCondition() { return _runScriptCondition[_recursionDepth]; } void AGOSEngine::setScriptReturn(int ret) { _runScriptReturn[_recursionDepth] = ret; } int AGOSEngine::getScriptReturn() { return _runScriptReturn[_recursionDepth]; } // ----------------------------------------------------------------------- // Common Opcodes // ----------------------------------------------------------------------- void AGOSEngine::o_invalid() { error("Invalid opcode %d", _opcode); } void AGOSEngine::o_at() { // 1: ptrA parent is setScriptCondition(me()->parent == getNextItemID()); } void AGOSEngine::o_notAt() { // 2: ptrA parent is not setScriptCondition(me()->parent != getNextItemID()); } void AGOSEngine::o_carried() { // 5: parent is 1 setScriptCondition(getNextItemPtr()->parent == getItem1ID()); } void AGOSEngine::o_notCarried() { // 6: parent isnot 1 setScriptCondition(getNextItemPtr()->parent != getItem1ID()); } void AGOSEngine::o_isAt() { // 7: parent is Item *item = getNextItemPtr(); setScriptCondition(item->parent == getNextItemID()); } void AGOSEngine::o_zero() { // 11: is zero setScriptCondition(getNextVarContents() == 0); } void AGOSEngine::o_notZero() { // 12: isnot zero setScriptCondition(getNextVarContents() != 0); } void AGOSEngine::o_eq() { // 13: equal uint tmp = getNextVarContents(); uint tmp2 = getVarOrWord(); #ifdef __DS__ // HACK: Skip attempt to read Calypso's letter manually, // due to speech segment been too large to fit into memory if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE) && getPlatform() == Common::kPlatformWindows && _currentTable) { if (_currentTable->id == 71 && tmp == 1 && tmp2 == 1) { setScriptCondition(false); return; } } #endif setScriptCondition(tmp == tmp2); } void AGOSEngine::o_notEq() { // 14: not equal uint tmp = getNextVarContents(); setScriptCondition(tmp != getVarOrWord()); } void AGOSEngine::o_gt() { // 15: is greater int16 tmp1 = getNextVarContents(); int16 tmp2 = getVarOrWord(); setScriptCondition(tmp1 > tmp2); } void AGOSEngine::o_lt() { // 16: is less int16 tmp1 = getNextVarContents(); int16 tmp2 = getVarOrWord(); setScriptCondition(tmp1 < tmp2); } void AGOSEngine::o_eqf() { // 17: is eq f uint tmp = getNextVarContents(); setScriptCondition(tmp == getNextVarContents()); } void AGOSEngine::o_notEqf() { // 18: is not equal f uint tmp = getNextVarContents(); setScriptCondition(tmp != getNextVarContents()); } void AGOSEngine::o_ltf() { // 19: is greater f int16 tmp1 = getNextVarContents(); int16 tmp2 = getNextVarContents(); setScriptCondition(tmp1 < tmp2); } void AGOSEngine::o_gtf() { // 20: is less f int16 tmp1 = getNextVarContents(); int16 tmp2 = getNextVarContents(); setScriptCondition(tmp1 > tmp2); } void AGOSEngine::o_chance() { // 23: chance int16 a = getVarOrWord(); if (a == 0) { setScriptCondition(false); return; } if (a == 100) { setScriptCondition(true); return; } a += _chanceModifier; if (a <= 0) { _chanceModifier = 0; setScriptCondition(false); } else if ((int16)_rnd.getRandomNumber(99) < a) { if (_chanceModifier <= 0) _chanceModifier -= 5; else _chanceModifier = 0; setScriptCondition(true); } else { if (_chanceModifier >= 0) _chanceModifier += 5; else _chanceModifier = 0; setScriptCondition(false); } } void AGOSEngine::o_isRoom() { // 25: is room setScriptCondition(isRoom(getNextItemPtr())); } void AGOSEngine::o_isObject() { // 26: is object setScriptCondition(isObject(getNextItemPtr())); } void AGOSEngine::o_state() { // 27: item state is Item *item = getNextItemPtr(); setScriptCondition((uint) item->state == getVarOrWord()); } void AGOSEngine::o_oflag() { // 28: item has prop SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); uint num = getVarOrByte(); setScriptCondition(subObject != NULL && (subObject->objectFlags & (1 << num)) != 0); } void AGOSEngine::o_destroy() { // 31: set no parent setItemParent(getNextItemPtr(), NULL); } void AGOSEngine::o_place() { // 33: set item parent Item *item = getNextItemPtr(); setItemParent(item, getNextItemPtr()); } void AGOSEngine::o_copyff() { // 36: copy var uint value = getNextVarContents(); writeNextVarContents(value); } void AGOSEngine::o_clear() { // 41: zero var writeNextVarContents(0); } void AGOSEngine::o_let() { // 42: set var uint var = getVarWrapper(); uint value = getVarOrWord(); if (getGameType() == GType_FF && _currentTable) { // WORKAROUND: When the repair man comes to fix the car, the game doesn't // wait long enough for the screen to completely scroll to the left side. if (_currentTable->id == 20438 && var == 103 && value == 60) { value = 71; } } writeVariable(var, value); } void AGOSEngine::o_add() { // 43: add uint var = getVarWrapper(); writeVariable(var, readVariable(var) + getVarOrWord()); // WORKAROUND: The conversation of the male in Vid-Phone Booth at Dave's Space Bar // is based on variable 116, but stops due to a missing option (37). if (getGameType() == GType_FF && _currentTable->id == 10538 && readVariable(116) == 37) writeVariable(116, 38); } void AGOSEngine::o_sub() { // 44: sub uint var = getVarWrapper(); writeVariable(var, readVariable(var) - getVarOrWord()); } void AGOSEngine::o_addf() { // 45: add f uint var = getVarWrapper(); writeVariable(var, readVariable(var) + getNextVarContents()); } void AGOSEngine::o_subf() { // 46: sub f uint var = getVarWrapper(); writeVariable(var, readVariable(var) - getNextVarContents()); } void AGOSEngine::o_mul() { // 47: mul uint var = getVarWrapper(); writeVariable(var, readVariable(var) * getVarOrWord()); } void AGOSEngine::o_div() { // 48: div uint var = getVarWrapper(); int value = getVarOrWord(); if (value == 0) error("o_div: Division by zero"); writeVariable(var, readVariable(var) / value); } void AGOSEngine::o_mulf() { // 49: mul f uint var = getVarWrapper(); writeVariable(var, readVariable(var) * getNextVarContents()); } void AGOSEngine::o_divf() { // 50: div f uint var = getVarWrapper(); int value = getNextVarContents(); if (value == 0) error("o_divf: Division by zero"); writeVariable(var, readVariable(var) / value); } void AGOSEngine::o_mod() { // 51: mod uint var = getVarWrapper(); int value = getVarOrWord(); if (value == 0) error("o_mod: Division by zero"); writeVariable(var, readVariable(var) % value); } void AGOSEngine::o_modf() { // 52: mod f uint var = getVarWrapper(); int value = getNextVarContents(); if (value == 0) error("o_modf: Division by zero"); writeVariable(var, readVariable(var) % value); } void AGOSEngine::o_random() { // 53: random uint var = getVarWrapper(); uint value = (uint16)getVarOrWord(); writeVariable(var, _rnd.getRandomNumber(value - 1)); } void AGOSEngine::o_goto() { // 55: set itemA parent uint item = getNextItemID(); setItemParent(me(), _itemArrayPtr[item]); } void AGOSEngine::o_oset() { // 56: set child2 fr bit SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); int value = getVarOrByte(); if (subObject != NULL && value >= 16) subObject->objectFlags |= (1 << value); } void AGOSEngine::o_oclear() { // 57: clear child2 fr bit SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); int value = getVarOrByte(); if (subObject != NULL && value >= 16) subObject->objectFlags &= ~(1 << value); } void AGOSEngine::o_putBy() { // 58: make siblings Item *item = getNextItemPtr(); setItemParent(item, derefItem(getNextItemPtr()->parent)); } void AGOSEngine::o_inc() { // 59: item inc state Item *item = getNextItemPtr(); if (item->state <= 30000) { setItemState(item, item->state + 1); synchChain(item); } } void AGOSEngine::o_dec() { // 60: item dec state Item *item = getNextItemPtr(); if (item->state >= 0) { setItemState(item, item->state - 1); synchChain(item); } } void AGOSEngine::o_setState() { // 61: item set state Item *item = getNextItemPtr(); int value = getVarOrWord(); if (value < 0) value = 0; if (value > 30000) value = 30000; setItemState(item, value); synchChain(item); } void AGOSEngine::o_print() { // 62: show int showMessageFormat("%d", getNextVarContents()); } void AGOSEngine::o_message() { // 63: show string nl showMessageFormat("%s\n", getStringPtrByID(getNextStringID())); } void AGOSEngine::o_msg() { // 64: show string showMessageFormat("%s", getStringPtrByID(getNextStringID())); } void AGOSEngine::o_end() { // 68: exit interpreter quitGame(); // Make sure the quit event is processed immediately. delay(0); } void AGOSEngine::o_done() { // 69: return 1 setScriptReturn(1); } void AGOSEngine::o_process() { // 71: start subroutine uint16 id = getVarOrWord(); if (!_copyProtection && getGameType() == GType_WW && id == 71) { // Copy protection was disabled in Good Old Games release return; } Subroutine *sub = getSubroutineByID(id); if (sub != NULL) { #ifdef __DS__ // HACK: Skip scene of Simon reading letter from Calypso // due to speech segment been too large to fit into memory if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE) && getPlatform() == Common::kPlatformWindows && sub->id == 2922) { // set parent special _noParentNotify = true; setItemParent(derefItem(16), me()); _noParentNotify = false; // set parent special _noParentNotify = true; setItemParent(derefItem(14), me()); _noParentNotify = false; // set item parent setItemParent(derefItem(12), me()); return; } #endif startSubroutine(sub); } } void AGOSEngine::o_when() { // 76: add timeout uint16 timeout = getVarOrWord(); addTimeEvent(timeout, getVarOrWord()); } void AGOSEngine::o_if1() { // 77: has item minus 1 setScriptCondition(_subjectItem != NULL); } void AGOSEngine::o_if2() { // 78: has item minus 3 setScriptCondition(_objectItem != NULL); } void AGOSEngine::o_isCalled() { // 79: childstruct fr2 is SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); uint stringId = getNextStringID(); setScriptCondition((subObject != NULL) && subObject->objectName == stringId); } void AGOSEngine::o_is() { // 80: item equal setScriptCondition(getNextItemPtr() == getNextItemPtr()); } void AGOSEngine::o_debug() { // 82: debug opcode getVarOrByte(); } void AGOSEngine::o_comment() { // 87: comment getNextStringID(); } void AGOSEngine::o_haltAnimation() { // 88: stop animation _videoLockOut |= 0x10; if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { VgaTimerEntry *vte = _vgaTimerList; while (vte->delay) { if (vte->type == ANIMATE_EVENT) vte->delay += 10; vte++; } _scrollCount = 0; _scrollFlag = 0; } } void AGOSEngine::o_restartAnimation() { // 89: restart animation _videoLockOut &= ~0x10; } void AGOSEngine::o_getParent() { // 90: set minusitem to parent Item *i = getNextItemPtr(); if (getVarOrByte() == 1) _subjectItem = derefItem(i->parent); else _objectItem = derefItem(i->parent); } void AGOSEngine::o_getNext() { // 91: set minusitem to next Item *i = getNextItemPtr(); if (getVarOrByte() == 1) _subjectItem = derefItem(i->next); else _objectItem = derefItem(i->next); } void AGOSEngine::o_getChildren() { // 92: set minusitem to child Item *i = getNextItemPtr(); if (getVarOrByte() == 1) _subjectItem = derefItem(i->child); else _objectItem = derefItem(i->child); } void AGOSEngine::o_picture() { // 96 uint vga_res = getVarOrWord(); uint mode = getVarOrByte(); // WORKAROUND: For a script bug in the Amiga AGA/CD32 versions // When selecting locations on the magical map, the script looks // for vga_res 12701, but only vga_res 12700 exists. if (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformAmiga && vga_res == 12701) { return; } if (getGameType() == GType_PP && getGameId() != GID_DIMP) { if (vga_res == 8700 && getBitFlag(107)) { _vgaPeriod = 30; } _picture8600 = (vga_res == 8600); } setWindowImageEx(mode, vga_res); } void AGOSEngine::o_loadZone() { // 97: load zone uint vga_res = getVarOrWord(); _videoLockOut |= 0x80; if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { vc27_resetSprite(); vc29_stopAllSounds(); } loadZone(vga_res); if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { _copyScnFlag = 0; _vgaSpriteChanged = 0; } _videoLockOut &= ~0x80; } void AGOSEngine::o_killAnimate() { // 100: kill animations _videoLockOut |= 0x8000; vc27_resetSprite(); _videoLockOut &= ~0x8000; } void AGOSEngine::o_defWindow() { // 101: define window uint num = getVarOrByte(); uint x = getVarOrWord(); uint y = getVarOrWord(); uint w = getVarOrWord(); uint h = getVarOrWord(); uint flags = getVarOrWord(); uint color = getVarOrWord(); uint fillColor, textColor; if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { fillColor = color % 100; textColor = color / 100; } else { fillColor = color; textColor = 0; } num &= 7; if (_windowArray[num]) closeWindow(num); _windowArray[num] = openWindow(x, y, w, h, flags, fillColor, textColor); if (num == _curWindow) { _textWindow = _windowArray[num]; justifyStart(); } } void AGOSEngine::o_window() { // 102 changeWindow(getVarOrByte() & 7); } void AGOSEngine::o_cls() { // 103 mouseOff(); removeIconArray(_curWindow); showMessageFormat("\x0C"); _oracleMaxScrollY = 0; _noOracleScroll = 0; mouseOn(); } void AGOSEngine::o_closeWindow() { // 104 closeWindow(getVarOrByte() & 7); } void AGOSEngine::o_addBox() { // 107: add item box uint flags = 0; uint id = getVarOrWord(); uint params = id / 1000; uint x, y, w, h, verb; Item *item; id = id % 1000; if (params & 1) flags |= kBFInvertTouch; if (params & 2) flags |= kBFNoTouchName; if (params & 4) flags |= kBFBoxItem; if (params & 8) flags |= kBFTextBox; if (params & 16) flags |= kBFDragBox; x = getVarOrWord(); y = getVarOrWord(); w = getVarOrWord(); h = getVarOrWord(); item = getNextItemPtrStrange(); verb = getVarOrWord(); if (x >= 1000) { verb += 0x4000; x -= 1000; } defineBox(id, x, y, w, h, flags, verb, item); } void AGOSEngine::o_delBox() { // 108: delete box undefineBox(getVarOrWord()); } void AGOSEngine::o_enableBox() { // 109: enable box enableBox(getVarOrWord()); } void AGOSEngine::o_disableBox() { // 110: set hitarea bit 0x40 disableBox(getVarOrWord()); } void AGOSEngine::o_moveBox() { // 111: set hitarea xy uint hitarea_id = getVarOrWord(); uint x = getVarOrWord(); uint y = getVarOrWord(); moveBox(hitarea_id, x, y); } void AGOSEngine::o_doIcons() { // 114 Item *item = getNextItemPtr(); uint num = getVarOrByte(); mouseOff(); drawIconArray(num, item, 0, 0); mouseOn(); } void AGOSEngine::o_isClass() { // 115: item has flag Item *item = getNextItemPtr(); setScriptCondition((item->classFlags & (1 << getVarOrByte())) != 0); } void AGOSEngine::o_setClass() { // 116: item set flag Item *item = getNextItemPtr(); item->classFlags |= (1 << getVarOrByte()); } void AGOSEngine::o_unsetClass() { // 117: item clear flag Item *item = getNextItemPtr(); item->classFlags &= ~(1 << getVarOrByte()); } void AGOSEngine::o_waitSync() { // 119: wait vga uint var = getVarOrWord(); _scriptVar2 = (var == 200); if (var != 200 || !_skipVgaWait) waitForSync(var); _skipVgaWait = false; } void AGOSEngine::o_sync() { // 120: sync sendSync(getVarOrWord()); } void AGOSEngine::o_defObj() { // 121: set vga item uint slot = getVarOrByte(); _objectArray[slot] = getNextItemPtr(); } void AGOSEngine::o_here() { // 125: item is sibling with item 1 Item *item = getNextItemPtr(); setScriptCondition(me()->parent == item->parent); } void AGOSEngine::o_doClassIcons() { // 126: do class icons Item *item = getNextItemPtr(); uint num = getVarOrByte(); uint a = getVarOrByte(); mouseOff(); if (getGameType() == GType_ELVIRA1) drawIconArray(num, item, 0, a); else drawIconArray(num, item, 0, 1 << a); mouseOn(); } void AGOSEngine::o_playTune() { // 127: play tune uint16 music = getVarOrWord(); uint16 track = getVarOrWord(); if (music != _lastMusicPlayed) { _lastMusicPlayed = music; playMusic(music, track); } } void AGOSEngine::o_setAdjNoun() { // 130: set adj noun uint var = getVarOrByte(); if (var == 1) { _scriptAdj1 = getNextWord(); _scriptNoun1 = getNextWord(); } else { _scriptAdj2 = getNextWord(); _scriptNoun2 = getNextWord(); } } void AGOSEngine::o_saveUserGame() { // 132: save user game if (getGameId() == GID_SIMON1CD32) { // The Amiga CD32 version of Simon the Sorcerer 1 uses a single slot if (!saveGame(0, "Default Saved Game")) { vc33_setMouseOn(); fileError(_windowArray[5], true); } } else { _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); userGame(false); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } } void AGOSEngine::o_loadUserGame() { // 133: load user game if (getGameId() == GID_SIMON1CD32) { // The Amiga CD32 version of Simon the Sorcerer 1 uses a single slot if (!loadGame(genSaveName(0))) { vc33_setMouseOn(); fileError(_windowArray[5], false); } } else { _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); userGame(true); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } } void AGOSEngine::o_copysf() { // 136: set var to item unk3 Item *item = getNextItemPtr(); writeNextVarContents(item->state); } void AGOSEngine::o_restoreIcons() { // 137 uint num = getVarOrByte(); WindowBlock *window = _windowArray[num & 7]; if (window->iconPtr) drawIconArray(num, window->iconPtr->itemRef, window->iconPtr->line, window->iconPtr->classMask); } void AGOSEngine::o_freezeZones() { // 138: freeze zones freezeBottom(); if (!_copyProtection && !(getFeatures() & GF_TALKIE) && _currentTable) { if ((getGameType() == GType_SIMON1 && _currentTable->id == 2924) || (getGameType() == GType_SIMON2 && _currentTable->id == 1322)) { _variableArray[134] = 3; _variableArray[135] = 3; setBitFlag(135, 1); setScriptCondition(0); } } } void AGOSEngine::o_placeNoIcons() { // 139: set parent special Item *item = getNextItemPtr(); _noParentNotify = true; setItemParent(item, getNextItemPtr()); _noParentNotify = false; } void AGOSEngine::o_clearTimers() { // 140: clear timers killAllTimers(); if (getGameType() == GType_SIMON1) addTimeEvent(3, 160); } void AGOSEngine::o_setDollar() { // 141: set m1 to m3 uint which = getVarOrByte(); Item *item = getNextItemPtr(); if (which == 1) { _subjectItem = item; } else { _objectItem = item; } } void AGOSEngine::o_isBox() { // 142: is box dead setScriptCondition(isBoxDead(getVarOrWord())); } // ----------------------------------------------------------------------- byte AGOSEngine::getByte() { return *_codePtr++; } int AGOSEngine::getNextWord() { int16 a = (int16)READ_BE_UINT16(_codePtr); _codePtr += 2; return a; } uint AGOSEngine::getNextStringID() { return (uint16)getNextWord(); } uint AGOSEngine::getVarOrByte() { if (getGameType() == GType_ELVIRA1) { return getVarOrWord(); } else { uint a = *_codePtr++; if (a != 255) return a; return readVariable(*_codePtr++); } } uint AGOSEngine::getVarOrWord() { uint a = READ_BE_UINT16(_codePtr); _codePtr += 2; if (getGameType() == GType_PP) { if (a >= 60000 && a < 62048) { return readVariable(a - 60000); } } else { if (a >= 30000 && a < 30512) { return readVariable(a - 30000); } } return a; } uint AGOSEngine::getVarWrapper() { if (getGameType() == GType_ELVIRA1 || getGameType() == GType_PP) return getVarOrWord(); else return getVarOrByte(); } uint AGOSEngine::getNextVarContents() { return (uint16)readVariable(getVarWrapper()); } uint AGOSEngine::readVariable(uint16 variable) { if (variable >= _numVars) error("readVariable: Variable %d out of range", variable); if (getGameType() == GType_PP) { return (uint16)_variableArray[variable]; } else if (getGameType() == GType_FF) { if (getBitFlag(83)) return (uint16)_variableArray2[variable]; else return (uint16)_variableArray[variable]; } else { return _variableArray[variable]; } } void AGOSEngine::writeNextVarContents(uint16 contents) { writeVariable(getVarWrapper(), contents); } void AGOSEngine::writeVariable(uint16 variable, uint16 contents) { if (variable >= _numVars) error("writeVariable: Variable %d out of range", variable); if (getGameType() == GType_FF && getBitFlag(83)) _variableArray2[variable] = contents; else _variableArray[variable] = contents; } int AGOSEngine::runScript() { bool flag; if (shouldQuit()) return 1; do { if (DebugMan.isDebugChannelEnabled(kDebugOpcode)) dumpOpcode(_codePtr); if (getGameType() == GType_ELVIRA1) { _opcode = getVarOrWord(); if (_opcode == 10000) return 0; } else { _opcode = getByte(); if (_opcode == 0xFF) return 0; } if (_runScriptReturn1) return 1; /* Invert condition? */ flag = false; if (getGameType() == GType_ELVIRA1) { if (_opcode == 203) { flag = true; _opcode = getVarOrWord(); if (_opcode == 10000) return 0; } } else { if (_opcode == 0) { flag = true; _opcode = getByte(); if (_opcode == 0xFF) return 0; } } setScriptCondition(true); setScriptReturn(0); if (_opcode > _numOpcodes) error("Invalid opcode '%d' encountered", _opcode); executeOpcode(_opcode); } while (getScriptCondition() != flag && !getScriptReturn() && !shouldQuit()); return (shouldQuit()) ? 1 : getScriptReturn(); } Child *nextSub(Child *sub, int16 key) { Child *a = sub->next; while (a) { if (a->type == key) return a; a = a->next; } return NULL; } void AGOSEngine::synchChain(Item *i) { SubChain *c = (SubChain *)findChildOfType(i, kChainType); while (c) { setItemState(derefItem(c->chChained), i->state); c = (SubChain *)nextSub((Child *)c, kChainType); } } void AGOSEngine::sendSync(uint a) { uint16 id = to16Wrapper(a); _videoLockOut |= 0x8000; _vcPtr = (byte *)&id; vc15_sync(); _videoLockOut &= ~0x8000; } void AGOSEngine::stopAnimate(uint16 a) { uint16 b = to16Wrapper(a); _videoLockOut |= 0x8000; _vcPtr = (byte *)&b; vc60_stopAnimation(); _videoLockOut &= ~0x8000; } void AGOSEngine::waitForSync(uint a) { const uint maxCount = (getGameType() == GType_SIMON1) ? 1000 : 2500; if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE)) { if (a != 200) { uint16 tmp = _lastVgaWaitFor; _lastVgaWaitFor = 0; if (tmp == a) return; } } _vgaWaitFor = a; _syncCount = 0; _exitCutscene = false; _rightButtonDown = false; while (_vgaWaitFor != 0 && !shouldQuit()) { if (_rightButtonDown) { if (_vgaWaitFor == 200 && (getGameType() == GType_FF || !getBitFlag(14))) { skipSpeech(); break; } } if (_exitCutscene) { if (getGameType() == GType_ELVIRA1) { if (_variableArray[105] == 0) { _variableArray[105] = 255; break; } } else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { if (_vgaWaitFor == 51) { setBitFlag(244, 1); break; } } else { if (getBitFlag(9)) { endCutscene(); break; } } } processSpecialKeys(); if (_syncCount >= maxCount) { warning("waitForSync: wait timed out"); break; } delay(1); } } } // End of namespace AGOS