diff options
Diffstat (limited to 'engines/voyeur/files_threads.cpp')
-rw-r--r-- | engines/voyeur/files_threads.cpp | 1731 |
1 files changed, 1731 insertions, 0 deletions
diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp new file mode 100644 index 0000000000..700944f7ef --- /dev/null +++ b/engines/voyeur/files_threads.cpp @@ -0,0 +1,1731 @@ +/* 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::_useCount[8]; + +void ThreadResource::init() { + Common::fill(&_useCount[0], &_useCount[8], 0); +} + +ThreadResource::ThreadResource(BoltFilesState &state, const byte *src):_vm(state._vm) { + _stateId = READ_LE_UINT16(&src[0]); + _stackId = READ_LE_UINT16(&src[0]); + _savedStateId = READ_LE_UINT16(&src[0]); + _savedStackId = READ_LE_UINT16(&src[0]); + _ctlPtr = nullptr; + _aptPos = Common::Point(-1, -1); + + _newStateId = -1; + _newStackId = -1; + _stateFlags = 0; + _stateCount = 0; + _parseCount = 0; + _nextStateId = 0; + _threadInfoPtr = nullptr; + _playCommandsPtr = nullptr; +} + +void ThreadResource::initThreadStruct(int idx, int id) { + _stackId = -1; + if (loadAStack(idx)) { + _savedStateId = _savedStackId = -1; + _stateId = id; + _newStateId = -1; + _newStackId = -1; + + doState(); + } +} + +bool ThreadResource::loadAStack(int stackId) { + if (_vm->_stampFlags & 1) { + if (stackId < 0) + error("loadAStack() - Invalid stackId %d", stackId); + + unloadAStack(_stackId); + if (!_useCount[stackId]) { + BoltEntry &boltEntry = _vm->_stampLibPtr->boltEntry(_vm->_controlPtr->_memberIds[stackId]); + if (!boltEntry._data) + return false; + + _vm->_controlPtr->_entries[stackId] = boltEntry._data; + } + + ++_useCount[stackId]; + } + + _ctlPtr = _vm->_controlPtr->_entries[stackId]; + _stackId = stackId; + return true; +} + +void ThreadResource::unloadAStack(int stackId) { + if (stackId < 0) + return; + + if ((_vm->_stampFlags & 1) && _useCount[stackId]) { + if (--_useCount[stackId] == 0) { + _vm->_stampLibPtr->freeBoltMember(_vm->_controlPtr->_memberIds[stackId]); + } + } +} + +bool ThreadResource::doState() { + if (!getStateInfo()) + return false; + + getButtonsFlags(); + + _vm->_glGoState = -1; + _vm->_glGoStack = -1; + + performOpenCard(); + if (_stateFlags & 1) { + return chooseSTAMPButton(_vm->getRandomNumber(_stateCount - 1)); + } else { + return true; + } +} + +bool ThreadResource::getStateInfo() { + int id = READ_LE_UINT16(_ctlPtr); + + if (id <= _stateId) { + return false; + } else { + uint32 fld = READ_LE_UINT32(_ctlPtr + 2); + fld += _stateId << 3; + _nextStateId = READ_LE_UINT32(_ctlPtr + fld + 4); + + fld = READ_LE_UINT32(_ctlPtr + fld); + byte *baseP = _ctlPtr + fld; + _stateCount = READ_LE_UINT16(baseP); + _stateFlags = READ_LE_UINT16(baseP + 2); + _parseCount = READ_LE_UINT16(baseP + 4); + + _playCommandsPtr = getDataOffset(); + _playCommandsPtr += (READ_LE_UINT32(baseP + 6) / 2) << 1; + + _threadInfoPtr = baseP + 10; + + getButtonsText(); + return true; + } +} + +byte *ThreadResource::getDataOffset() { + uint32 offset = READ_LE_UINT32(_ctlPtr + 10); + return _ctlPtr + offset; +} + +void ThreadResource::getButtonsText() { + int idx = 0; + + for (const byte *p = _threadInfoPtr; *p != 0x49; p = getNextRecord(p)) { + if (*p == 0xC0) { + ++p; + if (*p++ & 0x80) { + assert(idx < 63); + p += 4; + } + + ++idx; + } + } +} + +void ThreadResource::getButtonsFlags() { + int idx = 0; + + for (const byte *p = _threadInfoPtr; *p != 0x49; p = getNextRecord(p)) { + if (*p == 0xC0) { + if (*++p & 0x20) + _stateFlags |= 2; + + _buttonFlags[idx] = *p++; + _buttonIds[idx] = *p++; + + if (_buttonFlags[idx] & 0x80) + p += 4; + + ++idx; + } + } +} + +void ThreadResource::unloadAllStacks(VoyeurEngine *vm) { + if (vm->_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 = _threadInfoPtr; *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 = _threadInfoPtr; 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 = _threadInfoPtr; *p != 0x49; p = getNextRecord(p)) { + if (*p == 0x48) { + cardAction(p + 1); + return; + } + } +} + +void ThreadResource::cardAction(const byte *card) { + _vm->_glGoState = -1; + _vm->_glGoStack = -1; + + // Loop to perform card commands + while (!_vm->shouldQuit() && *card < 70 && _vm->_glGoState == -1) { + card = cardPerform(card); + } +} + +bool ThreadResource::chooseSTAMPButton(int buttonId) { + for (int idx = 0; idx < _stateCount; ++idx) { + if (_buttonIds[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->_glGoState); + } + + while (!_vm->shouldQuit() && _vm->_glGoState != -1 && flag) { + doSTAMPCardAction(); + flag = goToState(-1, _vm->_glGoState); + } + + return flag; + } + } + + return false; +} + +void ThreadResource::parsePlayCommands() { + _vm->_voy->_playStampMode = -1; + _vm->_voy->_audioVisualStartTime = 0; + _vm->_voy->_audioVisualDuration = 0; + _vm->_voy->_boltGroupId2 = -1; + _vm->_voy->_computerTextId = -1; + _vm->_voy->_eventFlags &= ~EVTFLAG_8; + _vm->_eventsManager->_videoDead = -1; + + // Reset hotspot data + _vm->_voy->_videoHotspotTimes.reset(); + _vm->_voy->_audioHotspotTimes.reset(); + _vm->_voy->_evidenceHotspotTimes.reset(); + Common::fill(&_vm->_voy->_roomHotspotsEnabled[0], &_vm->_voy->_roomHotspotsEnabled[20], false); + byte *dataP = _playCommandsPtr; + 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 + 1, _parseCount, id); + dataP += 2; + + switch (id) { + case 1: + _vm->_currentVocId = READ_LE_UINT16(dataP); + dataP += 2; + break; + + case 2: + // Play an audio event + v2 = READ_LE_UINT16(dataP); + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + _vm->_audioVideoId = READ_LE_UINT16(dataP + 2) - 1; + _vm->_voy->_audioVisualStartTime = READ_LE_UINT16(dataP + 4); + _vm->_voy->_audioVisualDuration = READ_LE_UINT16(dataP + 6); + + if (_vm->_voy->_RTVNum < _vm->_voy->_audioVisualStartTime || + (_vm->_voy->_audioVisualStartTime + _vm->_voy->_audioVisualDuration) < _vm->_voy->_RTVNum) { + _vm->_audioVideoId = -1; + } else { + _vm->_voy->_vocSecondsOffset = _vm->_voy->_RTVNum - _vm->_voy->_audioVisualStartTime; + _vm->_voy->addAudioEventStart(); + + // Play the audio + assert(_vm->_audioVideoId < 38); + _vm->playAudio(_vm->_audioVideoId); + + _vm->_voy->addAudioEventEnd(); + _vm->_eventsManager->incrementTime(1); + _vm->_eventsManager->incrementTime(1); + _vm->_audioVideoId = -1; + parseIndex = 999; + } + } + + dataP += 8; + break; + + case 3: + // Play a video event + v2 = READ_LE_UINT16(dataP); + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + _vm->_audioVideoId = READ_LE_UINT16(dataP + 2) - 1; + _vm->_voy->_audioVisualStartTime = READ_LE_UINT16(dataP + 4); + _vm->_voy->_audioVisualDuration = READ_LE_UINT16(dataP + 6); + + if (_vm->_voy->_RTVNum < _vm->_voy->_audioVisualStartTime || + (_vm->_voy->_audioVisualStartTime + _vm->_voy->_audioVisualDuration) < _vm->_voy->_RTVNum) { + _vm->_audioVideoId = -1; + } else { + _vm->_voy->_vocSecondsOffset = _vm->_voy->_RTVNum - _vm->_voy->_audioVisualStartTime; + _vm->_voy->addVideoEventStart(); + _vm->_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; + _vm->_voy->_eventFlags |= EVTFLAG_RECORDING; + _vm->playAVideo(_vm->_audioVideoId); + + _vm->_voy->_eventFlags &= ~EVTFLAG_RECORDING; + _vm->_voy->_eventFlags |= EVTFLAG_TIME_DISABLED; + _vm->_voy->addVideoEventEnd(); + _vm->_eventsManager->incrementTime(1); + + _vm->_audioVideoId = -1; + _vm->_playStampGroupId = -1; + + if (_vm->_eventsManager->_videoDead != -1) { + _vm->_bVoy->freeBoltGroup(0xE00); + _vm->_eventsManager->_videoDead = -1; + _vm->flipPageAndWait(); + } + + _vm->_eventsManager->_videoDead = -1; + if (_stateCount == 2 && _vm->_eventsManager->_mouseClicked == 0) { + _vm->_voy->_playStampMode = 132; + parseIndex = 999; + } else { + _vm->_voy->_playStampMode = 129; + } + } + } + + dataP += 8; + break; + + case 4: + case 22: + // Case 22: Endgame news reports + _vm->_audioVideoId = READ_LE_UINT16(dataP) - 1; + dataP += 2; + + if (id == 22) { + int resolveIndex = READ_LE_UINT16(dataP); + dataP += 2; + _vm->_playStampGroupId = _vm->_resolvePtr[resolveIndex]; + } + + _vm->_voy->_vocSecondsOffset = 0; + _vm->_voy->_audioVisualStartTime = _vm->_voy->_RTVNum; + _vm->_voy->_eventFlags &= ~(EVTFLAG_TIME_DISABLED | EVTFLAG_RECORDING); + _vm->playAVideo(_vm->_audioVideoId); + _vm->_voy->_eventFlags |= EVTFLAG_TIME_DISABLED; + + if (id != 22) { + _vm->_audioVideoId = -1; + parseIndex = 999; + } else { + int count = _vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)->_entries.size() / 2; + _vm->_soundManager->stopVOCPlay(); + _vm->_eventsManager->getMouseInfo(); + + for (int i = 0; i < count; ++i) { + pic = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + i * 2)._picResource; + pal = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + i * 2 + 1)._cMapResource; + + _vm->_graphicsManager->_vPort->setupViewPort(pic); + pal->startFade(); + + _vm->flipPageAndWaitForFade(); + + if (i > 0) { + _vm->_bVoy->freeBoltMember(_vm->_playStampGroupId + i * 2); + _vm->_bVoy->freeBoltMember(_vm->_playStampGroupId + i * 2 + 1); + } + + Common::String file = Common::String::format("news%d.voc", i + 1); + _vm->_soundManager->startVOCPlay(file); + + while (!_vm->shouldQuit() && !_vm->_eventsManager->_mouseClicked && + _vm->_soundManager->getVOCStatus()) { + _vm->_eventsManager->delayClick(1); + _vm->_eventsManager->getMouseInfo(); + } + + _vm->_soundManager->stopVOCPlay(); + + if (i == (count - 1)) + _vm->_eventsManager->delayClick(480); + + if (_vm->shouldQuit() || _vm->_eventsManager->_mouseClicked) + break; + } + + _vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId); + _vm->_playStampGroupId = -1; + _vm->_audioVideoId = -1; + parseIndex = 999; + } + break; + + case 5: + // Check whether transition to a given time period is allowed, and + // if so, load the time information for the new time period + v2 = READ_LE_UINT16(dataP); + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + _vm->_voy->_playStampMode = 5; + int count = READ_LE_UINT16(dataP + 2); + _vm->_voy->_RTVLimit = READ_LE_UINT16(dataP + 4); + + if (_vm->_voy->_transitionId != count) { + if (_vm->_voy->_transitionId > 1) + _vm->_voy->_eventFlags &= ~EVTFLAG_100; + + _vm->_voy->_transitionId = count; + _vm->_gameMinute = LEVEL_M[count - 1]; + _vm->_gameHour = LEVEL_H[count - 1]; + //_vm->_v2A0A2 = 0; + _vm->_voy->_RTVNum = 0; + _vm->_voy->_RTANum = 255; + } + + _vm->_voy->_isAM = (_vm->_voy->_transitionId == 6); + } + + dataP += 6; + break; + + case 6: + _vm->_voy->_playStampMode = 6; + v2 = READ_LE_UINT16(dataP); + _vm->_playStampGroupId = _vm->_resolvePtr[v2]; + dataP += 2; + break; + + case 7: + // Load the video event scene hotspot times data + v2 = READ_LE_UINT16(dataP); + v3 = READ_LE_UINT16(dataP + 2) - 1; + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + int idx = 0; + while (_vm->_voy->_videoHotspotTimes._min[idx][v3] != 9999) + ++idx; + + v2 = READ_LE_UINT16(dataP + 4); + _vm->_voy->_videoHotspotTimes._min[idx][v3] = v2; + _vm->_voy->_videoHotspotTimes._max[idx][v3] = v2 + READ_LE_UINT16(dataP + 6) - 2; + } + + dataP += 8; + break; + + case 8: + // Load the audio event scene hotspot times data + v2 = READ_LE_UINT16(dataP); + v3 = READ_LE_UINT16(dataP + 2) - 1; + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + int idx = 0; + while (_vm->_voy->_audioHotspotTimes._min[idx][v3] != 9999) + ++idx; + + v2 = READ_LE_UINT16(dataP + 4); + _vm->_voy->_audioHotspotTimes._min[idx][v3] = v2; + _vm->_voy->_audioHotspotTimes._max[idx][v3] = v2 + READ_LE_UINT16(dataP + 6) - 2; + } + + dataP += 8; + break; + + case 9: + // Load up evidence event scene hotspot times data + v2 = READ_LE_UINT16(dataP); + v3 = READ_LE_UINT16(dataP + 2) - 1; + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + int idx = 0; + while (_vm->_voy->_evidenceHotspotTimes._min[idx][v3] != 9999) + ++idx; + + v2 = READ_LE_UINT16(dataP + 4); + _vm->_voy->_evidenceHotspotTimes._min[idx][v3] = v2; + _vm->_voy->_evidenceHotspotTimes._max[idx][v3] = v2 + READ_LE_UINT16(dataP + 6) - 2; + } + + dataP += 8; + break; + + case 10: + // Pick the person who is to die, during startup + if (_vm->_iForceDeath == -1) { + // No specific person has been preset to be killed, so pick one randomly. + // The loop below was used because the victim was persisted from the previous + // play-through, so it ensured that a different victim is picked. + int randomVal; + do { + randomVal = _vm->getRandomNumber(3) + 1; + } while (randomVal == _vm->_voy->_victimNumber); + + _vm->_voy->_victimNumber = randomVal; + _vm->_controlPtr->_state->_victimIndex = randomVal; + } else { + // Player has seen something that locks in the character to die + _vm->_voy->_victimNumber = _vm->_iForceDeath; + _vm->_controlPtr->_state->_victimIndex = _vm->_iForceDeath; + } + + _vm->saveLastInplay(); + break; + + case 11: + _vm->_voy->_eventFlags |= EVTFLAG_2; + break; + + case 12: + v2 = READ_LE_UINT16(dataP); + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + _vm->_voy->_boltGroupId2 = _vm->_resolvePtr[READ_LE_UINT16(dataP + 2)]; + _vm->_voy->_roomHotspotsEnabled[READ_LE_UINT16(dataP + 4) - 1] = true; + } + + dataP += 6; + break; + + case 13: + v2 = READ_LE_UINT16(dataP); + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) { + _vm->_voy->_computerTextId = READ_LE_UINT16(dataP + 2) - 1; + _vm->_voy->_computerTimeMin = READ_LE_UINT16(dataP + 4); + _vm->_voy->_computerTimeMax = READ_LE_UINT16(dataP + 6); + + _vm->_voy->_computerScreenRect.left = COMPUTER_SCREEN_TABLE[_vm->_voy->_computerTextId * 4]; + _vm->_voy->_computerScreenRect.top = COMPUTER_SCREEN_TABLE[_vm->_voy->_computerTextId * 4 + 1]; + _vm->_voy->_computerScreenRect.right = COMPUTER_SCREEN_TABLE[_vm->_voy->_computerTextId * 4 + 2]; + _vm->_voy->_computerScreenRect.bottom = COMPUTER_SCREEN_TABLE[_vm->_voy->_computerTextId * 4 + 3]; + } + + dataP += 8; + break; + + case 14: + _vm->_playStampGroupId = 2048; + _vm->_voy->_playStampMode = 130; + break; + + case 15: + _vm->showEndingNews(); + break; + + case 16: + _vm->_voy->_playStampMode = 16; + break; + + case 17: + _vm->_voy->_playStampMode = 17; + break; + + case 18: + // Called during the murder (Sunday 10:30PM) time period, to specify the + // time expired point at which the murder takes place + v2 = READ_LE_UINT16(dataP); + v3 = READ_LE_UINT16(dataP + 2); + + if (v2 == 0 || _vm->_controlPtr->_state->_victimIndex == v2) + _vm->_voy->_murderThreshold = v3; + + dataP += 4; + break; + + case 19: + _vm->_voy->_aptLoadMode = 140; + loadTheApt(); + _vm->_voy->_aptLoadMode = 141; + freeTheApt(); + break; + + case 20: + _vm->_voy->_aptLoadMode = -1; + loadTheApt(); + _vm->_voy->_aptLoadMode = 141; + freeTheApt(); + break; + + case 21: + _vm->_voy->_aptLoadMode = -1; + loadTheApt(); + _vm->_voy->_aptLoadMode = 140; + freeTheApt(); + break; + + case 23: + _vm->_voy->_transitionId = 17; + _vm->_voy->_aptLoadMode = -1; + loadTheApt(); + _vm->_voy->_aptLoadMode = 144; + freeTheApt(); + break; + + default: + break; + } + } +} + +const byte *ThreadResource::cardPerform(const byte *card) { + uint16 id = *card++; + int subId = 5; + uint32 v2; + byte bVal; + uint32 idx1, idx2; + debugC(DEBUG_BASIC, kDebugScripts, "cardPerform - %d", id); + + switch (id) { + case 1: + v2 = READ_LE_UINT32(card); + card += 4; + _vm->_controlPtr->_state->_vals[*card++] = v2; + break; + + case 2: + v2 = _vm->_controlPtr->_state->_vals[*card++]; + _vm->_controlPtr->_state->_vals[*card++] = v2; + break; + + case 3: + v2 = READ_LE_UINT32(card); + card += 4; + _vm->_controlPtr->_state->_vals[*card++] = v2; + break; + + case 4: + v2 = _vm->_controlPtr->_state->_vals[*card++]; + _vm->_controlPtr->_state->_vals[*card++] = v2; + break; + + case 5: { + v2 = READ_LE_UINT32(card); + card += 4; + int &v = _vm->_controlPtr->_state->_vals[*card++]; + v -= v2; + break; + } + + case 6: { + idx1 = *card++; + idx2 = *card++; + + v2 = _vm->_controlPtr->_state->_vals[idx1]; + int &v = _vm->_controlPtr->_state->_vals[idx2]; + v -= v2; + break; + } + + case 7: { + int v3 = *card++; + v2 = READ_LE_UINT32(card); + card += 4; + int &v = _vm->_controlPtr->_state->_vals[v3]; + v *= v2; + break; + } + + case 8: { + idx1 = *card++; + idx2 = *card++; + + int &v1 = _vm->_controlPtr->_state->_vals[idx1]; + v2 = _vm->_controlPtr->_state->_vals[idx2]; + v1 *= v2; + break; + } + + case 9: { + idx1 = *card++; + v2 = READ_LE_UINT32(card); + card += 4; + + int &v = _vm->_controlPtr->_state->_vals[idx1]; + v /= v2; + break; + } + + case 10: { + idx1 = *card++; + idx2 = *card++; + + int &v1 = _vm->_controlPtr->_state->_vals[idx1]; + v2 = _vm->_controlPtr->_state->_vals[idx2]; + v1 /= v2; + break; + } + + case 11: + v2 = READ_LE_UINT32(card); + card += 4; + v2 = _vm->getRandomNumber(v2 - 1) + 1; + _vm->_controlPtr->_state->_vals[*card++] = v2; + break; + + case 17: + _vm->_glGoState = READ_LE_UINT16(card); + card += 2; + _vm->_glGoStack = -1; + break; + + case 18: + v2 = _vm->_controlPtr->_state->_vals[*card++]; + _vm->_glGoState = getStateFromID(v2); + break; + + case 19: + _vm->_glGoState = READ_LE_UINT32(card); + card += 4; + _vm->_glGoStack = READ_LE_UINT16(card); + card += 2; + break; + + case 23: + case 24: + case 27: + case 28: + subId -= 3; + // Deliberate fall-through + + case 21: + case 22: + case 25: + case 26: + bVal = card[subId]; + if (bVal == 61) { + if (cardPerform2(card, id)) { + card += subId; + 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 += subId; + 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 += subId; + card = cardPerform(card); + while (*card++ != 61) ; + } else { + card += subId; + while (*card != 61 && *card != 29) + ++card; + } + } + break; + + case 41: + bVal = *card++; + assert(bVal < 8); + card += 6; + break; + + case 45: + _newStateId = _nextStateId; + _newStackId = _stackId; + break; + + case 46: + _vm->_glGoState = _newStateId; + _vm->_glGoStack = _newStackId; + _newStateId = -1; + _newStackId = -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) { + int vLong, vLong2; + + switch (cardCmdId) { + case 21: + vLong = (int32)READ_LE_UINT32(pSrc + 1); + return _vm->_controlPtr->_state->_vals[*pSrc] == vLong; + + case 22: + vLong = (int32)READ_LE_UINT32(pSrc + 1); + return _vm->_controlPtr->_state->_vals[*pSrc] != vLong; + + case 23: + vLong = _vm->_controlPtr->_state->_vals[*pSrc]; + vLong2 = _vm->_controlPtr->_state->_vals[*(pSrc + 1)]; + return vLong == vLong2; + + case 24: + vLong = _vm->_controlPtr->_state->_vals[*pSrc]; + vLong2 = _vm->_controlPtr->_state->_vals[*(pSrc + 1)]; + return vLong != vLong2; + + case 25: + vLong = _vm->_controlPtr->_state->_vals[*pSrc]; + vLong2 = (int32)READ_LE_UINT32(pSrc + 1); + return vLong < vLong2; + + case 26: + vLong = _vm->_controlPtr->_state->_vals[*pSrc]; + vLong2 = (int32)READ_LE_UINT32(pSrc + 1); + return vLong > vLong2; + + case 27: + vLong = _vm->_controlPtr->_state->_vals[*pSrc]; + vLong2 = _vm->_controlPtr->_state->_vals[*(pSrc + 1)]; + return vLong < vLong2; + + case 28: + vLong = _vm->_controlPtr->_state->_vals[*pSrc]; + vLong2 = _vm->_controlPtr->_state->_vals[*(pSrc + 1)]; + return vLong > vLong2; + + default: + return false; + } +} + +int ThreadResource::doApt() { + loadTheApt(); + + _vm->_currentVocId = 151; + _vm->_voy->_viewBounds = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._rectResource; + Common::Array<RectEntry> &hotspots = _vm->_bVoy->boltEntry( + _vm->_playStampGroupId + 1)._rectResource->_entries; + _vm->_eventsManager->getMouseInfo(); + + // Very first time apartment is shown, start the phone message + if (_aptPos.x == -1) { + _aptPos.x = hotspots[2].left; + _aptPos.y = hotspots[2].top; + _vm->_currentVocId = 153; + } + + if (_vm->_voy->_playStampMode == 16) { + hotspots[0].left = 999; + hotspots[3].left = 999; + _aptPos.x = hotspots[4].left + 28; + _aptPos.y = hotspots[4].top + 28; + } + + _vm->_eventsManager->setMousePos(Common::Point(_aptPos.x, _aptPos.y)); + _vm->_soundManager->startVOCPlay(_vm->_soundManager->getVOCFileName(_vm->_currentVocId)); + _vm->_currentVocId = 151; + + _vm->_graphicsManager->setColor(129, 82, 82, 82); + _vm->_graphicsManager->setColor(130, 112, 112, 112); + _vm->_graphicsManager->setColor(131, 215, 215, 215); + _vm->_graphicsManager->setColor(132, 235, 235, 235); + + _vm->_eventsManager->_intPtr._hasPalette = true; + + // Set up the cursors + PictureResource *unselectedCursor = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 2)._picResource; + PictureResource *selectedCursor = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 3)._picResource; + unselectedCursor->_keyColor = 0xff; + selectedCursor->_keyColor = 0xff; + _vm->_eventsManager->setCursor(unselectedCursor); + _vm->_eventsManager->showCursor(); + + // Main loop to allow users to move the cursor and select hotspots + int hotspotId; + int prevHotspotId = -1; + Common::Point pt; + PictureResource *pic; + Common::Rect gmmHotspot(75, 125, 130, 140); + + do { + _vm->_voyeurArea = AREA_APARTMENT; + + if (_vm->_loadGameSlot != -1) { + // Load a savegame + _vm->loadGame(_vm->_loadGameSlot); + _vm->_loadGameSlot = -1; + } + + _vm->_eventsManager->getMouseInfo(); + if (!_vm->_soundManager->getVOCStatus()) { + // Previous sound ended, so start up a new one + _vm->_currentVocId = 151 - _vm->getRandomNumber(4); + _vm->_soundManager->startVOCPlay(_vm->_soundManager->getVOCFileName(_vm->_currentVocId)); + } + + // Loop through the hotspot list + hotspotId = -1; + pt = _vm->_eventsManager->getMousePos() + Common::Point(16, 16); + for (int idx = 0; idx < (int)hotspots.size(); ++idx) { + if (hotspots[idx].contains(pt)) { + // Cursor is within hotspot area + + // Don't allow the camera to be highlighted on Monday morning. + if (idx == 0 && _vm->_voy->_transitionId == 17) + continue; + + // Set the highlighted hotspot Id + hotspotId = idx; + + if (hotspotId != prevHotspotId) { + // Check for whether to replace hotspot Id for "Watch TV" for + // "Review the Tape" if player has already watched the TV + if ((_vm->_voy->_eventFlags & EVTFLAG_100) && (hotspotId == 2)) + hotspotId = 5; + + // Draw the text description for the highlighted hotspot + pic = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + + hotspotId + 6)._picResource; + _vm->_graphicsManager->sDrawPic(pic, _vm->_graphicsManager->_vPort, + Common::Point(106, 200)); + } + + break; + } + } + + // Check for presence in ScummVM GMM + if (gmmHotspot.contains(pt)) + hotspotId = 42; + + // Update the cursor to either standard or highlighted eye cursor + _vm->_eventsManager->setCursor((hotspotId == -1) ? unselectedCursor : selectedCursor); + _vm->flipPageAndWait(); + + if (hotspotId == 42 && _vm->_eventsManager->_leftClick) { + // Show the ScummVM GMM + _vm->_eventsManager->getMouseInfo(); + _vm->openMainMenuDialog(); + } + + } while (!_vm->shouldQuit() && (!_vm->_eventsManager->_leftClick || hotspotId == -1)); + + _vm->_eventsManager->hideCursor(); + pt = _vm->_eventsManager->getMousePos(); + _aptPos.x = pt.x; + _aptPos.y = pt.y; + + switch (hotspotId) { + case 0: + _vm->_voy->_aptLoadMode = 140; + break; + case 1: + _vm->_voy->_aptLoadMode = 143; + break; + case 2: + _vm->_voy->_aptLoadMode = 142; + case 5: + _vm->_voy->_aptLoadMode = 141; + break; + default: + _vm->_voy->_aptLoadMode = -1; + break; + } + + freeTheApt(); + + if (_vm->_voy->_transitionId == 1 && hotspotId == 0) + _vm->checkTransition(); + + if (!hotspotId) + _vm->makeViewFinder(); + + return hotspotId; +} + +void ThreadResource::doRoom() { + VoyeurEngine &vm = *_vm; + SVoy voy = *vm._voy; + + vm.makeViewFinderP(); + voy._fadingType = 0; + + if (!vm._bVoy->getBoltGroup(vm._playStampGroupId)) + return; + + vm._graphicsManager->_backColors = vm._bVoy->boltEntry(vm._playStampGroupId + 1)._cMapResource; + vm._graphicsManager->_backgroundPage = vm._bVoy->boltEntry(vm._playStampGroupId)._picResource; + vm._graphicsManager->_vPort->setupViewPort(vm._graphicsManager->_backgroundPage); + vm._graphicsManager->_backColors->startFade(); + + voy._fadingStep1 = 2; + voy._fadingStep2 = 0; + voy._fadingType = 1; + + Common::Array<RectEntry> &hotspots = vm._bVoy->boltEntry(vm._playStampGroupId + 4)._rectResource->_entries; + int hotspotId = -1; + + PictureResource *crosshairsCursor = vm._bVoy->boltEntry(vm._playStampGroupId + 2)._picResource; + PictureResource *magnifierCursor = vm._bVoy->boltEntry(vm._playStampGroupId + 3)._picResource; + vm._eventsManager->showCursor(); + + RectResource viewBounds(48, 38, 336, 202); + voy._viewBounds = &viewBounds; + + vm._eventsManager->getMouseInfo(); + vm._eventsManager->setMousePos(Common::Point(192, 120)); + voy._fadingType = 0; + vm._currentVocId = 146; + voy._musicStartTime = voy._RTVNum; + + voy._vocSecondsOffset = 0; + vm._soundManager->startVOCPlay(vm._currentVocId); + voy._eventFlags &= ~EVTFLAG_TIME_DISABLED; + + bool breakFlag = false; + while (!vm.shouldQuit() && !breakFlag) { + _vm->_voyeurArea = AREA_ROOM; + vm._graphicsManager->setColor(128, 0, 255, 0); + vm._eventsManager->_intPtr._hasPalette = true; + + do { + if (vm._currentVocId != -1 && !vm._soundManager->getVOCStatus()) { + voy._musicStartTime = voy._RTVNum; + voy._vocSecondsOffset = 0; + vm._soundManager->startVOCPlay(vm._currentVocId); + } + + vm._eventsManager->getMouseInfo(); + Common::Point pt = vm._eventsManager->getMousePos(); + pt += Common::Point(30, 15); + + hotspotId = -1; + + if (voy._computerTextId != -1 && voy._computerScreenRect.contains(pt)) + hotspotId = 999; + + for (uint idx = 0; idx < hotspots.size(); ++idx) { + if (hotspots[idx].contains(pt)) { + int arrIndex = hotspots[idx]._arrIndex; + if (voy._roomHotspotsEnabled[arrIndex - 1]) { + hotspotId = idx; + break; + } + } + } + + if (hotspotId == -1) { + vm._eventsManager->setCursorColor(128, 0); + vm._eventsManager->setCursor(crosshairsCursor); + } else if (hotspotId != 999 || voy._RTVNum < voy._computerTimeMin || + (voy._computerTimeMax - 2) < voy._RTVNum) { + vm._eventsManager->setCursorColor(128, 1); + vm._eventsManager->setCursor(magnifierCursor); + } else { + vm._eventsManager->setCursorColor(128, 2); + vm._eventsManager->setCursor(magnifierCursor); + } + + vm._eventsManager->_intPtr._hasPalette = true; + vm._graphicsManager->flipPage(); + vm._eventsManager->sWaitFlip(); + } while (!vm.shouldQuit() && !vm._eventsManager->_mouseClicked); + + if (!vm._eventsManager->_leftClick || hotspotId == -1) { + if (vm._eventsManager->_rightClick) + breakFlag = true; + + Common::Point pt = vm._eventsManager->getMousePos(); + vm._eventsManager->getMouseInfo(); + vm._eventsManager->setMousePos(pt); + } else { + voy._eventFlags |= EVTFLAG_RECORDING; + vm._eventsManager->hideCursor(); + vm._eventsManager->startCursorBlink(); + + if (hotspotId == 999) { + _vm->flipPageAndWait(); + + if (vm._currentVocId != -1) { + voy._vocSecondsOffset = voy._RTVNum - voy._musicStartTime; + vm._soundManager->stopVOCPlay(); + } + + vm.getComputerBrush(); + _vm->flipPageAndWait(); + + vm._voy->addComputerEventStart(); + + vm._eventsManager->_mouseClicked = false; + vm._eventsManager->startCursorBlink(); + + int totalChars = vm.doComputerText(9999); + if (totalChars) + vm._voy->addComputerEventEnd(totalChars); + + vm._bVoy->freeBoltGroup(0x4900); + } else { + vm.doEvidDisplay(hotspotId, 999); + } + + voy._eventFlags &= ~EVTFLAG_RECORDING; + if (!vm._eventsManager->_mouseClicked) + vm._eventsManager->delayClick(18000); + + // WORKAROUND: Skipped code from the original, that freed the group, + // reloaded it, and reloaded the cursors + + vm._graphicsManager->_backColors = vm._bVoy->boltEntry( + vm._playStampGroupId + 1)._cMapResource; + vm._graphicsManager->_backgroundPage = vm._bVoy->boltEntry( + vm._playStampGroupId)._picResource; + + vm._graphicsManager->_vPort->setupViewPort(); + vm._graphicsManager->_backColors->startFade(); + _vm->flipPageAndWait(); + + while (!vm.shouldQuit() && (vm._eventsManager->_fadeStatus & 1)) + vm._eventsManager->delay(1); + vm._eventsManager->hideCursor(); + + while (!vm.shouldQuit() && voy._fadingAmount2 > 0) { + if (voy._fadingAmount1 < 63) { + voy._fadingAmount1 += 4; + if (voy._fadingAmount1 > 63) + voy._fadingAmount1 = 63; + } + + if (voy._fadingAmount2 > 0) { + voy._fadingAmount2 -= 8; + if (voy._fadingAmount2 < 0) + voy._fadingAmount2 = 0; + } + + vm._eventsManager->delay(1); + } + + _vm->flipPageAndWait(); + + vm._graphicsManager->fadeUpICF1(); + voy._eventFlags &= EVTFLAG_RECORDING; + vm._eventsManager->showCursor(); + } + } + + voy._eventFlags = EVTFLAG_TIME_DISABLED; + vm._eventsManager->incrementTime(1); + voy._viewBounds = nullptr; + voy._fadingType = 0; + vm.makeViewFinderP(); + + if (voy._boltGroupId2 != -1) { + vm._bVoy->freeBoltGroup(voy._boltGroupId2); + voy._boltGroupId2 = -1; + } + + if (vm._playStampGroupId != -1) { + vm._bVoy->freeBoltGroup(vm._playStampGroupId); + vm._playStampGroupId = -1; + } + + if (vm._currentVocId != -1) { + vm._soundManager->stopVOCPlay(); + vm._currentVocId = -1; + } + + vm._eventsManager->hideCursor(); + chooseSTAMPButton(0); +} + +int ThreadResource::doInterface() { + PictureResource *pic; + Common::Point pt; + + _vm->_voy->_eventFlags |= EVTFLAG_TIME_DISABLED; + if (_vm->_voy->_abortInterface) { + _vm->_voy->_abortInterface = false; + return -2; + } + + _vm->_voy->_eventFlags &= ~EVTFLAG_100; + _vm->_playStampGroupId = -1; + _vm->_eventsManager->_intPtr._flashStep = 1; + _vm->_eventsManager->_intPtr._flashTimer = 0; + + if (_vm->_voy->_RTVNum >= _vm->_voy->_RTVLimit || _vm->_voy->_RTVNum < 0) + _vm->_voy->_RTVNum = _vm->_voy->_RTVLimit - 1; + + if (_vm->_voy->_transitionId < 15 && _vm->_debugger->_isTimeActive + && (_vm->_voy->_RTVLimit - 3) < _vm->_voy->_RTVNum) { + _vm->_voy->_RTVNum = _vm->_voy->_RTVLimit; + _vm->makeViewFinder(); + + _vm->initIFace(); + _vm->_eventsManager->hideCursor(); + _vm->_voy->_RTVNum = _vm->_voy->_RTVLimit - 4; + _vm->_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; + + while (!_vm->shouldQuit() && _vm->_voy->_RTVNum < _vm->_voy->_RTVLimit) { + _vm->flashTimeBar(); + _vm->_eventsManager->delayClick(1); + } + + _vm->_voy->_eventFlags |= EVTFLAG_TIME_DISABLED; + chooseSTAMPButton(20); + parsePlayCommands(); + + _vm->_eventsManager->showCursor(); + } + + _vm->checkTransition(); + _vm->makeViewFinder(); + _vm->_eventsManager->getMouseInfo(); + _vm->initIFace(); + + Common::Array<RectEntry> *hotspots = &_vm->_bVoy->boltEntry( + _vm->_playStampGroupId + 1)._rectResource->_entries; + _vm->_currentVocId = 151 - _vm->getRandomNumber(5); + _vm->_voy->_vocSecondsOffset = _vm->getRandomNumber(29); + + Common::String fname = _vm->_soundManager->getVOCFileName(_vm->_currentVocId); + _vm->_soundManager->startVOCPlay(fname); + _vm->_eventsManager->getMouseInfo(); + + _vm->_graphicsManager->setColor(240, 220, 220, 220); + _vm->_eventsManager->_intPtr._hasPalette = true; + _vm->_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; + + // Set the cusor + PictureResource *crosshairsCursor = _vm->_bVoy->boltEntry(0x112)._picResource; + PictureResource *eyeCursor = _vm->_bVoy->boltEntry(0x113)._picResource; + PictureResource *listenCursor = _vm->_bVoy->boltEntry(0x114)._picResource; + PictureResource *mangifyCursor = _vm->_bVoy->boltEntry(0x115)._picResource; + + _vm->_eventsManager->setCursor(crosshairsCursor); + + // Main loop + int regionIndex = 0; + Common::Rect mansionViewBounds(MANSION_VIEW_X, MANSION_VIEW_Y, + MANSION_VIEW_X + MANSION_VIEW_WIDTH, MANSION_VIEW_Y + MANSION_VIEW_HEIGHT); + + do { + _vm->_voyeurArea = AREA_INTERFACE; + _vm->doTimeBar(); + _vm->_eventsManager->getMouseInfo(); + + if (checkMansionScroll()) + _vm->doScroll(_vm->_mansionViewPos); + + _vm->checkPhoneCall(); + if (!_vm->_soundManager->getVOCStatus()) { + _vm->_currentVocId = 151 - _vm->getRandomNumber(5); + _vm->_soundManager->startVOCPlay(_vm->_soundManager->getVOCFileName(_vm->_currentVocId)); + } + + // Calculate the mouse position within the entire mansion + pt = _vm->_eventsManager->getMousePos(); + if (!mansionViewBounds.contains(pt)) + pt = Common::Point(-1, -1); + else + pt = _vm->_mansionViewPos + + Common::Point(pt.x - MANSION_VIEW_X, pt.y - MANSION_VIEW_Y); + regionIndex = -1; + + for (int hotspotIdx = 0; hotspotIdx < (int)hotspots->size(); ++hotspotIdx) { + if ((*hotspots)[hotspotIdx].contains(pt)) { + // Rect check done + for (int arrIndex = 0; arrIndex < 3; ++arrIndex) { + if (_vm->_voy->_audioHotspotTimes.isInRange(arrIndex, hotspotIdx, _vm->_voy->_RTVNum)) { + // Set the ear cursor for an audio event + _vm->_eventsManager->setCursor(listenCursor); + regionIndex = hotspotIdx; + } + + if (_vm->_voy->_evidenceHotspotTimes.isInRange(arrIndex, hotspotIdx, _vm->_voy->_RTVNum)) { + // Set the magnifier cursor for an evidence event + _vm->_eventsManager->setCursor(mangifyCursor); + regionIndex = hotspotIdx; + } + } + + for (int arrIndex = 0; arrIndex < 8; ++arrIndex) { + if (_vm->_voy->_videoHotspotTimes.isInRange(arrIndex, hotspotIdx, _vm->_voy->_RTVNum)) { + // Set the eye cursor for a video event + _vm->_eventsManager->setCursor(eyeCursor); + regionIndex = hotspotIdx; + } + } + } + } + + if (regionIndex == -1) { + // Reset back to the crosshairs cursor + _vm->_eventsManager->setCursor(crosshairsCursor); + } + + // Regularly update the time display + if (_vm->_voy->_RTANum & 2) { + _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_gameMinute / 10, Common::Point(190, 25)); + _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_gameMinute % 10, Common::Point(201, 25)); + + if (_vm->_voy->_RTANum & 4) { + int v = _vm->_gameHour / 10; + _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + v == 0 ? 10 : v, Common::Point(161, 25)); + _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort, + _vm->_gameHour % 10, Common::Point(172, 25)); + + pic = _vm->_bVoy->boltEntry(_vm->_voy->_isAM ? 272 : 273)._picResource; + _vm->_graphicsManager->sDrawPic(pic, _vm->_graphicsManager->_vPort, + Common::Point(215, 27)); + } + } + + _vm->_voy->_RTANum = 0; + _vm->flipPageAndWait(); + + pt = _vm->_eventsManager->getMousePos(); + if ((_vm->_voy->_RTVNum >= _vm->_voy->_RTVLimit) || ((_vm->_voy->_eventFlags & 0x80) && + _vm->_eventsManager->_rightClick && (pt.x == 0))) { + // Time to transition to the next time period + _vm->_eventsManager->getMouseInfo(); + + if (_vm->_voy->_transitionId == 15) { + regionIndex = 20; + _vm->_voy->_transitionId = 17; + _vm->_soundManager->stopVOCPlay(); + _vm->checkTransition(); + _vm->_eventsManager->_leftClick = true; + } else { + _vm->_voy->_eventFlags |= EVTFLAG_TIME_DISABLED; + + chooseSTAMPButton(20); + parsePlayCommands(); + _vm->checkTransition(); + _vm->makeViewFinder(); + + _vm->initIFace(); + + hotspots = &_vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._rectResource->_entries; + _vm->_eventsManager->getMouseInfo(); + + _vm->_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED; + _vm->_eventsManager->_intPtr._flashStep = 1; + _vm->_eventsManager->_intPtr._flashTimer = 0; + } + } + } while (!_vm->_eventsManager->_rightClick && !_vm->shouldQuit() && + (!_vm->_eventsManager->_leftClick || regionIndex == -1)); + + _vm->_eventsManager->hideCursor(); + _vm->_voy->_eventFlags |= EVTFLAG_TIME_DISABLED; + _vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId); + if (_vm->_currentVocId != -1) + _vm->_soundManager->stopVOCPlay(); + + return !_vm->_eventsManager->_rightClick ? regionIndex : -2; +} + +bool ThreadResource::checkMansionScroll() { + Common::Point pt = _vm->_eventsManager->getMousePos() - + Common::Point(MANSION_VIEW_X, MANSION_VIEW_Y); + Common::Point &viewPos = _vm->_mansionViewPos; + bool result = false; + + // Scroll mansion view if close to any of the mansion edges + if (pt.x >= 0 && pt.x < MANSION_SCROLL_AREA_X && viewPos.x > 0) { + viewPos.x = MAX(viewPos.x - MANSION_SCROLL_INC_X, 0); + result = true; + } + if (pt.x >= (MANSION_VIEW_WIDTH - MANSION_SCROLL_AREA_X) && + pt.x < MANSION_VIEW_WIDTH && viewPos.x < MANSION_MAX_X) { + viewPos.x = MIN(viewPos.x + MANSION_SCROLL_INC_X, MANSION_MAX_X); + result = true; + } + if (pt.y >= 0 && pt.y < MANSION_SCROLL_AREA_Y && viewPos.y > 0) { + viewPos.y = MAX(viewPos.y - MANSION_SCROLL_INC_Y, 0); + result = true; + } + if (pt.y >= (MANSION_VIEW_HEIGHT - MANSION_SCROLL_AREA_Y) && + pt.y < MANSION_VIEW_HEIGHT && viewPos.y < MANSION_MAX_Y) { + viewPos.y = MIN(viewPos.y + MANSION_SCROLL_INC_Y, MANSION_MAX_Y); + result = true; + } + + // Return whether mansion view area has changed + return result; +} + +bool ThreadResource::goToStateID(int stackId, int id) { + debugC(DEBUG_BASIC, kDebugScripts, "goToStateID - %d, %d", stackId, id); + + // Save current stack + savePrevious(); + + if (_stackId == stackId || stackId == -1 || loadAStack(stackId)) { + // Now in the correct state + _stateId = getStateFromID(id); + + if (_stateId != -1) { + return doState(); + } else { + _stateId = _savedStateId; + _stackId = _savedStackId; + } + } + + return false; +} + +bool ThreadResource::goToState(int stackId, int stateId) { + debugC(DEBUG_BASIC, kDebugScripts, "goToState - %d, %d", stackId, stateId); + + savePrevious(); + if (stackId == -1 || loadAStack(stackId)) { + if (stateId != -1) + _stateId = stateId; + + return doState(); + } else { + return false; + } +} + +void ThreadResource::savePrevious() { + if (_savedStateId != _stateId || _stackId != _savedStackId) { + _savedStateId = _stateId; + _savedStackId = _stackId; + } +} + +void ThreadResource::setButtonFlag(int idx, byte bits) { + _buttonFlags[idx] |= bits; +} + +void ThreadResource::clearButtonFlag(int idx, byte bits) { + _buttonFlags[idx] &= ~bits; +} + +void ThreadResource::loadTheApt() { + switch (_vm->_voy->_transitionId) { + case 1: + case 2: + case 5: + case 6: + case 7: + case 8: + case 9: + case 17: + _vm->_playStampGroupId = 0x5700; + break; + case 3: + _vm->_playStampGroupId = 0x5800; + break; + case 4: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + _vm->_playStampGroupId = 0x5900; + break; + default: + break; + } + + if (_vm->_voy->_aptLoadMode == 143) + _vm->_voy->_aptLoadMode = -1; + + if (_vm->_voy->_aptLoadMode != -1) { + doAptAnim(1); + _vm->_bVoy->getBoltGroup(_vm->_playStampGroupId); + _vm->_voy->_aptLoadMode = -1; + _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry( + _vm->_playStampGroupId + 5)._picResource; + _vm->_graphicsManager->_vPort->setupViewPort( + _vm->_graphicsManager->_backgroundPage); + } else { + _vm->_bVoy->getBoltGroup(_vm->_playStampGroupId); + _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry( + _vm->_playStampGroupId + 5)._picResource; + _vm->_graphicsManager->_vPort->setupViewPort( + _vm->_graphicsManager->_backgroundPage); + } + + CMapResource *pal = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 4)._cMapResource; + pal->_steps = 1; + pal->startFade(); + _vm->flipPageAndWaitForFade(); +} + +void ThreadResource::freeTheApt() { + _vm->_graphicsManager->fadeDownICF1(5); + _vm->flipPageAndWaitForFade(); + + _vm->_graphicsManager->fadeUpICF1(); + + if (_vm->_currentVocId != -1) { + _vm->_soundManager->stopVOCPlay(); + _vm->_currentVocId = -1; + } + + if (_vm->_voy->_aptLoadMode == -1) { + _vm->_graphicsManager->fadeDownICF(6); + } else { + doAptAnim(2); + } + + if (_vm->_voy->_aptLoadMode == 140) { + _vm->_graphicsManager->screenReset(); + _vm->_graphicsManager->resetPalette(); + } + + _vm->_graphicsManager->_vPort->setupViewPort(nullptr); + _vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId); + _vm->_playStampGroupId = -1; + _vm->_voy->_viewBounds = nullptr; +} + +void ThreadResource::doAptAnim(int mode) { + _vm->_bVoy->freeBoltGroup(0x100); + + // Figure out the resource to use + int id = 0; + switch (_vm->_voy->_aptLoadMode) { + case 140: + id = 0x5A00; + break; + case 141: + id = 0x6000; + break; + case 142: + id = 0x6600; + break; + case 143: + id = 0x6C00; + break; + case 144: + id = 0x6F00; + break; + default: + break; + } + + int id2 = (id == 0x6C00 || id == 0x6F00) ? 1 : 2; + switch (_vm->_voy->_transitionId) { + case 3: + id += id2 << 8; + break; + case 4: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + id += id2 << 9; + break; + default: + break; + } + + if (mode == 1) + id += 0x100; + + // Do the display + if (_vm->_bVoy->getBoltGroup(id)) { + CMapResource *pal = _vm->_bVoy->boltEntry(id)._cMapResource; + pal->_steps = 1; + + for (int idx = 0; (idx < 6) && !_vm->shouldQuit(); ++idx) { + PictureResource *pic = _vm->_bVoy->boltEntry(id + idx + 1)._picResource; + _vm->_graphicsManager->_vPort->setupViewPort(pic); + pal->startFade(); + + _vm->flipPageAndWait(); + _vm->_eventsManager->delayClick(5); + } + + _vm->_bVoy->freeBoltGroup(id); + } + + _vm->_bVoy->getBoltGroup(0x100); +} + +void ThreadResource::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_aptPos.x); + s.syncAsSint16LE(_aptPos.y); + + int stateId = _stateId; + int stackId = _stackId; + s.syncAsSint16LE(stateId); + s.syncAsSint16LE(stackId); + + if (s.isLoading() && (stateId != _stateId || stackId != _stackId)) + goToState(stackId, stateId); + + s.syncAsSint16LE(_savedStateId); + s.syncAsSint16LE(_savedStackId); +} + +} // End of namespace Voyeur |