/* 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. * */ #include "voyeur/files.h" #include "voyeur/graphics.h" #include "voyeur/voyeur.h" #include "voyeur/staticres.h" namespace Voyeur { int ThreadResource::_stampFlags = 0; int ThreadResource::_useCount[8]; byte *ThreadResource::_threadDataPtr = NULL; CMapResource *ThreadResource::_cmd14Pal = NULL; ThreadResource::ThreadResource(BoltFilesState &state, const byte *src): _vm(state._vm) { _flags = src[8]; _ctlPtr = nullptr; } void ThreadResource::initThreadStruct(int idx, int id) { _controlIndex = -1; if (loadAStack(idx)) { _field4 = _field6 = -1; _threadId = id; _field3A = -1; _field3E = -1; doState(); } } bool ThreadResource::loadAStack(int idx) { if (_stampFlags & 1) { unloadAStack(_controlIndex); if (!_useCount[idx]) { BoltEntry &boltEntry = _vm->_stampLibPtr->boltEntry(_vm->_controlPtr->_memberIds[idx]); if (!boltEntry._data) return false; _vm->_controlPtr->_entries[idx] = boltEntry._data; } ++_useCount[idx]; } _ctlPtr = _vm->_controlPtr->_entries[idx]; return true; } void ThreadResource::unloadAStack(int idx) { if ((_stampFlags & 1) && _useCount[idx]) { if (--_useCount[idx] == 0) { _vm->_stampLibPtr->freeBoltMember(_vm->_controlPtr->_memberIds[idx]); } } } bool ThreadResource::doState() { _flags |= 1; if (!getStateInfo()) return false; getButtonsFlags(); getField1CE(); _vm->_glGoScene = -1; _vm->_glGoStack = -1; performOpenCard(); if (_field40 & 1) { return chooseSTAMPButton(_vm->getRandomNumber(_field42 - 1)); } else { return true; } } bool ThreadResource::getStateInfo() { _field9 = 0; int id = READ_LE_UINT16(_ctlPtr); if (id <= _threadId) { _field9 |= 0x80; return false; } else { uint32 fld = READ_LE_UINT32(_ctlPtr + 2); fld += _threadId << 3; _field46 = READ_LE_UINT32(_ctlPtr + fld + 4); fld = READ_LE_UINT32(_ctlPtr + fld); byte *baseP = _ctlPtr + fld; _field42 = READ_LE_UINT16(baseP); _field40 = READ_LE_UINT16(baseP + 2); _parseCount = READ_LE_UINT16(baseP + 4); _field28E = getDataOffset(); _field28E += (READ_LE_UINT32(baseP + 6) / 2) << 1; _field4A = baseP + 10; getButtonsText(); return true; } } byte *ThreadResource::getDataOffset() { uint32 offset = READ_LE_UINT32(_ctlPtr + 10); _threadDataPtr = _ctlPtr + offset; return _threadDataPtr; } void ThreadResource::getButtonsText() { int idx = 0; for (const byte *p = _field4A; *p != 0x49; p = getNextRecord(p)) { if (*p == 0xC0) { ++p; if (*p++ & 0x80) { assert(idx < 63); _field8E[idx] = getRecordOffset(p); p += 4; } ++idx; _field8E[idx] = NULL; } } } void ThreadResource::getButtonsFlags() { int idx = 0; for (const byte *p = _field4A; *p != 0x49; p = getNextRecord(p)) { if (*p == 0xC0) { if (*++p & 0x20) _field40 |= 2; _buttonFlags[idx] = *p++; _field18E[idx] = *p++; if (_buttonFlags[idx] & 0x80) p += 4; ++idx; } } } void ThreadResource::getField1CE() { int idx = 0; for (const byte *p = _field4A; *p++ != 0x49; p = getNextRecord(p)) { assert(idx < 47); _field1CE[idx++] = getRecordOffset(p); _field1CE[idx] = NULL; p += 4; } } void ThreadResource::unloadAllStacks(VoyeurEngine *vm) { if (_stampFlags & 1) { for (int i = 0; i < 8; ++i) { if (_useCount[i]) vm->_stampLibPtr->freeBoltMember(vm->_controlPtr->_memberIds[i]); } } } void ThreadResource::performOpenCard() { for (const byte *p = _field4A; *p != 0x49; p = getNextRecord(p)) { if (*p == 0x47) { cardAction(p + 1); return; } } } void ThreadResource::initUseCount() { Common::fill(&_useCount[0], &_useCount[8], 0); } const byte *ThreadResource::getRecordOffset(const byte *p) { uint32 recSize = READ_LE_UINT32(p) + READ_LE_UINT32(_ctlPtr + 6); return _ctlPtr + recSize; } const byte *ThreadResource::getNextRecord(const byte *p) { byte v = *p++; switch (v) { case 2: case 4: case 6: case 8: case 10: return p + 8; case 1: case 3: case 5: case 7: case 9: case 11: case 21: case 22: case 25: case 26: return p + 5; case 17: case 23: case 24: case 27: case 28: return p + 2; case 19: case 41: return p + 6; case 18: case 51: case 52: return p + 1; case 74: return p + 4; case 192: if (*p & 0x80) p += 4; return p + 2; default: return p; } } const byte *ThreadResource::getSTAMPCard(int cardId) { const byte *p; int count = 0; for (p = _field4A; count <= cardId && *p != 0x49; p = getNextRecord(p)) { if (*p == 0xC0) ++count; } return p; } int ThreadResource::getStateFromID(uint32 id) { int count = READ_LE_UINT16(_ctlPtr); for (int i = 0; i < count; ++i) { uint32 sid = getSID(i); if (sid == id) return i; } return -1; } uint32 ThreadResource::getSID(int sid) { uint32 offset = READ_LE_UINT32(_ctlPtr + 2) + (sid << 3) + 4; return READ_LE_UINT32(_ctlPtr + offset); } void ThreadResource::doSTAMPCardAction() { for (const byte *p = _field4A; *p != 0x49; p = getNextRecord(p)) { if (*p == 0x48) { cardAction(p + 1); return; } } } void ThreadResource::cardAction(const byte *card) { _vm->_glGoScene = -1; _vm->_glGoStack = -1; // Loop to perform card commands while (!_vm->shouldQuit() && *card < 70 && _vm->_glGoScene == -1) { card = cardPerform(card); } } bool ThreadResource::chooseSTAMPButton(int buttonId) { _flags &= ~1; for (int idx = 0; idx < _field42; ++idx) { if (_field18E[idx] == buttonId) { const byte *card = getSTAMPCard(idx); cardAction(card); bool flag = true; while (!_vm->shouldQuit() && _vm->_glGoStack != -1 && flag) { doSTAMPCardAction(); flag = goToStateID(_vm->_glGoStack, _vm->_glGoScene); } while (!_vm->shouldQuit() && _vm->_glGoScene != -1 && flag) { doSTAMPCardAction(); flag = goToState(-1, _vm->_glGoScene); } return flag; } } return false; } void ThreadResource::parsePlayCommands() { _vm->_voy._field470 = -1; _vm->_voy._field468 = 0; _vm->_voy._field46A = 0; _vm->_voy._field47A = -1; _vm->_voy._field4E2 = -1; _vm->_voy._field478 &= ~8; _vm->_eventsManager._videoDead = -1; Common::fill(&_vm->_voy._arr1[0][0], &_vm->_voy._arr1[8][20], 9999); Common::fill(&_vm->_voy._arr2[0][0], &_vm->_voy._arr2[8][20], 0); Common::fill(&_vm->_voy._arr3[0][0], &_vm->_voy._arr3[3][20], 9999); Common::fill(&_vm->_voy._arr4[0][0], &_vm->_voy._arr4[3][20], 0); Common::fill(&_vm->_voy._arr5[0][0], &_vm->_voy._arr5[3][20], 9999); Common::fill(&_vm->_voy._arr6[0][0], &_vm->_voy._arr6[3][20], 0); Common::fill(&_vm->_voy._arr7[0], &_vm->_voy._arr7[20], 0); byte *dataP = _field28E; int v2, v3; PictureResource *pic; CMapResource *pal; for (int parseIndex = 0; parseIndex < _parseCount; ++parseIndex) { uint16 id = READ_LE_UINT16(dataP); debugC(DEBUG_BASIC, kDebugScripts, "parsePlayCommands (%d of %d) - cmd #%d", parseIndex, _parseCount, id); dataP += 2; switch (id) { case 1: _vm->_playStamp2 = READ_LE_UINT16(dataP); dataP += 2; break; case 2: v2 = READ_LE_UINT16(dataP); if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { _vm->_eventsManager._videoComputerBut4 = READ_LE_UINT16(dataP + 2); _vm->_voy._field468 = READ_LE_UINT16(dataP + 4); _vm->_voy._field46A = READ_LE_UINT16(dataP + 6); if (_vm->_voy._RTVNum < _vm->_voy._field468 || (_vm->_voy._field468 + _vm->_voy._field46A) < _vm->_voy._RTVNum) { _vm->_eventsManager._videoComputerBut4 = -1; } else { _vm->_voy._vocSecondsOffset = _vm->_voy._RTVNum - _vm->_voy._field468; addAudioEventStart(); assert(_vm->_eventsManager._videoComputerBut4 < 38); _vm->_graphicsManager._backgroundPage = _vm->_bVoy->boltEntry( 0x7F00 + BLIND_TABLE[_vm->_eventsManager._videoComputerBut4])._picResource; _vm->_graphicsManager._backColors = _vm->_bVoy->boltEntry(0x7F01 + BLIND_TABLE[_vm->_eventsManager._videoComputerBut4])._cMapResource; (*_vm->_graphicsManager._vPort)->setupViewPort(); _vm->_graphicsManager._backColors->startFade(); (*_vm->_graphicsManager._vPort)->_flags |= 8; _vm->_graphicsManager.flipPage(); _vm->_eventsManager.sWaitFlip(); while (!_vm->shouldQuit() && (_vm->_eventsManager._fadeStatus & 1)) _vm->_eventsManager.delay(1); _vm->_voy._field478 = -2; _vm->_soundManager.setVOCOffset(_vm->_voy._vocSecondsOffset * 11025); Common::String filename = _vm->_soundManager.getVOCFileName( _vm->_eventsManager._videoComputerBut4 + 159); _vm->_soundManager.startVOCPlay(filename); _vm->_voy._field478 |= 16; _vm->_eventsManager.startCursorBlink(); while (!_vm->shouldQuit() && !_vm->_voy._incriminate && _vm->_soundManager.getVOCStatus()) _vm->_eventsManager.delay(1); _vm->_voy._field478 |= 1; _vm->_soundManager.stopVOCPlay(); addAudioEventEnd(); _vm->_eventsManager.incrementTime(1); _vm->_eventsManager.incrementTime(1); _vm->_bVoy->freeBoltGroup(0x17F00); _vm->_voy._field478 = -17; _vm->_eventsManager._videoComputerBut4 = -1; _vm->_voy._field470 = 129; parseIndex = 999; } } dataP += 8; break; case 3: v2 = READ_LE_UINT16(dataP); if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { _vm->_eventsManager._videoComputerBut4 = READ_LE_UINT16(dataP + 2); _vm->_voy._field468 = READ_LE_UINT16(dataP + 4); _vm->_voy._field46A = READ_LE_UINT16(dataP + 6); if (_vm->_voy._RTVNum < _vm->_voy._field468 || (_vm->_voy._field468 + _vm->_voy._field46A) < _vm->_voy._RTVNum) { _vm->_eventsManager._videoComputerBut4 = -1; } else { _vm->_voy._vocSecondsOffset = _vm->_voy._RTVNum - _vm->_voy._field468; addAudioEventStart(); _vm->_voy._field478 &= ~1; _vm->_voy._field478 |= 0x10; _vm->playAVideo(_vm->_eventsManager._videoComputerBut4); _vm->_voy._field478 &= ~0x10; _vm->_voy._field478 |= 1; addVideoEventEnd(); _vm->_eventsManager.incrementTime(1); _vm->_eventsManager._videoComputerBut4 = -1; _vm->_playStamp1 = -1; if (_vm->_eventsManager._videoDead != -1) { _vm->_bVoy->freeBoltGroup(0x10E00); _vm->_eventsManager._videoDead = -1; (*_vm->_graphicsManager._vPort)->_flags |= 8; _vm->_graphicsManager.flipPage(); _vm->_eventsManager.sWaitFlip(); } _vm->_eventsManager._videoDead = -1; if (_field42 == 2 && _vm->_voy._incriminate == 0) { _vm->_voy._field470 = 132; parseIndex = 999; } else { _vm->_voy._field470 = 129; } } } dataP += 8; break; case 4: case 22: _vm->_eventsManager._videoComputerBut4 = READ_LE_UINT16(dataP) - 1; dataP += 2; if (id == 22) { int resolveIndex = READ_LE_UINT16(dataP); dataP += 2; _vm->_playStamp1 = _vm->_resolvePtr[resolveIndex]; } _vm->_voy._vocSecondsOffset = 0; _vm->_voy._field468 = _vm->_voy._RTVNum; _vm->_voy._field478 &= ~0x11; _vm->playAVideo(_vm->_eventsManager._videoComputerBut4); _vm->_voy._field478 |= 1; if (id != 2) { _vm->_eventsManager._videoComputerBut4 = -1; parseIndex = 999; } else { // TODO: Double-check this int count = _vm->_bVoy->getBoltGroup(_vm->_playStamp1)->_entries.size(); _vm->_soundManager.stopVOCPlay(); _vm->_eventsManager.getMouseInfo(); for (int i = 0; i < count; ++i) { pic = _vm->_bVoy->boltEntry(_vm->_playStamp1 + i * 2)._picResource; pal = _vm->_bVoy->boltEntry(_vm->_playStamp1 + i * 2 + 1)._cMapResource; (*_vm->_graphicsManager._vPort)->setupViewPort(pic); pal->startFade(); (*_vm->_graphicsManager._vPort)->_flags |= 8; _vm->_graphicsManager.flipPage(); _vm->_eventsManager.sWaitFlip(); while (!_vm->shouldQuit() && (_vm->_eventsManager._fadeStatus & 1)) _vm->_eventsManager.delay(1); if (i > 0) { _vm->_bVoy->freeBoltMember(_vm->_playStamp1 + i * 2); _vm->_bVoy->freeBoltMember(_vm->_playStamp1 + i * 2 + 1); } Common::String file = Common::String::format("news%d.voc", i + 1); _vm->_soundManager.startVOCPlay(file); while (!_vm->shouldQuit() && !_vm->_voy._incriminate && _vm->_soundManager.getVOCStatus()) { _vm->_eventsManager.delay(1); _vm->_eventsManager.getMouseInfo(); } _vm->_soundManager.stopVOCPlay(); if (i == (count - 1)) _vm->_eventsManager.delay(480); if (_vm->shouldQuit() || _vm->_voy._incriminate) break; } _vm->_bVoy->freeBoltGroup(_vm->_playStamp1); _vm->_playStamp1 = -1; _vm->_eventsManager._videoComputerBut4 = -1; parseIndex = 999; } break; case 5: v2 = READ_LE_UINT16(dataP); if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { _vm->_voy._field470 = 5; int count = READ_LE_UINT16(dataP + 2); _vm->_voy._field476 = READ_LE_UINT16(dataP + 4); if (_vm->_voy._field474 != count) { if (_vm->_voy._field474 > 1) _vm->_voy._field478 &= ~0x100; _vm->_voy._field474 = count; _vm->_eventsManager._videoComputerBut1 = LEVEL_M[count - 1]; _vm->_eventsManager._videoComputerNum = LEVEL_H[count - 1]; //_vm->_v2A0A2 = 0; _vm->_voy._RTVNum = 0; _vm->_voy._RTANum = 255; } _vm->_voy._delaySecs = (_vm->_voy._field474 == 6) ? 1 : 0; } dataP += 6; break; case 6: _vm->_voy._field470 = 6; v2 = READ_LE_UINT16(dataP); _vm->_playStamp1 = _vm->_resolvePtr[v2]; dataP += 2; break; case 7: v2 = READ_LE_UINT16(dataP); v3 = READ_LE_UINT16(dataP + 2) - 1; if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { int idx = 0; while (_vm->_voy._arr1[idx][v3] != 9999) ++idx; v2 = READ_LE_UINT16(dataP + 4); _vm->_voy._arr1[idx][v3] = v2; _vm->_voy._arr2[idx][v3] = v2 + READ_LE_UINT16(dataP + 6) - 2; } dataP += 8; break; case 8: v2 = READ_LE_UINT16(dataP); v3 = READ_LE_UINT16(dataP + 2) - 1; if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { int idx = 0; while (_vm->_voy._arr3[idx][v3] != 9999) ++idx; v2 = READ_LE_UINT16(dataP + 4); _vm->_voy._arr3[idx][v3] = v2; _vm->_voy._arr4[idx][v3] = v2 + READ_LE_UINT16(dataP + 6) - 2; } dataP += 8; break; case 9: v2 = READ_LE_UINT16(dataP); v3 = READ_LE_UINT16(dataP + 2) - 1; if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { int idx = 0; while (_vm->_voy._arr5[idx][v3] != 9999) ++idx; v2 = READ_LE_UINT16(dataP + 4); _vm->_voy._arr5[idx][v3] = v2; _vm->_voy._arr6[idx][v3] = v2 + READ_LE_UINT16(dataP + 6) - 2; } dataP += 8; break; case 10: if (_vm->_iForceDeath == -1) { int randomVal; do { randomVal = _vm->getRandomNumber(3) + 1; } while (randomVal == _vm->_voy._field4380); _vm->_voy._field4380 = randomVal; WRITE_LE_UINT16(_vm->_controlPtr->_ptr + 4, randomVal); } else { _vm->_voy._field4380 = _vm->_iForceDeath; WRITE_LE_UINT16(_vm->_controlPtr->_ptr + 4, _vm->_iForceDeath); } _vm->saveLastInplay(); break; case 11: _vm->_voy._field478 = 2; break; case 12: v2 = READ_LE_UINT16(dataP); if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { _vm->_voy._field47A = _vm->_resolvePtr[READ_LE_UINT16(dataP + 2)]; _vm->_voy._arr7[READ_LE_UINT16(dataP + 4) - 1] = 1; } dataP += 6; break; case 13: v2 = READ_LE_UINT16(dataP); if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) { _vm->_voy._field4E2 = READ_LE_UINT16(dataP + 2); _vm->_voy._field4EC = READ_LE_UINT16(dataP + 4); _vm->_voy._field4EE = READ_LE_UINT16(dataP + 6); _vm->_voy._rect4E4.left = COMP_BUT_TABLE[_vm->_voy._field4E2 * 4]; _vm->_voy._rect4E4.top = COMP_BUT_TABLE[_vm->_voy._field4E2 * 4 + 1]; _vm->_voy._rect4E4.right = COMP_BUT_TABLE[_vm->_voy._field4E2 * 4 + 2]; _vm->_voy._rect4E4.bottom = COMP_BUT_TABLE[_vm->_voy._field4E2 * 4 + 3]; } dataP += 8; break; case 14: _vm->_playStamp1 = 2048; _vm->_voy._field470 = 130; break; case 15: _vm->_playStamp1 = (_vm->_voy._field4382 - 1) * 8 + 0x7700; _vm->_voy._field47A = ((READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) - 1) << 8) + 0x7B00; pic = _vm->_bVoy->boltEntry(_vm->_playStamp1)._picResource; _cmd14Pal = _vm->_bVoy->boltEntry(_vm->_playStamp1 + 1)._cMapResource; (*_vm->_graphicsManager._vPort)->setupViewPort(pic); _cmd14Pal->startFade(); (*_vm->_graphicsManager._vPort)->_flags |= 8; _vm->_graphicsManager.flipPage(); _vm->_eventsManager.sWaitFlip(); while (!_vm->shouldQuit() && (_vm->_eventsManager._fadeStatus & 1)) _vm->_eventsManager.delay(1); _vm->_eventsManager.getMouseInfo(); for (int idx = 1; idx < 4; ++idx) { if (idx == 3) { pic = _vm->_bVoy->boltEntry(_vm->_voy._field47A)._picResource; _cmd14Pal = _vm->_bVoy->boltEntry(_vm->_voy._field47A + 1)._cMapResource; } else { pic = _vm->_bVoy->boltEntry(_vm->_playStamp1 + idx * 2)._picResource; _cmd14Pal = _vm->_bVoy->boltEntry(_vm->_playStamp1 + idx * 2 + 1)._cMapResource; } (*_vm->_graphicsManager._vPort)->setupViewPort(pic); _cmd14Pal->startFade(); (*_vm->_graphicsManager._vPort)->_flags |= 8; _vm->_graphicsManager.flipPage(); _vm->_eventsManager.sWaitFlip(); while (!_vm->shouldQuit() && (_vm->_eventsManager._fadeStatus & 1)) _vm->_eventsManager.delay(1); _vm->_bVoy->freeBoltMember(_vm->_playStamp1 + (idx - 1) * 2); _vm->_bVoy->freeBoltMember(_vm->_playStamp1 + (idx - 1) * 2 + 1); Common::String fname = Common::String::format("news%d.voc", idx); while (!_vm->shouldQuit() && !_vm->_voy._incriminate && _vm->_soundManager.getVOCStatus()) _vm->_eventsManager.delay(1); _vm->_soundManager.stopVOCPlay(); if (idx == 3) _vm->_eventsManager.delay(3); if (_vm->shouldQuit() || _vm->_voy._incriminate) break; } _vm->_bVoy->freeBoltGroup(_vm->_playStamp1); _vm->_bVoy->freeBoltGroup(_vm->_voy._field47A); _vm->_playStamp1 = -1; _vm->_voy._field47A = -1; break; case 16: _vm->_voy._field470 = 16; break; case 17: _vm->_voy._field470 = 17; break; case 18: v2 = READ_LE_UINT16(dataP); v3 = READ_LE_UINT16(dataP + 2); if (v2 == 0 || READ_LE_UINT16(_vm->_controlPtr->_ptr + 4) == 0) _vm->_voy._field4F2 = v3; dataP += 4; break; case 19: _vm->_voy._field472 = 140; _vm->loadTheApt(); _vm->_voy._field472 = 141; _vm->freeTheApt(); break; case 20: _vm->_voy._field472 = -1; _vm->loadTheApt(); _vm->_voy._field472 = 141; _vm->freeTheApt(); break; case 21: _vm->_voy._field472 = -1; _vm->loadTheApt(); _vm->_voy._field472 = 140; _vm->freeTheApt(); break; case 23: _vm->_voy._field474 = 17; _vm->_voy._field472 = -1; _vm->loadTheApt(); _vm->_voy._field472 = 144; _vm->freeTheApt(); break; default: break; } } } const byte *ThreadResource::cardPerform(const byte *card) { int var7 = 0; uint32 varC = 0; const byte *p, *p2; byte *pDest; uint16 id = *card++; int varD = 5; uint32 v2; int v3; byte bVal; uint32 idx1, idx2; switch (id) { case 1: v2 = READ_LE_UINT32(card); card += 4; WRITE_LE_UINT32(_vm->_controlPtr->_ptr + (*card << 2), v2); ++card; break; case 2: v2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2)), WRITE_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2), v2); break; case 3: v2 = READ_LE_UINT32(card); card += 4; WRITE_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2), v2); break; case 4: v2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2)); WRITE_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2), v2); break; case 5: v2 = READ_LE_UINT32(card); card += 4; pDest = _vm->_controlPtr->_ptr + (*card++ << 2); WRITE_LE_UINT32(pDest, READ_LE_UINT32(pDest) - v2); break; case 6: idx1 = *card++; idx2 = *card++; v2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + idx2); pDest = _vm->_controlPtr->_ptr + idx1; WRITE_LE_UINT32(pDest, READ_LE_UINT32(pDest) - v2); break; case 7: v3 = *card++; v2 = READ_LE_UINT32(card); card += 4; pDest = _vm->_controlPtr->_ptr + (v3 << 2); WRITE_LE_UINT32(pDest, READ_LE_UINT32(pDest) * v2); break; case 8: idx1 = *card++; idx2 = *card++; pDest = _vm->_controlPtr->_ptr + (idx1 << 2); p2 = _vm->_controlPtr->_ptr + (idx2 << 2); WRITE_LE_UINT32(pDest, READ_LE_UINT32(pDest) * READ_LE_UINT32(p2)); break; case 9: idx1 = *card++; v2 = READ_LE_UINT32(card); card += 4; pDest = _vm->_controlPtr->_ptr + (idx1 << 2); WRITE_LE_UINT32(pDest, READ_LE_UINT32(pDest) / v2); break; case 10: idx1 = *card++; idx2 = *card++; pDest = _vm->_controlPtr->_ptr + (idx1 << 2); p2 = _vm->_controlPtr->_ptr + (idx2 << 2); WRITE_LE_UINT32(pDest, READ_LE_UINT32(pDest) / READ_LE_UINT32(p2)); break; case 11: v2 = READ_LE_UINT32(card); card += 4; v2 = _vm->getRandomNumber(v2 - 1) + 1; WRITE_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2), v2); break; case 17: _vm->_glGoScene = READ_LE_UINT16(card); card += 2; _vm->_glGoStack = -1; break; case 18: v2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*card++ << 2)); _vm->_glGoScene = getStateFromID(v2); break; case 19: _vm->_glGoScene = READ_LE_UINT32(card); card += 4; _vm->_glGoStack = READ_LE_UINT16(card); card += 2; break; case 22: case 23: case 26: case 27: varD -= 3; // Deliberate fall-through case 20: case 21: case 24: case 25: bVal = card[varD]; if (bVal == 61) { if (cardPerform2(card, id)) { card += varD; while (*card != 30 && *card != 29) card = cardPerform(card); if (*card == 29) { int count = 1; while (count > 0) { card = getNextRecord(card); if (*card == 30) --count; if (*card >= 21 && *card <= 28) ++count; } } } else { card += varD; int count = 1; while (count > 0) { card = getNextRecord(card); if (*card == 29 || *card == 30) --count; if (*card < 21 || *card > 28) continue; const byte *nextP = getNextRecord(card + 2); if (*nextP == 61) ++count; } } ++card; } else { if (cardPerform2(card, id)) { card += varD; card = cardPerform(card); while (*card++ != 61) ; } else { card += varD; while (*card != 61 && *card != 29) ++card; } } break; case 41: bVal = *card++; assert(bVal < 8); _fieldA[bVal] = READ_LE_UINT32(card); card += 4; _field2A[bVal] = READ_LE_UINT16(card); card += 2; case 45: _field3A = _field46; _field3E = _controlIndex; break; case 46: _vm->_glGoScene = _field3A; _vm->_glGoStack = _field3E; _field3A = -1; _field3E = -1; break; case 51: setButtonFlag(READ_LE_UINT16(card), 64); break; case 52: clearButtonFlag(READ_LE_UINT16(card), 64); break; default: break; } return card; } bool ThreadResource::cardPerform2(const byte *pSrc, int cardCmdId) { uint32 vLong, vLong2; switch (cardCmdId) { case 21: vLong = READ_LE_UINT32(pSrc + 1); return READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)) == vLong; case 22: vLong = READ_LE_UINT32(pSrc + 1); return READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)) != vLong; case 23: vLong = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)); vLong2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*(pSrc + 1) << 2)); return vLong == vLong2; case 24: vLong = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)); vLong2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*(pSrc + 1) << 2)); return vLong != vLong2; case 25: vLong = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)); vLong2 = READ_LE_UINT32(pSrc + 1); return vLong < vLong2; case 26: vLong = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)); vLong2 = READ_LE_UINT32(pSrc + 1); return vLong > vLong2; case 27: vLong = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)); vLong2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*(pSrc + 1) << 2)); return vLong < vLong2; case 28: vLong = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*pSrc << 2)); vLong2 = READ_LE_UINT32(_vm->_controlPtr->_ptr + (*(pSrc + 1) << 2)); return vLong > vLong2; default: return false; } } int ThreadResource::doApt() { warning("TODO: doApt"); return 0; } void ThreadResource::doRoom() { warning("TODO: doRoom"); } int ThreadResource::doInterface() { warning("TODO: doInterface"); return 0; } void ThreadResource::addAudioEventStart() { _vm->_voy._events.push_back(VoyeurEvent(_vm->_eventsManager._videoComputerNum, _vm->_eventsManager._videoComputerBut1, _vm->_voy._delaySecs, 2, _vm->_eventsManager._videoComputerBut4, _vm->_voy._vocSecondsOffset, _vm->_eventsManager._videoDead)); } void ThreadResource::addAudioEventEnd() { error("TODO: addAudioEventEnd"); } void ThreadResource::addVideoEventEnd() { error("TODO: addVideoEventEnd"); } bool ThreadResource::goToStateID(int stackId, int sceneId) { debugC(DEBUG_BASIC, kDebugScripts, "goToStateID - %d, %d", stackId, sceneId); // Save current stack savePrevious(); if (_controlIndex == stackId || stackId == -1 || loadAStack(stackId)) { // Now in the correct state _threadId = getStateFromID(sceneId); if (_threadId != -1) { return doState(); } else { _threadId = _field4; _controlIndex = _field6; } } return false; } bool ThreadResource::goToState(int stackId, int sceneId) { debugC(DEBUG_BASIC, kDebugScripts, "goToState - %d, %d", stackId, sceneId); savePrevious(); if (stackId == -1 || loadAStack(stackId)) { if (sceneId != -1) _threadId = sceneId; return doState(); } else { return false; } } void ThreadResource::savePrevious() { if (_field4 == _threadId && _controlIndex == _field6) { _flags &= ~1; } else { _flags |= 1; _field4 = _threadId; _field6 = _controlIndex; } } void ThreadResource::setButtonFlag(int idx, byte bits) { _buttonFlags[idx] |= bits; } void ThreadResource::clearButtonFlag(int idx, byte bits) { _buttonFlags[idx] &= ~bits; } } // End of namespace Voyeur