diff options
Diffstat (limited to 'engines/hopkins/saveload.cpp')
| -rw-r--r-- | engines/hopkins/saveload.cpp | 333 | 
1 files changed, 333 insertions, 0 deletions
| diff --git a/engines/hopkins/saveload.cpp b/engines/hopkins/saveload.cpp new file mode 100644 index 0000000000..af0b043641 --- /dev/null +++ b/engines/hopkins/saveload.cpp @@ -0,0 +1,333 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "hopkins/saveload.h" + +#include "hopkins/files.h" +#include "hopkins/globals.h" +#include "hopkins/hopkins.h" + + +#include "common/system.h" +#include "common/savefile.h" +#include "graphics/surface.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" + +namespace Hopkins { + +const char *SAVEGAME_STR = "HOPKINS"; +#define SAVEGAME_STR_SIZE 13 + +SaveLoadManager::SaveLoadManager(HopkinsEngine *vm) { +	_vm = vm; +} + +bool SaveLoadManager::save(const Common::String &file, const void *buf, size_t n) { +	Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(file); + +	if (f) { +		size_t bytesWritten = f->write(buf, n); +		f->finalize(); +		delete f; + +		return bytesWritten == n; +	} else +		return false; +} + +// Save File +bool SaveLoadManager::saveFile(const Common::String &file, const void *buf, size_t n) { +	return save(file, buf, n); +} + +void SaveLoadManager::initSaves() { +	Common::String dataFilename = "HISCORE.DAT"; +	byte data[100]; +	Common::fill(&data[0], &data[100], 0); + +	saveFile(dataFilename, data, 100); +} + +void SaveLoadManager::load(const Common::String &file, byte *buf) { +	Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(file); +	if (f == NULL) +		error("Error openinig file - %s", file.c_str()); + +	int32 filesize = f->size(); +	f->read(buf, filesize); +	delete f; +} + +bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header) { +	char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; +	header._thumbnail = NULL; + +	// Validate the header Id +	in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); +	if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE)) +		return false; + +	header._version = in->readByte(); +	if (header._version > HOPKINS_SAVEGAME_VERSION) +		return false; + +	// Read in the string +	header._saveName.clear(); +	char ch; +	while ((ch = (char)in->readByte()) != '\0') header._saveName += ch; + +	// Get the thumbnail +	header._thumbnail = Graphics::loadThumbnail(*in); +	if (!header._thumbnail) +		return false; + +	// Read in save date/time +	header._year = in->readSint16LE(); +	header._month = in->readSint16LE(); +	header._day = in->readSint16LE(); +	header._hour = in->readSint16LE(); +	header._minute = in->readSint16LE(); +	header._totalFrames = in->readUint32LE(); + +	return true; +} + +void SaveLoadManager::writeSavegameHeader(Common::OutSaveFile *out, hopkinsSavegameHeader &header) { +	// Write out a savegame header +	out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1); + +	out->writeByte(HOPKINS_SAVEGAME_VERSION); + +	// Write savegame name +	out->write(header._saveName.c_str(), header._saveName.size() + 1); + +	// Create a thumbnail and save it +	Graphics::Surface *thumb = new Graphics::Surface(); +	createThumbnail(thumb); +	Graphics::saveThumbnail(*out, *thumb); +	thumb->free(); +	delete thumb; + +	// Write out the save date/time +	TimeDate td; +	g_system->getTimeAndDate(td); +	out->writeSint16LE(td.tm_year + 1900); +	out->writeSint16LE(td.tm_mon + 1); +	out->writeSint16LE(td.tm_mday); +	out->writeSint16LE(td.tm_hour); +	out->writeSint16LE(td.tm_min); +	out->writeUint32LE(_vm->_events->_gameCounter); +} + +Common::Error SaveLoadManager::saveGame(int slot, const Common::String &saveName) { +	/* Pack any necessary data into the savegame data structure */ +	// Set the selected slot number +	_vm->_globals->_saveData->_data[svLastSavegameSlot] = slot; + +	// Set up the inventory +	for (int i = 0; i < 35; ++i) +		_vm->_globals->_saveData->_inventory[i] = _vm->_globals->_inventory[i]; + +	_vm->_globals->_saveData->_mapCarPosX = _vm->_objectsMan->_mapCarPosX; +	_vm->_globals->_saveData->_mapCarPosY = _vm->_objectsMan->_mapCarPosY; + +	/* Create the savegame */ +	Common::OutSaveFile *savefile = g_system->getSavefileManager()->openForSaving(_vm->generateSaveName(slot)); +	if (!savefile) +		return Common::kCreatingFileFailed; + +	// Set up the serializer +	Common::Serializer serializer(NULL, savefile); + +	// Write out the savegame header +	hopkinsSavegameHeader header; +	header._saveName = saveName; +	header._version = HOPKINS_SAVEGAME_VERSION; +	writeSavegameHeader(savefile, header); + +	// Write out the savegame data +	syncSavegameData(serializer, header._version); + +	// Save file complete +	savefile->finalize(); +	delete savefile; + +	return Common::kNoError; +} + +Common::Error SaveLoadManager::loadGame(int slot) { +	// Try and open the save file for reading +	Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading( +		_vm->generateSaveName(slot)); +	if (!savefile) +		return Common::kReadingFailed; + +	// Set up the serializer +	Common::Serializer serializer(savefile, NULL); + +	// Read in the savegame header +	hopkinsSavegameHeader header; +	readSavegameHeader(savefile, header); +	if (header._thumbnail) +		header._thumbnail->free(); +	delete header._thumbnail; + +	// Read in the savegame data +	syncSavegameData(serializer, header._version); + +	// Loading save file complete +	delete savefile; + +	// Unpack the inventory +	for (int i = 0; i < 35; ++i) +		_vm->_globals->_inventory[i] = _vm->_globals->_saveData->_inventory[i]; + +	// Set variables from loaded data as necessary +	_vm->_globals->_saveData->_data[svLastSavegameSlot] = slot; +	_vm->_globals->_exitId = _vm->_globals->_saveData->_data[svLastScreenId]; +	_vm->_globals->_saveData->_data[svLastPrevScreenId] = 0; +	_vm->_globals->_screenId = 0; +	_vm->_objectsMan->_mapCarPosX = _vm->_globals->_saveData->_mapCarPosX; +	_vm->_objectsMan->_mapCarPosY = _vm->_globals->_saveData->_mapCarPosY; + +	return Common::kNoError; +} + +bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header) { +	// Try and open the save file for reading +	Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading( +		g_vm->generateSaveName(slot)); +	if (!saveFile) +		return false; + +	bool result = readSavegameHeader(saveFile, header); +	delete saveFile; +	return result; +} + +#define REDUCE_AMOUNT 80 + +void SaveLoadManager::createThumbnail(Graphics::Surface *s) { +	int w = _vm->_graphicsMan->zoomOut(SCREEN_WIDTH, REDUCE_AMOUNT); +	int h = _vm->_graphicsMan->zoomOut(SCREEN_HEIGHT - 40, REDUCE_AMOUNT); + +	Graphics::Surface thumb8; +	thumb8.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + +	_vm->_graphicsMan->reduceScreenPart(_vm->_graphicsMan->_frontBuffer, (byte *)thumb8.pixels, +		_vm->_events->_startPos.x, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 40, 80); + +	// Convert the 8-bit pixel to 16 bit surface +	s->create(w, h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); + +	const byte *srcP = (const byte *)thumb8.pixels; +	uint16 *destP = (uint16 *)s->pixels; + +	for (int yp = 0; yp < h; ++yp) { +		// Copy over the line, using the source pixels as lookups into the pixels palette +		const byte *lineSrcP = srcP; +		uint16 *lineDestP = destP; + +		for (int xp = 0; xp < w; ++xp) +			*lineDestP++ = *(uint16 *)&_vm->_graphicsMan->_palettePixels[*lineSrcP++ * 2]; + +		// Move to the start of the next line +		srcP += w; +		destP += w; +	} +	thumb8.free(); +} + +void SaveLoadManager::syncSavegameData(Common::Serializer &s, int version) { +	s.syncBytes(&_vm->_globals->_saveData->_data[0], 2050); +	syncCharacterLocation(s, _vm->_globals->_saveData->_cloneHopkins); +	syncCharacterLocation(s, _vm->_globals->_saveData->_realHopkins); +	syncCharacterLocation(s, _vm->_globals->_saveData->_samantha); + +	for (int i = 0; i < 35; ++i) +		s.syncAsSint16LE(_vm->_globals->_saveData->_inventory[i]); + +	if (version > 1) { +		s.syncAsSint16LE(_vm->_globals->_saveData->_mapCarPosX); +		s.syncAsSint16LE(_vm->_globals->_saveData->_mapCarPosY); +	} else { +		_vm->_globals->_saveData->_mapCarPosX = _vm->_globals->_saveData->_mapCarPosY = 0; +	} + +} + +void SaveLoadManager::syncCharacterLocation(Common::Serializer &s, CharacterLocation &item) { +	s.syncAsSint16LE(item._pos.x); +	s.syncAsSint16LE(item._pos.y); +	s.syncAsSint16LE(item._startSpriteIndex); +	s.syncAsSint16LE(item._location); +	s.syncAsSint16LE(item._zoomFactor); +} + +void SaveLoadManager::convertThumb16To8(Graphics::Surface *thumb16, Graphics::Surface *thumb8) { +	thumb8->create(thumb16->w, thumb16->h, Graphics::PixelFormat::createFormatCLUT8()); +	Graphics::PixelFormat pixelFormat16(2, 5, 6, 5, 0, 11, 5, 0, 0); + +	byte paletteR[PALETTE_SIZE]; +	byte paletteG[PALETTE_SIZE]; +	byte paletteB[PALETTE_SIZE]; +	for (int palIndex = 0; palIndex < PALETTE_SIZE; ++palIndex) { +		uint16 p = READ_UINT16(&_vm->_graphicsMan->_palettePixels[palIndex * 2]); +		pixelFormat16.colorToRGB(p, paletteR[palIndex], paletteG[palIndex], paletteB[palIndex]); +	} + +	const uint16 *srcP = (const uint16 *)thumb16->pixels; +	byte *destP = (byte *)thumb8->pixels; + +	for (int yp = 0; yp < thumb16->h; ++yp) { +		const uint16 *lineSrcP = srcP; +		byte *lineDestP = destP; + +		for (int xp = 0; xp < thumb16->w; ++xp) { +			byte r, g, b; +			pixelFormat16.colorToRGB(*lineSrcP++, r, g, b); + +			// Scan the palette for the closest match +			int difference = 99999, foundIndex = 0; +			for (int palIndex = 0; palIndex < PALETTE_SIZE; ++palIndex) { +				byte rCurrent = paletteR[palIndex]; +				byte gCurrent = paletteG[palIndex]; +				byte bCurrent = paletteB[palIndex]; + +				int diff = ABS((int)r - (int)rCurrent) + ABS((int)g - (int)gCurrent) + ABS((int)b - (int)bCurrent); +				if (diff < difference) { +					difference = diff; +					foundIndex = palIndex; +				} +			} + +			*lineDestP++ = foundIndex; +		} + +		// Move to the start of the next line +		srcP += thumb16->w; +		destP += thumb16->w; +	} +} + +} // End of namespace Hopkins | 
