[Scummvm-cvs-logs] SF.net SVN: scummvm:[53841] scummvm/trunk/engines/lastexpress

littleboy at users.sourceforge.net littleboy at users.sourceforge.net
Tue Oct 26 02:41:43 CEST 2010


Revision: 53841
          http://scummvm.svn.sourceforge.net/scummvm/?rev=53841&view=rev
Author:   littleboy
Date:     2010-10-26 00:41:42 +0000 (Tue, 26 Oct 2010)

Log Message:
-----------
LASTEXPRESS: Savegame support update

 - Implement Menu::startGame() properly
 - Add stubs functions for game restart
 - Made savegame headers serializable and moved validity checks inside struct definition
 - Implement create/init savegame functions
 - Add SavegameStream to be able to read/write to the same memory stream
 - Add stubs for setup, writeEntry & loadEntry functions

Modified Paths:
--------------
    scummvm/trunk/engines/lastexpress/game/logic.cpp
    scummvm/trunk/engines/lastexpress/game/logic.h
    scummvm/trunk/engines/lastexpress/game/menu.cpp
    scummvm/trunk/engines/lastexpress/game/menu.h
    scummvm/trunk/engines/lastexpress/game/savegame.cpp
    scummvm/trunk/engines/lastexpress/game/savegame.h
    scummvm/trunk/engines/lastexpress/shared.h

Modified: scummvm/trunk/engines/lastexpress/game/logic.cpp
===================================================================
--- scummvm/trunk/engines/lastexpress/game/logic.cpp	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/game/logic.cpp	2010-10-26 00:41:42 UTC (rev 53841)
@@ -402,7 +402,23 @@
 // Game over, Chapters & credits
 //////////////////////////////////////////////////////////////////////////
 
-// Handle game over
+/**
+ * Resets the game state.
+ */
+void Logic::resetState() {
+	getState()->scene = kSceneDefault;
+
+	warning("Logic::resetState: not implemented! You need to restart the engine until this is implemented.");
+}
+
+/**
+ * Handle game over
+ *
+ * @param type 		 The savegame type.
+ * @param value 	 The value (event, time, index, ...)
+ * @param sceneIndex Index of the scene to show.
+ * @param showScene  true to show a scene, false to return to menu directly
+ */
 void Logic::gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, bool showScene) const {
 
 	getSound()->processEntries();

Modified: scummvm/trunk/engines/lastexpress/game/logic.h
===================================================================
--- scummvm/trunk/engines/lastexpress/game/logic.h	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/game/logic.h	2010-10-26 00:41:42 UTC (rev 53841)
@@ -54,6 +54,7 @@
 	void eventMouse(const Common::Event &ev);
 	void eventTick(const Common::Event &ev);
 
+	void resetState();
 	void gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, bool showScene) const;
 	void playFinalSequence() const;
 	void updateCursor(bool redraw = true) const;

Modified: scummvm/trunk/engines/lastexpress/game/menu.cpp
===================================================================
--- scummvm/trunk/engines/lastexpress/game/menu.cpp	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/game/menu.cpp	2010-10-26 00:41:42 UTC (rev 53841)
@@ -360,7 +360,7 @@
 	_gameId(kGameBlue), _hasShownStartScreen(false), _hasShownIntro(false),
 	_isShowingCredits(false), _isGameStarted(false), _isShowingMenu(false),
 	_creditsSequenceIndex(0), _checkHotspotsTicks(15),  _mouseFlags(Common::EVENT_INVALID), _lastHotspot(NULL),
