/* 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/voyeur.h" #include "voyeur/staticres.h" #include "voyeur/animation.h" namespace Voyeur { void VoyeurEngine::playStamp() { _stampLibPtr = NULL; _filesManager.openBoltLib("stampblt.blt", _stampLibPtr); _stampLibPtr->getBoltGroup(0); _controlPtr->_state = _stampLibPtr->boltEntry(_controlPtr->_stateId >> 16)._stateResource; assert(_controlPtr->_state); _resolvePtr = &RESOLVE_TABLE[0]; initStamp(); PtrResource *threadsList = _stampLibPtr->boltEntry(3)._ptrResource; _mainThread = threadsList->_entries[0]->_threadResource; _mainThread->initThreadStruct(0, 0); _voy._isAM = false; _gameHour = 9; _gameMinute = 0; _voy._abortInterface = true; int buttonId; bool breakFlag = false; while (!breakFlag && !shouldQuit()) { _voyeurArea = AREA_NONE; _eventsManager.getMouseInfo(); _playStampGroupId = _currentVocId = -1; _audioVideoId = -1; _mainThread->parsePlayCommands(); bool flag = breakFlag = (_voy._eventFlags & EVTFLAG_2) != 0; switch (_voy._playStampMode) { case 5: buttonId = _mainThread->doInterface(); if (buttonId == -2) { switch (_mainThread->doApt()) { case 0: _voy._aptLoadMode = 140; break; case 1: _voy._eventFlags &= ~EVTFLAG_TIME_DISABLED; _voy._abortInterface = true; _mainThread->chooseSTAMPButton(22); _voy._aptLoadMode = 143; break; case 2: _voy._eventFlags &= ~EVTFLAG_TIME_DISABLED; reviewTape(); _voy._abortInterface = true; _voy._aptLoadMode = 142; break; case 3: _voy._eventFlags &= ~EVTFLAG_TIME_DISABLED; _mainThread->chooseSTAMPButton(21); break; case 4: breakFlag = true; break; case 5: doGossip(); _voy._abortInterface = true; _voy._aptLoadMode = 141; _voy._eventFlags &= ~EVTFLAG_100; break; default: break; } } else { _mainThread->chooseSTAMPButton(buttonId); } flag = true; break; case 6: _mainThread->doRoom(); flag = true; break; case 16: _voy._transitionId = 17; buttonId = _mainThread->doApt(); switch (buttonId) { case 1: _mainThread->chooseSTAMPButton(22); flag = true; break; case 2: reviewTape(); _voy._abortInterface = true; break; case 4: flag = true; breakFlag = true; break; default: break; } break; case 17: // Called the police, showing the tape doTapePlaying(); if (!checkForMurder() && _voy._transitionId <= 15) checkForIncriminate(); if (_voy._videoEventId != -1) { // Show the found video that is of interest to the police playAVideoEvent(_voy._videoEventId); _voy._eventFlags &= ~EVTFLAG_RECORDING; } // Handle response _mainThread->chooseSTAMPButton(0); flag = true; break; case 130: { // user selected to send the tape if (_bVoy->getBoltGroup(_playStampGroupId)) { _graphicsManager._backgroundPage = _bVoy->boltEntry(_playStampGroupId)._picResource; _graphicsManager._backColors = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource; buttonId = getChooseButton(); if (_eventsManager._rightClick) // Aborted out of selecting a recipient buttonId = 4; _bVoy->freeBoltGroup(_playStampGroupId); _graphicsManager.screenReset(); _playStampGroupId = -1; flag = true; if (buttonId != 4) { _voy._playStampMode = 131; _voy.checkForKey(); _mainThread->chooseSTAMPButton(buttonId); } else { _mainThread->chooseSTAMPButton(buttonId); _voy._abortInterface = true; } } break; } default: break; } do { if (flag) { if (_currentVocId != -1) { _soundManager.stopVOCPlay(); _currentVocId = -1; } _audioVideoId = -1; if (_voy._boltGroupId2 != -1) { _bVoy->freeBoltGroup(_voy._boltGroupId2); _voy._boltGroupId2 = -1; } if (_playStampGroupId != -1) { _bVoy->freeBoltGroup(_playStampGroupId); _playStampGroupId = -1; } // Break out of loop flag = false; } else if (_mainThread->_stateFlags & 2) { _eventsManager.getMouseInfo(); _mainThread->chooseSTAMPButton(0); flag = true; } else { _mainThread->chooseSTAMPButton(0); flag = true; } } while (flag); } _voy._viewBounds = nullptr; closeStamp(); _stampLibPtr->freeBoltGroup(0); delete _stampLibPtr; } void VoyeurEngine::initStamp() { _stampFlags &= ~1; _stackGroupPtr = _controlGroupPtr; if (!_controlPtr->_entries[0]) error("No control entries"); ThreadResource::initUseCount(); } void VoyeurEngine::closeStamp() { ThreadResource::unloadAllStacks(this); } void VoyeurEngine::doTailTitle() { (*_graphicsManager._vPort)->setupViewPort(NULL); _graphicsManager.screenReset(); if (_bVoy->getBoltGroup(0x600)) { RL2Decoder decoder; decoder.loadFile("a1100200.rl2"); decoder.start(); decoder.play(this); if (!shouldQuit() && !_eventsManager._mouseClicked) { doClosingCredits(); if (!shouldQuit() && !_eventsManager._mouseClicked) { _graphicsManager.screenReset(); PictureResource *pic = _bVoy->boltEntry(0x602)._picResource; CMapResource *pal = _bVoy->boltEntry(0x603)._cMapResource; (*_graphicsManager._vPort)->setupViewPort(pic); pal->startFade(); flipPageAndWaitForFade(); _eventsManager.delayClick(300); pic = _bVoy->boltEntry(0x604)._picResource; pal = _bVoy->boltEntry(0x605)._cMapResource; (*_graphicsManager._vPort)->setupViewPort(pic); pal->startFade(); flipPageAndWaitForFade(); _eventsManager.delayClick(120); _soundManager.stopVOCPlay(); } } _bVoy->freeBoltGroup(0x600); } if (!shouldQuit()) { _bVoy->getBoltGroup(0x100); doPiracy(); } } void VoyeurEngine::doClosingCredits() { if (!_bVoy->getBoltGroup(0x400)) return; const char *msg = (const char *)_bVoy->memberAddr(0x404); const byte *creditList = (const byte *)_bVoy->memberAddr(0x405); (*_graphicsManager._vPort)->setupViewPort(NULL); _graphicsManager.setColor(1, 180, 180, 180); _graphicsManager.setColor(2, 200, 200, 200); _eventsManager._intPtr._hasPalette = true; _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x402)._fontResource; _graphicsManager._fontPtr->_foreColor = 2; _graphicsManager._fontPtr->_backColor = 2; _graphicsManager._fontPtr->_fontSaveBack = false; _graphicsManager._fontPtr->_fontFlags = 0; _soundManager.startVOCPlay(152); FontInfoResource &fi = *_graphicsManager._fontPtr; for (int idx = 0; idx < 78; ++idx) { const byte *entry = creditList + idx * 6; int flags = READ_LE_UINT16(entry + 4); if (flags & 0x10) (*_graphicsManager._vPort)->fillPic(); if (flags & 1) { fi._foreColor = 1; fi._curFont = _bVoy->boltEntry(0x402)._fontResource; fi._justify = ALIGN_CENTER; fi._justifyWidth = 384; fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry)); (*_graphicsManager._vPort)->drawText(msg); msg += strlen(msg) + 1; } if (flags & 0x40) { fi._foreColor = 2; fi._curFont = _bVoy->boltEntry(0x400)._fontResource; fi._justify = ALIGN_CENTER; fi._justifyWidth = 384; fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry)); (*_graphicsManager._vPort)->drawText(msg); msg += strlen(msg) + 1; } if (flags & 2) { fi._foreColor = 1; fi._curFont = _bVoy->boltEntry(0x400)._fontResource; fi._justify = ALIGN_LEFT; fi._justifyWidth = 384; fi._justifyHeight = 240; fi._pos = Common::Point(38, READ_LE_UINT16(entry)); (*_graphicsManager._vPort)->drawText(msg); msg += strlen(msg) + 1; fi._foreColor = 2; fi._justify = ALIGN_LEFT; fi._justifyWidth = 384; fi._justifyHeight = 240; fi._pos = Common::Point(198, READ_LE_UINT16(entry)); (*_graphicsManager._vPort)->drawText(msg); msg += strlen(msg) + 1; } if (flags & 4) { fi._foreColor = 1; fi._curFont = _bVoy->boltEntry(0x402)._fontResource; fi._justify = ALIGN_CENTER; fi._justifyWidth = 384; fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry)); (*_graphicsManager._vPort)->drawText(msg); msg += strlen(msg) + 1; fi._foreColor = 2; fi._curFont = _bVoy->boltEntry(0x400)._fontResource; fi._justify = ALIGN_CENTER; fi._justifyWidth = 384; fi._justifyHeight = 240; fi._pos = Common::Point(0, READ_LE_UINT16(entry) + 13); (*_graphicsManager._vPort)->drawText(msg); msg += strlen(msg) + 1; } if (flags & 0x20) { flipPageAndWait(); _eventsManager.delayClick(READ_LE_UINT16(entry + 2) * 60); } if (shouldQuit() || _eventsManager._mouseClicked) break; } _soundManager.stopVOCPlay(); _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; _bVoy->freeBoltGroup(0x400); } void VoyeurEngine::doPiracy() { _graphicsManager.screenReset(); _graphicsManager.setColor(1, 0, 0, 0); _graphicsManager.setColor(2, 255, 255, 255); _eventsManager._intPtr._hasPalette = true; (*_graphicsManager._vPort)->setupViewPort(NULL); (*_graphicsManager._vPort)->fillPic(1); FontInfoResource &fi = *_graphicsManager._fontPtr; fi._curFont = _bVoy->boltEntry(0x101)._fontResource; fi._foreColor = 2; fi._backColor = 2; fi._fontSaveBack = false; fi._fontFlags = 0; fi._justify = ALIGN_CENTER; fi._justifyWidth = 384; fi._justifyHeight = 230; // Loop through the piracy message array to draw each line int yp, idx; for (idx = 0, yp = 33; idx < 10; ++idx) { fi._pos = Common::Point(0, yp); (*_graphicsManager._vPort)->drawText(PIRACY_MESSAGE[idx]); yp += fi._curFont->_fontHeight + 4; } flipPageAndWait(); _eventsManager.getMouseInfo(); _eventsManager.delayClick(720); } void VoyeurEngine::reviewTape() { int eventStart = 0; int newX = -1; int newY = -1; int eventLine = 7; Common::Rect tempRect(58, 30, 58 + 223, 30 + 124); Common::Point pt; int foundIndex; _bVoy->getBoltGroup(0x900); PictureResource *cursor = _bVoy->boltEntry(0x903)._picResource; if ((_voy._eventCount - 8) != 0) eventStart = MAX(_voy._eventCount - 8, 0); if ((eventStart + _voy._eventCount) <= 7) eventLine = eventStart + _voy._eventCount - 1; bool breakFlag = false; while (!shouldQuit() && !breakFlag) { _voy._viewBounds = _bVoy->boltEntry(0x907)._rectResource; Common::Array &hotspots = _bVoy->boltEntry(0x906)._rectResource->_entries; _graphicsManager._backColors = _bVoy->boltEntry(0x902)._cMapResource; _graphicsManager._backgroundPage = _bVoy->boltEntry(0x901)._picResource; (*_graphicsManager._vPort)->setupViewPort(_graphicsManager._backgroundPage); _graphicsManager._backColors->startFade(); flipPageAndWaitForFade(); _graphicsManager.setColor(1, 32, 32, 32); _graphicsManager.setColor(2, 96, 96, 96); _graphicsManager.setColor(3, 160, 160, 160); _graphicsManager.setColor(4, 224, 224, 224); _graphicsManager.setColor(9, 24, 64, 24); _graphicsManager.setColor(10, 64, 132, 64); _graphicsManager.setColor(11, 100, 192, 100); _graphicsManager.setColor(12, 120, 248, 120); _eventsManager.setCursorColor(128, 1); _eventsManager._intPtr._hasPalette = true; _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x909)._fontResource; _graphicsManager._fontPtr->_fontSaveBack = false; _graphicsManager._fontPtr->_fontFlags = 0; _eventsManager.getMouseInfo(); if (newX == -1) { _eventsManager.setMousePos(Common::Point(hotspots[1].left + 12, hotspots[1].top + 6)); } else { _eventsManager.setMousePos(Common::Point(newX, newY)); } _currentVocId = 151; _voy._vocSecondsOffset = 0; bool needRedraw = true; do { if (_currentVocId != -1 && !_soundManager.getVOCStatus()) { _voy._musicStartTime = _voy._RTVNum; _soundManager.startVOCPlay(_currentVocId); } if (needRedraw) { needRedraw = false; flipPageAndWait(); _graphicsManager._drawPtr->_penColor = 0; _graphicsManager._drawPtr->_pos = Common::Point(tempRect.left, tempRect.top); _graphicsManager._backgroundPage->sFillBox(tempRect.width(), tempRect.height()); int yp = 45; int eventNum = eventStart; for (int lineNum = 0; lineNum < 8 && eventNum < _voy._eventCount; ++lineNum, ++eventNum) { _graphicsManager._fontPtr->_picFlags = 0; _graphicsManager._fontPtr->_picSelect = 0xff; _graphicsManager._fontPtr->_picPick = 7; _graphicsManager._fontPtr->_picOnOff = (lineNum == eventLine) ? 8 : 0; _graphicsManager._fontPtr->_pos = Common::Point(68, yp); _graphicsManager._fontPtr->_justify = ALIGN_LEFT; _graphicsManager._fontPtr->_justifyWidth = 0; _graphicsManager._fontPtr->_justifyHeight = 0; Common::String msg = _eventsManager.getEvidString(eventNum); _graphicsManager._backgroundPage->drawText(msg); yp += 15; } (*_graphicsManager._vPort)->addSaveRect( (*_graphicsManager._vPort)->_lastPage, tempRect); flipPageAndWait(); (*_graphicsManager._vPort)->addSaveRect( (*_graphicsManager._vPort)->_lastPage, tempRect); } _graphicsManager.sDrawPic(cursor, *_graphicsManager._vPort, _eventsManager.getMousePos()); flipPageAndWait(); _eventsManager.getMouseInfo(); foundIndex = -1; Common::Point tempPos = _eventsManager.getMousePos() + Common::Point(14, 7); for (uint idx = 0; idx < hotspots.size(); ++idx) { if (hotspots[idx].contains(tempPos)) { // Found hotspot area foundIndex = idx; break; } } pt = _eventsManager.getMousePos(); if (tempPos.x >= 68 && tempPos.x <= 277 && tempPos.y >= 31 && tempPos.y <= 154) { tempPos.y -= 2; foundIndex = (tempPos.y - 31) / 15; if ((tempPos.y - 31) % 15 >= 12 || (eventStart + foundIndex) >= _voy._eventCount) { _eventsManager.setCursorColor(128, 0); foundIndex = 999; } else if (!_eventsManager._leftClick) { _eventsManager.setCursorColor(128, 2); foundIndex = -1; } else { _eventsManager.setCursorColor(128, 2); eventLine = foundIndex; flipPageAndWait(); _graphicsManager._drawPtr->_penColor = 0; _graphicsManager._drawPtr->_pos = Common::Point(tempRect.left, tempRect.top); _graphicsManager._backgroundPage->sFillBox(tempRect.width(), tempRect.height()); int yp = 45; int eventNum = eventStart; for (int idx = 0; idx < 8 && eventNum < _voy._eventCount; ++idx, ++eventNum) { _graphicsManager._fontPtr->_picFlags = 0; _graphicsManager._fontPtr->_picSelect = 0xff; _graphicsManager._fontPtr->_picPick = 7; _graphicsManager._fontPtr->_picOnOff = (idx == eventLine) ? 8 : 0; _graphicsManager._fontPtr->_pos = Common::Point(68, yp); _graphicsManager._fontPtr->_justify = ALIGN_LEFT; _graphicsManager._fontPtr->_justifyWidth = 0; _graphicsManager._fontPtr->_justifyHeight = 0; Common::String msg = _eventsManager.getEvidString(eventNum); _graphicsManager._backgroundPage->drawText(msg); yp += 15; } (*_graphicsManager._vPort)->addSaveRect( (*_graphicsManager._vPort)->_lastPage, tempRect); flipPageAndWait(); (*_graphicsManager._vPort)->addSaveRect( (*_graphicsManager._vPort)->_lastPage, tempRect); flipPageAndWait(); _eventsManager.getMouseInfo(); foundIndex = -1; } } else if ((_voy._eventFlags & EVTFLAG_40) && _voy._viewBounds->left == pt.x && _voy._viewBounds->bottom == pt.y) { foundIndex = 999; } else if ((_voy._eventFlags & EVTFLAG_40) && _voy._viewBounds->left == pt.x && _voy._viewBounds->top == pt.y) { foundIndex = 998; } else { _eventsManager.setCursorColor(128, (foundIndex == -1) ? 0 : 1); } _eventsManager._intPtr._hasPalette = true; if (_eventsManager._mouseClicked) { switch (foundIndex) { case 2: if (eventStart > 0) { --eventStart; needRedraw = true; } foundIndex = -1; break; case 3: if (eventStart > 0) { eventStart -= 8; if (eventStart < 0) eventStart = 0; needRedraw = true; } foundIndex = -1; break; case 4: if ((_voy._eventCount - 8) > eventStart) { ++eventStart; needRedraw = true; } foundIndex = -1; break; case 5: if (_voy._eventCount >= 8 && (_voy._eventCount - 8) != eventStart) { eventStart += 8; if ((_voy._eventCount - 8) < eventStart) eventStart = _voy._eventCount - 8; needRedraw = true; } foundIndex = -1; break; default: break; } while (eventLine > 0 && (eventLine + eventStart) >= _voy._eventCount) --eventLine; } pt = _eventsManager.getMousePos(); if (_eventsManager._mouseClicked && _voy._viewBounds->left == pt.x && (_voy._eventFlags & EVTFLAG_40) && _eventsManager._rightClick) { _controlPtr->_state->_victimIndex = (pt.y / 60) + 1; foundIndex = -1; _eventsManager._rightClick = 0; } if (_eventsManager._rightClick) foundIndex = 0; } while (!shouldQuit() && (!_eventsManager._mouseClicked || foundIndex == -1)); newY = _eventsManager.getMousePos().y; _voy._fadingType = 0; _voy._viewBounds = nullptr; (*_graphicsManager._vPort)->setupViewPort(NULL); if (_currentVocId != -1) { _voy._vocSecondsOffset = _voy._RTVNum - _voy._musicStartTime; _soundManager.stopVOCPlay(); } // Break out if the exit button was pressed if (!foundIndex) break; int eventIndex = eventStart + eventLine; VoyeurEvent &e = _voy._events[eventIndex]; switch (e._type) { case EVTYPE_VIDEO: playAVideoEvent(eventIndex); break; case EVTYPE_AUDIO: { _audioVideoId = e._audioVideoId; _voy._vocSecondsOffset = e._computerOn; _bVoy->getBoltGroup(0x7F00); _graphicsManager._backgroundPage = _bVoy->boltEntry(0x7F00 + BLIND_TABLE[_audioVideoId])._picResource; _graphicsManager._backColors = _bVoy->boltEntry(0x7F01 + BLIND_TABLE[_audioVideoId])._cMapResource; (*_graphicsManager._vPort)->setupViewPort(_graphicsManager._backgroundPage); _graphicsManager._backColors->startFade(); flipPageAndWaitForFade(); _eventsManager._intPtr._flashStep = 1; _eventsManager._intPtr._flashTimer = 0; _voy._eventFlags &= ~EVTFLAG_TIME_DISABLED; // Play suond for the given duration _soundManager.setVOCOffset(_voy._vocSecondsOffset); _soundManager.startVOCPlay(_audioVideoId + 159); uint32 secondsDuration = e._computerOff; _eventsManager.getMouseInfo(); while (!_eventsManager._mouseClicked && _soundManager.getVOCStatus() && _soundManager.getVOCFrame() < secondsDuration) { _eventsManager.getMouseInfo(); _eventsManager.delay(10); } _voy._eventFlags |= EVTFLAG_TIME_DISABLED; _soundManager.stopVOCPlay(); _bVoy->freeBoltGroup(0x7F00); break; } case EVTYPE_EVID: _voy.reviewAnEvidEvent(eventIndex); _voy._vocSecondsOffset = _voy._RTVNum - _voy._musicStartTime; _soundManager.stopVOCPlay(); _bVoy->getBoltGroup(0x900); break; case EVTYPE_COMPUTER: _voy.reviewComputerEvent(eventIndex); _voy._vocSecondsOffset = _voy._RTVNum - _voy._musicStartTime; _soundManager.stopVOCPlay(); _bVoy->getBoltGroup(0x900); break; default: break; } } _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; (*_graphicsManager._vPort)->fillPic(0); flipPageAndWait(); _bVoy->freeBoltGroup(0x900); } void VoyeurEngine::doGossip() { _graphicsManager.resetPalette(); _graphicsManager.screenReset(); if (!_bVoy->getBoltGroup(0x300)) return; // Load the gossip animation RL2Decoder decoder; decoder.loadFile("a2050100.rl2", false); decoder.start(); // Get the resource data for the first gossip video PictureResource *bgPic = _bVoy->boltEntry(0x300)._picResource; CMapResource *pal = _bVoy->boltEntry(0x301)._cMapResource; pal->startFade(); // Transfer initial background to video decoder PictureResource videoFrame(decoder.getVideoTrack()->getBackSurface()); bgPic->_bounds.moveTo(0, 0); _graphicsManager.sDrawPic(bgPic, &videoFrame, Common::Point(0, 0)); byte *frameNumsP = _bVoy->memberAddr(0x309); byte *posP = _bVoy->boltEntry(0x30A)._data; // Play the initial gossip video decoder.play(this, 0x302, frameNumsP, posP); decoder.close(); // Reset the palette and clear the screen _graphicsManager.resetPalette(); _graphicsManager.screenReset(); // Play interview video RL2Decoder decoder2; decoder2.loadFile("a2110100.rl2", true); decoder2.start(); _eventsManager.getMouseInfo(); decoder2.play(this); decoder2.close(); _bVoy->freeBoltGroup(0x300); _graphicsManager.screenReset(); } void VoyeurEngine::doTapePlaying() { if (!_bVoy->getBoltGroup(0xA00)) return; _eventsManager.getMouseInfo(); _graphicsManager._backColors = _bVoy->boltEntry(0xA01)._cMapResource; _graphicsManager._backgroundPage = _bVoy->boltEntry(0xA00)._picResource; PictureResource *pic = _bVoy->boltEntry(0xA02)._picResource; VInitCycleResource *cycle = _bVoy->boltEntry(0xA05)._vInitCycleResource; (*_graphicsManager._vPort)->setupViewPort(_graphicsManager._backgroundPage); _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point(57, 30)); _graphicsManager._backColors->startFade(); flipPageAndWaitForFade(); cycle->vStartCycle(); _soundManager.startVOCPlay("vcr.voc"); while (!shouldQuit() && !_eventsManager._mouseClicked && _soundManager.getVOCStatus()) { _eventsManager.delayClick(2); } _soundManager.stopVOCPlay(); cycle->vStopCycle(); _bVoy->freeBoltGroup(0xA00); } bool VoyeurEngine::checkForMurder() { int oldMurderIndex = _controlPtr->_state->_victimMurderIndex; for (int idx = 0; idx < _voy._eventCount; ++idx) { VoyeurEvent &evt = _voy._events[idx]; if (evt._type == EVTYPE_VIDEO) { switch (_controlPtr->_state->_victimIndex) { case 1: if (evt._audioVideoId == 41 && evt._computerOn <= 15 && (evt._computerOff + evt._computerOn) >= 16) { _controlPtr->_state->_victimMurderIndex = 1; } break; case 2: if (evt._audioVideoId == 53 && evt._computerOn <= 19 && (evt._computerOff + evt._computerOn) >= 21) { _controlPtr->_state->_victimMurderIndex = 2; } break; case 3: if (evt._audioVideoId == 50 && evt._computerOn <= 28 && (evt._computerOff + evt._computerOn) >= 29) { _controlPtr->_state->_victimMurderIndex = 3; } break; case 4: if (evt._audioVideoId == 43 && evt._computerOn <= 10 && (evt._computerOff + evt._computerOn) >= 14) { _controlPtr->_state->_victimMurderIndex = 4; } break; default: break; } } if (_controlPtr->_state->_victimMurderIndex == _controlPtr->_state->_victimIndex) { _voy._videoEventId = idx; return true; } } _controlPtr->_state->_victimMurderIndex = oldMurderIndex; _voy._videoEventId = -1; return false; } bool VoyeurEngine::checkForIncriminate() { _voy._incriminatedVictimNumber = 0; for (int idx = 0; idx < _voy._eventCount; ++idx) { VoyeurEvent &evt = _voy._events[idx]; if (evt._type == EVTYPE_VIDEO) { if (evt._audioVideoId == 44 && evt._computerOn <= 40 && (evt._computerOff + evt._computerOn) >= 70) { _voy._incriminatedVictimNumber = 1; } if (evt._audioVideoId == 44 && evt._computerOn <= 79 && (evt._computerOff + evt._computerOn) >= 129) { _voy._incriminatedVictimNumber = 1; } if (evt._audioVideoId == 20 && evt._computerOn <= 28 && (evt._computerOff + evt._computerOn) >= 45) { _voy._incriminatedVictimNumber = 2; } if (evt._audioVideoId == 35 && evt._computerOn <= 17 && (evt._computerOff + evt._computerOn) >= 36) { _voy._incriminatedVictimNumber = 3; } if (evt._audioVideoId == 30 && evt._computerOn <= 80 && (evt._computerOff + evt._computerOn) >= 139) { _voy._incriminatedVictimNumber = 4; } } if (_voy._incriminatedVictimNumber) { _controlPtr->_state->_victimMurderIndex = 88; _voy._videoEventId = idx; return true; } } _voy._videoEventId = -1; return false; } void VoyeurEngine::playAVideoEvent(int eventIndex) { VoyeurEvent &evt = _voy._events[eventIndex]; _audioVideoId = evt._audioVideoId; _voy._vocSecondsOffset = evt._computerOn; _eventsManager._videoDead = evt._dead; _voy._eventFlags &= ~EVTFLAG_TIME_DISABLED; playAVideoDuration(_audioVideoId, evt._computerOff); _voy._eventFlags |= EVTFLAG_TIME_DISABLED; if (_eventsManager._videoDead != -1) { _bVoy->freeBoltGroup(0xE00); _eventsManager._videoDead = -1; flipPageAndWait(); _eventsManager._videoDead = -1; } _audioVideoId = -1; if (_eventsManager._videoDead != -1) { _bVoy->freeBoltGroup(0xE00); _eventsManager._videoDead = -1; flipPageAndWait(); } } int VoyeurEngine::getChooseButton() { int prevIndex = -2; Common::Array &hotspots = _bVoy->boltEntry(_playStampGroupId + 6)._rectResource->_entries; int selectedIndex = -1; (*_graphicsManager._vPort)->setupViewPort(_graphicsManager._backgroundPage); _graphicsManager._backColors->_steps = 0; _graphicsManager._backColors->startFade(); flipPageAndWait(); _voy._viewBounds = _bVoy->boltEntry(_playStampGroupId + 7)._rectResource; PictureResource *cursorPic = _bVoy->boltEntry(_playStampGroupId + 2)._picResource; do { do { if (_currentVocId != -1 && !_soundManager.getVOCStatus()) _soundManager.startVOCPlay(_currentVocId); _eventsManager.getMouseInfo(); selectedIndex = -1; Common::Point pt = _eventsManager.getMousePos(); for (uint idx = 0; idx < hotspots.size(); ++idx) { if (hotspots[idx].contains(pt)) { if (!_voy._victimMurdered || ((int)idx + 1) != _controlPtr->_state->_victimIndex) { selectedIndex = idx; if (selectedIndex != prevIndex) { PictureResource *btnPic = _bVoy->boltEntry(_playStampGroupId + 8 + idx)._picResource; _graphicsManager.sDrawPic(btnPic, *_graphicsManager._vPort, Common::Point(106, 200)); cursorPic = _bVoy->boltEntry(_playStampGroupId + 4)._picResource; } } } } if (selectedIndex == -1) { cursorPic = _bVoy->boltEntry(_playStampGroupId + 2)._picResource; PictureResource *btnPic = _bVoy->boltEntry(_playStampGroupId + 12)._picResource; _graphicsManager.sDrawPic(btnPic, *_graphicsManager._vPort, Common::Point(106, 200)); } _graphicsManager.sDrawPic(cursorPic, *_graphicsManager._vPort, Common::Point(pt.x + 13, pt.y - 12)); flipPageAndWait(); } while (!shouldQuit() && !_eventsManager._mouseClicked); } while (!shouldQuit() && selectedIndex == -1 && !_eventsManager._rightClick); return selectedIndex; } void VoyeurEngine::makeViewFinder() { _graphicsManager._backgroundPage = _bVoy->boltEntry(0x103)._picResource; _graphicsManager.sDrawPic(_graphicsManager._backgroundPage, *_graphicsManager._vPort, Common::Point(0, 0)); CMapResource *pal = _bVoy->boltEntry(0x104)._cMapResource; int palOffset = 0; switch (_voy._transitionId) { case 1: case 2: case 5: case 6: case 7: case 8: case 9: case 17: palOffset = 0; break; case 3: palOffset = 1; break; case 4: case 10: case 11: case 12: case 13: case 14: case 15: case 16: palOffset = 2; break; default: break; } (*_graphicsManager._vPort)->drawIfaceTime(); doTimeBar(); pal->startFade(); flipPageAndWaitForFade(); _graphicsManager.setColor(241, 105, 105, 105); _graphicsManager.setColor(242, 105, 105, 105); _graphicsManager.setColor(243, 105, 105, 105); _graphicsManager.setColor(palOffset + 241, 219, 235, 235); _eventsManager._intPtr._hasPalette = true; } void VoyeurEngine::makeViewFinderP() { _graphicsManager.screenReset(); } void VoyeurEngine::initIFace() { int playStamp1 = _playStampGroupId; switch (_voy._transitionId) { case 0: break; case 1: case 2: case 5: case 6: case 7: case 8: case 9: _playStampGroupId = 0xB00; break; case 3: _playStampGroupId = 0xC00; break; default: _playStampGroupId = 0xD00; break; } if (playStamp1 != -1) _bVoy->freeBoltGroup(playStamp1, true); _bVoy->getBoltGroup(_playStampGroupId); CMapResource *pal = _bVoy->boltEntry(_playStampGroupId + 2)._cMapResource; pal->startFade(); // Start the mansion off centered _mansionViewPos = Common::Point((MANSION_MAX_X - MANSION_VIEW_WIDTH) / 2, (MANSION_MAX_Y - MANSION_VIEW_HEIGHT) / 2); doScroll(_mansionViewPos); _voy._viewBounds = _bVoy->boltEntry(_playStampGroupId)._rectResource; // Show the cursor using ScummVM functionality _eventsManager.showCursor(); // Note: the original did two loops to preload members here, which is // redundant for ScummVM, since computers are faster these days, and // getting resources as needed will be fast enough. } void VoyeurEngine::doScroll(const Common::Point &pt) { Common::Rect clipRect(72, 47, 72 + 240, 47 + 148); (*_graphicsManager._vPort)->setupViewPort(NULL, &clipRect); int base = 0; switch (_voy._transitionId) { case 0: break; case 1: case 2: case 5: case 6: case 7: case 8: case 9: base = 0xB00; break; case 3: base = 0xC00; break; default: base = 0xD00; } if (base) { PictureResource *pic = _bVoy->boltEntry(base + 3)._picResource; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 104)); pic = _bVoy->boltEntry(base + 4)._picResource; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 44)); pic = _bVoy->boltEntry(base + 5)._picResource; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 16)); pic = _bVoy->boltEntry(base + 6)._picResource; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 76)); pic = _bVoy->boltEntry(base + 7)._picResource; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 136)); } (*_graphicsManager._vPort)->setupViewPort(NULL); } void VoyeurEngine::checkTransition() { Common::String time, day; if (_voy._transitionId != _checkTransitionId) { // Get the day day = getDayName(); // Only proceed if a valid day string was returned if (!day.empty()) { _graphicsManager.fadeDownICF(6); // Get the time of day string time = getTimeOfDay(); // Show a transition card with the day and time, and wait doTransitionCard(day, time); _eventsManager.delayClick(180); } _checkTransitionId = _voy._transitionId; } } Common::String VoyeurEngine::getDayName() { switch (_voy._transitionId) { case 0: return ""; case 1: case 2: case 3: case 4: return SATURDAY; case 17: return MONDAY; default: return SUNDAY; } } Common::String VoyeurEngine::getTimeOfDay() { if (_voy._transitionId == 17) return ""; return Common::String::format("%d:%02d%s", _gameHour, _gameMinute, _voy._isAM ? AM : PM); } int VoyeurEngine::doComputerText(int maxLen) { FontInfoResource &font = *_graphicsManager._fontPtr; int totalChars = 0; font._curFont = _bVoy->boltEntry(0x4910)._fontResource; font._foreColor = 129; font._fontSaveBack = false; font._fontFlags = 0; if (_voy._vocSecondsOffset > 60) _voy._vocSecondsOffset = 0; if (_voy._RTVNum > _voy._computerTimeMax && maxLen == 9999) { if (_currentVocId != -1) _soundManager.startVOCPlay(_currentVocId); font._justify = ALIGN_LEFT; font._justifyWidth = 384; font._justifyHeight = 100; font._pos = Common::Point(128, 100); (*_graphicsManager._vPort)->drawText(END_OF_MESSAGE); } else if (_voy._RTVNum < _voy._computerTimeMin && maxLen == 9999) { if (_currentVocId != -1) _soundManager.startVOCPlay(_currentVocId); font._justify = ALIGN_LEFT; font._justifyWidth = 384; font._justifyHeight = 100; font._pos = Common::Point(120, 100); (*_graphicsManager._vPort)->drawText(START_OF_MESSAGE); } else { char *msg = (char *)_bVoy->memberAddr(0x4900 + _voy._computerTextId); font._pos = Common::Point(96, 60); bool showEnd = true; int yp = 60; do { if (_currentVocId != -1 && !_soundManager.getVOCStatus()) { if (_voy._vocSecondsOffset > 60) _voy._vocSecondsOffset = 0; _soundManager.startVOCPlay(_currentVocId); } char c = *msg++; if (c == '\0') { if (showEnd) { _eventsManager.delay(90); _graphicsManager._drawPtr->_pos = Common::Point(96, 54); _graphicsManager._drawPtr->_penColor = 254; (*_graphicsManager._vPort)->sFillBox(196, 124); _graphicsManager._fontPtr->_justify = ALIGN_LEFT; _graphicsManager._fontPtr->_justifyWidth = 384; _graphicsManager._fontPtr->_justifyHeight = 100; _graphicsManager._fontPtr->_pos = Common::Point(128, 100); (*_graphicsManager._vPort)->drawText(END_OF_MESSAGE); } break; } if (c == '~' || c == '^') { if (c == '^') { yp += 10; } else { _eventsManager.delay(90); _graphicsManager._drawPtr->_pos = Common::Point(96, 54); _graphicsManager._drawPtr->_penColor = 255; (*_graphicsManager._vPort)->sFillBox(196, 124); yp = 60; } _graphicsManager._fontPtr->_pos = Common::Point(96, yp); } else if (c == '_') { showEnd = false; } else { _graphicsManager._fontPtr->_justify = ALIGN_LEFT; _graphicsManager._fontPtr->_justifyWidth = 0; _graphicsManager._fontPtr->_justifyHeight = 0; (*_graphicsManager._vPort)->drawText(Common::String(c)); _eventsManager.delay(4); } flipPageAndWait(); _eventsManager.getMouseInfo(); ++totalChars; } while (!shouldQuit() && !_eventsManager._mouseClicked && totalChars < maxLen); _voy._computerTimeMax = 0; } flipPageAndWait(); _graphicsManager._fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource; return totalChars; } void VoyeurEngine::getComputerBrush() { if (_bVoy->getBoltGroup(0x4900)) { PictureResource *pic = _bVoy->boltEntry(0x490E)._picResource; int xp = (384 - pic->_bounds.width()) / 2; int yp = (240 - pic->_bounds.height()) / 2 - 4; (*_graphicsManager._vPort)->drawPicPerm(pic, Common::Point(xp, yp)); CMapResource *pal = _bVoy->boltEntry(0x490F)._cMapResource; pal->startFade(); } } void VoyeurEngine::doTimeBar() { flashTimeBar(); if (_voy._RTVLimit > 0) { if (_voy._RTVNum > _voy._RTVLimit || _voy._RTVNum < 0) _voy._RTVNum = _voy._RTVLimit - 1; _timeBarVal = _voy._RTVNum; int height = ((_voy._RTVLimit - _voy._RTVNum) * 59) / _voy._RTVLimit; int fullHeight = MAX(151 - height, 93); _graphicsManager._drawPtr->_penColor = 134; _graphicsManager._drawPtr->_pos = Common::Point(39, 92); (*_graphicsManager._vPort)->sFillBox(6, fullHeight - 92); if (height > 0) { _graphicsManager.setColor(215, 238, 238, 238); _eventsManager._intPtr._hasPalette = true; _graphicsManager._drawPtr->_penColor = 215; _graphicsManager._drawPtr->_pos = Common::Point(39, fullHeight); (*_graphicsManager._vPort)->sFillBox(6, height); } } } void VoyeurEngine::flashTimeBar() { if (_voy._RTVNum >= 0 && (_voy._RTVLimit - _voy._RTVNum) < 11 && (_eventsManager._intPtr._flashTimer >= (_flashTimeVal + 15) || _eventsManager._intPtr._flashTimer < _flashTimeVal)) { // Within camera low power range _flashTimeVal = _eventsManager._intPtr._flashTimer; if (_flashTimeFlag) _graphicsManager.setColor(240, 220, 20, 20); else _graphicsManager.setColor(240, 220, 220, 220); _eventsManager._intPtr._hasPalette = true; _flashTimeFlag = !_flashTimeFlag; } } void VoyeurEngine::checkPhoneCall() { if ((_voy._RTVLimit - _voy._RTVNum) >= 36 && _voy._totalPhoneCalls < 5 && _currentVocId <= 151 && _currentVocId > 146) { if ((_voy._switchBGNum < _checkPhoneVal || _checkPhoneVal > 180) && !_soundManager.getVOCStatus()) { int soundIndex; do { soundIndex = getRandomNumber(4); } while (_voy._phoneCallsReceived[soundIndex]); _currentVocId = 154 + soundIndex; _soundManager.stopVOCPlay(); _soundManager.startVOCPlay(_currentVocId); _checkPhoneVal = _voy._switchBGNum; _voy._phoneCallsReceived[soundIndex] = true; ++_voy._totalPhoneCalls; } } } void VoyeurEngine::doEvidDisplay(int evidId, int eventId) { _eventsManager.getMouseInfo(); flipPageAndWait(); if (_currentVocId != -1) { _voy._vocSecondsOffset = _voy._RTVNum - _voy._musicStartTime; _soundManager.stopVOCPlay(); } _bVoy->getBoltGroup(_voy._boltGroupId2); PictureResource *pic = _bVoy->boltEntry(_voy._boltGroupId2 + evidId * 2)._picResource; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point( (384 - pic->_bounds.width()) / 2, (240 - pic->_bounds.height()) / 2)); _bVoy->freeBoltMember(_voy._boltGroupId2 + evidId * 2); CMapResource *pal = _bVoy->boltEntry(_voy._boltGroupId2 + evidId * 2 + 1)._cMapResource; pal->startFade(); while (!shouldQuit() && (_eventsManager._fadeStatus & 1)) _eventsManager.delay(1); _bVoy->freeBoltMember(_voy._boltGroupId2 + evidId * 2 + 1); Common::Array &hotspots = _bVoy->boltEntry(_playStampGroupId + 4)._rectResource->_entries; int count = hotspots[evidId]._count; if (count > 0) { for (int idx = 1; idx <= count; ++idx) { _voy._evPicPtrs[idx - 1] = _bVoy->boltEntry(_voy._boltGroupId2 + (evidId + idx) * 2)._picResource; _voy._evCmPtrs[idx - 1] = _bVoy->boltEntry(_voy._boltGroupId2 + (evidId + idx) * 2 + 1)._cMapResource; } } flipPageAndWait(); _eventsManager.stopEvidDim(); if (eventId == 999) _voy.addEvidEventStart(evidId); _eventsManager.getMouseInfo(); int arrIndex = 0; int evidIdx = evidId; while (!shouldQuit() && !_eventsManager._rightClick) { _voyeurArea = AREA_EVIDENCE; if (_currentVocId != -1 && !_soundManager.getVOCStatus()) { if (_voy._vocSecondsOffset > 60) _voy._vocSecondsOffset = 0; _soundManager.startVOCPlay(_currentVocId); } _eventsManager.delayClick(600); if (_eventsManager._rightClick) break; if (count == 0 || evidIdx >= eventId) continue; pic = _voy._evPicPtrs[arrIndex]; _graphicsManager.sDrawPic(pic, *_graphicsManager._vPort, Common::Point((384 - pic->_bounds.width()) / 2, (240 - pic->_bounds.height()) / 2)); _voy._evCmPtrs[arrIndex]->startFade(); while (!shouldQuit() && (_eventsManager._fadeStatus & 1)) _eventsManager.delay(1); flipPageAndWait(); _eventsManager.delay(6); ++evidIdx; ++arrIndex; --count; } if (eventId == 999) _voy.addEvidEventEnd(evidIdx); for (int idx = 1; idx <= hotspots[evidId]._count; ++idx) { _bVoy->freeBoltMember(_voy._boltGroupId2 + (evidId + idx) * 2); _bVoy->freeBoltMember(_voy._boltGroupId2 + (evidId + idx) * 2 + 1); } } } // End of namespace Voyeur