Beispiel #1
0
SaveStateList ToonMetaEngine::listSaves(const char *target) const {
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	Common::StringArray filenames;
	Common::String pattern = target;
	pattern += ".???";

	filenames = saveFileMan->listSavefiles(pattern);
	sort(filenames.begin(), filenames.end());   // Sort (hopefully ensuring we are sorted numerically..)

	SaveStateList saveList;
	int slotNum = 0;
	for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
		// Obtain the last 3 digits of the filename, since they correspond to the save slot
		slotNum = atoi(filename->c_str() + filename->size() - 3);

		if (slotNum >= 0 && slotNum <= 99) {
			Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
			if (file) {
				int32 version = file->readSint32BE();
				if (version != TOON_SAVEGAME_VERSION) {
					delete file;
					continue;
				}

				// read name
				uint16 nameSize = file->readUint16BE();
				if (nameSize >= 255) {
					delete file;
					continue;
				}
				char name[256];
				file->read(name, nameSize);
				name[nameSize] = 0;

				saveList.push_back(SaveStateDescriptor(slotNum, name));
				delete file;
			}
		}
	}

	return saveList;
}
Beispiel #2
0
SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
	Common::String fileName = Common::String::format("%s.%03d", target, slot);
	Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);

	if (file) {

		int32 version = file->readSint32BE();
		if (version != TOON_SAVEGAME_VERSION) {
			delete file;
			return SaveStateDescriptor();
		}

		uint32 saveNameLength = file->readUint16BE();
		char saveName[256];
		file->read(saveName, saveNameLength);
		saveName[saveNameLength] = 0;

		SaveStateDescriptor desc(slot, saveName);

		Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
		desc.setThumbnail(thumbnail);

		uint32 saveDate = file->readUint32BE();
		uint16 saveTime = file->readUint16BE();

		int day = (saveDate >> 24) & 0xFF;
		int month = (saveDate >> 16) & 0xFF;
		int year = saveDate & 0xFFFF;

		desc.setSaveDate(year, month, day);

		int hour = (saveTime >> 8) & 0xFF;
		int minutes = saveTime & 0xFF;

		desc.setSaveTime(hour, minutes);

		delete file;
		return desc;
	}

	return SaveStateDescriptor();
}
Beispiel #3
0
SaveStateList CGEMetaEngine::listSaves(const char *target) const {
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	Common::StringArray filenames;
	Common::String pattern = target;
	pattern += ".###";

	filenames = saveFileMan->listSavefiles(pattern);

	SaveStateList saveList;
	for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
		// Obtain the last 3 digits of the filename, since they correspond to the save slot
		int slotNum = atoi(filename->c_str() + filename->size() - 3);

		if (slotNum >= 0 && slotNum <= 99) {

			Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
			if (file) {
				CGE::SavegameHeader header;

				// Check to see if it's a ScummVM savegame or not
				char buffer[kSavegameStrSize + 1];
				file->read(buffer, kSavegameStrSize + 1);

				if (!strncmp(buffer, CGE::savegameStr, kSavegameStrSize + 1)) {
					// Valid savegame
					if (CGE::CGEEngine::readSavegameHeader(file, header)) {
						saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
					}
				} else {
					// Must be an original format savegame
					saveList.push_back(SaveStateDescriptor(slotNum, "Unknown"));
				}

				delete file;
			}
		}
	}

	// Sort saves based on slot number.
	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
	return saveList;
}
Beispiel #4
0
SaveStateList CineMetaEngine::listSaves(const char *target) const {
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	SaveStateList saveList;

	Common::String pattern = target;
	pattern += ".#";
	Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
	Common::StringArray::const_iterator file;

	Common::String filename = target;
	filename += ".dir";
	Common::InSaveFile *in = saveFileMan->openForLoading(filename);
	if (in) {
		typedef char CommandeType[20];
		CommandeType saveNames[10];

		// Initialize all savegames' descriptions to empty strings
		// so that if the savegames' descriptions can only be partially read from file
		// then the missing ones are correctly set to empty strings.
		memset(saveNames, 0, sizeof(saveNames));

		in->read(saveNames, 10 * 20);
		CommandeType saveDesc;

		for (file = filenames.begin(); file != filenames.end(); ++file) {
			// Obtain the last digit of the filename, since they correspond to the save slot
			int slotNum = atoi(file->c_str() + file->size() - 1);

			// Copy the savegame description making sure it ends with a trailing zero
			strncpy(saveDesc, saveNames[slotNum], 20);
			saveDesc[sizeof(CommandeType) - 1] = 0;

			saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
		}
	}

	delete in;

	// Sort saves based on slot number.
	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
	return saveList;
}
Beispiel #5
0
SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
	Common::String fileName = Common::String::format("%s.%03d", target, slot);
	Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);

	if (f) {
		CGE::SavegameHeader header;

		// Check to see if it's a ScummVM savegame or not
		char buffer[kSavegameStrSize + 1];
		f->read(buffer, kSavegameStrSize + 1);

		bool hasHeader = !strncmp(buffer, CGE::savegameStr, kSavegameStrSize + 1) &&
			CGE::CGEEngine::readSavegameHeader(f, header, false);
		delete f;

		if (!hasHeader) {
			// Original savegame perhaps?
			SaveStateDescriptor desc(slot, "Unknown");
			return desc;
		} else {
			// Create the return descriptor
			SaveStateDescriptor desc(slot, header.saveName);
			desc.setThumbnail(header.thumbnail);
			desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
			desc.setSaveTime(header.saveHour, header.saveMinutes);

			if (header.playTime) {
				desc.setPlayTime(header.playTime * 1000);
			}

			// Slot 0 is used for the 'automatic save on exit' save in Soltys, thus
			// we prevent it from being deleted or overwritten by accident.
			desc.setDeletableFlag(slot != 0);
			desc.setWriteProtectedFlag(slot == 0);

			return desc;
		}
	}

	return SaveStateDescriptor();
}
Beispiel #6
0
void CineMetaEngine::removeSaveState(const char *target, int slot) const {
	// Load savegame descriptions from index file
	typedef char CommandeType[20];
	CommandeType saveNames[10];

	// Initialize all savegames' descriptions to empty strings
	// so that if the savegames' descriptions can only be partially read from file
	// then the missing ones are correctly set to empty strings.
	memset(saveNames, 0, sizeof(saveNames));

	Common::InSaveFile *in;
	in = g_system->getSavefileManager()->openForLoading(Common::String::format("%s.dir", target));

	if (!in)
		return;

	in->read(saveNames, 10 * 20);
	delete in;

	// Set description for selected slot
	char slotName[20];
	slotName[0] = 0;
	strncpy(saveNames[slot], slotName, 20);

	// Update savegame descriptions
	Common::String indexFile = Common::String::format("%s.dir", target);
	Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(indexFile);
	if (!out) {
		warning("Unable to open file %s for saving", indexFile.c_str());
		return;
	}

	out->write(saveNames, 10 * 20);
	delete out;

	// Delete save file
	char saveFileName[256];
	sprintf(saveFileName, "%s.%1d", target, slot);

	g_system->getSavefileManager()->removeSavefile(saveFileName);
}
Beispiel #7
0
SaveStateList AdlMetaEngine::listSaves(const char *target) const {
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	Common::StringArray files = saveFileMan->listSavefiles(Common::String(target) + ".s##");

	SaveStateList saveList;

	for (uint i = 0; i < files.size(); ++i) {
		const Common::String &fileName = files[i];
		Common::InSaveFile *inFile = saveFileMan->openForLoading(fileName);
		if (!inFile) {
			warning("Cannot open save file '%s'", fileName.c_str());
			continue;
		}

		if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) {
			warning("No header found in '%s'", fileName.c_str());
			delete inFile;
			continue;
		}

		byte saveVersion = inFile->readByte();
		if (saveVersion != SAVEGAME_VERSION) {
			warning("Unsupported save game version %i found in '%s'", saveVersion, fileName.c_str());
			delete inFile;
			continue;
		}

		char name[SAVEGAME_NAME_LEN] = { };
		inFile->read(name, sizeof(name) - 1);
		delete inFile;

		int slotNum = atoi(fileName.c_str() + fileName.size() - 2);
		SaveStateDescriptor sd(slotNum, name);
		saveList.push_back(sd);
	}

	// Sort saves based on slot number.
	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
	return saveList;
}
Beispiel #8
0
SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
	Common::String fileName = Common::String::format("%s.%03d", target, slot);
	Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
	if (file) {
		char saveIdentBuffer[5];
		file->read(saveIdentBuffer, 5);

		int32 version = file->readByte();
		if (version > GNAP_SAVEGAME_VERSION) {
			delete file;
			return SaveStateDescriptor();
		}

		Common::String saveName;
		char ch;
		while ((ch = (char)file->readByte()) != '\0')
			saveName += ch;

		SaveStateDescriptor desc(slot, saveName);

		if (version != 1) {
			Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
			desc.setThumbnail(thumbnail);
		}

		int year = file->readSint16LE();
		int month = file->readSint16LE();
		int day = file->readSint16LE();
		int hour = file->readSint16LE();
		int minutes = file->readSint16LE();

		desc.setSaveDate(year, month, day);
		desc.setSaveTime(hour, minutes);

		delete file;
		return desc;
	}

	return SaveStateDescriptor();
}
Beispiel #9
0
SaveStateList WageMetaEngine::listSaves(const char *target) const {
	const uint32 WAGEflag = MKTAG('W','A','G','E');
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	Common::StringArray filenames;
	char saveDesc[128] = {0};
	Common::String pattern = target;
	pattern += ".###";

	filenames = saveFileMan->listSavefiles(pattern);

	SaveStateList saveList;
	for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
		// Obtain the last 3 digits of the filename, since they correspond to the save slot
		int slotNum = atoi(file->c_str() + file->size() - 3);

		if (slotNum >= 0 && slotNum <= 999) {
			Common::InSaveFile *in = saveFileMan->openForLoading(*file);
			if (in) {
				saveDesc[0] = 0;
				in->seek(in->size() - 8);
				uint32 offset = in->readUint32BE();
				uint32 type = in->readUint32BE();
				if (type == WAGEflag) {
					in->seek(offset);

					type = in->readUint32BE();
					if (type == WAGEflag) {
						in->read(saveDesc, 127);
					}
				}
				saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
				delete in;
			}
		}
	}

	// Sort saves based on slot number.
	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
	return saveList;
}
Beispiel #10
0
bool CineEngine::loadSaveDirectory() {
    Common::InSaveFile *fHandle;
    fHandle = _saveFileMan->openForLoading(Common::String::format("%s.dir", _targetName.c_str()));

    if (!fHandle) {
        return false;
    }

    // Initialize all savegames' descriptions to empty strings
    // so that if the savegames' descriptions can only be partially read from file
    // then the missing ones are correctly set to empty strings.
    memset(currentSaveName, 0, sizeof(currentSaveName));

    fHandle->read(currentSaveName, 10 * 20);
    delete fHandle;

    // Make sure all savegames' descriptions end with a trailing zero.
    for (int i = 0; i < ARRAYSIZE(currentSaveName); i++)
        currentSaveName[i][sizeof(CommandeType) - 1] = 0;

    return true;
}
Beispiel #11
0
int16 GameDatabaseV3::loadgame(const char *filename, int16 version) {
	Common::InSaveFile *in;
	uint32 expectedSize = 4 + 4 + 2 + _gameStateSize;

	if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
		warning("Can't open file '%s', game not loaded", filename);
		return 1;
	}

	uint32 header = in->readUint32BE();
	if (header != MKTAG('S','G','A','M')) {
		warning("Save game header missing");
		delete in;
		return 1;
	}

	uint32 size = in->readUint32LE();
	int16 saveVersion = in->readUint16LE();

	if (saveVersion != version) {
		warning("Save game %s was saved with a different version of the game. Game version is %d, save version is %d", filename, version, saveVersion);
		delete in;
		return 1;
	}

	if (size != expectedSize) {
		warning("Unexpected save game size. Expected %d, size is %d", expectedSize, size);
		delete in;
		return 1;
	}

	in->skip(64); // skip savegame description
	in->read(_gameState, _gameStateSize);
	delete in;

	_objectPropertyCache.clear();	// make sure to clear cache

	return 0;
}
Beispiel #12
0
SaveStateList DreamWebMetaEngine::listSaves(const char *target) const {
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D??");
	Common::sort(files.begin(), files.end());

	SaveStateList saveList;
	for(uint i = 0; i < files.size(); ++i) {
		const Common::String &file = files[i];
		Common::InSaveFile *stream = saveFileMan->openForLoading(file);
		if (!stream)
			error("cannot open save file %s", file.c_str());
		char name[17] = {};
		stream->seek(0x61);
		stream->read(name, sizeof(name) - 1);
		delete stream;

		int slotNum = atoi(file.c_str() + file.size() - 2);
		SaveStateDescriptor sd(slotNum, name);
		saveList.push_back(sd);
	}

	return saveList;
}
Beispiel #13
0
uint32 Sword2Engine::restoreData(uint16 slotNo, byte *buffer, uint32 bufferSize) {
	char *saveFileName = getSaveFileName(slotNo);

	Common::InSaveFile *in;

	if (!(in = _saveFileMan->openForLoading(saveFileName))) {
		// error: couldn't open file
		return SR_ERR_FILEOPEN;
	}

	// Read savegame into the buffer
	uint32 itemsRead = in->read(buffer, bufferSize);

	delete in;

	if (itemsRead != bufferSize) {
		// We didn't get all of it. At the moment we have no way of
		// knowing why, so assume that it's an incompatible savegame.

		return SR_ERR_INCOMPATIBLE;
	}

	return SR_OK;
}
Beispiel #14
0
bool GameDatabaseV3::getSavegameDescription(const char *filename, Common::String &description, int16 version) {
	Common::InSaveFile *in;
	char desc[64];

	if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
		return false;
	}

	uint32 header = in->readUint32BE();
	if (header != MKTAG('S','G','A','M')) {
		warning("Save game header missing");
		delete in;
		return false;
	}

	int32 size = in->readUint32LE();
	int16 saveVersion = in->readUint16LE();

	if (saveVersion != version) {
		warning("Save game %s was saved with a different version of the game. Game version is %d, save version is %d", filename, version, saveVersion);
		delete in;
		return false;
	}

	if (size != in->size() - 64) {
		warning("Unexpected save game size. Expected %d, size is %d (file size - 64)", size, in->size() - 64);
		delete in;
		return false;
	}

	in->read(desc, 64);
	description = desc;

	delete in;
	return true;
}
Beispiel #15
0
void SagaEngine::load(const char *fileName) {
	Common::InSaveFile *in;
	int commonBufferSize;
	int sceneNumber, insetSceneNumber;
	int mapx, mapy;
	char title[TITLESIZE];

	if (!(in = _saveFileMan->openForLoading(fileName))) {
		return;
	}

	_saveHeader.type = in->readUint32BE();
	_saveHeader.size = in->readUint32LE();
	_saveHeader.version = in->readUint32LE();
	in->read(_saveHeader.name, sizeof(_saveHeader.name));

	// Some older saves were not written in an endian safe fashion.
	// We try to detect this here by checking for extremly high version values.
	// If found, we retry with the data swapped.
	if (_saveHeader.version > 0xFFFFFF) {
		warning("This savegame is not endian safe, retrying with the data swapped");
		_saveHeader.version = SWAP_BYTES_32(_saveHeader.version);
	}

	debug(2, "Save version: 0x%X", _saveHeader.version);

	if (_saveHeader.version < 4)
		warning("This savegame is not endian-safe. There may be problems");

	if (_saveHeader.type != MKTAG('S','A','G','A')) {
		error("SagaEngine::load wrong save game format");
	}

	if (_saveHeader.version > 4) {
		in->read(title, TITLESIZE);
		debug(0, "Save is for: %s", title);
	}

	if (_saveHeader.version >= 6) {
		// We don't need the thumbnail here, so just read it and discard it
		Graphics::skipThumbnail(*in);

		in->readUint32BE();	// save date
		in->readUint16BE(); // save time

		if (_saveHeader.version >= 8) {
			uint32 playTime = in->readUint32BE();
			g_engine->setTotalPlayTime(playTime * 1000);
		}
	}

	// Clear pending events here, and don't process queued music events
	_events->clearList(false);

	// Surrounding scene
	sceneNumber = in->readSint32LE();
#ifdef ENABLE_IHNM
	if (getGameId() == GID_IHNM) {
		int currentChapter = _scene->currentChapterNumber();
		_scene->setChapterNumber(in->readSint32LE());
		in->skip(4);	// obsolete, was used for setting the protagonist
		if (_scene->currentChapterNumber() != currentChapter)
			_scene->changeScene(-2, 0, kTransitionFade, _scene->currentChapterNumber());
		_scene->setCurrentMusicTrack(in->readSint32LE());
		_scene->setCurrentMusicRepeat(in->readSint32LE());
		_music->stop();
		if (_scene->currentChapterNumber() == 8)
			_interface->setMode(kPanelChapterSelection);
		if (!isIHNMDemo()) {
			_music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL);
		} else {
			_music->play(3, MUSIC_LOOP);
		}
	}