-	_currentIndex(0), _currentTime(0), _lowerTime(0), _index(0), _index2(0), _time(0), _delta(0), _handleTimeDelta(false) {
+	_currentIndex(0), _currentTime(0), _lowerTime(0), _index(0), _savegameIndex(0), _time(0), _delta(0), _handleTimeDelta(false) {
 
 	_clock = new Clock(_engine);
 	_trainLine = new TrainLine(_engine);
@@ -661,8 +661,8 @@
 			if (_isGameStarted) {
 				showFrame(kOverlayEggButtons, kButtonContinue, true);
 
-				if (_index2 == _index) {
-					showFrame(kOverlayTooltip, isGameFinished() ? kTooltipViewGameEnding : kTooltipContinueGame, true);
+				if (_savegameIndex == _index) {
+					showFrame(kOverlayTooltip, getSaveLoad()->isGameFinished(_index, _savegameIndex) ? kTooltipViewGameEnding : kTooltipContinueGame, true);
 				} else {
 					showFrame(kOverlayTooltip, kTooltipContinueRewoundGame, true);
 				}
@@ -828,7 +828,7 @@
 
 	//////////////////////////////////////////////////////////////////////////
 	case kMenuForwardGame:
-		if (_index2 <= _index || _currentTime > _time) {
+		if (_savegameIndex <= _index || _currentTime > _time) {
 			hideOverlays();
 			break;
 		}
@@ -1075,7 +1075,7 @@
 
 	// Create a new savegame if needed
 	if (!SaveLoad::isSavegamePresent(_gameId))
-		SaveLoad::writeMainHeader(_gameId);
+		getSaveLoad()->create(_gameId);
 
 	if (doSavegame)
 		getSaveLoad()->saveGame(kSavegameTypeEvent2, kEntityPlayer, kEventNone);
@@ -1084,18 +1084,12 @@
 		// TODO: remove existing savegame temp file
 	}
 
-	// Init savegame and get the header data
-	getSaveLoad()->initSavegame(_gameId, true);
-	SaveLoad::SavegameMainHeader header;
-	if (!SaveLoad::loadMainHeader(_gameId, &header))
-		error("Menu::init: Corrupted savegame - Recovery path not implemented!");
+	// Init savegame & menu values
+	_savegameIndex = getSaveLoad()->init(_gameId, true);
+	_lowerTime = getSaveLoad()->getTime(_savegameIndex);
 
-	// Init Menu values
-	_index2 = header.index;
-	_lowerTime = getSaveLoad()->getEntry(_index2)->time;
-
 	if (useSameIndex)
-		_index = _index2;
+		_index = _savegameIndex;
 
 	//if (!getGlobalTimer())
 	//	_index3 = 0;
@@ -1103,8 +1097,8 @@
 	if (!getProgress().chapter)
 		getProgress().chapter = kChapter1;
 
-	getState()->time = getSaveLoad()->getEntry(_index)->time;
-	getProgress().chapter = getSaveLoad()->getEntry(_index)->chapter;
+	getState()->time = getSaveLoad()->getTime(_index);
+	getProgress().chapter = getSaveLoad()->getChapter(_index);
 
 	if (_lowerTime >= kTimeStartGame) {
 		_currentTime = getState()->time;
@@ -1117,11 +1111,26 @@
 }
 
 void Menu::startGame() {
-	// TODO: we need to reset the current scene
-	getState()->scene = kSceneDefault;
+	// TODO: Clear train sequences & savegame headers
 
-	getEntities()->setup(true, kEntityPlayer);
-	warning("Menu::startGame: not implemented!");
+	if (0 /* test for temp filename */ ) {
+		if (_savegameIndex == _index)
+			getSaveLoad()->loadGame(_gameId);
+		else
+			getSaveLoad()->loadGame2(_gameId);
+	} else {
+		if (_savegameIndex == _index) {
+			setGlobalTimer(0);
+			if (_index) {
+				getSaveLoad()->loadGame(_gameId);
+			} else {
+				getLogic()->resetState();
+				getEntities()->setup(true, kEntityPlayer);
+			}
+		} else {
+			getSaveLoad()->loadGame2(_gameId);
+		}
+	}
 }
 
 // Switch to the next savegame
@@ -1132,7 +1141,7 @@
 
 	// Initialize savegame if needed
 	if (!SaveLoad::isSavegamePresent(_gameId))
-		SaveLoad::writeMainHeader(_gameId);
+		getSaveLoad()->create(_gameId);
 
 	getState()->time = 0;
 
@@ -1141,53 +1150,11 @@
 	_trainLine->clear();
 
 	// Clear loaded savegame data
-	getSaveLoad()->clearEntries();
+	getSaveLoad()->clear();
 
 	init(false, kSavegameTypeIndex, 0);
 }
 
-bool Menu::isGameFinished() const {
-	SaveLoad::SavegameEntryHeader *data = getSaveLoad()->getEntry(_index);
-
-	if (_index2 != _index)
-		return false;
-
-	if (data->type != SaveLoad::kHeaderType2)
-		return false;
-
-	return (data->event == kEventAnnaKilled
-		 || data->event == kEventKronosHostageAnnaNoFirebird
-		 || data->event == kEventKahinaPunchBaggageCarEntrance
-		 || data->event == kEventKahinaPunchBlue
-		 || data->event == kEventKahinaPunchYellow
-		 || data->event == kEventKahinaPunchSalon
-		 || data->event == kEventKahinaPunchKitchen
-		 || data->event == kEventKahinaPunchBaggageCar
-		 || data->event == kEventKahinaPunchCar
-		 || data->event == kEventKahinaPunchSuite4
-		 || data->event == kEventKahinaPunchRestaurant
-		 || data->event == kEventKahinaPunch
-		 || data->event == kEventKronosGiveFirebird
-		 || data->event == kEventAugustFindCorpse
-		 || data->event == kEventMertensBloodJacket
-		 || data->event == kEventMertensCorpseFloor
-		 || data->event == kEventMertensCorpseBed
-		 || data->event == kEventCoudertBloodJacket
-		 || data->event == kEventGendarmesArrestation
-		 || data->event == kEventAbbotDrinkGiveDetonator
-		 || data->event == kEventMilosCorpseFloor
-		 || data->event == kEventLocomotiveAnnaStopsTrain
-		 || data->event == kEventTrainStopped
-		 || data->event == kEventCathVesnaRestaurantKilled
-		 || data->event == kEventCathVesnaTrainTopKilled
-		 || data->event == kEventLocomotiveConductorsDiscovered
-		 || data->event == kEventViennaAugustUnloadGuns
-		 || data->event == kEventViennaKronosFirebird
-		 || data->event == kEventVergesAnnaDead
-		 || data->event == kEventTrainExplosionBridge
-		 || data->event == kEventKronosBringNothing);
-}
-
 //////////////////////////////////////////////////////////////////////////
 // Overlays & elements
 //////////////////////////////////////////////////////////////////////////
@@ -1307,7 +1274,7 @@
 
 		// Iterate through existing entries
 		do {
-			if (getSaveLoad()->getEntry(entryIndex)->time <= value)
+			if (getSaveLoad()->getTime(entryIndex) <= value)
 				break;
 
 			entryIndex--;
@@ -1320,7 +1287,7 @@
 			break;
 
 		do {
-			if (getSaveLoad()->getEntry(entryIndex)->event == (EventIndex)value)
+			if (getSaveLoad()->getValue(entryIndex) == value)
 				break;
 
 			entryIndex--;
@@ -1332,7 +1299,7 @@
 		if (_index > 1) {
 			uint32 index = _index;
 			do {
-				if (getSaveLoad()->getEntry(index)->event == (EventIndex)value)
+				if (getSaveLoad()->getValue(index) == value)
 					break;
 
 				index--;
@@ -1347,7 +1314,7 @@
 
 	if (entryIndex) {
 		_currentIndex = entryIndex;
-		updateTime(getSaveLoad()->getEntry(entryIndex)->time);
+		updateTime(getSaveLoad()->getTime(entryIndex));
 	}
 }
 
@@ -1381,7 +1348,7 @@
 				if ((int32)_index >= 0) {
 					do {
 						// Calculate new delta
-						int32 newDelta = time1 - getSaveLoad()->getEntry(currentIndex)->time;
+						int32 newDelta = time1 - getSaveLoad()->getTime(currentIndex);
 
 						if (newDelta >= 0 && timeDelta >= newDelta) {
 							timeDelta = newDelta;
@@ -1398,10 +1365,10 @@
 			if (searchEntry) {
 				uint32 currentIndex = _index;
 
-				if (_index2 >= _index) {
+				if (_savegameIndex >= _index) {
 					do {
 						// Calculate new delta
-						int32 newDelta = getSaveLoad()->getEntry(currentIndex)->time - time1;
+						int32 newDelta = getSaveLoad()->getTime(currentIndex) - time1;
 
 						if (newDelta >= 0 && timeDelta > newDelta) {
 							timeDelta = newDelta;
@@ -1409,7 +1376,7 @@
 						}
 
 						++currentIndex;
-					} while (currentIndex >= _index2);
+					} while (currentIndex >= _savegameIndex);
 				}
 			} else {
 				index = _index + 1;
@@ -1421,45 +1388,45 @@
 	}
 
 	if (_index == _currentIndex) {
-		if (getProgress().chapter != getSaveLoad()->getEntry(index)->chapter)
-			getProgress().chapter = getSaveLoad()->getEntry(_index)->chapter;
+		if (getProgress().chapter != getSaveLoad()->getChapter(index))
+			getProgress().chapter = getSaveLoad()->getChapter(_index);
 	}
 }
 
 void Menu::goToTime(uint32 time) {
 
 	uint32 entryIndex = 0;
-	uint32 deltaTime = (uint32)ABS((int32)(getSaveLoad()->getEntry(0)->time - time));
+	uint32 deltaTime = (uint32)ABS((int32)(getSaveLoad()->getTime(0) - time));
 	uint32 index = 0;
 
 	do {
-		uint32 deltaTime2 = (uint32)ABS((int32)(getSaveLoad()->getEntry(index)->time - time));
+		uint32 deltaTime2 = (uint32)ABS((int32)(getSaveLoad()->getTime(index) - time));
 		if (deltaTime2 < deltaTime) {
 			deltaTime = deltaTime2;
 			entryIndex = index;
 		}
 
 		++index;
-	} while (_index2 >= index);
+	} while (_savegameIndex >= index);
 
 	_currentIndex = entryIndex;
-	updateTime(getSaveLoad()->getEntry(entryIndex)->time);
+	updateTime(getSaveLoad()->getTime(entryIndex));
 }
 
 void Menu::setTime() {
 	_currentIndex = _index;
-	_currentTime = getSaveLoad()->getEntry(_currentIndex)->time;
+	_currentTime = getSaveLoad()->getTime(_currentIndex);
 
 	if (_time == _currentTime)
 		adjustTime();
 }
 
 void Menu::forwardTime() {
-	if (_index2 <= _index)
+	if (_savegameIndex <= _index)
 		return;
 
-	_currentIndex = _index2;
-	updateTime(getSaveLoad()->getEntry(_currentIndex)->time);
+	_currentIndex = _savegameIndex;
+	updateTime(getSaveLoad()->getTime(_currentIndex));
 }
 
 void Menu::rewindTime() {
@@ -1467,7 +1434,7 @@
 		return;
 
 	_currentIndex = 0;
-	updateTime(getSaveLoad()->getEntry(_currentIndex)->time);
+	updateTime(getSaveLoad()->getTime(_currentIndex));
 }
 
 void Menu::adjustTime() {

Modified: scummvm/trunk/engines/lastexpress/game/menu.h
===================================================================
--- scummvm/trunk/engines/lastexpress/game/menu.h	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/game/menu.h	2010-10-26 00:41:42 UTC (rev 53841)
@@ -145,7 +145,6 @@
 	// Game-related
 	void startGame();
 	void switchGame();
-	bool isGameFinished() const;
 
 	//////////////////////////////////////////////////////////////////////////
 	// Overlays & elements
@@ -183,7 +182,7 @@
 	uint32 _lowerTime;    // lower time value
 
 	uint32 _index;
-	uint32 _index2;
+	uint32 _savegameIndex;
 	uint32 _time;
 	uint32 _delta;
 	bool _handleTimeDelta;

Modified: scummvm/trunk/engines/lastexpress/game/savegame.cpp
===================================================================
--- scummvm/trunk/engines/lastexpress/game/savegame.cpp	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/game/savegame.cpp	2010-10-26 00:41:42 UTC (rev 53841)
@@ -23,8 +23,10 @@
  *
  */
 
+#include "lastexpress/game/savegame.h"
+
 #include "lastexpress/game/logic.h"
-#include "lastexpress/game/savegame.h"
+#include "lastexpress/game/menu.h"
 #include "lastexpress/game/state.h"
 
 #include "lastexpress/debug.h"
@@ -36,10 +38,6 @@
 
 namespace LastExpress {
 
-// Savegame signatures
-#define SAVEGAME_SIGNATURE 0x12001200
-#define SAVEGAME_HEADER    0xE660E660
-
 // Names of savegames
 static const struct {
 	const char *saveFile;
@@ -56,18 +54,94 @@
 // Constructors
 //////////////////////////////////////////////////////////////////////////
 
-SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine) {
-	_gameTicksLastSavegame = 0;
+SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0) {
 }
 
 SaveLoad::~SaveLoad() {
+	clear();
+
+	SAFE_DELETE(_savegame);
+
 	//Zero passed pointers
 	_engine = NULL;
+}
 
-	clearEntries();
+void SaveLoad::initStream() {
+	SAFE_DELETE(_savegame);
+
+	_savegame = new SavegameStream();
 }
 
+void SaveLoad::flushStream(GameId id) {
+	Common::OutSaveFile *save = openForSaving(id);
+	if (!save)
+		error("SaveLoad::initSave: Cannot init savegame (%s)!", getFilename(id).c_str());
+
+	save->write(_savegame->getData(), _savegame->size());
+
+	delete save;
+}
+
 //////////////////////////////////////////////////////////////////////////
+// Init
+//////////////////////////////////////////////////////////////////////////
+void SaveLoad::create(GameId id) {
+	initStream();
+
+	Common::Serializer ser(NULL, _savegame);
+	SavegameMainHeader header;
+	header.saveLoadWithSerializer(ser);
+
+	flushStream(id);
+}
+
+uint32 SaveLoad::init(GameId id, bool resetHeaders) {
+	initStream();
+
+	// Open savegame
+	Common::InSaveFile *save = openForLoading(id);
+	if (save->size() < 32)
+		error("SaveLoad::init - Savegame seems to be corrupted (not enough data: %i bytes)", save->size());
+
+	// Load all savegame data
+	while (!save->eos() && !save->err())
+		_savegame->writeByte(save->readByte());
+	_savegame->seek(0);
+
+	delete save;
+
+	// Load the main header
+	Common::Serializer ser(_savegame, NULL);
+	SavegameMainHeader header;
+	header.saveLoadWithSerializer(ser);
+	if (!header.isValid())
+		error("SaveLoad::init - Savegame seems to be corrupted (invalid header)");
+
+	// Reset cached entry headers if needed
+	if (resetHeaders) {
+		clear();
+
+		SavegameEntryHeader *header = new SavegameEntryHeader();
+		header->time = kTimeCityParis;
+		header->chapter = kChapter1;
+
+		_gameHeaders.push_back(header);
+	}
+
+	warning("SaveLoad::initSavegame: not implemented!");
+
+	// return the index to the current save game entry (we store count + 1 entries, so we're good)
+	return 0; //header.count;
+}
+
+void SaveLoad::clear() {
+	for (uint i = 0; i < _gameHeaders.size(); i++)
+		SAFE_DELETE(_gameHeaders[i]);
+
+	_gameHeaders.clear();
+}
+
+//////////////////////////////////////////////////////////////////////////
 // Save & Load
 //////////////////////////////////////////////////////////////////////////
 
@@ -80,21 +154,80 @@
 	//Common::InSaveFile *save = SaveLoad::openForLoading(id);
 	// Validate header
 
-
-
-
 	error("SaveLoad::loadgame: not implemented!");
 
 	return false;
 }
 
+bool SaveLoad::loadGame2(GameId id) {
+	error("SaveLoad::loadgame2: not implemented!");
+}
+
 // Save game
 void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) {
+	if (getState()->scene <= kSceneIntro)
+		return;
 
-	// Save ticks
-	_gameTicksLastSavegame = getState()->timeTicks;
+	// Validate main header
+	SavegameMainHeader header;
+	if (!loadMainHeader(_savegame, &header)) {
+		debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str());
+		return;
+	}
 
-	warning("SaveLoad::savegame: not implemented!");
+	// Validate the current entry if it exists
+	if (header.count > 0) {
+		_savegame->seek(header.offsetEntry);
+
+		// Load entry header
+		SavegameEntryHeader entry;
+		Common::Serializer ser(_savegame, NULL);
+		entry.saveLoadWithSerializer(ser);
+
+		if (!entry.isValid() || getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time))
+			return;
+
+		if ((type == kSavegameTypeTime || type == kSavegameTypeEvent)
+		 && (entry.type == kSavegameTypeTickInterval && (getState()->time - entry.time) < 450)) {
+			_savegame->seek(header.offsetEntry);
+			--header.count;
+		} else {
+			_savegame->seek(header.offset);
+		}
+	} else {
+		// Seek to the next savegame entry
+		_savegame->seek(header.offset);
+	}
+
+	if (type != kSavegameTypeEvent2 && type != kSavegameTypeAuto)
+		header.offsetEntry = _savegame->pos();
+
+	// Write the savegame entry
+	writeEntry(type, entity, value);
+
+	if (!header.keepIndex)
+		++header.count;
+
+	if (type == kSavegameTypeEvent2 || type == kSavegameTypeAuto) {
+		header.keepIndex = 1;
+	} else {
+		header.keepIndex = 0;
+		header.offset = _savegame->pos();
+
+		// Save ticks
+		_gameTicksLastSavegame = getState()->timeTicks;
+	}
+
+	// Validate the main header
+	if (!header.isValid())
+		error("SaveLoad::saveGame: main game header is invalid!");
+
+	// Write the main header
+	_savegame->seek(0);
+	Common::Serializer ser(NULL, _savegame);
+	header.saveLoadWithSerializer(ser);
+
+	flushStream(getMenu()->getGameId());
 }
 
 void SaveLoad::saveVolumeBrightness() {
@@ -107,7 +240,7 @@
 
 // Check if a specific savegame exists
 bool SaveLoad::isSavegamePresent(GameId id) {
-	if (g_system->getSavefileManager()->listSavefiles(getSavegameName(id)).size() == 0)
+	if (g_system->getSavefileManager()->listSavefiles(getFilename(id)).size() == 0)
 		return false;
 
 	return true;
@@ -116,114 +249,57 @@
 // Check if the game has been started in the specific savegame
 bool SaveLoad::isSavegameValid(GameId id) {
 	if (!isSavegamePresent(id)) {
-		debugC(2, kLastExpressDebugSavegame, "SaveLoad::isSavegameValid - Savegame does not exist: %s", getSavegameName(id).c_str());
+		debugC(2, kLastExpressDebugSavegame, "SaveLoad::isSavegameValid - Savegame does not exist: %s", getFilename(id).c_str());
 		return false;
 	}
 
 	SavegameMainHeader header;
-	if (!loadMainHeader(id, &header))
-		return false;
 
-	return validateMainHeader(header);
+	Common::InSaveFile *save = openForLoading(id);
+	return loadMainHeader(save, &header);
 }
 
-
 //////////////////////////////////////////////////////////////////////////
 // Headers
 //////////////////////////////////////////////////////////////////////////
-bool SaveLoad::loadMainHeader(GameId id, SavegameMainHeader *header) {
-	// Read first 32 bytes of savegame
-	Common::InSaveFile *save = openForLoading(id);
-	if (!save) {
-		debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Cannot open savegame for reading: %s", getSavegameName(id).c_str());
+bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header) {
+	if (!stream)
 		return false;
-	}
 
-	// Check there is enough data
-	if (save->size() < 32) {
-		debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Savegame seems to be corrupted (not enough data: %i bytes): %s", save->size(), getSavegameName(id).c_str());
-		delete save;
+	// Check there is enough data (32 bytes)
+	if (stream->size() < 32) {
+		debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Savegame seems to be corrupted (not enough data: %i bytes)!", stream->size());
 		return false;
 	}
 
-	header->signature = save->readUint32LE();
-	header->index = save->readUint32LE();
-	header->time = save->readUint32LE();
-	header->field_C = save->readUint32LE();
-	header->field_10 = save->readUint32LE();
-	header->brightness = save->readSint32LE();
-	header->volume = save->readSint32LE();
-	header->field_1C = save->readUint32LE();
+	// Rewind stream
+	stream->seek(0);
 
-	delete save;
+	Common::Serializer ser(stream, NULL);
+	header->saveLoadWithSerializer(ser);
 
-	// Valide the header
-	if (!validateMainHeader(*header)) {
-		debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Cannot validate main header for savegame %s.", getSavegameName(id).c_str());
+	// Validate the header
+	if (!header->isValid()) {
+		debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Cannot validate main header!");
 		return false;
 	}
 
 	return true;
 }
 
-void SaveLoad::loadEntryHeader(Common::InSaveFile *save, SavegameEntryHeader *header) {
-	header->signature = save->readUint32LE();
-	header->type = (HeaderType)save->readUint32LE();
-	header->time = save->readUint32LE();
-	header->field_C = save->readUint32LE();
-	header->chapter = (ChapterIndex)save->readUint32LE();
-	header->event = (EventIndex)save->readUint32LE();
-	header->field_18 = save->readUint32LE();
-	header->field_1C = save->readUint32LE();
+void SaveLoad::loadEntryHeader(SavegameEntryHeader *header) {
+	error("SaveLoad::loadEntryHeader: not implemented!");
 }
 
-bool SaveLoad::validateMainHeader(const SavegameMainHeader &header) {
-	if (header.signature != SAVEGAME_SIGNATURE)
-		return false;
-
-	/* Check not needed as it can never be < 0
-	if (header.chapter < 0)
-		return false;*/
-
-	if (header.time < 32)
-		return false;
-
-	if (header.field_C < 32)
-		return false;
-
-	if (header.field_10 != 1 && header.field_10)
-		return false;
-
-	if (header.brightness < 0 || header.brightness > 6)
-		return false;
-
-	if (header.volume < 0 || header.volume > 7)
-		return false;
-
-	if (header.field_1C != 9)
-		return false;
-
-	return true;
+//////////////////////////////////////////////////////////////////////////
+// Entries
+//////////////////////////////////////////////////////////////////////////
+void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) {
+	warning("SaveLoad::writeEntry: not implemented!");
 }
 
-bool SaveLoad::validateEntryHeader(const SavegameEntryHeader &header) {
-	if (header.signature != SAVEGAME_HEADER)
-		return false;
-
-	if (header.type < kHeaderType1 || header.type > kHeaderType5)
-		return false;
-
-	if (header.time < kTimeStartGame || header.time > kTimeCityConstantinople)
-		return false;
-
-	if (header.field_C <= 0 || header.field_C >= 15)
-		return false;
-
-	/* No check for < 0, as it cannot happen normaly */
-	if (header.chapter == 0)
-		return false;
-
-	return true;
+void SaveLoad::readEntry(SavegameType type, EntityIndex entity, uint32 value) {
+	warning("SaveLoad::readEntry: not implemented!");
 }
 
 SaveLoad::SavegameEntryHeader *SaveLoad::getEntry(uint32 index) {
@@ -233,78 +309,80 @@
 	return _gameHeaders[index];
 }
 
-void SaveLoad::clearEntries() {
-	for (uint i = 0; i < _gameHeaders.size(); i++)
-		SAFE_DELETE(_gameHeaders[i]);
-
-	_gameHeaders.clear();
-}
-
 //////////////////////////////////////////////////////////////////////////
-// Init
+// Checks
 //////////////////////////////////////////////////////////////////////////
-void SaveLoad::writeMainHeader(GameId id) {
-	Common::OutSaveFile *save = openForSaving(id);
-	if (!save) {
-		debugC(2, kLastExpressDebugSavegame, "SaveLoad::initSavegame - Cannot open savegame for writing: %s", getSavegameName(id).c_str());
-		return;
-	}
+bool SaveLoad::isGameFinished(uint32 menuIndex, uint32 savegameIndex) {
+	SavegameEntryHeader *data = getEntry(menuIndex);
 
-	// Write default values to savegame
-	save->writeUint32LE(SAVEGAME_SIGNATURE);
-	save->writeUint32LE(0);
-	save->writeUint32LE(32);
-	save->writeUint32LE(32);
-	save->writeUint32LE(0);
-	save->writeUint32LE(3);
-	save->writeUint32LE(7);
-	save->writeUint32LE(9);
+	if (savegameIndex != menuIndex)
+		return false;
 
-	delete save;
+	if (data->type != kSavegameTypeEvent)
+		return false;
+
+	return (data->value == kEventAnnaKilled
+	     || data->value == kEventKronosHostageAnnaNoFirebird
+	     || data->value == kEventKahinaPunchBaggageCarEntrance
+	     || data->value == kEventKahinaPunchBlue
+	     || data->value == kEventKahinaPunchYellow
+	     || data->value == kEventKahinaPunchSalon
+	     || data->value == kEventKahinaPunchKitchen
+	     || data->value == kEventKahinaPunchBaggageCar
+	     || data->value == kEventKahinaPunchCar
+	     || data->value == kEventKahinaPunchSuite4
+	     || data->value == kEventKahinaPunchRestaurant
+	     || data->value == kEventKahinaPunch
+	     || data->value == kEventKronosGiveFirebird
+	     || data->value == kEventAugustFindCorpse
+	     || data->value == kEventMertensBloodJacket
+	     || data->value == kEventMertensCorpseFloor
+	     || data->value == kEventMertensCorpseBed
+	     || data->value == kEventCoudertBloodJacket
+	     || data->value == kEventGendarmesArrestation
+	     || data->value == kEventAbbotDrinkGiveDetonator
+	     || data->value == kEventMilosCorpseFloor
+	     || data->value == kEventLocomotiveAnnaStopsTrain
+	     || data->value == kEventTrainStopped
+	     || data->value == kEventCathVesnaRestaurantKilled
+	     || data->value == kEventCathVesnaTrainTopKilled
+	     || data->value == kEventLocomotiveConductorsDiscovered
+	     || data->value == kEventViennaAugustUnloadGuns
+	     || data->value == kEventViennaKronosFirebird
+	     || data->value == kEventVergesAnnaDead
+	     || data->value == kEventTrainExplosionBridge
+	     || data->value == kEventKronosBringNothing);
 }
 
-void SaveLoad::initSavegame(GameId id, bool resetHeaders) {
-	//Common::OutSaveFile *save = openForSaving(id);
-	//if (!save) {
-	//	debugC(2, kLastExpressDebugSavegame, "SaveLoad::initSavegame - Cannot open savegame for writing: %s", getSavegameName(id).c_str());
-	//	return;
-	//}
 
-	if (resetHeaders) {
-		clearEntries();
-
-		SavegameEntryHeader *header = new SavegameEntryHeader();
-		header->time = kTimeCityParis;
-		header->chapter = kChapter1;
-
-		_gameHeaders.push_back(header);
-	}
-
-	// Open the savegame and read all game headers
-
-	warning("SaveLoad::initSavegame: not implemented!");
-
-	//delete save;
-}
-
 //////////////////////////////////////////////////////////////////////////
 // Private methods
 //////////////////////////////////////////////////////////////////////////
 
 // Get the file name from the savegame ID
-Common::String SaveLoad::getSavegameName(GameId id) {
+Common::String SaveLoad::getFilename(GameId id) {
 	if (id >= 6)
-		error("SaveLoad::getSavegameName - attempting to use an invalid game id. Valid values: 0 - 5, was %d", id);
+		error("SaveLoad::getName - attempting to use an invalid game id. Valid values: 0 - 5, was %d", id);
 
 	return gameInfo[id].saveFile;
 }
 
 Common::InSaveFile *SaveLoad::openForLoading(GameId id) {
-	return g_system->getSavefileManager()->openForLoading(getSavegameName(id));
+	Common::InSaveFile *load = g_system->getSavefileManager()->openForLoading(getFilename(id));
+
+	if (!load)
+		debugC(2, kLastExpressDebugSavegame, "SaveLoad::openForLoading - Cannot open savegame for loading: %s", getFilename(id).c_str());
+
+	return load;
 }
 
 Common::OutSaveFile *SaveLoad::openForSaving(GameId id) {
-	return g_system->getSavefileManager()->openForSaving(getSavegameName(id));
+	Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id));
+
+	if (!save)
+		debugC(2, kLastExpressDebugSavegame, "SaveLoad::openForSaving - Cannot open savegame for writing: %s", getFilename(id).c_str());
+
+	return save;
 }
 
 } // End of namespace LastExpress

Modified: scummvm/trunk/engines/lastexpress/game/savegame.h
===================================================================
--- scummvm/trunk/engines/lastexpress/game/savegame.h	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/game/savegame.h	2010-10-26 00:41:42 UTC (rev 53841)
@@ -77,95 +77,208 @@
 #include "lastexpress/shared.h"
 
 #include "common/savefile.h"
+#include "common/serializer.h"
 
 namespace LastExpress {
 
+// Savegame signatures
+#define SAVEGAME_SIGNATURE 0x12001200
+#define SAVEGAME_HEADER    0xE660E660
+
 class LastExpressEngine;
 
 class SaveLoad {
 public:
-	enum HeaderType {
-		kHeaderTypeNone = 0,
-		kHeaderType1 = 1,
-		kHeaderType2 = 2,
-		kHeaderType3 = 3,
-		kHeaderType4 = 4,
-		kHeaderType5 = 5
+	SaveLoad(LastExpressEngine *engine);
+	~SaveLoad();
+
+	// Init
+	void create(GameId id);
+	void clear();
+	uint32 init(GameId id, bool resetHeaders);
+
+	// Save & Load
+	bool loadGame(GameId id);
+	bool loadGame2(GameId id);
+	void saveGame(SavegameType type, EntityIndex entity, uint32 value);
+
+	void saveVolumeBrightness();
+
+	// Getting information
+	static bool isSavegamePresent(GameId id);
+	static bool isSavegameValid(GameId id);
+
+	bool isGameFinished(uint32 menuIndex, uint32 savegameIndex);
+
+	// Accessors
+ 	TimeValue    getTime(uint32 index) { return getEntry(index)->time; }
+	ChapterIndex getChapter(uint32 index) { return getEntry(index)->chapter; }
+	uint32       getValue(uint32 index) { return getEntry(index)->value; }
+	uint32       getLastSavegameTicks() const { return _gameTicksLastSavegame; }
+
+private:
+	class SavegameStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream {
+	public:
+		SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES),
+		 _eos(false) {}
+
+		int32 pos() const { return MemoryWriteStreamDynamic::pos(); }
+		int32 size() const { return MemoryWriteStreamDynamic::size(); }
+		bool seek(int32 offset, int whence = SEEK_SET) { return MemoryWriteStreamDynamic::seek(offset, whence); }
+		bool eos() const { return _eos; }
+		uint32 read(void *dataPtr, uint32 dataSize) {
+			if ((int32)dataSize > size() - pos()) {
+				dataSize = size() - pos();
+				_eos = true;
+			}
+			memcpy(dataPtr, getData() + pos(), dataSize);
+
+			seek(dataSize, SEEK_CUR);
+
+			return dataSize;
+		}
+	private:
+		bool _eos;
 	};
 
-	struct SavegameMainHeader {
+	LastExpressEngine *_engine;
+
+	struct SavegameMainHeader : Common::Serializable {
 		uint32 signature;
-		uint32 index;
-		uint32 time;
-		uint32 field_C;
-		uint32 field_10;
+		uint32 count;
+		uint32 offset;
+		uint32 offsetEntry;
+		uint32 keepIndex;
 		int32 brightness;
 		int32 volume;
 		uint32 field_1C;
+
+		SavegameMainHeader() {
+			signature = SAVEGAME_SIGNATURE;
+			count = 0;
+			offset = 32;
+			offsetEntry = 32;
+			keepIndex = 0;
+			brightness = 3;
+			volume = 7;
+			field_1C = 9;
+		}
+
+		void saveLoadWithSerializer(Common::Serializer &s) {
+			s.syncAsUint32LE(signature);
+			s.syncAsUint32LE(count);
+			s.syncAsUint32LE(offset);
+			s.syncAsUint32LE(offsetEntry);
+			s.syncAsUint32LE(keepIndex);
+			s.syncAsUint32LE(brightness);
+			s.syncAsUint32LE(volume);
+			s.syncAsUint32LE(field_1C);
+		}
+
+		bool isValid() {
+			if (signature != SAVEGAME_SIGNATURE)
+				return false;
+
+			/* Check not needed as it can never be < 0
+			if (header.chapter < 0)
+				return false;*/
+
+			if (offset < 32)
+				return false;
+
+			if (offsetEntry < 32)
+				return false;
+
+			if (keepIndex != 1 && keepIndex != 0)
+				return false;
+
+			if (brightness < 0 || brightness > 6)
+				return false;
+
+			if (volume < 0 || volume > 7)
+				return false;
+
+			if (field_1C != 9)
+				return false;
+
+			return true;
+		}
 	};
 
-	struct SavegameEntryHeader {
+	struct SavegameEntryHeader : Common::Serializable {
 		uint32 signature;
-		HeaderType type;
-		uint32 time;
+		SavegameType type;
+		TimeValue time;
 		int field_C;
 		ChapterIndex chapter;
-		EventIndex event;
+		uint32 value;
 		int field_18;
 		int field_1C;
 
 		SavegameEntryHeader() {
 			signature = 0;
-			type = kHeaderTypeNone;
-			time = 0;
+			type = kSavegameTypeIndex;
+			time = kTimeNone;
 			field_C = 0;
 			chapter = kChapterAll;
-			event = kEventNone;
+			value = 0;
 			field_18 = 0;
 			field_1C = 0;
 		}
-	};
 
-	SaveLoad(LastExpressEngine *engine);
-	~SaveLoad();
+		void saveLoadWithSerializer(Common::Serializer &s) {
+			s.syncAsUint32LE(signature);
+			s.syncAsUint32LE(type);
+			s.syncAsUint32LE(time);
+			s.syncAsUint32LE(field_C);
+			s.syncAsUint32LE(chapter);
+			s.syncAsUint32LE(value);
+			s.syncAsUint32LE(field_18);
+			s.syncAsUint32LE(field_1C);
+		}
 
-	// Save & Load
-	bool loadGame(GameId id);
-	void saveGame(SavegameType type, EntityIndex entity, uint32 value);
+		bool isValid() {
+			if (signature != SAVEGAME_HEADER)
+				return false;
 
-	void saveVolumeBrightness();
+			if (type < kSavegameTypeTime || type > kSavegameTypeTickInterval)
+				return false;
 
-	// Init
-	void initSavegame(GameId id, bool resetHeaders);
-	static void writeMainHeader(GameId id);
+			if (time < kTimeStartGame || time > kTimeCityConstantinople)
+				return false;
 
-	// Getting information
-	static bool isSavegamePresent(GameId id);
-	static bool isSavegameValid(GameId id);
+			if (field_C <= 0 || field_C >= 15)
+				return false;
 
-	// Opening save files
-	static Common::InSaveFile *openForLoading(GameId id);
-	static Common::OutSaveFile *openForSaving(GameId id);
+			/* No check for < 0, as it cannot happen normaly */
+			if (chapter == 0)
+				return false;
 
-	// Headers
-	static bool loadMainHeader(GameId id, SavegameMainHeader *header);
-	SavegameEntryHeader *getEntry(uint32 index);
-	void clearEntries();
+			return true;
+		}
+	};
 
-	uint32 getLastSavegameTicks() const { return _gameTicksLastSavegame; }
+	SavegameStream *_savegame;
+	Common::Array<SavegameEntryHeader *> _gameHeaders;
+	uint32 _gameTicksLastSavegame;
 
-private:
-	LastExpressEngine *_engine;
+	// Headers
+	static bool loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header);
+	void loadEntryHeader(SavegameEntryHeader *header);
 
-	uint32 _gameTicksLastSavegame;
-	Common::Array<SavegameEntryHeader *> _gameHeaders;
+	// Entries
+	void writeEntry(SavegameType type, EntityIndex entity, uint32 value);
+	void readEntry(SavegameType type, EntityIndex entity, uint32 value);
+	SavegameEntryHeader *getEntry(uint32 index);
 
-	static Common::String getSavegameName(GameId id);
+	// Opening save files
+	static Common::String getFilename(GameId id);
+	static Common::InSaveFile  *openForLoading(GameId id);
+	static Common::OutSaveFile *openForSaving(GameId id);
 
-	static void loadEntryHeader(Common::InSaveFile *save, SavegameEntryHeader *header);
-
-	static bool validateMainHeader(const SavegameMainHeader &header);
-	static bool validateEntryHeader(const SavegameEntryHeader &header);
+	// Savegame stream
+	void initStream();
+	void flushStream(GameId id);
 };
 
 } // End of namespace LastExpress

Modified: scummvm/trunk/engines/lastexpress/shared.h
===================================================================
--- scummvm/trunk/engines/lastexpress/shared.h	2010-10-25 23:34:36 UTC (rev 53840)
+++ scummvm/trunk/engines/lastexpress/shared.h	2010-10-26 00:41:42 UTC (rev 53841)
@@ -342,6 +342,8 @@
 	kSceneNone                    = 0,
 	kSceneMenu                    = 1,
 
+	kSceneIntro                   = 30,
+
 	// Inventory
 	kSceneMatchbox                = 31,
 	kSceneTelegram                = 32,


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list