mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-01 16:35:20 +00:00
00e59a3122
This commit introduces the following changes: 1. Graphics::loadThumbnail() Now returns a boolean and takes a new argument skipThumbnail which defaults to false. In case of true, loadThumbnail() reads past the thumbnail data in the input stream instead of actually loading the thumbnail. This simplifies savegame handling where, up until now, many engines always read the whole savegame metadata (including the thumbnail) and then threw away the thumbnail when not needed (which is in almost all cases, the most common exception being MetaEngine::querySaveMetaInfos() which is responsible for loading savegame metadata for displaying it in the GUI launcher. 2. readSavegameHeader() Engines which already implement such a method (name varies) now take a new argument skipThumbnail (default: true) which is passed through to loadThumbnail(). This means that the default case for readSavegameHeader() is now _not_ loading the thumbnail from a savegame and just reading past it. In those cases, e.g. querySaveMetaInfos(), where we actually are interested in loading the thumbnail readSavegameHeader() needs to explicitely be called with skipThumbnail == false. Engines whose readSavegameHeader() (name varies) already takes an argument loadThumbnail have been adapted to have a similar prototype and semantics. I.e. readSaveHeader(in, loadThumbnail, header) now is readSaveHeader(in, header, skipThumbnail). 3. Error handling Engines which previously did not check the return value of readSavegameHeader() (name varies) now do so ensuring that possibly broken savegames (be it a broken thumbnail or something else) don't make it into the GUI launcher list in the first place.
919 lines
23 KiB
C++
919 lines
23 KiB
C++
/* 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/animation.h"
|
|
#include "voyeur/screen.h"
|
|
#include "voyeur/staticres.h"
|
|
#include "common/scummsys.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/debug-channels.h"
|
|
#include "graphics/palette.h"
|
|
#include "graphics/scaler.h"
|
|
#include "graphics/thumbnail.h"
|
|
|
|
namespace Voyeur {
|
|
|
|
VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc) : Engine(syst),
|
|
_gameDescription(gameDesc), _randomSource("Voyeur"),
|
|
_defaultFontInfo(3, 0xff, 0xff, 0, 0, ALIGN_LEFT, 0, Common::Point(), 1, 1,
|
|
Common::Point(1, 1), 1, 0, 0) {
|
|
_debugger = nullptr;
|
|
_eventsManager = nullptr;
|
|
_filesManager = nullptr;
|
|
_screen = nullptr;
|
|
_soundManager = nullptr;
|
|
_voy = nullptr;
|
|
_bVoy = NULL;
|
|
|
|
_iForceDeath = ConfMan.getInt("boot_param");
|
|
if (_iForceDeath < 1 || _iForceDeath > 4)
|
|
_iForceDeath = -1;
|
|
|
|
_controlPtr = NULL;
|
|
_stampFlags = 0;
|
|
_playStampGroupId = _currentVocId = 0;
|
|
_audioVideoId = -1;
|
|
_checkTransitionId = -1;
|
|
_gameHour = 0;
|
|
_gameMinute = 0;
|
|
_flashTimeVal = 0;
|
|
_flashTimeFlag = false;
|
|
_timeBarVal = -1;
|
|
_checkPhoneVal = 0;
|
|
_voyeurArea = AREA_NONE;
|
|
_loadGameSlot = -1;
|
|
|
|
DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
|
|
|
|
_stampLibPtr = nullptr;
|
|
_controlGroupPtr = nullptr;
|
|
_stampData = nullptr;
|
|
_stackGroupPtr = nullptr;
|
|
_glGoState = -1;
|
|
_glGoStack = -1;
|
|
_resolvePtr = nullptr;
|
|
_mainThread = nullptr;
|
|
|
|
centerMansionView();
|
|
}
|
|
|
|
VoyeurEngine::~VoyeurEngine() {
|
|
delete _bVoy;
|
|
delete _voy;
|
|
delete _soundManager;
|
|
delete _screen;
|
|
delete _filesManager;
|
|
delete _eventsManager;
|
|
delete _debugger;
|
|
}
|
|
|
|
Common::Error VoyeurEngine::run() {
|
|
ESP_Init();
|
|
globalInitBolt();
|
|
|
|
if (doHeadTitle()) {
|
|
// The original allows the victim to be explicitly specified via the command line.
|
|
// This is possible in ScummVM by using a boot parameter.
|
|
if (_iForceDeath >= 1 && _iForceDeath <= 4)
|
|
_voy->_eventFlags |= EVTFLAG_VICTIM_PRESET;
|
|
|
|
|
|
playStamp();
|
|
if (!shouldQuit())
|
|
doTailTitle();
|
|
}
|
|
|
|
return Common::kNoError;
|
|
}
|
|
|
|
|
|
int VoyeurEngine::getRandomNumber(int maxNumber) {
|
|
return _randomSource.getRandomNumber(maxNumber);
|
|
}
|
|
|
|
void VoyeurEngine::ESP_Init() {
|
|
ThreadResource::init();
|
|
|
|
if (ConfMan.hasKey("save_slot"))
|
|
_loadGameSlot = ConfMan.getInt("save_slot");
|
|
}
|
|
|
|
void VoyeurEngine::globalInitBolt() {
|
|
_debugger = new Debugger(this);
|
|
_eventsManager = new EventsManager(this);
|
|
_filesManager = new FilesManager(this);
|
|
_screen = new Screen(this);
|
|
_soundManager = new SoundManager(_mixer);
|
|
_voy = new SVoy(this);
|
|
|
|
initBolt();
|
|
|
|
_filesManager->openBoltLib("bvoy.blt", _bVoy);
|
|
_bVoy->getBoltGroup(0x000);
|
|
_bVoy->getBoltGroup(0x100);
|
|
|
|
_screen->_fontPtr = &_defaultFontInfo;
|
|
_screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
|
|
assert(_screen->_fontPtr->_curFont);
|
|
|
|
// Setup default flags
|
|
_voy->_viewBounds = nullptr;
|
|
|
|
_eventsManager->addFadeInt();
|
|
}
|
|
|
|
void VoyeurEngine::initBolt() {
|
|
vInitInterrupts();
|
|
_screen->sInitGraphics();
|
|
_eventsManager->vInitColor();
|
|
initInput();
|
|
}
|
|
|
|
void VoyeurEngine::vInitInterrupts() {
|
|
_eventsManager->_intPtr._palette = &_screen->_VGAColors[0];
|
|
}
|
|
|
|
void VoyeurEngine::initInput() {
|
|
}
|
|
|
|
bool VoyeurEngine::doHeadTitle() {
|
|
// char dest[144];
|
|
|
|
_eventsManager->startMainClockInt();
|
|
|
|
if (_loadGameSlot == -1) {
|
|
// Show starting screen
|
|
if (_bVoy->getBoltGroup(0x500)) {
|
|
showConversionScreen();
|
|
_bVoy->freeBoltGroup(0x500);
|
|
|
|
if (shouldQuit())
|
|
return false;
|
|
}
|
|
|
|
if (ConfMan.getBool("copy_protection")) {
|
|
// Display lock screen
|
|
bool result = doLock();
|
|
if (!result || shouldQuit())
|
|
return false;
|
|
}
|
|
|
|
// Show the title screen
|
|
_eventsManager->getMouseInfo();
|
|
showTitleScreen();
|
|
if (shouldQuit())
|
|
return false;
|
|
|
|
// Opening
|
|
_eventsManager->getMouseInfo();
|
|
doOpening();
|
|
if (shouldQuit())
|
|
return false;
|
|
|
|
_eventsManager->getMouseInfo();
|
|
doTransitionCard("Saturday Afternoon", "Player's Apartment");
|
|
_eventsManager->delayClick(90);
|
|
|
|
if (_voy->_eventFlags & EVTFLAG_VICTIM_PRESET) {
|
|
// Preset victim turned on, so add a default set of incriminating videos
|
|
_voy->addEvent(18, 1, EVTYPE_VIDEO, 33, 0, 998, -1);
|
|
_voy->addEvent(18, 2, EVTYPE_VIDEO, 41, 0, 998, -1);
|
|
_voy->addEvent(18, 3, EVTYPE_VIDEO, 47, 0, 998, -1);
|
|
_voy->addEvent(18, 4, EVTYPE_VIDEO, 53, 0, 998, -1);
|
|
_voy->addEvent(18, 5, EVTYPE_VIDEO, 46, 0, 998, -1);
|
|
_voy->addEvent(18, 6, EVTYPE_VIDEO, 50, 0, 998, -1);
|
|
_voy->addEvent(18, 7, EVTYPE_VIDEO, 40, 0, 998, -1);
|
|
_voy->addEvent(18, 8, EVTYPE_VIDEO, 43, 0, 998, -1);
|
|
_voy->addEvent(19, 1, EVTYPE_AUDIO, 20, 0, 998, -1);
|
|
}
|
|
}
|
|
|
|
_voy->_aptLoadMode = 140;
|
|
return true;
|
|
}
|
|
|
|
void VoyeurEngine::showConversionScreen() {
|
|
_screen->_backgroundPage = _bVoy->boltEntry(0x502)._picResource;
|
|
_screen->_vPort->setupViewPort();
|
|
flipPageAndWait();
|
|
|
|
// Immediate palette load to show the initial screen
|
|
CMapResource *cMap = _bVoy->getCMapResource(0x503);
|
|
assert(cMap);
|
|
cMap->_steps = 0;
|
|
cMap->startFade();
|
|
|
|
// Wait briefly
|
|
_eventsManager->delayClick(150);
|
|
if (shouldQuit())
|
|
return;
|
|
|
|
// Fade out the screen
|
|
cMap = _bVoy->getCMapResource(0x504);
|
|
cMap->_steps = 30;
|
|
cMap->startFade();
|
|
if (shouldQuit())
|
|
return;
|
|
|
|
flipPageAndWaitForFade();
|
|
|
|
_screen->screenReset();
|
|
}
|
|
|
|
bool VoyeurEngine::doLock() {
|
|
bool result = true;
|
|
int buttonVocSize, wrongVocSize;
|
|
byte *buttonVoc = _filesManager->fload("button.voc", &buttonVocSize);
|
|
byte *wrongVoc = _filesManager->fload("wrong.voc", &wrongVocSize);
|
|
|
|
if (_bVoy->getBoltGroup(0x700)) {
|
|
Common::String password = "3333";
|
|
|
|
_screen->_backgroundPage = _bVoy->getPictureResource(0x700);
|
|
_screen->_backColors = _bVoy->getCMapResource(0x701);
|
|
PictureResource *cursorPic = _bVoy->getPictureResource(0x702);
|
|
_voy->_viewBounds = _bVoy->boltEntry(0x704)._rectResource;
|
|
Common::Array<RectEntry> &hotspots = _bVoy->boltEntry(0x705)._rectResource->_entries;
|
|
|
|
assert(cursorPic);
|
|
_screen->_vPort->setupViewPort();
|
|
|
|
_screen->_backColors->startFade();
|
|
_screen->_vPort->_parent->_flags |= DISPFLAG_8;
|
|
_screen->flipPage();
|
|
_eventsManager->sWaitFlip();
|
|
|
|
while (!shouldQuit() && (_eventsManager->_fadeStatus & 1))
|
|
_eventsManager->delay(1);
|
|
|
|
_eventsManager->setCursorColor(127, 0);
|
|
_screen->setColor(1, 64, 64, 64);
|
|
_screen->setColor(2, 96, 96, 96);
|
|
_screen->setColor(3, 160, 160, 160);
|
|
_screen->setColor(4, 224, 224, 224);
|
|
|
|
// Set up the cursor
|
|
_eventsManager->setCursor(cursorPic);
|
|
_eventsManager->showCursor();
|
|
|
|
_eventsManager->_intPtr._hasPalette = true;
|
|
|
|
_screen->_fontPtr->_curFont = _bVoy->boltEntry(0x708)._fontResource;
|
|
_screen->_fontPtr->_fontSaveBack = 0;
|
|
_screen->_fontPtr->_fontFlags = DISPFLAG_NONE;
|
|
|
|
Common::String dateString = "ScummVM";
|
|
Common::String displayString = Common::String::format("Last Play %s", dateString.c_str());
|
|
|
|
bool firstLoop = true;
|
|
bool breakFlag = false;
|
|
while (!breakFlag && !shouldQuit()) {
|
|
_screen->_vPort->setupViewPort();
|
|
flipPageAndWait();
|
|
|
|
// Display the last play time
|
|
_screen->_fontPtr->_pos = Common::Point(0, 97);
|
|
_screen->_fontPtr->_justify = ALIGN_CENTER;
|
|
_screen->_fontPtr->_justifyWidth = 384;
|
|
_screen->_fontPtr->_justifyHeight = 97;
|
|
|
|
_screen->_vPort->drawText(displayString);
|
|
flipPageAndWait();
|
|
|
|
if (firstLoop) {
|
|
firstLoop = false;
|
|
displayString = "";
|
|
}
|
|
|
|
// Loop for getting key presses
|
|
int key;
|
|
do {
|
|
do {
|
|
// Scan through the list of key rects to check if a keypad key is highlighted
|
|
key = -1;
|
|
Common::Point mousePos = _eventsManager->getMousePos() + Common::Point(20, 10);
|
|
|
|
int keyCount = hotspots.size();
|
|
for (int keyIndex = 0; keyIndex < keyCount; ++keyIndex) {
|
|
if (hotspots[keyIndex].contains(mousePos)) {
|
|
key = keyIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_eventsManager->setCursorColor(127, (key == -1) ? 0 : 1);
|
|
_eventsManager->_intPtr._hasPalette = true;
|
|
|
|
_eventsManager->delay(1);
|
|
_eventsManager->getMouseInfo();
|
|
} while (!shouldQuit() && !_eventsManager->_mouseClicked);
|
|
_eventsManager->_mouseClicked = false;
|
|
} while (!shouldQuit() && key == -1);
|
|
|
|
_soundManager->abortVOCMap();
|
|
_soundManager->playVOCMap(buttonVoc, buttonVocSize);
|
|
|
|
while (_soundManager->getVOCStatus()) {
|
|
if (shouldQuit())
|
|
break;
|
|
_eventsManager->delay(1);
|
|
}
|
|
|
|
// Process the key
|
|
if (key < 10) {
|
|
// Numeric key
|
|
if (displayString.size() < 10) {
|
|
displayString += '0' + key;
|
|
continue;
|
|
}
|
|
} else if (key == 10) {
|
|
// Accept key
|
|
if ((password.empty() && displayString.empty()) || (password == displayString)) {
|
|
breakFlag = true;
|
|
result = true;
|
|
break;
|
|
}
|
|
} else if (key == 11) {
|
|
// New code
|
|
if ((password.empty() && displayString.empty()) || (password != displayString)) {
|
|
_screen->_vPort->setupViewPort();
|
|
password = displayString;
|
|
displayString = "";
|
|
continue;
|
|
}
|
|
} else if (key == 12) {
|
|
// Exit keyword
|
|
breakFlag = true;
|
|
result = false;
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
_soundManager->playVOCMap(wrongVoc, wrongVocSize);
|
|
}
|
|
|
|
_screen->fillPic(_screen->_vPort, 0);
|
|
flipPageAndWait();
|
|
_screen->resetPalette();
|
|
|
|
_voy->_viewBounds = nullptr;
|
|
_bVoy->freeBoltGroup(0x700);
|
|
}
|
|
|
|
_eventsManager->hideCursor();
|
|
|
|
delete[] buttonVoc;
|
|
delete[] wrongVoc;
|
|
|
|
return result;
|
|
}
|
|
|
|
void VoyeurEngine::showTitleScreen() {
|
|
if (!_bVoy->getBoltGroup(0x500))
|
|
return;
|
|
|
|
_screen->_backgroundPage = _bVoy->getPictureResource(0x500);
|
|
|
|
_screen->_vPort->setupViewPort();
|
|
flipPageAndWait();
|
|
|
|
// Immediate palette load to show the initial screen
|
|
CMapResource *cMap = _bVoy->getCMapResource(0x501);
|
|
assert(cMap);
|
|
cMap->_steps = 60;
|
|
cMap->startFade();
|
|
|
|
// Wait briefly
|
|
_eventsManager->delayClick(200);
|
|
if (shouldQuit()) {
|
|
_bVoy->freeBoltGroup(0x500);
|
|
return;
|
|
}
|
|
|
|
// Fade out the screen
|
|
cMap = _bVoy->getCMapResource(0x504);
|
|
cMap->_steps = 30;
|
|
cMap->startFade();
|
|
|
|
flipPageAndWaitForFade();
|
|
if (shouldQuit()) {
|
|
_bVoy->freeBoltGroup(0x500);
|
|
return;
|
|
}
|
|
|
|
_screen->screenReset();
|
|
_eventsManager->delayClick(200);
|
|
|
|
// Voyeur title
|
|
playRL2Video("a1100100.rl2");
|
|
_screen->screenReset();
|
|
|
|
_bVoy->freeBoltGroup(0x500);
|
|
}
|
|
|
|
void VoyeurEngine::doOpening() {
|
|
_screen->screenReset();
|
|
|
|
if (!_bVoy->getBoltGroup(0x200))
|
|
return;
|
|
|
|
byte *frameTable = _bVoy->memberAddr(0x215);
|
|
byte *xyTable = _bVoy->memberAddr(0x216);
|
|
// byte *whTable = _bVoy->memberAddr(0x217);
|
|
int frameIndex = 0;
|
|
bool creditShow = true;
|
|
PictureResource *textPic = nullptr;
|
|
Common::Point textPos;
|
|
|
|
_voy->_vocSecondsOffset = 0;
|
|
_voy->_RTVNum = 0;
|
|
_voy->_audioVisualStartTime = _voy->_RTVNum;
|
|
_voy->_eventFlags |= EVTFLAG_RECORDING;
|
|
_gameHour = 4;
|
|
_gameMinute = 0;
|
|
_audioVideoId = 1;
|
|
_eventsManager->_videoDead = -1;
|
|
_voy->addVideoEventStart();
|
|
|
|
_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED;
|
|
|
|
for (int i = 0; i < 256; ++i)
|
|
_screen->setColor(i, 8, 8, 8);
|
|
|
|
_eventsManager->_intPtr._hasPalette = true;
|
|
_screen->_vPort->setupViewPort();
|
|
flipPageAndWait();
|
|
|
|
RL2Decoder decoder;
|
|
decoder.loadRL2File("a2300100.rl2", false);
|
|
decoder.start();
|
|
|
|
while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked) {
|
|
if (decoder.hasDirtyPalette()) {
|
|
const byte *palette = decoder.getPalette();
|
|
_screen->setPalette(palette, 0, 256);
|
|
}
|
|
|
|
if (decoder.needsUpdate()) {
|
|
const Graphics::Surface *frame = decoder.decodeNextFrame();
|
|
_screen->blitFrom(*frame);
|
|
|
|
if (decoder.getCurFrame() >= (int32)READ_LE_UINT32(frameTable + frameIndex * 4)) {
|
|
if (creditShow) {
|
|
// Show a credit
|
|
textPic = _bVoy->boltEntry(frameIndex / 2 + 0x202)._picResource;
|
|
textPos = Common::Point(READ_LE_UINT16(xyTable + frameIndex * 2),
|
|
READ_LE_UINT16(xyTable + (frameIndex + 1) * 2));
|
|
|
|
creditShow = false;
|
|
} else {
|
|
textPic = nullptr;
|
|
|
|
creditShow = true;
|
|
}
|
|
|
|
++frameIndex;
|
|
}
|
|
|
|
if (textPic) {
|
|
_screen->sDrawPic(textPic, _screen->_vPort, textPos);
|
|
}
|
|
|
|
flipPageAndWait();
|
|
}
|
|
|
|
_eventsManager->getMouseInfo();
|
|
g_system->delayMillis(10);
|
|
}
|
|
|
|
if ((_voy->_RTVNum - _voy->_audioVisualStartTime) < 2)
|
|
_eventsManager->delay(60);
|
|
|
|
_voy->_eventFlags |= EVTFLAG_TIME_DISABLED;
|
|
_voy->addVideoEventEnd();
|
|
_voy->_eventFlags &= ~EVTFLAG_RECORDING;
|
|
|
|
_bVoy->freeBoltGroup(0x200);
|
|
}
|
|
|
|
void VoyeurEngine::playRL2Video(const Common::String &filename) {
|
|
RL2Decoder decoder;
|
|
decoder.loadRL2File(filename, false);
|
|
decoder.start();
|
|
|
|
while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked) {
|
|
if (decoder.hasDirtyPalette()) {
|
|
const byte *palette = decoder.getPalette();
|
|
_screen->setPalette(palette, 0, 256);
|
|
}
|
|
|
|
if (decoder.needsUpdate()) {
|
|
const Graphics::Surface *frame = decoder.decodeNextFrame();
|
|
_screen->blitFrom(*frame);
|
|
}
|
|
|
|
_eventsManager->getMouseInfo();
|
|
g_system->delayMillis(10);
|
|
}
|
|
}
|
|
|
|
void VoyeurEngine::playAVideo(int videoId) {
|
|
playAVideoDuration(videoId, 9999);
|
|
}
|
|
|
|
void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
|
|
int totalFrames = duration * 10;
|
|
|
|
if (videoId == -1)
|
|
return;
|
|
|
|
PictureResource *pic = NULL;
|
|
if (videoId == 42) {
|
|
_bVoy->getBoltGroup(0xE00);
|
|
_eventsManager->_videoDead = 0;
|
|
pic = _bVoy->boltEntry(0xE00 + _eventsManager->_videoDead)._picResource;
|
|
}
|
|
|
|
RL2Decoder decoder;
|
|
decoder.loadVideo(videoId);
|
|
|
|
decoder.seek(Audio::Timestamp(_voy->_vocSecondsOffset * 1000));
|
|
decoder.start();
|
|
int endFrame = decoder.getCurFrame() + totalFrames;
|
|
|
|
_eventsManager->getMouseInfo();
|
|
_eventsManager->startCursorBlink();
|
|
|
|
while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked &&
|
|
(decoder.getCurFrame() < endFrame)) {
|
|
if (decoder.needsUpdate()) {
|
|
const Graphics::Surface *frame = decoder.decodeNextFrame();
|
|
_screen->blitFrom(*frame);
|
|
|
|
if (_voy->_eventFlags & EVTFLAG_RECORDING)
|
|
_screen->drawDot();
|
|
}
|
|
|
|
if (decoder.hasDirtyPalette()) {
|
|
const byte *palette = decoder.getPalette();
|
|
_screen->setPalette(palette, 0, decoder.getPaletteCount());
|
|
_screen->setOneColor(128, 220, 20, 20);
|
|
}
|
|
|
|
_eventsManager->getMouseInfo();
|
|
g_system->delayMillis(10);
|
|
}
|
|
|
|
// RL2 finished
|
|
_screen->screenReset();
|
|
_voy->_eventFlags &= ~EVTFLAG_RECORDING;
|
|
|
|
if (_voy->_eventFlags & EVTFLAG_8) {
|
|
assert(pic);
|
|
byte *imgData = _screen->_vPort->_currentPic->_imgData;
|
|
_screen->_vPort->_currentPic->_imgData = pic->_imgData;
|
|
pic->_imgData = imgData;
|
|
_voy->_eventFlags &= ~EVTFLAG_8;
|
|
}
|
|
|
|
if (videoId == 42)
|
|
_bVoy->freeBoltGroup(0xE00);
|
|
}
|
|
|
|
void VoyeurEngine::playAudio(int audioId) {
|
|
_bVoy->getBoltGroup(0x7F00);
|
|
_screen->_backgroundPage = _bVoy->boltEntry(0x7F00 +
|
|
BLIND_TABLE[audioId] * 2)._picResource;
|
|
_screen->_backColors = _bVoy->boltEntry(0x7F01 +
|
|
BLIND_TABLE[audioId] * 2)._cMapResource;
|
|
|
|
_screen->_vPort->setupViewPort();
|
|
_screen->_backColors->startFade();
|
|
flipPageAndWaitForFade();
|
|
|
|
_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED;
|
|
_soundManager->setVOCOffset(_voy->_vocSecondsOffset);
|
|
Common::String filename = _soundManager->getVOCFileName(
|
|
audioId + 159);
|
|
_soundManager->startVOCPlay(filename);
|
|
_voy->_eventFlags |= EVTFLAG_RECORDING;
|
|
_eventsManager->startCursorBlink();
|
|
|
|
while (!shouldQuit() && !_eventsManager->_mouseClicked &&
|
|
_soundManager->getVOCStatus())
|
|
_eventsManager->delayClick(1);
|
|
|
|
_voy->_eventFlags |= EVTFLAG_TIME_DISABLED;
|
|
_soundManager->stopVOCPlay();
|
|
|
|
_bVoy->freeBoltGroup(0x7F00);
|
|
_screen->_vPort->setupViewPort(NULL);
|
|
|
|
_voy->_eventFlags &= ~EVTFLAG_RECORDING;
|
|
_voy->_playStampMode = 129;
|
|
}
|
|
|
|
void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::String &location) {
|
|
_screen->setColor(128, 16, 16, 16);
|
|
_screen->setColor(224, 220, 220, 220);
|
|
_eventsManager->_intPtr._hasPalette = true;
|
|
|
|
_screen->_vPort->setupViewPort(NULL);
|
|
_screen->_vPort->fillPic(0x80);
|
|
_screen->flipPage();
|
|
_eventsManager->sWaitFlip();
|
|
|
|
flipPageAndWait();
|
|
_screen->_vPort->fillPic(0x80);
|
|
|
|
FontInfoResource &fi = *_screen->_fontPtr;
|
|
fi._curFont = _bVoy->boltEntry(257)._fontResource;
|
|
fi._foreColor = 224;
|
|
fi._fontSaveBack = 0;
|
|
fi._pos = Common::Point(0, 116);
|
|
fi._justify = ALIGN_CENTER;
|
|
fi._justifyWidth = 384;
|
|
fi._justifyHeight = 120;
|
|
|
|
_screen->_vPort->drawText(time);
|
|
|
|
if (!location.empty()) {
|
|
fi._pos = Common::Point(0, 138);
|
|
fi._justify = ALIGN_CENTER;
|
|
fi._justifyWidth = 384;
|
|
fi._justifyHeight = 140;
|
|
|
|
_screen->_vPort->drawText(location);
|
|
}
|
|
|
|
flipPageAndWait();
|
|
}
|
|
|
|
void VoyeurEngine::saveLastInplay() {
|
|
// No implementation in ScummVM version
|
|
}
|
|
|
|
void VoyeurEngine::flipPageAndWait() {
|
|
_screen->_vPort->_flags |= DISPFLAG_8;
|
|
_screen->flipPage();
|
|
_eventsManager->sWaitFlip();
|
|
}
|
|
|
|
void VoyeurEngine::flipPageAndWaitForFade() {
|
|
flipPageAndWait();
|
|
|
|
while (!shouldQuit() && (_eventsManager->_fadeStatus & 1))
|
|
_eventsManager->delay(1);
|
|
}
|
|
|
|
void VoyeurEngine::showEndingNews() {
|
|
_playStampGroupId = (_voy->_incriminatedVictimNumber - 1) * 256 + 0x7700;
|
|
_voy->_boltGroupId2 = (_controlPtr->_state->_victimIndex - 1) * 256 + 0x7B00;
|
|
|
|
_bVoy->getBoltGroup(_playStampGroupId);
|
|
_bVoy->getBoltGroup(_voy->_boltGroupId2);
|
|
|
|
PictureResource *pic = _bVoy->boltEntry(_playStampGroupId)._picResource;
|
|
CMapResource *pal = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource;
|
|
|
|
_screen->_vPort->setupViewPort(pic);
|
|
pal->startFade();
|
|
flipPageAndWaitForFade();
|
|
|
|
_eventsManager->getMouseInfo();
|
|
|
|
for (int idx = 1; idx < 4; ++idx) {
|
|
if (idx == 3) {
|
|
pic = _bVoy->boltEntry(_voy->_boltGroupId2)._picResource;
|
|
pal = _bVoy->boltEntry(_voy->_boltGroupId2 + 1)._cMapResource;
|
|
} else {
|
|
pic = _bVoy->boltEntry(_playStampGroupId + idx * 2)._picResource;
|
|
pal = _bVoy->boltEntry(_playStampGroupId + idx * 2 + 1)._cMapResource;
|
|
}
|
|
|
|
_screen->_vPort->setupViewPort(pic);
|
|
pal->startFade();
|
|
flipPageAndWaitForFade();
|
|
|
|
_bVoy->freeBoltMember(_playStampGroupId + (idx - 1) * 2);
|
|
_bVoy->freeBoltMember(_playStampGroupId + (idx - 1) * 2 + 1);
|
|
|
|
Common::String fname = Common::String::format("news%d.voc", idx);
|
|
_soundManager->startVOCPlay(fname);
|
|
|
|
_eventsManager->getMouseInfo();
|
|
while (!shouldQuit() && !_eventsManager->_mouseClicked &&
|
|
_soundManager->getVOCStatus()) {
|
|
_eventsManager->delay(1);
|
|
_eventsManager->getMouseInfo();
|
|
}
|
|
|
|
_soundManager->stopVOCPlay();
|
|
if (idx == 3)
|
|
_eventsManager->delay(3);
|
|
|
|
if (shouldQuit() || _eventsManager->_mouseClicked)
|
|
break;
|
|
}
|
|
|
|
_bVoy->freeBoltGroup(_playStampGroupId);
|
|
_bVoy->freeBoltGroup(_voy->_boltGroupId2);
|
|
_playStampGroupId = -1;
|
|
_voy->_boltGroupId2 = -1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
Common::String VoyeurEngine::generateSaveName(int slot) {
|
|
return Common::String::format("%s.%03d", _targetName.c_str(), slot);
|
|
}
|
|
|
|
/**
|
|
* Returns true if it is currently okay to restore a game
|
|
*/
|
|
bool VoyeurEngine::canLoadGameStateCurrently() {
|
|
return _voyeurArea == AREA_APARTMENT;
|
|
}
|
|
|
|
/**
|
|
* Returns true if it is currently okay to save the game
|
|
*/
|
|
bool VoyeurEngine::canSaveGameStateCurrently() {
|
|
return _voyeurArea == AREA_APARTMENT;
|
|
}
|
|
|
|
/**
|
|
* Load the savegame at the specified slot index
|
|
*/
|
|
Common::Error VoyeurEngine::loadGameState(int slot) {
|
|
_loadGameSlot = slot;
|
|
return Common::kNoError;
|
|
}
|
|
|
|
void VoyeurEngine::loadGame(int slot) {
|
|
// Open up the save file
|
|
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(generateSaveName(slot));
|
|
if (!saveFile)
|
|
return;
|
|
|
|
Common::Serializer serializer(saveFile, NULL);
|
|
|
|
// Store the current time index before the game is loaded
|
|
_checkTransitionId = _voy->_transitionId;
|
|
|
|
// Stop any playing sound
|
|
_soundManager->stopVOCPlay();
|
|
|
|
// Read in the savegame header
|
|
VoyeurSavegameHeader header;
|
|
if (!header.read(saveFile))
|
|
return;
|
|
|
|
serializer.setVersion(header._version);
|
|
synchronize(serializer);
|
|
|
|
delete saveFile;
|
|
|
|
// Show a transition card if the time index has changed
|
|
checkTransition();
|
|
|
|
// Load the apartment
|
|
_mainThread->loadTheApt();
|
|
}
|
|
|
|
/**
|
|
* Save the game to the given slot index, and with the given name
|
|
*/
|
|
Common::Error VoyeurEngine::saveGameState(int slot, const Common::String &desc) {
|
|
// Open the save file for writing
|
|
Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(generateSaveName(slot));
|
|
if (!saveFile)
|
|
return Common::kCreatingFileFailed;
|
|
|
|
// Write out the header
|
|
VoyeurSavegameHeader header;
|
|
header.write(saveFile, this, desc);
|
|
|
|
// Set up a serializer
|
|
Common::Serializer serializer(NULL, saveFile);
|
|
|
|
// Synchronise the data
|
|
serializer.setVersion(VOYEUR_SAVEGAME_VERSION);
|
|
synchronize(serializer);
|
|
|
|
saveFile->finalize();
|
|
delete saveFile;
|
|
|
|
return Common::kNoError;
|
|
}
|
|
|
|
void VoyeurEngine::synchronize(Common::Serializer &s) {
|
|
s.syncAsSint16LE(_glGoState);
|
|
s.syncAsSint16LE(_glGoStack);
|
|
s.syncAsSint16LE(_stampFlags);
|
|
s.syncAsSint16LE(_playStampGroupId);
|
|
s.syncAsSint16LE(_currentVocId);
|
|
s.syncAsSint16LE(_audioVideoId);
|
|
|
|
s.syncAsSint16LE(_iForceDeath);
|
|
s.syncAsSint16LE(_gameHour);
|
|
s.syncAsSint16LE(_gameMinute);
|
|
s.syncAsSint16LE(_flashTimeVal);
|
|
s.syncAsSint16LE(_flashTimeFlag);
|
|
s.syncAsSint16LE(_timeBarVal);
|
|
s.syncAsSint16LE(_checkPhoneVal);
|
|
|
|
// Sub-systems
|
|
_voy->synchronize(s);
|
|
_screen->synchronize(s);
|
|
_mainThread->synchronize(s);
|
|
_controlPtr->_state->synchronize(s);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
bool VoyeurSavegameHeader::read(Common::InSaveFile *f, bool skipThumbnail) {
|
|
uint32 signature = f->readUint32BE();
|
|
if (signature != MKTAG('V', 'O', 'Y', 'R')) {
|
|
warning("Invalid savegame");
|
|
return false;
|
|
}
|
|
|
|
_version = f->readByte();
|
|
if (_version > VOYEUR_SAVEGAME_VERSION)
|
|
return false;
|
|
|
|
char c;
|
|
_saveName = "";
|
|
while ((c = f->readByte()) != 0)
|
|
_saveName += c;
|
|
|
|
// Get the thumbnail
|
|
if (!Graphics::loadThumbnail(*f, _thumbnail, skipThumbnail)) {
|
|
return false;
|
|
}
|
|
|
|
// Read in the save datet/ime
|
|
_saveYear = f->readSint16LE();
|
|
_saveMonth = f->readSint16LE();
|
|
_saveDay = f->readSint16LE();
|
|
_saveHour = f->readSint16LE();
|
|
_saveMinutes = f->readSint16LE();
|
|
_totalFrames = f->readUint32LE();
|
|
|
|
return true;
|
|
}
|
|
|
|
void VoyeurSavegameHeader::write(Common::OutSaveFile *f, VoyeurEngine *vm, const Common::String &saveName) {
|
|
// Write ident string
|
|
f->writeUint32BE(MKTAG('V', 'O', 'Y', 'R'));
|
|
|
|
// Write out savegame version
|
|
f->writeByte(VOYEUR_SAVEGAME_VERSION);
|
|
|
|
// Write out savegame name
|
|
f->write(saveName.c_str(), saveName.size());
|
|
f->writeByte(0);
|
|
|
|
// Create a thumbnail and save it
|
|
Graphics::Surface *thumb = new Graphics::Surface();
|
|
::createThumbnail(thumb, (const byte *)vm->_screen->getPixels(),
|
|
SCREEN_WIDTH, SCREEN_HEIGHT, vm->_screen->_VGAColors);
|
|
Graphics::saveThumbnail(*f, *thumb);
|
|
thumb->free();
|
|
delete thumb;
|
|
|
|
// Write the save datet/ime
|
|
TimeDate td;
|
|
g_system->getTimeAndDate(td);
|
|
f->writeSint16LE(td.tm_year + 1900);
|
|
f->writeSint16LE(td.tm_mon + 1);
|
|
f->writeSint16LE(td.tm_mday);
|
|
f->writeSint16LE(td.tm_hour);
|
|
f->writeSint16LE(td.tm_min);
|
|
f->writeUint32LE(vm->_eventsManager->getGameCounter());
|
|
}
|
|
|
|
} // End of namespace Voyeur
|