#endif

	// Inset scene
	insetSceneNumber = in->readSint32LE();

#ifdef ENABLE_IHNM
	if (getGameId() == GID_IHNM) {
		_globalFlags = in->readUint32LE();
		for (int i = 0; i < ARRAYSIZE(_ethicsPoints); i++)
			_ethicsPoints[i] = in->readSint16LE();
	}
#endif

	_interface->loadState(in);

	_actor->loadState(in);

	commonBufferSize = in->readSint16LE();
	_script->_commonBuffer.resize(commonBufferSize);
	in->read(_script->_commonBuffer.getBuffer(), commonBufferSize);

	if (getGameId() == GID_ITE) {
		mapx = in->readSint16LE();
		mapy = in->readSint16LE();
		_isoMap->setMapPosition(mapx, mapy);
	}
	// Note: the mapx, mapy ISO map positions were incorrectly saved
	// for IHNM too, which has no ISO map scenes, up to save version 6.
	// Since they're at the end of the savegame, we just ignore them

	delete in;

	// Mute volume to prevent outScene music play
	int volume = _music->getVolume();
	_music->setVolume(0);

	_scene->clearSceneQueue();
	_scene->changeScene(sceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade);

	_events->handleEvents(0); //dissolve backgrounds

	if (insetSceneNumber != sceneNumber) {
		_render->setFlag(RF_DISABLE_ACTORS);
		_scene->draw();
		_render->drawScene();
		_render->clearFlag(RF_DISABLE_ACTORS);
		_scene->changeScene(insetSceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade);
	}

	_music->setVolume(volume);

	_interface->draw();

	// Abort any scene entry protagonist animations and auto-cue speeches.
	// Fixes bug #10009.
	_actor->abortAllSpeeches();
	_actor->_protagonist->_location = _actor->_protagonist->_finalTarget;
	_actor->actorEndWalk(ID_PROTAG, true);
}
Beispiel #16
0
bool CGEEngine::loadGame(int slotNumber, SavegameHeader *header, bool tiny) {
	debugC(1, kCGEDebugEngine, "CGEEngine::loadgame(%d, header, %s)", slotNumber, tiny ? "true" : "false");

	Common::MemoryReadStream *readStream;
	SavegameHeader saveHeader;

	if (slotNumber == -1) {
		// Loading the data for the initial game state
		EncryptedStream file = EncryptedStream(this, kSavegame0Name);
		int size = file.size();
		byte *dataBuffer = (byte *)malloc(size);
		file.read(dataBuffer, size);
		readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);

	} else {
		// Open up the savegame file
		Common::String slotName = generateSaveName(slotNumber);
		Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);

		// Read the data into a data buffer
		int size = saveFile->size();
		byte *dataBuffer = (byte *)malloc(size);
		saveFile->read(dataBuffer, size);
		readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);
		delete saveFile;
	}

	// Check to see if it's a ScummVM savegame or not
	char buffer[kSavegameStrSize + 1];
	readStream->read(buffer, kSavegameStrSize + 1);

	if (strncmp(buffer, savegameStr, kSavegameStrSize + 1) != 0) {
		// It's not, so rewind back to the start
		readStream->seek(0);

		if (header)
			// Header wanted where none exists, so return false
			return false;
	} else {
		// Found header
		if (!readSavegameHeader(readStream, saveHeader)) {
			delete readStream;
			return false;
		}

		if (header) {
			*header = saveHeader;
			delete readStream;
			return true;
		}

		// Delete the thumbnail
		saveHeader.thumbnail->free();
		delete saveHeader.thumbnail;
	}

	// Get in the savegame
	syncGame(readStream, NULL, tiny);

	delete readStream;
	return true;
}
Beispiel #17
0
bool loadGame(const Common::String &fname) {
	Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(fname);
	FILETIME savedGameTime;

	while (allRunningFunctions)
		finishFunction(allRunningFunctions);

	if (fp == NULL)
		return false;

	bool headerBad = false;
	if (fp->readByte() != 'S')
		headerBad = true;
	if (fp->readByte() != 'L')
		headerBad = true;
	if (fp->readByte() != 'U')
		headerBad = true;
	if (fp->readByte() != 'D')
		headerBad = true;
	if (fp->readByte() != 'S')
		headerBad = true;
	if (fp->readByte() != 'A')
		headerBad = true;
	if (headerBad) {
		fatal(ERROR_GAME_LOAD_NO, fname);
		return NULL;
	}
	char c;
	c = fp->readByte();
	while ((c = fp->readByte()))
		;

	int majVersion = fp->readByte();
	int minVersion = fp->readByte();
	ssgVersion = VERSION(majVersion, minVersion);

	if (ssgVersion >= VERSION(1, 4)) {
		if (!g_sludge->_gfxMan->skipThumbnail(fp))
			return fatal(ERROR_GAME_LOAD_CORRUPT, fname);
	}

	uint32 bytes_read = fp->read(&savedGameTime, sizeof(FILETIME));
	if (bytes_read != sizeof(FILETIME) && fp->err()) {
		warning("Reading error in loadGame.");
	}

	if (savedGameTime.dwLowDateTime != fileTime.dwLowDateTime || savedGameTime.dwHighDateTime != fileTime.dwHighDateTime) {
		return fatal(ERROR_GAME_LOAD_WRONG, fname);
	}

	// DON'T ADD ANYTHING NEW BEFORE THIS POINT!

	if (ssgVersion >= VERSION(1, 4)) {
		allowAnyFilename = fp->readByte();
	}
	captureAllKeys = fp->readByte();
	fp->readByte();  // updateDisplay (part of movie playing)

	g_sludge->_txtMan->loadFont(ssgVersion, fp);

	killAllPeople();
	killAllRegions();

	int camerX = fp->readUint16BE();
	int camerY = fp->readUint16BE();
	float camerZ;
	if (ssgVersion >= VERSION(2, 0)) {
		camerZ = fp->readFloatLE();
	} else {
		camerZ = 1.0;
	}

	brightnessLevel = fp->readByte();

	g_sludge->_gfxMan->loadHSI(fp, 0, 0, true);
	g_sludge->_evtMan->loadHandlers(fp);
	loadRegions(fp);

	if (!g_sludge->_cursorMan->loadCursor(fp)) {
		return false;
	}

	LoadedFunction *rFunc;
	LoadedFunction **buildList = &allRunningFunctions;

	int countFunctions = fp->readUint16BE();
	while (countFunctions--) {
		rFunc = loadFunction(fp);
		rFunc->next = NULL;
		(*buildList) = rFunc;
		buildList = &(rFunc->next);
	}

	for (int a = 0; a < numGlobals; a++) {
		unlinkVar(globalVars[a]);
		loadVariable(&globalVars[a], fp);
	}

	loadPeople(fp);

	if (fp->readByte()) {
		if (!setFloor(fp->readUint16BE()))
			return false;
	} else
		setFloorNull();

	if (!g_sludge->_gfxMan->loadZBuffer(fp))
		return false;

	if (!g_sludge->_gfxMan->loadLightMap(ssgVersion, fp)) {
		return false;
	}

	fadeMode = fp->readByte();
	g_sludge->_speechMan->load(fp);
	loadStatusBars(fp);
	g_sludge->_soundMan->loadSounds(fp);

	saveEncoding = fp->readUint16BE();

	if (ssgVersion >= VERSION(1, 6)) {
		if (ssgVersion < VERSION(2, 0)) {
			// aaLoad
			fp->readByte();
			fp->readFloatLE();
			fp->readFloatLE();
		}

		blur_loadSettings(fp);
	}

	if (ssgVersion >= VERSION(1, 3)) {
		g_sludge->_gfxMan->loadColors(fp);

		// Read parallax layers
		while (fp->readByte()) {
			int im = fp->readUint16BE();
			int fx = fp->readUint16BE();
			int fy = fp->readUint16BE();

			if (!g_sludge->_gfxMan->loadParallax(im, fx, fy))
				return false;
		}

		g_sludge->_languageMan->loadLanguageSetting(fp);
	}

	g_sludge->_gfxMan->nosnapshot();
	if (ssgVersion >= VERSION(1, 4)) {
		if (fp->readByte()) {
			if (!g_sludge->_gfxMan->restoreSnapshot(fp))
				return false;
		}
	}

	delete fp;

	g_sludge->_gfxMan->setCamera(camerX, camerY, camerZ);

	clearStackLib();
	return true;
}
Beispiel #18
0
SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
	static char fileName[MAX_FILE_NAME];
	sprintf(fileName, "%s.s%02d", target, slot);
	char title[TITLESIZE];

	Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);

	if (in) {
		uint32 type = in->readUint32BE();
		in->readUint32LE();		// size
		uint32 version = in->readUint32LE();
		char name[SAVE_TITLE_SIZE];
		in->read(name, sizeof(name));

		SaveStateDescriptor desc(slot, name);

		// Some older saves were not written in an endian safe fashion.
		// We try to detect this here by checking for extremly high version values.
		// If found, we retry with the data swapped.
		if (version > 0xFFFFFF) {
			warning("This savegame is not endian safe, retrying with the data swapped");
			version = SWAP_BYTES_32(version);
		}

		debug(2, "Save version: 0x%X", version);

		if (version < 4)
			warning("This savegame is not endian-safe. There may be problems");

		if (type != MKTAG('S','A','G','A')) {
			error("SagaEngine::load wrong save game format");
		}

		if (version > 4) {
			in->read(title, TITLESIZE);
			debug(0, "Save is for: %s", title);
		}

		if (version >= 6) {
			Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
			desc.setThumbnail(thumbnail);

			uint32 saveDate = in->readUint32BE();
			uint16 saveTime = in->readUint16BE();

			int day = (saveDate >> 24) & 0xFF;
			int month = (saveDate >> 16) & 0xFF;
			int year = saveDate & 0xFFFF;

			desc.setSaveDate(year, month, day);

			int hour = (saveTime >> 8) & 0xFF;
			int minutes = saveTime & 0xFF;

			desc.setSaveTime(hour, minutes);

			if (version >= 8) {
				uint32 playTime = in->readUint32BE();
				desc.setPlayTime(playTime * 1000);
			}
		}

		delete in;

		return desc;
	}
