aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/voyeur/detection.cpp14
-rw-r--r--engines/voyeur/events.h1
-rw-r--r--engines/voyeur/files.h4
-rw-r--r--engines/voyeur/files_threads.cpp11
-rw-r--r--engines/voyeur/graphics.cpp4
-rw-r--r--engines/voyeur/graphics.h6
-rw-r--r--engines/voyeur/voyeur.cpp305
-rw-r--r--engines/voyeur/voyeur.h24
-rw-r--r--engines/voyeur/voyeur_game.cpp34
9 files changed, 304 insertions, 99 deletions
diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp
index e9a5b8d982..10f96042e0 100644
--- a/engines/voyeur/detection.cpp
+++ b/engines/voyeur/detection.cpp
@@ -121,6 +121,8 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const {
sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
SaveStateList saveList;
+ Voyeur::VoyeurSavegameHeader header;
+
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
const char *ext = strrchr(file->c_str(), '.');
int slot = ext ? atoi(ext + 1) : -1;
@@ -129,6 +131,10 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
+ if (header.read(in)) {
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+ header._thumbnail->free();
+ }
delete in;
}
}
@@ -151,10 +157,16 @@ SaveStateDescriptor VoyeurMetaEngine::querySaveMetaInfos(const char *target, int
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename);
if (f) {
+ Voyeur::VoyeurSavegameHeader header;
+ header.read(f);
delete f;
// Create the return descriptor
- SaveStateDescriptor desc(slot, "");
+ SaveStateDescriptor desc(slot, header._saveName);
+ desc.setThumbnail(header._thumbnail);
+ desc.setSaveDate(header._saveYear, header._saveMonth, header._saveDay);
+ desc.setSaveTime(header._saveHour, header._saveMinutes);
+ desc.setPlayTime(header._totalFrames * GAME_FRAME_TIME);
return desc;
}
diff --git a/engines/voyeur/events.h b/engines/voyeur/events.h
index 3c474aaded..753139bf35 100644
--- a/engines/voyeur/events.h
+++ b/engines/voyeur/events.h
@@ -141,6 +141,7 @@ public:
void showCursor();
void hideCursor();
Common::Point getMousePos() { return _mousePos; }
+ uint32 getGameCounter() const { return _gameCounter; }
void getMouseInfo();
void checkForKey();
void startCursorBlink();
diff --git a/engines/voyeur/files.h b/engines/voyeur/files.h
index b1eef580d1..f14b744721 100644
--- a/engines/voyeur/files.h
+++ b/engines/voyeur/files.h
@@ -537,6 +537,10 @@ public:
void checkForMurder();
void checkForIncriminate();
+ /**
+ * Synchronizes the game data
+ */
+ void synchronize(Common::Serializer &s);
};
} // End of namespace Voyeur
diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp
index 4348a14896..cee4e46c81 100644
--- a/engines/voyeur/files_threads.cpp
+++ b/engines/voyeur/files_threads.cpp
@@ -1062,6 +1062,13 @@ int ThreadResource::doApt() {
PictureResource *pic;
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
@@ -1760,4 +1767,8 @@ void ThreadResource::doAptAnim(int mode) {
_vm->_bVoy->getBoltGroup(0x100);
}
+void ThreadResource::synchronize(Common::Serializer &s) {
+ warning("TODO: ThreadResource::synchronize");
+}
+
} // End of namespace Voyeur
diff --git a/engines/voyeur/graphics.cpp b/engines/voyeur/graphics.cpp
index ec26017541..1e21818450 100644
--- a/engines/voyeur/graphics.cpp
+++ b/engines/voyeur/graphics.cpp
@@ -750,4 +750,8 @@ void GraphicsManager::drawDot() {
}
}
+void GraphicsManager::synchronize(Common::Serializer &s) {
+ warning("TODO: GraphicsManager::synchronize");
+}
+
} // End of namespace Voyeur
diff --git a/engines/voyeur/graphics.h b/engines/voyeur/graphics.h
index 970e814be2..ccc20e5df9 100644
--- a/engines/voyeur/graphics.h
+++ b/engines/voyeur/graphics.h
@@ -26,6 +26,7 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
+#include "common/serializer.h"
#include "graphics/surface.h"
namespace Voyeur {
@@ -117,6 +118,11 @@ public:
void fadeUpICF1(int steps);
void fadeDownICF(int steps);
void drawDot();
+
+ /**
+ * Synchronizes the game data
+ */
+ void synchronize(Common::Serializer &s);
};
} // End of namespace Voyeur
diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp
index d6b95316be..72678fa6f0 100644
--- a/engines/voyeur/voyeur.cpp
+++ b/engines/voyeur/voyeur.cpp
@@ -28,6 +28,9 @@
#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 {
@@ -37,8 +40,6 @@ VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc)
_gameDescription(gameDesc), _randomSource("Voyeur"), _soundManager(_mixer),
_defaultFontInfo(3, 0xff, 0xff, 0, 0, ALIGN_LEFT, 0, Common::Point(), 1, 1,
Common::Point(1, 1), 1, 0, 0) {
- DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level");
- DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
_bVoy = NULL;
_iForceDeath = -1;
_controlPtr = NULL;
@@ -54,6 +55,7 @@ VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc)
_timeBarVal = -1;
_checkPhoneVal = 0;
_voyeurArea = AREA_NONE;
+ _loadGameSlot = -1;
initialiseManagers();
}
@@ -62,39 +64,6 @@ VoyeurEngine::~VoyeurEngine() {
delete _bVoy;
}
-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 true;
-}
-
-/**
- * Returns true if it is currently okay to save the game
- */
-bool VoyeurEngine::canSaveGameStateCurrently() {
- return true;
-}
-
-/**
- * Load the savegame at the specified slot index
- */
-Common::Error VoyeurEngine::loadGameState(int slot) {
- return Common::kNoError;
-}
-
-/**
- * Save the game to the given slot index, and with the given name
- */
-Common::Error VoyeurEngine::saveGameState(int slot, const Common::String &desc) {
- //TODO
- return Common::kNoError;
-}
-
Common::Error VoyeurEngine::run() {
ESP_Init();
globalInitBolt();
@@ -130,6 +99,12 @@ void VoyeurEngine::initialiseManagers() {
void VoyeurEngine::ESP_Init() {
ThreadResource::init();
+
+ DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level");
+ DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
+
+ if (ConfMan.hasKey("save_slot"))
+ _loadGameSlot = ConfMan.getInt("save_slot");
}
void VoyeurEngine::globalInitBolt() {
@@ -173,58 +148,61 @@ bool VoyeurEngine::doHeadTitle() {
// char dest[144];
_eventsManager.startMainClockInt();
+
+ if (_loadGameSlot == -1) {
/*
- // Show starting screen
- if (_bVoy->getBoltGroup(0x500)) {
- showConversionScreen();
- _bVoy->freeBoltGroup(0x500);
+ // Show starting screen
+ if (_bVoy->getBoltGroup(0x500)) {
+ showConversionScreen();
+ _bVoy->freeBoltGroup(0x500);
- if (shouldQuit())
- return false;
- }
+ if (shouldQuit())
+ return false;
+ }
- if (ConfMan.getBool("copy_protection")) {
- // Display lock screen
- bool result = doLock();
- if (!result || shouldQuit())
- return false;
- }
+ if (ConfMan.getBool("copy_protection")) {
+ // Display lock screen
+ bool result = doLock();
+ if (!result || shouldQuit())
+ return false;
+ }
- // Show the title screen
- showTitleScreen();
- if (shouldQuit())
- return false;
+ // Show the title screen
+ showTitleScreen();
+ if (shouldQuit())
+ return false;
- // Opening
- if (!_eventsManager._mouseClicked) {
- doOpening();
- doTransitionCard("Saturday Afternoon", "Player's Apartment");
- _eventsManager.delayClick(90);
- } else {
- _eventsManager._mouseClicked = false;
- }
+ // Opening
+ if (!_eventsManager._mouseClicked) {
+ doOpening();
+ doTransitionCard("Saturday Afternoon", "Player's Apartment");
+ _eventsManager.delayClick(90);
+ } else {
+ _eventsManager._mouseClicked = false;
+ }
*/
- if (_voy._field478 & 0x80) {
- // Add initial game event set
- if (_voy._eventCount <= 1)
- _voy.addEvent(18, 1, EVTYPE_VIDEO, 33, 0, 998, -1);
- if (_voy._eventCount <= 2)
- _voy.addEvent(18, 2, EVTYPE_VIDEO, 41, 0, 998, -1);
- if (_voy._eventCount <= 3)
- _voy.addEvent(18, 3, EVTYPE_VIDEO, 47, 0, 998, -1);
- if (_voy._eventCount <= 4)
- _voy.addEvent(18, 4, EVTYPE_VIDEO, 53, 0, 998, -1);
- if (_voy._eventCount <= 5)
- _voy.addEvent(18, 5, EVTYPE_VIDEO, 46, 0, 998, -1);
- if (_voy._eventCount <= 6)
- _voy.addEvent(18, 6, EVTYPE_VIDEO, 50, 0, 998, -1);
- if (_voy._eventCount <= 7)
- _voy.addEvent(18, 7, EVTYPE_VIDEO, 40, 0, 998, -1);
- if (_voy._eventCount <= 8)
- _voy.addEvent(18, 8, EVTYPE_VIDEO, 43, 0, 998, -1);
- if (_voy._eventCount <= 9)
- _voy.addEvent(19, 1, EVTYPE_AUDIO, 20, 0, 998, -1);
- }
+ if (_voy._field478 & 0x80) {
+ // Add initial game event set
+ if (_voy._eventCount <= 1)
+ _voy.addEvent(18, 1, EVTYPE_VIDEO, 33, 0, 998, -1);
+ if (_voy._eventCount <= 2)
+ _voy.addEvent(18, 2, EVTYPE_VIDEO, 41, 0, 998, -1);
+ if (_voy._eventCount <= 3)
+ _voy.addEvent(18, 3, EVTYPE_VIDEO, 47, 0, 998, -1);
+ if (_voy._eventCount <= 4)
+ _voy.addEvent(18, 4, EVTYPE_VIDEO, 53, 0, 998, -1);
+ if (_voy._eventCount <= 5)
+ _voy.addEvent(18, 5, EVTYPE_VIDEO, 46, 0, 998, -1);
+ if (_voy._eventCount <= 6)
+ _voy.addEvent(18, 6, EVTYPE_VIDEO, 50, 0, 998, -1);
+ if (_voy._eventCount <= 7)
+ _voy.addEvent(18, 7, EVTYPE_VIDEO, 40, 0, 998, -1);
+ if (_voy._eventCount <= 8)
+ _voy.addEvent(18, 8, EVTYPE_VIDEO, 43, 0, 998, -1);
+ if (_voy._eventCount <= 9)
+ _voy.addEvent(19, 1, EVTYPE_AUDIO, 20, 0, 998, -1);
+ }
+ }
_voy._field472 = 140;
return true;
@@ -674,4 +652,169 @@ void VoyeurEngine::flipPageAndWaitForFade() {
_eventsManager.delay(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(g_vm->generateSaveName(slot));
+ if (!saveFile)
+ return;
+
+ Common::Serializer serializer(saveFile, NULL);
+
+ // Read in the savegame header
+ VoyeurSavegameHeader header;
+ if (!header.read(saveFile))
+ return;
+ if (header._thumbnail)
+ header._thumbnail->free();
+ delete header._thumbnail;
+
+ serializer.syncVersion(header._version);
+ synchronize(serializer);
+
+ delete saveFile;
+}
+
+/**
+ * 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
+ synchronize(serializer);
+
+ saveFile->finalize();
+ delete saveFile;
+
+ return Common::kNoError;
+}
+
+void VoyeurEngine::synchronize(Common::Serializer &s) {
+ s.syncAsSint16LE(_glGoScene);
+ s.syncAsSint16LE(_glGoStack);
+ s.syncAsSint16LE(_bob);
+ s.syncAsSint16LE(_stampFlags);
+ s.syncAsSint16LE(_playStampGroupId);
+ s.syncAsSint16LE(_currentVocId);
+ s.syncAsSint16LE(_videoId);
+
+ s.syncAsSint16LE(_iForceDeath);
+ s.syncAsSint16LE(_checkTransitionId);
+ s.syncAsSint16LE(_gameHour);
+ s.syncAsSint16LE(_gameMinute);
+ s.syncAsSint16LE(_flashTimeVal);
+ s.syncAsSint16LE(_flashTimeFlag);
+ s.syncAsSint16LE(_timeBarVal);
+ s.syncAsSint16LE(_checkPhoneVal);
+
+ // Sub-systems
+ _voy.synchronize(s);
+ _graphicsManager.synchronize(s);
+ _mainThread->synchronize(s);
+}
+
+/*------------------------------------------------------------------------*/
+
+bool VoyeurSavegameHeader::read(Common::InSaveFile *f) {
+ char id[4];
+ _thumbnail = NULL;
+
+ f->read(&id[0], 4);
+ if (strncmp(id, "VOYR", 4)) {
+ warning("Invalid savegame");
+ return false;
+ }
+
+ _version = f->readByte();
+ if (_version > VOYEUR_SAVEGAME_VERSION)
+ return false;
+
+ char c;
+ while ((c = f->readByte()) != 0)
+ _saveName += c;
+
+ // Get the thumbnail
+ _thumbnail = Graphics::loadThumbnail(*f);
+ if (!_thumbnail)
+ 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->write("VOYR", 4);
+
+ // 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, (byte *)vm->_graphicsManager._screenSurface.getPixels(),
+ SCREEN_WIDTH, SCREEN_HEIGHT, vm->_graphicsManager._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
diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h
index 4ee5f84b02..1622524108 100644
--- a/engines/voyeur/voyeur.h
+++ b/engines/voyeur/voyeur.h
@@ -33,6 +33,8 @@
#include "common/system.h"
#include "common/error.h"
#include "common/random.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
#include "common/util.h"
#include "engines/engine.h"
#include "graphics/surface.h"
@@ -134,6 +136,11 @@ private:
void playAVideoEvent(int eventIndex);
int getChooseButton();
+
+ /**
+ * Synchronizes the game data
+ */
+ void synchronize(Common::Serializer &s);
protected:
// Engine APIs
virtual Common::Error run();
@@ -169,7 +176,9 @@ public:
int _timeBarVal;
int _checkPhoneVal;
Common::Point _mansionViewPos;
+ ThreadResource *_mainThread;
VoyeurArea _voyeurArea;
+ int _loadGameSlot;
public:
VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc);
virtual ~VoyeurEngine();
@@ -187,6 +196,7 @@ public:
virtual bool canSaveGameStateCurrently();
virtual Common::Error loadGameState(int slot);
virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ void loadGame(int slot);
void playRL2Video(const Common::String &filename);
void doTransitionCard(const Common::String &time, const Common::String &location);
@@ -243,6 +253,20 @@ public:
Common::String getTimeOfDay();
};
+#define VOYEUR_SAVEGAME_VERSION 1
+
+struct VoyeurSavegameHeader {
+ uint8 _version;
+ Common::String _saveName;
+ Graphics::Surface *_thumbnail;
+ int _saveYear, _saveMonth, _saveDay;
+ int _saveHour, _saveMinutes;
+ int _totalFrames;
+
+ bool read(Common::InSaveFile *f);
+ void write(Common::OutSaveFile *f, VoyeurEngine *vm, const Common::String &saveName);
+};
+
} // End of namespace Voyeur
#endif /* VOYEUR_VOYEUR_H */
diff --git a/engines/voyeur/voyeur_game.cpp b/engines/voyeur/voyeur_game.cpp
index 2212453cdf..64af53899d 100644
--- a/engines/voyeur/voyeur_game.cpp
+++ b/engines/voyeur/voyeur_game.cpp
@@ -35,8 +35,8 @@ void VoyeurEngine::playStamp() {
initStamp();
PtrResource *threadsList = _stampLibPtr->boltEntry(3)._ptrResource;
- ThreadResource *threadP = threadsList->_entries[0]->_threadResource;
- threadP->initThreadStruct(0, 0);
+ _mainThread = threadsList->_entries[0]->_threadResource;
+ _mainThread->initThreadStruct(0, 0);
_voy._isAM = false;
_gameHour = 9;
@@ -51,23 +51,23 @@ void VoyeurEngine::playStamp() {
_playStampGroupId = _currentVocId = -1;
_videoId = -1;
- threadP->parsePlayCommands();
+ _mainThread->parsePlayCommands();
bool flag = breakFlag = (_voy._field478 & 2) != 0;
switch (_voy._field470) {
case 5:
- buttonId = threadP->doInterface();
+ buttonId = _mainThread->doInterface();
if (buttonId == -2) {
- switch (threadP->doApt()) {
+ switch (_mainThread->doApt()) {
case 0:
_voy._field472 = 140;
break;
case 1:
_voy._field478 &= ~1;
_voy._field46E = true;
- threadP->chooseSTAMPButton(22);
+ _mainThread->chooseSTAMPButton(22);
_voy._field472 = 143;
break;
case 2:
@@ -78,7 +78,7 @@ void VoyeurEngine::playStamp() {
break;
case 3:
_voy._field478 &= ~1;
- threadP->chooseSTAMPButton(21);
+ _mainThread->chooseSTAMPButton(21);
break;
case 4:
breakFlag = true;
@@ -93,24 +93,24 @@ void VoyeurEngine::playStamp() {
break;
}
} else {
- threadP->chooseSTAMPButton(buttonId);
+ _mainThread->chooseSTAMPButton(buttonId);
}
flag = true;
break;
case 6:
- threadP->doRoom();
+ _mainThread->doRoom();
flag = true;
break;
case 16:
_voy._transitionId = 17;
- buttonId = threadP->doApt();
+ buttonId = _mainThread->doApt();
switch (buttonId) {
case 1:
- threadP->chooseSTAMPButton(22);
+ _mainThread->chooseSTAMPButton(22);
flag = true;
break;
case 2:
@@ -136,7 +136,7 @@ void VoyeurEngine::playStamp() {
_voy._field478 &= ~0x10;
}
- threadP->chooseSTAMPButton(0);
+ _mainThread->chooseSTAMPButton(0);
flag = true;
break;
@@ -158,10 +158,10 @@ void VoyeurEngine::playStamp() {
if (buttonId == 4) {
_voy._field470 = 131;
_eventsManager.checkForKey();
- threadP->chooseSTAMPButton(buttonId);
+ _mainThread->chooseSTAMPButton(buttonId);
flag = true;
} else {
- threadP->chooseSTAMPButton(buttonId);
+ _mainThread->chooseSTAMPButton(buttonId);
_voy._field46E = true;
}
}
@@ -194,12 +194,12 @@ void VoyeurEngine::playStamp() {
// Break out of loop
flag = false;
- } else if (threadP->_field40 & 2) {
+ } else if (_mainThread->_field40 & 2) {
_eventsManager.getMouseInfo();
- threadP->chooseSTAMPButton(0);
+ _mainThread->chooseSTAMPButton(0);
flag = true;
} else {
- threadP->chooseSTAMPButton(0);
+ _mainThread->chooseSTAMPButton(0);
flag = true;
}
} while (flag);