Beispiel #19
0
void AGOSEngine_Feeble::listSaveGames(int n) {
	char b[108];
	Common::InSaveFile *in;
	uint16 j, k, z, maxFiles;
	int OK;
	memset(b, 0, 108);

	maxFiles = countSaveGames() - 1;
	j = maxFiles - n + 1;
	k = maxFiles - j + 1;
	z = maxFiles;
	if (getBitFlag(95)) {
		j++;
		z++;
	}

	while (!shouldQuit()) {
		OK = 1;
		if (getBitFlag(93) || getBitFlag(94)) {
			OK = 0;
			if (j > z)
				break;
		}

		if (getBitFlag(93)) {
			if (((_newLines + 1) >= _textWindow->scrollY) && ((_newLines + 1) < (_textWindow->scrollY + 3)))
				OK = 1;
		}

		if (getBitFlag(94)) {
			if ((_newLines + 1) == (_textWindow->scrollY + 7))
				OK = 1;
		}


		if (OK == 1) {
			if (j == maxFiles + 1) {
				showMessageFormat("\n");
				hyperLinkOn(j + 400);
				setTextColor(116);
				showMessageFormat(" %d. ", 1);
				hyperLinkOff();
				setTextColor(113);
				k++;
				j--;
			}

			if (!(in = _saveFileMan->openForLoading(genSaveName(j))))
				break;
			in->read(b, 100);
			delete in;
		}

		showMessageFormat("\n");
		hyperLinkOn(j + 400);
		setTextColor(116);
		if (k < 10)
			showMessageFormat(" ");
		showMessageFormat("%d. ", k);
		setTextColor(113);
		showMessageFormat("%s ", b);
		hyperLinkOff();
		j--;
		k++;
	}
}
bool PersistenceService::loadGame(uint slotID) {
	Common::SaveFileManager *sfm = g_system->getSavefileManager();
	Common::InSaveFile *file;

	// Überprüfen, ob die Slot-ID zulässig ist.
	if (slotID >= SLOT_COUNT) {
		error("Tried to load from an invalid slot (%d). Only slot ids form 0 to %d are allowed.", slotID, SLOT_COUNT - 1);
		return false;
	}

	SavegameInformation &curSavegameInfo = _impl->_savegameInformations[slotID];

	// Überprüfen, ob der Slot belegt ist.
	if (!curSavegameInfo.isOccupied) {
		error("Tried to load from an empty slot (%d).", slotID);
		return false;
	}

	// Überprüfen, ob der Spielstand im angegebenen Slot mit der aktuellen Engine-Version kompatibel ist.
	// Im Debug-Modus wird dieser Test übersprungen. Für das Testen ist es hinderlich auf die Einhaltung dieser strengen Bedingung zu bestehen,
	// da sich die Versions-ID bei jeder Codeänderung mitändert.
#ifndef DEBUG
	if (!curSavegameInfo.isCompatible) {
		error("Tried to load a savegame (%d) that is not compatible with this engine version.", slotID);
		return false;
	}
#endif

	byte *compressedDataBuffer = new byte[curSavegameInfo.gamedataLength];
	byte *uncompressedDataBuffer = new byte[curSavegameInfo.gamedataUncompressedLength];
	Common::String filename = generateSavegameFilename(slotID);
	file = sfm->openForLoading(filename);

	file->seek(curSavegameInfo.gamedataOffset);
	file->read(reinterpret_cast<char *>(&compressedDataBuffer[0]), curSavegameInfo.gamedataLength);
	if (file->err()) {
		error("Unable to load the gamedata from the savegame file \"%s\".", filename.c_str());
		delete[] compressedDataBuffer;
		delete[] uncompressedDataBuffer;
		return false;
	}

	// Uncompress game data, if needed.
	unsigned long uncompressedBufferSize = curSavegameInfo.gamedataUncompressedLength;

	if (uncompressedBufferSize > curSavegameInfo.gamedataLength) {
		// Older saved game, where the game data was compressed again.
		if (!Common::uncompress(reinterpret_cast<byte *>(&uncompressedDataBuffer[0]), &uncompressedBufferSize,
					   reinterpret_cast<byte *>(&compressedDataBuffer[0]), curSavegameInfo.gamedataLength)) {
			error("Unable to decompress the gamedata from savegame file \"%s\".", filename.c_str());
			delete[] uncompressedDataBuffer;
			delete[] compressedDataBuffer;
			delete file;
			return false;
		}
	} else {
		// Newer saved game with uncompressed game data, copy it as-is.
		memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize);
	}

	InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength, curSavegameInfo.version);

	// Einzelne Engine-Module depersistieren.
	bool success = true;
	success &= Kernel::getInstance()->getScript()->unpersist(reader);
	// Muss unbedingt nach Script passieren. Da sonst die bereits wiederhergestellten Regions per Garbage-Collection gekillt werden.
	success &= RegionRegistry::instance().unpersist(reader);
	success &= Kernel::getInstance()->getGfx()->unpersist(reader);
	success &= Kernel::getInstance()->getSfx()->unpersist(reader);
	success &= Kernel::getInstance()->getInput()->unpersist(reader);

	delete[] compressedDataBuffer;
	delete[] uncompressedDataBuffer;
	delete file;

	if (!success) {
		error("Unable to unpersist the gamedata from savegame file \"%s\".", filename.c_str());
		return false;
	}

	return true;
}
Beispiel #21
0
void AGOSEngine_Feeble::saveUserGame(int slot) {
	WindowBlock *window;
	Common::InSaveFile *in;
	char name[108];
	int len;
	memset(name, 0, 108);

	window = _windowArray[3];

	window->textRow = (slot + 1 - window->scrollY) * 15;
	window->textColumn = 26;

	if ((in = _saveFileMan->openForLoading(genSaveName(readVariable(55))))) {
		in->read(name, 100);
		delete in;
	}

	len = 0;
	while (name[len]) {
		byte chr = name[len];
		window->textColumn += getFeebleFontSize(chr);
		len++;
	}

	windowPutChar(window, 0x7f);
	while (!shouldQuit()) {
		_keyPressed.reset();
		delay(1);

		if (_keyPressed.ascii == 0 || _keyPressed.ascii >= 127)
			continue;

		window->textColumn -= getFeebleFontSize(127);
		name[len] = 0;
		windowBackSpace(_windowArray[3]);

		if (_keyPressed.keycode == Common::KEYCODE_ESCAPE) {
			_variableArray[55] = 27;
			break;
		}
		if (_keyPressed.keycode == Common::KEYCODE_KP_ENTER || _keyPressed.keycode == Common::KEYCODE_RETURN) {
			if (!saveGame(readVariable(55), name))
				_variableArray[55] = (int16)0xFFFF;
			else
				_variableArray[55] = 0;
			break;
		}
		if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE && len != 0) {
			len--;
			byte chr = name[len];
			window->textColumn -= getFeebleFontSize(chr);
			name[len] = 0;
			windowBackSpace(_windowArray[3]);
		}
		if (_keyPressed.ascii >= 32 && window->textColumn + 26 <= window->width) {
			name[len++] = _keyPressed.ascii;
			windowPutChar(_windowArray[3], _keyPressed.ascii);
		}

		windowPutChar(window, 0x7f);
	}
}
Beispiel #22
0
SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
	Common::String fileName = Common::String::format("sword1.%03d", slot);
	char name[40];
	uint32 playTime = 0;
	byte versionSave;

	Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);

	if (in) {
		in->skip(4);		// header
		in->read(name, sizeof(name));
		in->read(&versionSave, 1);		// version

		SaveStateDescriptor desc(slot, name);

		desc.setDeletableFlag(true);
		desc.setWriteProtectedFlag(false);

		if (versionSave < 2) // These older version of the savegames used a flag to signal presence of thumbnail
			in->skip(1);

		if (Graphics::checkThumbnailHeader(*in)) {
			Graphics::Surface *thumbnail = new Graphics::Surface();
			assert(thumbnail);
			if (!Graphics::loadThumbnail(*in, *thumbnail)) {
				delete thumbnail;
				thumbnail = 0;
			}

			desc.setThumbnail(thumbnail);
		}

		uint32 saveDate = in->readUint32BE();
		uint16 saveTime = in->readUint16BE();
		if (versionSave > 1) // Previous versions did not have playtime data
			playTime = in->readUint32BE();

		int day = (saveDate >> 24) & 0xFF;
		int month = (saveDate >> 16) & 0xFF;
		int year = saveDate & 0xFFFF;

		desc.setSaveDate(year, month, day);

		int hour = (saveTime >> 8) & 0xFF;
		int minutes = saveTime & 0xFF;

		desc.setSaveTime(hour, minutes);

		if (versionSave > 1) {
			desc.setPlayTime(playTime * 1000);
		} else { //We have no playtime data
			desc.setPlayTime(0);
		}

		delete in;

		return desc;
	}

	return SaveStateDescriptor();
}
Beispiel #23
0
void BbvsEngine::loadgame(const char *filename) {
	Common::InSaveFile *in;
	if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
		warning("Can't open file '%s', game not loaded", filename);
		return;
	}

	SaveHeader header;

	kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
	
	if (errorCode != kRSHENoError) {
		warning("Error loading savegame '%s'", filename);
		delete in;
		return;
	}
	
	g_engine->setTotalPlayTime(header.playTime * 1000);
	
	memset(_sceneObjects, 0, sizeof(_sceneObjects));
	for (int i = 0; i < kSceneObjectsCount; ++i) {
		_sceneObjects[i].walkDestPt.x = -1;
		_sceneObjects[i].walkDestPt.y = -1;
	}

	_currSceneNum = 0;
	_newSceneNum = in->readUint32LE();
	
	initScene(false);

	_prevSceneNum = in->readUint32LE();
	_gameState = in->readUint32LE();
	_mouseCursorSpriteIndex = in->readUint32LE();
	_mousePos.x = in->readUint16LE();
	_mousePos.y = in->readUint16LE();
	_currVerbNum = in->readUint32LE();
	_activeItemType = in->readUint32LE();
	_activeItemIndex = in->readUint32LE();
	_verbPos.x = in->readUint16LE();
	_verbPos.y = in->readUint16LE();
	_inventoryButtonIndex = in->readUint32LE();
	_currInventoryItem = in->readUint32LE();
	_currTalkObjectIndex = in->readUint32LE();
	_currCameraNum = in->readUint32LE();
	_cameraPos.x = in->readUint16LE();
	_cameraPos.y = in->readUint16LE();
	_newCameraPos.x = in->readUint16LE();
	_newCameraPos.y = in->readUint16LE();
	_dialogSlotCount = in->readUint32LE();
	_walkMousePos.x = in->readUint16LE();
	_walkMousePos.y = in->readUint16LE();
	in->read(_backgroundSoundsActive, kSceneSoundsCount);
	in->read(_inventoryItemStatus, kInventoryItemStatusCount);
	in->read(_dialogItemStatus, kDialogItemStatusCount);
	in->read(_gameVars, kGameVarsCount);
	in->read(_sceneVisited, kSceneVisitedCount);
	for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
		SceneObject *obj = &_sceneObjects[i];
		obj->x = in->readUint32LE();
		obj->y = in->readUint32LE();
		obj->animIndex = in->readUint32LE();
		obj->frameIndex = in->readUint32LE();
		obj->frameTicks = in->readUint32LE();
		obj->walkCount = in->readUint32LE();
		obj->xIncr = in->readUint32LE(); 
		obj->yIncr = in->readUint32LE();
		obj->turnValue = in->readUint32LE(); 
		obj->turnCount = in->readUint32LE(); 
		obj->turnTicks = in->readUint32LE();
		obj->walkDestPt.x = in->readUint16LE();
		obj->walkDestPt.y = in->readUint16LE();
		obj->anim = obj->animIndex > 0 ? _gameModule->getAnimation(obj->animIndex) : 0;
	}
	
	updateWalkableRects();

	// Restart scene background sounds
	for (int i = 0; i < _gameModule->getSceneSoundsCount(); ++i) {
		if (_backgroundSoundsActive[i]) {
			SceneSound *sceneSound = _gameModule->getSceneSound(i);
			playSound(sceneSound->soundNum, true);
		}
	}

	_currAction = 0;
	_currActionCommandIndex = -1;

	delete in;

}
Beispiel #24
0
void BladeRunnerEngine::loadGame(const Common::String &filename, byte *thumbnail) {
	warning("BladeRunnerEngine::loadGame not finished");

	if (!playerHasControl() || _sceneScript->isInsideScript() || _aiScripts->isInsideScript()) {
		return;
	}

	Common::InSaveFile *commonSaveFile = getSaveFileManager()->openForLoading(filename);
	if (commonSaveFile->err()) {
		return;
	}

	void *buf = malloc(commonSaveFile->size());
	int dataSize = commonSaveFile->read(buf, commonSaveFile->size());

	SaveFileReadStream s((const byte*)buf, dataSize);

	_ambientSounds->removeAllNonLoopingSounds(true);
	_ambientSounds->removeAllLoopingSounds(1);
	_music->stop(2);
	_audioSpeech->stopSpeech();
	_actorDialogueQueue->flush(true, false);

	int size = s.readInt();

	if (size != dataSize) {
		return;
	}

	s.skip(9600); // thumbnail
	_settings->load(s);
	_scene->load(s);
	_scene->_exits->load(s);
	_scene->_regions->load(s);
	_scene->_set->load(s);
	for (uint i = 0; i != _gameInfo->getGlobalVarCount(); ++i) {
		_gameVars[i] = s.readInt();
	}
	_music->load(s);
	// _audioPlayer->load(s) // zero func
	// _audioSpeech->load(s) // zero func
	_combat->load(s);
	_gameFlags->load(s);
	_items->load(s);
	_sceneObjects->load(s);
	_ambientSounds->load(s);
	_overlays->load(s);
	_spinner->load(s);
	_scores->load(s);
	_dialogueMenu->load(s);
	_obstacles->load(s);
	_actorDialogueQueue->load(s);
	_waypoints->load(s);

	for (uint i = 0; i != _gameInfo->getActorCount(); ++i) {
		_actors[i]->load(s);

		int animationState = s.readInt();
		int animationFrame = s.readInt();
		int animationStateNext = s.readInt();
		int nextAnimation = s.readInt();
		_aiScripts->setAnimationState(i, animationState, animationFrame, animationStateNext, nextAnimation);
	}
	_actors[kActorVoiceOver]->load(s);

	_policeMaze->load(s);
	_crimesDatabase->load(s);

	_settings->setNewSetAndScene(_settings->getSet(), _settings->getScene());
	_settings->setChapter(_settings->getChapter());
}
Beispiel #25
0
int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
	char description[31], saveVersion, loadId[8];
	int i, vtEntries = MAX_VIEWTABLE;
	uint8 t;
	int16 parm[7];
	Common::InSaveFile *in;

	debugC(3, kDebugLevelMain | kDebugLevelSavegame, "AgiEngine::loadGame(%s)", fileName.c_str());

	if (!(in = _saveFileMan->openForLoading(fileName))) {
		warning("Can't open file '%s', game not loaded", fileName.c_str());
		return errBadFileOpen;
	} else {
		debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Successfully opened %s for reading", fileName.c_str());
	}

	uint32 typea = in->readUint32BE();
	if (typea == AGIflag) {
		debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Has AGI flag, good start");
	} else {
		warning("This doesn't appear to be an AGI savegame, game not restored");
		delete in;
		return errOK;
	}

	in->read(description, 31);

	debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Description is: %s", description);

	saveVersion = in->readByte();
	if (saveVersion < 2)	// is the save game pre-ScummVM?
		warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, SAVEGAME_VERSION);

	if (saveVersion < 3)
		warning("This save game contains no AGIPAL data, if the game is using the AGIPAL hack, it won't work correctly");

	if (saveVersion >= 4) {
		// We don't need the thumbnail here, so just read it and discard it
		Graphics::skipThumbnail(*in);

		in->readUint32BE();	// save date
		in->readUint16BE(); // save time
		// TODO: played time
	}

	_game.state = (State)in->readByte();

	in->read(loadId, 8);
	if (strcmp(loadId, _game.id) && checkId) {
		delete in;
		warning("This save seems to be from a different AGI game (save from %s, running %s), not loaded", loadId, _game.id);
		return errBadFileOpen;
	}

	strncpy(_game.id, loadId, 8);

	if (saveVersion >= 5) {
		char md5[32 + 1];

		for (i = 0; i < 32; i++) {
			md5[i] = in->readByte();

		}
		md5[i] = 0; // terminate

		// As noted above in AgiEngine::saveGame the MD5 sum field may be all zero
		// when the save was made via a fallback matched game. In this case we will
		// replace the MD5 sum with a nicer string, so that the user can easily see
		// this fact in the debug output. The string saved in "md5" will never match
		// any valid MD5 sum, thus it is safe to do that here.
		if (md5[0] == 0)
			strcpy(md5, "fallback matched");

		debug(0, "Saved game MD5: \"%s\"", md5);

		if (!getGameMD5()) {
			warning("Since your game was only detected via the fallback detector, there is no possibility to assure the save is compatible with your game version");

			debug(0, "The game used for saving is \"%s\".", md5);
		} else if (strcmp(md5, getGameMD5())) {
			warning("Game was saved with different gamedata - you may encounter problems");

			debug(0, "Your game is \"%s\" and save is \"%s\".", getGameMD5(), md5);
		}
	}

	for (i = 0; i < MAX_FLAGS; i++)
		_game.flags[i] = in->readByte();
	for (i = 0; i < MAX_VARS; i++)
		_game.vars[i] = in->readByte();

	setvar(vFreePages, 180); // Set amount of free memory to realistic value (Overwriting the just loaded value)

	_game.horizon = in->readSint16BE();
	_game.lineStatus = in->readSint16BE();
	_game.lineUserInput = in->readSint16BE();
	_game.lineMinPrint = in->readSint16BE();

	// These are never saved
	_game.cursorPos = 0;
	_game.inputBuffer[0] = 0;
	_game.echoBuffer[0] = 0;
	_game.keypress = 0;

	_game.inputMode = (InputMode)in->readSint16BE();
	_game.lognum = in->readSint16BE();

	_game.playerControl = in->readSint16BE();
	if (in->readSint16BE())
		quitGame();
	_game.statusLine = in->readSint16BE();
	_game.clockEnabled = in->readSint16BE();
	_game.exitAllLogics = in->readSint16BE();
	_game.pictureShown = in->readSint16BE();
	_game.hasPrompt = in->readSint16BE();
	_game.gameFlags = in->readSint16BE();
	_game.inputEnabled = in->readSint16BE();

	for (i = 0; i < _HEIGHT; i++)
		_game.priTable[i] = in->readByte();

	if (_game.hasWindow)
		closeWindow();

	_game.msgBoxTicks = 0;
	_game.block.active = false;
	// game.window - fixed by close_window()
	// game.has_window - fixed by close_window()

	_game.gfxMode = in->readSint16BE();
	_game.cursorChar = in->readByte();
	_game.colorFg = in->readSint16BE();
	_game.colorBg = in->readSint16BE();

	// game.hires - rebuilt from image stack
	// game.sbuf - rebuilt from image stack

	// game.ego_words - fixed by clean_input
	// game.num_ego_words - fixed by clean_input

	_game.numObjects = in->readSint16BE();
	for (i = 0; i < (int16)_game.numObjects; i++)
		objectSetLocation(i, in->readSint16BE());

	// Those are not serialized
	for (i = 0; i < MAX_DIRS; i++) {
		_game.controllerOccured[i] = false;
	}

	for (i = 0; i < MAX_STRINGS; i++)
		in->read(_game.strings[i], MAX_STRINGLEN);

	for (i = 0; i < MAX_DIRS; i++) {
		if (in->readByte() & RES_LOADED)
			agiLoadResource(rLOGIC, i);
		else
			agiUnloadResource(rLOGIC, i);
		_game.logics[i].sIP = in->readSint16BE();
		_game.logics[i].cIP = in->readSint16BE();
	}

	for (i = 0; i < MAX_DIRS; i++) {
		if (in->readByte() & RES_LOADED)
			agiLoadResource(rPICTURE, i);
		else
			agiUnloadResource(rPICTURE, i);
	}

	for (i = 0; i < MAX_DIRS; i++) {
		if (in->readByte() & RES_LOADED)
			agiLoadResource(rVIEW, i);
		else
			agiUnloadResource(rVIEW, i);
	}

	for (i = 0; i < MAX_DIRS; i++) {
		if (in->readByte() & RES_LOADED)
			agiLoadResource(rSOUND, i);
		else
			agiUnloadResource(rSOUND, i);
	}

	// game.pictures - loaded above
	// game.logics - loaded above
	// game.views - loaded above
	// game.sounds - loaded above

	for (i = 0; i < vtEntries; i++) {
		VtEntry *v = &_game.viewTable[i];

		v->stepTime = in->readByte();
		v->stepTimeCount = in->readByte();
		v->entry = in->readByte();
		v->xPos = in->readSint16BE();
		v->yPos = in->readSint16BE();
		v->currentView = in->readByte();

		// v->view_data - fixed below

		v->currentLoop = in->readByte();
		v->numLoops = in->readByte();

		// v->loop_data - fixed below

		v->currentCel = in->readByte();
		v->numCels = in->readByte();

		// v->cel_data - fixed below
		// v->cel_data_2 - fixed below

		v->xPos2 = in->readSint16BE();
		v->yPos2 = in->readSint16BE();

		// v->s - fixed below

		v->xSize = in->readSint16BE();
		v->ySize = in->readSint16BE();
		v->stepSize = in->readByte();
		v->cycleTime = in->readByte();
		v->cycleTimeCount = in->readByte();
		v->direction = in->readByte();

		v->motion = (MotionType)in->readByte();
		v->cycle = (CycleType)in->readByte();
		v->priority = in->readByte();

		v->flags = in->readUint16BE();

		v->parm1 = in->readByte();
		v->parm2 = in->readByte();
		v->parm3 = in->readByte();
		v->parm4 = in->readByte();
	}
	for (i = vtEntries; i < MAX_VIEWTABLE; i++) {
		memset(&_game.viewTable[i], 0, sizeof(VtEntry));
	}

	// Fix some pointers in viewtable

	for (i = 0; i < MAX_VIEWTABLE; i++) {
		VtEntry *v = &_game.viewTable[i];

		if (_game.dirView[v->currentView].offset == _EMPTY)
			continue;

		if (!(_game.dirView[v->currentView].flags & RES_LOADED))
			agiLoadResource(rVIEW, v->currentView);

		setView(v, v->currentView);	// Fix v->view_data
		setLoop(v, v->currentLoop);	// Fix v->loop_data
		setCel(v, v->currentCel);	// Fix v->cel_data
		v->celData2 = v->celData;
		v->s = NULL;	// not sure if it is used...
	}

	_sprites->eraseBoth();

	// Clear input line
	_gfx->clearScreen(0);
	writeStatus();

	// Recreate background from saved image stack
	clearImageStack();
	while ((t = in->readByte()) != 0) {
		for (i = 0; i < 7; i++)
			parm[i] = in->readSint16BE();
		replayImageStackCall(t, parm[0], parm[1], parm[2],
				parm[3], parm[4], parm[5], parm[6]);
	}

	// Load AGIPAL Data
	if (saveVersion >= 3)
		_gfx->setAGIPal(in->readSint16BE());

	delete in;
	debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Closed %s", fileName.c_str());

	setflag(fRestoreJustRan, true);

	_game.hasPrompt = 0;	// force input line repaint if necessary
	cleanInput();

	_sprites->eraseBoth();
	_sprites->blitBoth();
	_sprites->commitBoth();
	_picture->showPic();
	_gfx->doUpdate();

	return errOK;
}