Пример #1
0
bool T7GFont::load(Common::SeekableReadStream &stream) {
	// Read the mapping of characters to glyphs
	if (stream.read(_mapChar2Glyph, 128) < 128) {
		error("Groovie::T7GFont: Couldn't read the character to glyph map");
		return false;
	}

	// Calculate the number of glyphs
	byte numGlyphs = 0;
	for (int i = 0; i < 128; i++)
		if (_mapChar2Glyph[i] >= numGlyphs)
			numGlyphs = _mapChar2Glyph[i] + 1;

	// Read the glyph offsets
	uint16 *glyphOffsets = new uint16[numGlyphs];
	for (int i = 0; i < numGlyphs; i++)
		glyphOffsets[i] = stream.readUint16LE();

	if (stream.eos()) {
		error("Groovie::T7GFont: Couldn't read the glyph offsets");
		delete[] glyphOffsets;
		return false;
	}

	// Allocate the glyph data
	delete[] _glyphs;
	_glyphs = new Glyph[numGlyphs];

	// Ensure we're ready to read the first glyph. (Most versions don't
	// need it, but the russian one does. This fixes bug #3095031.)
	stream.seek(glyphOffsets[0]);

	// Read the glyphs
	_maxHeight = _maxWidth = 0;
	for (int i = 0; (i < numGlyphs) && !stream.eos(); i++) {
		// Verify we're at the expected stream position
		if (stream.pos() != glyphOffsets[i]) {
			uint16 offset = glyphOffsets[i];
			delete[] glyphOffsets;
			error("Groovie::T7GFont: Glyph %d starts at %d but the current "
				"offset is %d", i, offset, stream.pos());
			return false;
		}

		// Read the glyph information
		Glyph *g = &_glyphs[i];
		g->width = stream.readByte();
		g->julia = stream.readByte();

		// Read the pixels data into a dynamic array (we don't know its length)
		Common::Array<byte> data;
		data.reserve(300);
		byte b = stream.readByte();
		while (!stream.eos() && (b != 0xFF)) {
			data.push_back(b);
			b = stream.readByte();
		}

		// Verify the pixel data size
		assert (data.size() % g->width == 0);
		g->height = data.size() / g->width;

		// Copy the pixel data into the definitive static array
		g->pixels = new byte[data.size()];
		memcpy(g->pixels, data.begin(), data.size());

		// Update the max values
		if (g->width > _maxWidth)
			_maxWidth = g->width;
		if (g->height > _maxHeight)
			_maxHeight = g->height;
	}

	delete[] glyphOffsets;
	return true;
}
Пример #2
0
bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) {
	char musicName[13];
	char bgNames[8][13];

	// First check the temporary Operation Stealth savegame format header.
	ChunkHeader hdr;
	loadChunkHeader(in, hdr);
	if (hdr.id != TEMP_OS_FORMAT_ID) {
		warning("loadTempSaveOS: File has incorrect identifier. Not loading savegame");
		return false;
	} else if (hdr.version > CURRENT_OS_SAVE_VER) {
		warning("loadTempSaveOS: Detected newer format version. Not loading savegame");
		return false;
	} else if ((int)hdr.version < (int)CURRENT_OS_SAVE_VER) {
		warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break");
	} else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER
		debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match).");
	}

	// There shouldn't be any data in the header's chunk currently so it's an error if there is.
	if (hdr.size > 0) {
		warning("loadTempSaveOS: Format header's chunk seems to contain data so format is incorrect. Not loading savegame");
		return false;
	}

	// Ok, so we've got a correct header for a temporary Operation Stealth savegame.
	// Let's start loading the plain savegame data then.
	currentDisk = in.readUint16BE();
	in.read(currentPartName, 13);
	in.read(currentPrcName, 13);
	in.read(currentRelName, 13);
	in.read(currentMsgName, 13);

	// Load the 8 background names.
	for (uint i = 0; i < 8; i++) {
		in.read(bgNames[i], 13);
	}

	in.read(currentCtName, 13);

	// Moved the loading of current procedure, relation,
	// backgrounds and Ct here because if they were at the
	// end of this function then the global scripts loading
	// made an array out of bounds access. In the original
	// game's disassembly these aren't here but at the end.
	// The difference is probably in how we handle loading
	// the global scripts and some other things (i.e. the
	// loading routines aren't exactly the same and subtle
	// semantic differences result in having to do things
	// in a different order).
	{
		// Not sure if this is needed with Operation Stealth...
		checkDataDisk(currentDisk);

		if (strlen(currentPrcName)) {
			loadPrc(currentPrcName);
		}

		if (strlen(currentRelName)) {
			loadRel(currentRelName);
		}

		// Load first background (Uses loadBg)
		if (strlen(bgNames[0])) {
			loadBg(bgNames[0]);
		}

		// Add backgrounds 1-7 (Uses addBackground)
		for (int i = 1; i < 8; i++) {
			if (strlen(bgNames[i])) {
				addBackground(bgNames[i], i);
			}
		}

		if (strlen(currentCtName)) {
			loadCtOS(currentCtName);
		}
	}

	loadObjectTable(in);
	renderer->restorePalette(in, hdr.version);
	g_cine->_globalVars.load(in, NUM_MAX_VAR);
	loadZoneData(in);
	loadCommandVariables(in);
	char tempCommandBuffer[kMaxCommandBufferSize];
	in.read(tempCommandBuffer, kMaxCommandBufferSize);
	g_cine->_commandBuffer = tempCommandBuffer;
	renderer->setCommand(g_cine->_commandBuffer);
	loadZoneQuery(in);

	// TODO: Use the loaded string (Current music name (String, 13 bytes)).
	in.read(musicName, 13);

	// TODO: Use the loaded value (Is music loaded? (Uint16BE, Boolean)).
	in.readUint16BE();

	// TODO: Use the loaded value (Is music playing? (Uint16BE, Boolean)).
	in.readUint16BE();

	renderer->_cmdY      = in.readUint16BE();
	in.readUint16BE(); // Some unknown variable that seems to always be zero
	allowPlayerInput     = in.readUint16BE();
	playerCommand        = in.readUint16BE();
	commandVar1          = in.readUint16BE();
	isDrawCommandEnabled = in.readUint16BE();
	var5                 = in.readUint16BE();
	var4                 = in.readUint16BE();
	var3                 = in.readUint16BE();
	var2                 = in.readUint16BE();
	commandVar2          = in.readUint16BE();
	renderer->_messageBg = in.readUint16BE();

	// TODO: Use the loaded value (adBgVar1 (Uint16BE)).
	in.readUint16BE();

	currentAdditionalBgIdx = in.readSint16BE();
	currentAdditionalBgIdx2 = in.readSint16BE();

	// TODO: Check whether the scroll value really gets used correctly after this.
	// Note that the backgrounds are loaded only later than this value is set.
	renderer->setScroll(in.readUint16BE());

	// TODO: Use the loaded value (adBgVar0 (Uint16BE). Maybe this means bgVar0?).
	in.readUint16BE();

	disableSystemMenu = in.readUint16BE();

	// TODO: adBgVar1 = 1 here

	// Load the animDataTable entries
	in.readUint16BE(); // Entry count (255 in the PC version of Operation Stealth).
	in.readUint16BE(); // Entry size (36 in the PC version of Operation Stealth).
	loadResourcesFromSave(in, ANIMSIZE_30_PTRS_INTACT);

	loadScreenParams(in);
	loadGlobalScripts(in);
	loadObjectScripts(in);
	loadSeqList(in);
	loadOverlayList(in);
	loadBgIncrustFromSave(in);

	// Left this here instead of moving it earlier in this function with
	// the other current value loadings (e.g. loading of current procedure,
	// current backgrounds etc). Mostly emulating the way we've handled
	// Future Wars savegames and hoping that things work out.
	if (strlen(currentMsgName)) {
		loadMsg(currentMsgName);
	}

	// TODO: Add current music loading and playing here
	// TODO: Palette handling?

	if (in.pos() == in.size()) {
		debug(3, "loadTempSaveOS: Loaded the whole savefile.");
	} else {
		warning("loadTempSaveOS: Loaded the savefile but didn't exhaust it completely. Something was left over");
	}

	return !(in.eos() || in.err());
}
Пример #3
0
void Portrait::init() {
	// .BIN files are loaded from actors directory and from .\ directory
	// header:
	// 3 bytes "WIN"
	// 2 bytes main width (should be the same as first bitmap header width)
	// 2 bytes main height (should be the same as first bitmap header height)
	// 2 bytes animation count
	// 2 bytes unknown
	// 2 bytes unknown
	// 4 bytes paletteSize (base 1)
	//  -> 17 bytes
	// paletteSize bytes paletteData
	// 14 bytes bitmap header
	//  -> 4 bytes unknown
	//  -> 2 bytes height
	//  -> 2 bytes width
	//  -> 6 bytes unknown
	// height * width bitmap data
	// another animation count times bitmap header and data
	int32 fileSize = 0;
	Common::SeekableReadStream *file =
		SearchMan.createReadStreamForMember("actors/" + _resourceName + ".bin");
	if (!file) {
		file = SearchMan.createReadStreamForMember(_resourceName + ".bin");
		if (!file)
			error("portrait %s.bin not found", _resourceName.c_str());
	}
	fileSize = file->size();
	_fileData = new byte[fileSize];
	file->read(_fileData, fileSize);
	delete file;

	if (strncmp((char *)_fileData, "WIN", 3)) {
		error("portrait %s doesn't have valid header", _resourceName.c_str());
	}
	_width = READ_LE_UINT16(_fileData + 3);
	_height = READ_LE_UINT16(_fileData + 5);
	_bitmapCount = READ_LE_UINT16(_fileData + 7);
	_bitmaps = new PortraitBitmap[_bitmapCount];

	uint16 portraitPaletteSize = READ_LE_UINT16(_fileData + 13);
	byte *data = _fileData + 17;
	// Read palette
	memset(&_portraitPalette, 0, sizeof(Palette));
	uint16 palSize = 0, palNr = 0;
	while (palSize < portraitPaletteSize) {
		_portraitPalette.colors[palNr].b = *data++;
		_portraitPalette.colors[palNr].g = *data++;
		_portraitPalette.colors[palNr].r = *data++;
		_portraitPalette.colors[palNr].used = 1;
		_portraitPalette.intensity[palNr] = 100;
		palNr++; palSize += 3;
	}

	// Read all bitmaps
	PortraitBitmap *curBitmap = _bitmaps;
	uint16 bitmapNr;
	uint16 bytesPerLine;

	for (bitmapNr = 0; bitmapNr < _bitmapCount; bitmapNr++) {
		curBitmap->width = READ_LE_UINT16(data + 2);
		curBitmap->height = READ_LE_UINT16(data + 4);
		bytesPerLine = READ_LE_UINT16(data + 6);
		if (bytesPerLine < curBitmap->width)
			error("kPortrait: bytesPerLine larger than actual width");
		curBitmap->extraBytesPerLine = bytesPerLine - curBitmap->width;
		curBitmap->rawBitmap = data + 14;
		data += 14 + (curBitmap->height * bytesPerLine);
		curBitmap++;
	}

	// Offset table follows
	curBitmap = _bitmaps;
	int32 offsetTableSize = READ_LE_UINT32(data);
	assert((bitmapNr + 1) * 14 <= offsetTableSize);
	data += 4;
	byte *dataOffsetTable = data + 14; // we skip first bitmap offsets
	for (bitmapNr = 0; bitmapNr < _bitmapCount; bitmapNr++) {
		curBitmap->displaceX = READ_LE_UINT16(dataOffsetTable);
		curBitmap->displaceY = READ_LE_UINT16(dataOffsetTable + 2);
		dataOffsetTable += 14;
		curBitmap++;
	}
	data += offsetTableSize;

	// raw lip-sync data follows
}
Пример #4
0
bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
	destroy();

	if (stream.readByte() != 'B')
		return false;

	if (stream.readByte() != 'M')
		return false;

	/* uint32 fileSize = */ stream.readUint32LE();
	/* uint16 res1 = */ stream.readUint16LE();
	/* uint16 res2 = */ stream.readUint16LE();
	uint32 imageOffset = stream.readUint32LE();

	uint32 infoSize = stream.readUint32LE();
	if (infoSize != 40) {
		warning("Only Windows v3 bitmaps are supported");
		return false;
	}

	uint32 width = stream.readUint32LE();
	int32 height = stream.readSint32LE();

	if (width == 0 || height == 0)
		return false;

	if (height < 0) {
		warning("Right-side up bitmaps not supported");
		return false;
	}

	/* uint16 planes = */ stream.readUint16LE();
	uint16 bitsPerPixel = stream.readUint16LE();

	if (bitsPerPixel != 8 && bitsPerPixel != 24 && bitsPerPixel != 32) {
		warning("%dbpp bitmaps not supported", bitsPerPixel);
		return false;
	}

	uint32 compression = stream.readUint32LE();

	if (compression != 0) {
		warning("Compressed bitmaps not supported");
		return false;
	}

	/* uint32 imageSize = */ stream.readUint32LE();
	/* uint32 pixelsPerMeterX = */ stream.readUint32LE();
	/* uint32 pixelsPerMeterY = */ stream.readUint32LE();
	_paletteColorCount = stream.readUint32LE();
	/* uint32 colorsImportant = */ stream.readUint32LE();

	if (bitsPerPixel == 8) {
		if (_paletteColorCount == 0)
			_paletteColorCount = 256;

		// Read the palette
		_palette = new byte[_paletteColorCount * 3];
		for (uint16 i = 0; i < _paletteColorCount; i++) {
			_palette[i * 3 + 2] = stream.readByte();
			_palette[i * 3 + 1] = stream.readByte();
			_palette[i * 3 + 0] = stream.readByte();
			stream.readByte();
		}
	}

	// Start us at the beginning of the image
	stream.seek(imageOffset);

	Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();

	// BGRA for 24bpp and 32 bpp
	if (bitsPerPixel == 24 || bitsPerPixel == 32)
		format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0);

	_surface = new Graphics::Surface();
	_surface->create(width, height, format);

	int srcPitch = width * (bitsPerPixel >> 3);
	const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0;

	if (bitsPerPixel == 8) {
		byte *dst = (byte *)_surface->pixels;

		for (int32 i = 0; i < height; i++) {
			stream.read(dst + (height - i - 1) * width, width);
			stream.skip(extraDataLength);
		}
	} else if (bitsPerPixel == 24) {
		byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch;

		for (int32 i = 0; i < height; i++) {
			for (uint32 j = 0; j < width; j++) {
				byte b = stream.readByte();
				byte g = stream.readByte();
				byte r = stream.readByte();
				uint32 color = format.RGBToColor(r, g, b);

				*((uint32 *)dst) = color;
				dst += format.bytesPerPixel;
			}

			stream.skip(extraDataLength);
			dst -= _surface->pitch * 2;
		}
	} else { // 32 bpp
		byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch;

		for (int32 i = 0; i < height; i++) {
			for (uint32 j = 0; j < width; j++) {
				byte b = stream.readByte();
				byte g = stream.readByte();
				byte r = stream.readByte();
				// Ignore the last byte, as in v3 it is unused
				// and should thus NOT be used as alpha.
				// ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx
				stream.readByte();
				uint32 color = format.RGBToColor(r, g, b);

				*((uint32 *)dst) = color;
				dst += format.bytesPerPixel;
			}

			stream.skip(extraDataLength);
			dst -= _surface->pitch * 2;
		}
	}

	return true;
}
Пример #5
0
void Init::initGame() {
	initVideo();
	updateConfig();

	if (!_vm->isDemo()) {
		if (_vm->_dataIO->hasFile(_vm->_startStk))
			_vm->_dataIO->openArchive(_vm->_startStk, true);
	}

	_vm->_util->initInput();

	_vm->_video->initPrimary(_vm->_global->_videoMode);
	_vm->_global->_mouseXShift = 1;
	_vm->_global->_mouseYShift = 1;

	_palDesc = new Video::PalDesc;

	_vm->validateVideoMode(_vm->_global->_videoMode);

	_vm->_global->_setAllPalette = true;
	_palDesc->vgaPal = _vm->_draw->_vgaPalette;
	_palDesc->unused1 = _vm->_draw->_unusedPalette1;
	_palDesc->unused2 = _vm->_draw->_unusedPalette2;
	_vm->_video->setFullPalette(_palDesc);

	for (int i = 0; i < 10; i++)
		_vm->_draw->_fascinWin[i].id = -1;

	_vm->_draw->_winCount = 0;

	for (int i = 0; i < 8; i++)
		_vm->_draw->_fonts[i] = 0;

	if (_vm->isDemo()) {
		doDemo();
		delete _palDesc;
		_vm->_video->initPrimary(-1);
		cleanup();
		return;
	}

	if (_vm->_preGob) {
		_vm->_preGob->run();
		delete _palDesc;
		_vm->_video->initPrimary(-1);
		cleanup();
		return;
	}

	Common::SeekableReadStream *infFile = _vm->_dataIO->getFile("intro.inf");
	if (!infFile) {

		for (int i = 0; i < 4; i++)
			_vm->_draw->loadFont(i, _fontNames[i]);

	} else {

		for (int i = 0; i < 8; i++) {
			if (infFile->eos())
				break;

			Common::String font = infFile->readLine();
			if (infFile->eos() && font.empty())
				break;

			font += ".let";

			_vm->_draw->loadFont(i, font.c_str());
		}

		delete infFile;
	}

	if (_vm->_dataIO->hasFile(_vm->_startTot)) {
		_vm->_inter->allocateVars(Script::getVariablesCount(_vm->_startTot.c_str(), _vm));

		_vm->_game->_curTotFile = _vm->_startTot;

		_vm->_sound->cdTest(1, "GOB");
		_vm->_sound->cdLoadLIC("gob.lic");

		// Search for a Coktel logo animation or image to display
		if (_vm->_dataIO->hasFile("coktel.imd")) {
			_vm->_draw->initScreen();
			_vm->_draw->_cursorIndex = -1;

			_vm->_util->longDelay(200); // Letting everything settle

			VideoPlayer::Properties props;
			int slot;
			if ((slot = _vm->_vidPlayer->openVideo(true, "coktel.imd", props)) >= 0) {
				_vm->_vidPlayer->play(slot, props);
				_vm->_vidPlayer->closeVideo(slot);
			}

			_vm->_draw->closeScreen();
		} else if (_vm->_dataIO->hasFile("coktel.clt")) {
			Common::SeekableReadStream *stream = _vm->_dataIO->getFile("coktel.clt");
			if (stream) {
				_vm->_draw->initScreen();
				_vm->_util->clearPalette();

				stream->read((byte *)_vm->_draw->_vgaPalette, 768);
				delete stream;

				int32 size;
				byte *sprite = _vm->_dataIO->getFile("coktel.ims", size);
				if (sprite) {
					_vm->_video->drawPackedSprite(sprite, 320, 200, 0, 0, 0,
							*_vm->_draw->_frontSurface);
					_vm->_palAnim->fade(_palDesc, 0, 0);
					_vm->_util->delay(500);

					delete[] sprite;
				}

				_vm->_draw->closeScreen();
			}
		}

		_vm->_game->start();

		_vm->_sound->cdStop();
		_vm->_sound->cdUnloadLIC();

	}

	delete _palDesc;
	_vm->_dataIO->closeArchive(true);
	_vm->_video->initPrimary(-1);
	cleanup();
}
Пример #6
0
void ConversationData::load(const Common::String &filename) {
	Common::File inFile;
	char buffer[16];

	inFile.open(filename);
	MadsPack convFileUnpacked(&inFile);

	// **** Section 0: Header *************************************************
	Common::SeekableReadStream *convFile = convFileUnpacked.getItemStream(0);

	_nodeCount = convFile->readUint16LE();
	_dialogCount = convFile->readUint16LE();
	_messageCount = convFile->readUint16LE();
	_textLineCount = convFile->readUint16LE();
	_unk2 = convFile->readUint16LE();
	_maxImports = convFile->readUint16LE();
	_speakerCount = convFile->readUint16LE();

	for (uint idx = 0; idx < MAX_SPEAKERS; ++idx) {
		convFile->read(buffer, 16);
		_portraits[idx] = buffer;
	}

	for (uint idx = 0; idx < MAX_SPEAKERS; ++idx) {
		_speakerFrame[idx] = convFile->readUint16LE();
	}

	convFile->read(buffer, 14);
	_speechFile = Common::String(buffer);

	// Total text length in section 5
	_textSize = convFile->readUint32LE();
	_commandsSize = convFile->readUint32LE();

	// The rest of the section 0 is padding to allow room for a set of pointers
	// to the contents of the remaining sections loaded into memory as a
	// continuous data block containing both the header and the sections
	delete convFile;

	// **** Section 1: Nodes **************************************************
	convFile = convFileUnpacked.getItemStream(1);

	_nodes.clear();
	for (uint i = 0; i < _nodeCount; i++) {
		ConvNode node;
		node._index = convFile->readUint16LE();
		node._dialogCount = convFile->readUint16LE();
		node._unk1 = convFile->readSint16LE();	// TODO
		node._active = convFile->readSint16LE() != 0;
		node._unk3 = convFile->readSint16LE();	// TODO
		_nodes.push_back(node);
	}

	delete convFile;

	// **** Section 2: Dialogs ************************************************
	convFile = convFileUnpacked.getItemStream(2);
	assert(convFile->size() == _dialogCount * 8);

	_dialogs.resize(_dialogCount);
	for (uint idx = 0; idx < _dialogCount; ++idx) {
		_dialogs[idx]._textLineIndex = convFile->readSint16LE();
		_dialogs[idx]._speechIndex = convFile->readSint16LE();
		_dialogs[idx]._scriptOffset = convFile->readUint16LE();
		_dialogs[idx]._scriptSize = convFile->readUint16LE();
	}

	delete convFile;

	// **** Section 3: Messages ***********************************************
	convFile = convFileUnpacked.getItemStream(3);
	assert(convFile->size() == _messageCount * 4);

	_messages.resize(_messageCount);
	for (uint idx = 0; idx < _messageCount; ++idx) {
		_messages[idx]._stringIndex = convFile->readUint16LE();
		_messages[idx]._count = convFile->readUint16LE();
	}

	delete convFile;

	// **** Section 4: Text line offsets **************************************
	convFile = convFileUnpacked.getItemStream(4);
	assert(convFile->size() == _textLineCount * 2);

	uint16 *textLineOffsets = new uint16[_textLineCount];	// deleted below in section 5
	for (uint16 i = 0; i < _textLineCount; i++)
		textLineOffsets[i] = convFile->readUint16LE();

	delete convFile;

	// **** Section 5: Text lines *********************************************
	convFile = convFileUnpacked.getItemStream(5);
	assert(convFile->size() == _textSize);

	Common::String textLine;
	_textLines.resize(_textLineCount);
	char textLineBuffer[256];
	uint16 nextOffset;
	for (uint16 i = 0; i < _textLineCount; i++) {
		nextOffset = (i != _textLineCount - 1) ? textLineOffsets[i + 1] : convFile->size();
		convFile->read(textLineBuffer, nextOffset - textLineOffsets[i]);
		_textLines[i] = Common::String(textLineBuffer);
	}

	delete[] textLineOffsets;
	delete convFile;

	// **** Section 6: Scripts ************************************************
	convFile = convFileUnpacked.getItemStream(6);
	assert(convFile->size() == _commandsSize);

	for (uint idx = 0; idx < _dialogs.size(); ++idx) {
		// Move to the correct position for the dialog's script, and create
		// a memory stream to represent the data for just that script
		convFile->seek(_dialogs[idx]._scriptOffset);
		Common::SeekableReadStream *scriptStream = convFile->readStream(_dialogs[idx]._scriptSize);

		// Pass it to the dialog's script set class to parse into commands
		_dialogs[idx]._script.load(*scriptStream, _dialogs[idx]._scriptOffset);
		delete scriptStream;
	}

	delete convFile;
	inFile.close();
}
Пример #7
0
void KyraEngine_MR::initSceneScript(int unk1) {
	const SceneDesc &scene = _sceneList[_mainCharacter.sceneId];

	char filename[16];
	strcpy(filename, scene.filename1);
	strcat(filename, ".DAT");

	_res->exists(filename, true);
	Common::SeekableReadStream *stream = _res->createReadStream(filename);
	assert(stream);
	stream->seek(2, SEEK_CUR);

	byte scaleTable[15];
	stream->read(scaleTable, 15);
	stream->read(_sceneDatPalette, 45);
	stream->read(_sceneDatLayerTable, 15);
	int16 shapesCount = stream->readSint16LE();

	for (int i = 0; i < 15; ++i)
		_scaleTable[i] = (uint16(scaleTable[i]) << 8) / 100;

	if (shapesCount > 0) {
		strcpy(filename, scene.filename1);
		strcat(filename, "9.CPS");
		_screen->loadBitmap(filename, 3, 3, 0);
		int pageBackUp = _screen->_curPage;
		_screen->_curPage = 2;
		for (int i = 0; i < shapesCount; ++i) {
			int16 x = stream->readSint16LE();
			int16 y = stream->readSint16LE();
			int16 w = stream->readSint16LE();
			int16 h = stream->readSint16LE();
			_sceneShapeDescs[i].drawX = stream->readSint16LE();
			_sceneShapeDescs[i].drawY = stream->readSint16LE();
			_sceneShapes[i] = _screen->encodeShape(x, y, w, h, 0);
			assert(_sceneShapes[i]);
		}
		_screen->_curPage = pageBackUp;
	}
	delete stream;
	stream = 0;

	strcpy(filename, scene.filename1);
	strcat(filename, ".CPS");
	_screen->loadBitmap(filename, 3, 3, 0);

	Common::set_to(_specialSceneScriptState, ARRAYEND(_specialSceneScriptState), false);
	_sceneEnterX1 = 160;
	_sceneEnterY1 = 0;
	_sceneEnterX2 = 296;
	_sceneEnterY2 = 93;
	_sceneEnterX3 = 160;
	_sceneEnterY3 = 171;
	_sceneEnterX4 = 24;
	_sceneEnterY4 = 93;
	_sceneMinX = 0;
	_sceneMaxX = 319;

	_emc->init(&_sceneScriptState, &_sceneScriptData);
	strcpy(filename, scene.filename2);
	strcat(filename, ".EMC");
	_res->exists(filename, true);
	_emc->load(filename, &_sceneScriptData, &_opcodes);

	strcpy(filename, scene.filename2);
	strcat(filename, ".");
	loadLanguageFile(filename, _sceneStrings);

	runSceneScript8();
	_emc->start(&_sceneScriptState, 0);
	_sceneScriptState.regs[0] = _mainCharacter.sceneId;
	_sceneScriptState.regs[5] = unk1;
	while (_emc->isValid(&_sceneScriptState))
		_emc->run(&_sceneScriptState);

	_screen->copyRegionToBuffer(3, 0, 0, 320, 200, _gamePlayBuffer);

	for (int i = 0; i < 10; ++i) {
		_emc->init(&_sceneSpecialScripts[i], &_sceneScriptData);
		_emc->start(&_sceneSpecialScripts[i], i+9);
		_sceneSpecialScriptsTimer[i] = 0;
	}

	_sceneEnterX1 &= ~3;
	_sceneEnterY1 &= ~1;
	_sceneEnterX2 &= ~3;
	_sceneEnterY2 &= ~1;
	_sceneEnterX3 &= ~3;
	_sceneEnterY3 &= ~1;
	_sceneEnterX4 &= ~3;
	_sceneEnterY4 &= ~1;
}
Пример #8
0
int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize) {
	warning("TODO: fadeRead");
	stream.read(buf, totalSize);
	return totalSize;
}
Пример #9
0
void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface) {
	char buffer1[80];
	const char *sceneName;

	// TODO: Initialise spriteSet / xp_list

	if (sceneNumber > 0) {
		sceneName = MADSResourceManager::getResourceName(RESPREFIX_RM, sceneNumber, ".DAT");
	} else {
		strcpy(buffer1, "*");
		strcat(buffer1, resName);
		sceneName = buffer1; // TODO: Check whether this needs to be converted to 'HAG form'
	}

	Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneName);
	MadsPack sceneInfo(rawStream);

	// Chunk 0:
	// Basic scene info
	Common::SeekableReadStream *stream = sceneInfo.getItemStream(0);

	if (_vm->getGameType() == GType_RexNebular) {
		int resSceneId = stream->readUint16LE();
		assert(resSceneId == sceneNumber);
	} else {
		char roomFilename[10];
		char roomFilenameExpected[10];
		sprintf(roomFilenameExpected, "*RM%d", sceneNumber);

		stream->read(roomFilename, 6);
		roomFilename[6] = 0;
		assert(!strcmp(roomFilename, roomFilenameExpected));
	}

	// TODO: The following is wrong for Phantom/Dragon
	_artFileNum = stream->readUint16LE();
	_depthStyle = stream->readUint16LE();
	_width = stream->readUint16LE();
	_height = stream->readUint16LE();
	
	stream->skip(24);

	int nodeCount = stream->readUint16LE();
	_yBandsEnd = stream->readUint16LE();
	_yBandsStart = stream->readUint16LE();
	_maxScale = stream->readSint16LE();
	_minScale = stream->readSint16LE();
	for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
		_depthBands[i] = stream->readUint16LE();
	stream->skip(2);

	// Load in any scene objects
	for (int i = 0; i < nodeCount; ++i) {
		SceneNode rec;
		rec.load(stream);
		_nodes.push_back(rec);
	}
	for (int i = 0; i < 20 - nodeCount; ++i)
		stream->skip(48);

	// Add two extra nodes in that will be used for player movement
	for (int i = 0; i < 2; ++i) {
		SceneNode rec;
		_nodes.push_back(rec);
	}

	int setCount = stream->readUint16LE();
	stream->readUint16LE();
	for (int i = 0; i < setCount; ++i) {
		char buffer2[64];
		Common::String s(buffer2, 64);
		_setNames.push_back(s);
	}

	delete stream;

	// Initialise a copy of the surfaces if they weren't provided
	bool dsFlag = false, ssFlag = false;
	if (!surface) {
		surface = new M4Surface(_width, _height);
		ssFlag = true;
	} else if ((_width != surface->width()) || (_height != surface->height()))
		surface->setSize(_width, _height);

	if (!depthSurface) {
		depthSurface = new M4Surface(_width, _height);
		dsFlag = true;
	} else if ((_width != depthSurface->width()) || (_height != depthSurface->height()))
		depthSurface->setSize(_width, _height);


	// For Rex Nebular, read in the scene's compressed walk surface information
	if (_vm->getGameType() == GType_RexNebular) {
		assert(depthSurface);
		stream = sceneInfo.getItemStream(1);
		byte *walkData = (byte *)malloc(stream->size());
		stream->read(walkData, stream->size());

		// For Rex Nebular, the walk areas are part of the scene info
		byte *destP = depthSurface->getBasePtr(0, 0);
		const byte *srcP = walkData;
		byte runLength;

		// Run length encoded depth data
		while ((runLength = *srcP++) != 0) {
			if (_depthStyle == 2) {
				// 2-bit depth pixels
				byte byteVal = *srcP++;
				for (int byteCtr = 0; byteCtr < runLength; ++byteCtr) {
					byte v = byteVal;
					for (int bitCtr = 0; bitCtr < 4; ++bitCtr, v >>= 2)
						*destP++ = (((v & 1) + 1) << 3) - 1;
				}
			} else {
Пример #10
0
// This function leaks. For now I don't care
bool PspUnitTests::testFileSystem() {
	// create memory
	const uint32 BufSize = 32 * 1024;
	char* buffer = new char[BufSize];
	int i;
	Common::WriteStream *wrStream;
	Common::SeekableReadStream *rdStream;

	PSP_INFO_PRINT("testing fileSystem...\n");

	// fill buffer
	for (i=0; i<(int)BufSize; i += 4) {
		buffer[i] = 'A';
		buffer[i + 1] = 'B';
		buffer[i + 2] = 'C';
		buffer[i + 3] = 'D';
	}

	// create a file
	const char *path = "./file.test";
	Common::FSNode file(path);

	PSP_INFO_PRINT("creating write stream...\n");

	wrStream = file.createWriteStream();
	if (!wrStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	// write contents
	char* index = buffer;
	int32 totalLength = BufSize;
	int32 curLength = 50;

	PSP_INFO_PRINT("writing...\n");

	while(totalLength - curLength > 0) {
		if ((int)wrStream->write(index, curLength) != curLength) {
			PSP_ERROR("couldn't write %d bytes\n", curLength);
			return false;
		}
		totalLength -= curLength;
		index += curLength;
		//curLength *= 2;
		//PSP_INFO_PRINT("write\n");
	}

	// write the rest
	if ((int)wrStream->write(index, totalLength) != totalLength) {
		PSP_ERROR("couldn't write %d bytes\n", curLength);
		return false;
	}

	delete wrStream;

	PSP_INFO_PRINT("reading...\n");

	rdStream = file.createReadStream();
	if (!rdStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	// seek to beginning
	if (!rdStream->seek(0, SEEK_SET)) {
		PSP_ERROR("couldn't seek to the beginning after writing the file\n");
		return false;
	}

	// read the contents
	char *readBuffer = new char[BufSize + 4];
	memset(readBuffer, 0, (BufSize + 4));
	index = readBuffer;
	while (rdStream->read(index, 100) == 100) {
		index += 100;
	}

	if (!rdStream->eos()) {
		PSP_ERROR("didn't find EOS at end of stream\n");
		return false;
	}

	// compare
	for (i=0; i<(int)BufSize; i++)
		if (buffer[i] != readBuffer[i]) {
			PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]);
			return false;
		}

	// Check for exceeding limit
	for (i=0; i<4; i++) {
		if (readBuffer[BufSize + i]) {
			PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]);
		}
	}

	delete rdStream;

	PSP_INFO_PRINT("writing...\n");

	wrStream = file.createWriteStream();
	if (!wrStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	const char *phrase = "Jello is really fabulous";
	uint32 phraseLen = strlen(phrase);

	int ret;
	if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) {
		PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen);
		return false;
	}

	PSP_INFO_PRINT("reading...\n");

	delete wrStream;
	rdStream = file.createReadStream();
	if (!rdStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	char *readPhrase = new char[phraseLen + 2];
	memset(readPhrase, 0, phraseLen + 2);

	if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) {
		PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen);
		return false;
	}

	for (i=0; i<(int)phraseLen; i++) {
		if (readPhrase[i] != phrase[i]) {
			PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]);
			return false;
		}
	}

	// check for exceeding
	if (readPhrase[i] != 0) {
		PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i);
		return false;
	}

	PSP_INFO_PRINT("trying to read end...\n");

	// seek to end
	if (!rdStream->seek(0, SEEK_END)) {
		PSP_ERROR("couldn't seek to end for append\n");
		return false;
	};

	// try to read
	if (rdStream->read(readPhrase, 2) || !rdStream->eos()) {
		PSP_ERROR("was able to read at end of file\n");
		return false;
	}

	PSP_INFO_PRINT("ok\n");
	return true;
}
Пример #11
0
/**
 * Initialises and loads the data of an animation
 */
void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4Surface *surface, M4Surface *depthSurface) {
	MadsPack anim(filename.c_str(), _vm);
	bool madsRes = filename[0] == '*';
	char buffer[20];
	int streamIndex = 1;

	// Chunk 1: header
	// header

	Common::SeekableReadStream *animStream = anim.getItemStream(0);

	int spriteListCount = animStream->readUint16LE();
	int miscEntriesCount = animStream->readUint16LE();
	int frameEntryCount = animStream->readUint16LE();
	int messagesCount = animStream->readUint16LE();
	animStream->skip(1);
	_flags = animStream->readByte();

	animStream->skip(2);
	_animMode = animStream->readUint16LE();
	_roomNumber = animStream->readUint16LE();
	animStream->skip(2);
	_field12 = animStream->readUint16LE() != 0;
	_spriteListIndex = animStream->readUint16LE();
	_scrollX = animStream->readSint16LE();
	_scrollY = animStream->readSint16LE();
	_scrollTicks = animStream->readUint16LE();
	animStream->skip(8);
	
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_interfaceFile = Common::String(buffer);

	for (int i = 0; i < 10; ++i) {
		animStream->read(buffer, FILENAME_SIZE);
		buffer[FILENAME_SIZE] = '\0';
		_spriteSetNames[i] = Common::String(buffer);
	}

	animStream->skip(81);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_lbmFilename = Common::String(buffer);

	animStream->skip(365);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_spritesFilename = Common::String(buffer);

	animStream->skip(48);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_soundName = Common::String(buffer);

	animStream->skip(13);
	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	_dsrName = Common::String(buffer);

	animStream->read(buffer, FILENAME_SIZE);
	buffer[FILENAME_SIZE] = '\0';
	Common::String fontResource(buffer);

	if (_animMode == 4)
		flags |= 0x4000;
	if (flags & 0x100)
		loadInterface(surface, depthSurface);

	// Initialise the reference list
	for (int i = 0; i < spriteListCount; ++i)
		_spriteListIndexes.push_back(-1);

	delete animStream;

	if (messagesCount > 0) {
		// Chunk 2
		// Following is a list of any messages for the animation

		animStream = anim.getItemStream(streamIndex++);

		for (int i = 0; i < messagesCount; ++i) {
			AnimMessage rec;
			rec.soundId = animStream->readSint16LE();
			animStream->read(rec.msg, 64);
			animStream->skip(4);
			rec.pos.x = animStream->readSint16LE();
			rec.pos.y = animStream->readSint16LE();
			rec.flags = animStream->readUint16LE();
			rec.rgb1.r = animStream->readByte() << 2;
			rec.rgb1.g = animStream->readByte() << 2;
			rec.rgb1.b = animStream->readByte() << 2;
			rec.rgb2.r = animStream->readByte() << 2;
			rec.rgb2.g = animStream->readByte() << 2;
			rec.rgb2.b = animStream->readByte() << 2;
			animStream->skip(2);	// Space for kernelMsgIndex
			rec.kernelMsgIndex = -1;
			animStream->skip(6);
			rec.startFrame = animStream->readUint16LE();
			rec.endFrame = animStream->readUint16LE();
			animStream->skip(2);

			_messages.push_back(rec);
		}

		delete animStream;
	}

	if (frameEntryCount > 0) {
		// Chunk 3: animation frame info
		animStream = anim.getItemStream(streamIndex++);

		for (int i = 0; i < frameEntryCount; i++) {
			AnimFrameEntry rec;
			rec.frameNumber = animStream->readUint16LE();
			rec.seqIndex = animStream->readByte();
			rec.spriteSlot.spriteListIndex = animStream->readByte();
			rec.spriteSlot.frameNumber = animStream->readUint16LE();
			rec.spriteSlot.xp = animStream->readSint16LE();
			rec.spriteSlot.yp = animStream->readSint16LE();
			rec.spriteSlot.depth = animStream->readSByte();
			rec.spriteSlot.scale = (int8)animStream->readByte();

			_frameEntries.push_back(rec);
		}

		delete animStream;
	}

	if (miscEntriesCount > 0) {
		// Chunk 4: Misc Data
		animStream = anim.getItemStream(streamIndex);

		for (int i = 0; i < miscEntriesCount; ++i) {
			AnimMiscEntry rec;
			rec.soundNum = animStream->readByte();
			rec.msgIndex = animStream->readSByte();
			rec.numTicks = animStream->readUint16LE();
			rec.posAdjust.x = animStream->readUint16LE();
			rec.posAdjust.y = animStream->readUint16LE();
			animStream->readUint16LE();

			_miscEntries.push_back(rec);
		}

		delete animStream;
	}

	// If the animation specifies a font, then load it for access
	if (_flags & ANIM_CUSTOM_FONT) {
		Common::String fontName;
		if (madsRes)
			fontName += "*";
		fontName += fontResource;

		if (fontName != "")
			_font = _vm->_font->getFont(fontName.c_str());
		else
			warning("Attempted to set a font with an empty name");
	}

	// If a speech file is specified, then load it
	if (!_dsrName.empty())
		_vm->_sound->loadDSRFile(_dsrName.c_str());

	// Load all the sprite sets for the animation
	for (int i = 0; i < spriteListCount; ++i) {
		if (_field12 && (i == _spriteListIndex))
			// Skip over field, since it's manually loaded		
			continue;

		_spriteListIndexes[i] = _view->_spriteSlots.addSprites(_spriteSetNames[i].c_str());
	}


	if (_field12) {
		Common::String resName;
		if (madsRes)
			resName += "*";
		resName += _spriteSetNames[_spriteListIndex];
		
		_spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str());
	}

	// TODO: Unknown section about handling sprite set list combined with messages size

	// TODO: The original has two separate loops for the loop below based on _animMode == 4. Is it
	// perhaps that in that mode the sprite frames has a different format..?

	// Remap the sprite list index fields from the initial value to the indexes of the loaded
	// sprite sets for the animation
	for (uint i = 0; i < _frameEntries.size(); ++i)  {
		int idx = _frameEntries[i].spriteSlot.spriteListIndex;
		_frameEntries[i].spriteSlot.spriteListIndex = _spriteListIndexes[idx];
	}

	if (hasScroll())
		_nextScrollTimer = _madsVm->_currentTimer + _scrollTicks;
}
Пример #12
0
void AGOSEngine::loadGamePcFile() {
	Common::SeekableReadStream *in;
	int fileSize;

	if (getFileName(GAME_BASEFILE) != NULL) {
		/* Read main gamexx file */
		in = _archives.open(getFileName(GAME_BASEFILE));
		if (!in) {
			error("loadGamePcFile: Can't load gamexx file '%s'", getFileName(GAME_BASEFILE));
		}

		if (getFeatures() & GF_CRUNCHED_GAMEPC) {
			uint srcSize = in->size();
			byte *srcBuf = (byte *)malloc(srcSize);
			in->read(srcBuf, srcSize);

			uint dstSize = READ_BE_UINT32(srcBuf + srcSize - 4);
			byte *dstBuf = (byte *)malloc(dstSize);
			decrunchFile(srcBuf, dstBuf, srcSize);
			free(srcBuf);

			Common::MemoryReadStream stream(dstBuf, dstSize);
			readGamePcFile(&stream);
			free(dstBuf);
		} else {
			readGamePcFile(in);
		}
		delete in;
	}

	if (getFileName(GAME_TBLFILE) != NULL) {
		/* Read list of TABLE resources */
		in = _archives.open(getFileName(GAME_TBLFILE));
		if (!in) {
			error("loadGamePcFile: Can't load table resources file '%s'", getFileName(GAME_TBLFILE));
		}

		fileSize = in->size();

		_tblList = (byte *)malloc(fileSize);
		if (_tblList == NULL)
			error("loadGamePcFile: Out of memory for strip table list");
		in->read(_tblList, fileSize);
		delete in;

		/* Remember the current state */
		_subroutineListOrg = _subroutineList;
		_tablesHeapPtrOrg = _tablesHeapPtr;
		_tablesHeapCurPosOrg = _tablesHeapCurPos;
	}

	if (getFileName(GAME_STRFILE) != NULL) {
		/* Read list of TEXT resources */
		in = _archives.open(getFileName(GAME_STRFILE));
		if (!in)
			error("loadGamePcFile: Can't load text resources file '%s'", getFileName(GAME_STRFILE));

		fileSize = in->size();
		_strippedTxtMem = (byte *)malloc(fileSize);
		if (_strippedTxtMem == NULL)
			error("loadGamePcFile: Out of memory for strip text list");
		in->read(_strippedTxtMem, fileSize);
		delete in;
	}

	if (getFileName(GAME_STATFILE) != NULL) {
		/* Read list of ROOM STATE resources */
		in = _archives.open(getFileName(GAME_STATFILE));
		if (!in) {
			error("loadGamePcFile: Can't load state resources file '%s'", getFileName(GAME_STATFILE));
		}

		_numRoomStates = in->size() / 8;

		_roomStates = (RoomState *)calloc(_numRoomStates, sizeof(RoomState));
		if (_roomStates == NULL)
			error("loadGamePcFile: Out of memory for room state list");

		for (uint s = 0; s < _numRoomStates; s++) {
			uint16 num = in->readUint16BE() - (_itemArrayInited - 2);

			_roomStates[num].state = in->readUint16BE();
			_roomStates[num].classFlags = in->readUint16BE();
			_roomStates[num].roomExitStates = in->readUint16BE();
		}
		delete in;
	}

	if (getFileName(GAME_RMSLFILE) != NULL) {
		/* Read list of ROOM ITEMS resources */
		in = _archives.open(getFileName(GAME_RMSLFILE));
		if (!in) {
			error("loadGamePcFile: Can't load room resources file '%s'", getFileName(GAME_RMSLFILE));
		}

		fileSize = in->size();

		_roomsList = (byte *)malloc(fileSize);
		if (_roomsList == NULL)
			error("loadGamePcFile: Out of memory for room items list");
		in->read(_roomsList, fileSize);
		delete in;
	}

	if (getFileName(GAME_XTBLFILE) != NULL) {
		/* Read list of XTABLE resources */
		in = _archives.open(getFileName(GAME_XTBLFILE));
		if (!in) {
			error("loadGamePcFile: Can't load xtable resources file '%s'", getFileName(GAME_XTBLFILE));
		}

		fileSize = in->size();

		_xtblList = (byte *)malloc(fileSize);
		if (_xtblList == NULL)
			error("loadGamePcFile: Out of memory for strip xtable list");
		in->read(_xtblList, fileSize);
		delete in;

		/* Remember the current state */
		_xsubroutineListOrg = _subroutineList;
		_xtablesHeapPtrOrg = _tablesHeapPtr;
		_xtablesHeapCurPosOrg = _tablesHeapCurPos;
	}
}
Пример #13
0
	ASFGUID(Common::SeekableReadStream &stream) {
		stream.read(id, 16);
	}
Пример #14
0
bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) {
	char bgName[13];

	// At savefile position 0x0000:
	currentDisk = in.readUint16BE();

	// At 0x0002:
	in.read(currentPartName, 13);
	// At 0x000F:
	in.read(currentDatName, 13);

	// At 0x001C:
	musicIsPlaying = in.readSint16BE();

	// At 0x001E:
	in.read(currentPrcName, 13);
	// At 0x002B:
	in.read(currentRelName, 13);
	// At 0x0038:
	in.read(currentMsgName, 13);
	// At 0x0045:
	in.read(bgName, 13);
	// At 0x0052:
	in.read(currentCtName, 13);

	checkDataDisk(currentDisk);

	if (strlen(currentPartName)) {
		loadPart(currentPartName);
	}

	if (strlen(currentPrcName)) {
		loadPrc(currentPrcName);
	}

	if (strlen(currentRelName)) {
		loadRel(currentRelName);
	}

	if (strlen(bgName)) {
		loadBg(bgName);
	}

	if (strlen(currentCtName)) {
		loadCtFW(currentCtName);
	}

	// At 0x005F:
	loadObjectTable(in);

	// At 0x2043 (i.e. 0x005F + 2 * 2 + 255 * 32):
	renderer->restorePalette(in, 0);

	// At 0x2083 (i.e. 0x2043 + 16 * 2 * 2):
	g_cine->_globalVars.load(in, NUM_MAX_VAR);

	// At 0x2281 (i.e. 0x2083 + 255 * 2):
	loadZoneData(in);

	// At 0x22A1 (i.e. 0x2281 + 16 * 2):
	loadCommandVariables(in);

	// At 0x22A9 (i.e. 0x22A1 + 4 * 2):
	char tempCommandBuffer[kMaxCommandBufferSize];
	in.read(tempCommandBuffer, kMaxCommandBufferSize);
	g_cine->_commandBuffer = tempCommandBuffer;
	renderer->setCommand(g_cine->_commandBuffer);

	// At 0x22F9 (i.e. 0x22A9 + 0x50):
	renderer->_cmdY = in.readUint16BE();

	// At 0x22FB:
	bgVar0 = in.readUint16BE();
	// At 0x22FD:
	allowPlayerInput = in.readUint16BE();
	// At 0x22FF:
	playerCommand = in.readSint16BE();
	// At 0x2301:
	commandVar1 = in.readSint16BE();
	// At 0x2303:
	isDrawCommandEnabled = in.readUint16BE();
	// At 0x2305:
	var5 = in.readUint16BE();
	// At 0x2307:
	var4 = in.readUint16BE();
	// At 0x2309:
	var3 = in.readUint16BE();
	// At 0x230B:
	var2 = in.readUint16BE();
	// At 0x230D:
	commandVar2 = in.readSint16BE();

	// At 0x230F:
	renderer->_messageBg = in.readUint16BE();

	// At 0x2311:
	in.readUint16BE();
	// At 0x2313:
	in.readUint16BE();

	// At 0x2315:
	loadResourcesFromSave(in, saveGameFormat);

	loadScreenParams(in);
	loadGlobalScripts(in);
	loadObjectScripts(in);
	loadOverlayList(in);
	loadBgIncrustFromSave(in);

	if (strlen(currentMsgName)) {
		loadMsg(currentMsgName);
	}

	if (strlen(currentDatName)) {
		g_sound->loadMusic(currentDatName);
		if (musicIsPlaying) {
			g_sound->playMusic();
		}
	}

	return !(in.eos() || in.err());
}
Пример #15
0
bool EoBCoreEngine::importOriginalSaveFile(int destSlot, const char *sourceFile) {
	Common::Array<Common::String> origFiles;
	Common::Array<int> newSlots;

	if (sourceFile) {
		// If a source file is specified via the console command we just check whether it exists.
		if (Common::File::exists(sourceFile))
			origFiles.push_back(sourceFile);
		else
			return false;
	} else {
		// Check for original save files in the game path (usually at least the "Quick Start Party" file will be present).
		int numMax = (_flags.gameID == GI_EOB1) ? 1 : 6;
		const char *pattern = (_flags.gameID == GI_EOB1) ? "EOBDATA.SAV" : "EOBDATA%d.SAV";
		for (int i = 0; i < numMax; ++i) {
			Common::String temp = Common::String::format(pattern, i);
			Common::SeekableReadStream *fs = _res->createReadStream(temp);
			if (fs) {
				Common::String dsc;
				if (_flags.gameID == GI_EOB2) {
					char descStr[20];
					fs->read(descStr, 20);
					dsc = Common::String::format("(\"%s\")", descStr).c_str();
				}

				delete fs;
				::GUI::MessageDialog dialog(Common::String::format(_("The following original save game file has been found in your game path:\n\n%s %s\n\nDo you wish to use this save game file with ScummVM?\n\n"), temp.c_str(), dsc.c_str()), _("Yes"), _("No"));
				if (dialog.runModal())
					origFiles.push_back(temp);
			}
		}
	}

	int numFilesFound = origFiles.size();
	if (!numFilesFound)
		return false;

	_gui->updateSaveSlotsList(_targetName, true);

	// Find free save slots for the original save files
	if (destSlot == -1) {
		int assignedSlots = 0;
		for (int testSlot = 0; testSlot < 990 && assignedSlots < numFilesFound; testSlot++) {
			if (Common::find(_gui->_saveSlots.begin(), _gui->_saveSlots.end(), testSlot) == _gui->_saveSlots.end()) {
				newSlots.push_back(testSlot);
				assignedSlots++;
			}
		}

		// This will probably never happen, since we do have 990 save slots
		if (assignedSlots != numFilesFound)
			warning("%d original save files could not be converted due to missing save game slots", numFilesFound - assignedSlots);

	} else {
		newSlots.push_back(destSlot);
	}

	if (destSlot != -1) {
		if (Common::find(_gui->_saveSlots.begin(), _gui->_saveSlots.end(), destSlot) != _gui->_saveSlots.end()) {
			::GUI::MessageDialog dialog(Common::String::format(_("A save game file was found in the specified slot %d. Overwrite?\n\n"), destSlot), _("Yes"), _("No"));
			if (!dialog.runModal())
				return false;
		}
	}

	int importedCount = 0;
	for (int i = 0; i < numFilesFound; i++) {
		Common::String desc = readOriginalSaveFile(origFiles[i]);
		if (desc.empty()) {
			warning("Unable to import original save file '%s'", origFiles[i].c_str());
		} else {
			// We can't make thumbnails here, since we do not want to load all the level data, monsters, etc. for each save we convert.
			// Instead, we use an empty surface to avoid that createThumbnailFromScreen() makes a completely pointless thumbnail from
			// whatever screen that is currently shown when this function is called.
			Graphics::Surface dummy;
			saveGameStateIntern(newSlots[i], desc.c_str(), &dummy);
			warning("Imported original save file '%s' ('%s')", origFiles[i].c_str(), desc.c_str());
			importedCount++;
		}
	}

	_currentLevel = 0;
	_currentSub = 0;
	_currentBlock = 0;
	_currentDirection = 0;
	_itemInHand = 0;
	_hasTempDataFlags = 0;
	_partyEffectFlags = 0;
	memset(_characters, 0, sizeof(EoBCharacter) * 6);
	_inf->reset();

	if (destSlot == -1 && importedCount) {
		::GUI::MessageDialog dialog(Common::String::format(_("%d original save game files have been successfully imported into\nScummVM. If you want to manually import original save game files later you will\nneed to open the ScummVM debug console and use the command 'import_savefile'.\n\n"), importedCount));
		dialog.runModal();
	}

	return true;
}
Пример #16
0
/**
 * Load animDataTable from save
 * @param fHandle Savefile open for reading
 * @param saveGameFormat The used savegame format
 * @todo Add Operation Stealth savefile support
 *
 * Unlike the old code, this one actually rebuilds the table one frame
 * at a time.
 */
void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) {
	int16 currentAnim, foundFileIdx;
	char *animName, part[256], name[10];

	strcpy(part, currentPartName);

	// We only support these variations of the savegame format at the moment.
	assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT);

	const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
	const int fileStartPos = fHandle.pos();
	currentAnim = 0;
	while (currentAnim < NUM_MAX_ANIMDATA) {
		// Seek to the start of the current animation's entry
		fHandle.seek(fileStartPos + currentAnim * entrySize);
		// Read in the current animation entry
		fHandle.readUint16BE(); // width
		fHandle.readUint16BE();
		fHandle.readUint16BE(); // bpp
		fHandle.readUint16BE(); // height

		bool validPtr = false;
		// Handle variables only present in animation entries of size 30
		if (entrySize == 30) {
			validPtr = (fHandle.readUint32BE() != 0); // Read data pointer
			fHandle.readUint32BE(); // Discard mask pointer
		}

		foundFileIdx = fHandle.readSint16BE();
		fHandle.readSint16BE(); // frame
		fHandle.read(name, 10);

		// Handle variables only present in animation entries of size 23
		if (entrySize == 23) {
			validPtr = (fHandle.readByte() != 0);
		}

		// Don't try to load invalid entries.
		if (foundFileIdx < 0 || !validPtr) {
			currentAnim++; // Jump over the invalid entry
			continue;
		}

		// Alright, the animation entry looks to be valid so let's start handling it...
		if (strcmp(currentPartName, name)) {
			closePart();
			loadPart(name);
		}

		animName = g_cine->_partBuffer[foundFileIdx].partName;
		loadRelatedPalette(animName); // Is this for Future Wars only?
		const int16 prevAnim = currentAnim;
		currentAnim = loadResource(animName, currentAnim);
		assert(currentAnim > prevAnim); // Make sure we advance forward
	}

	loadPart(part);

	// Make sure we jump over all the animation entries
	fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize);
}
Пример #17
0
bool BinkPlayer::loadFile(const Common::String &filename) {
	_fname = filename;

	if (_demo) {
		// The demo uses a .lab suffix
		_fname += ".lab";
		return MoviePlayer::loadFile(_fname);
	}

	_fname += ".m4b";

	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(_fname);
	if (!stream) {
		warning("BinkPlayer::loadFile(): Can't create stream for: %s", _fname.c_str());
		return false;
	}

	// set the default start of the bink video in case there is no SMUSH header
	uint32 startBinkPos = 0x0;

	// clear existing subtitles
	_subtitles.clear();

	char header[6];
	// read the first 5 bytes of the header
	stream->read(header, 5);
	header[5] = 0;

	if (!strcmp(header, "SMUSH")) {
		// handle SMUSH header
		unsigned char smushHeader[0x2000];

		// read the first part
		uint32 consumed = 16;
		stream->read(smushHeader, consumed);

		// decode the first part
		for (unsigned int i = 0; i < consumed; i++) {
			smushHeader[i] ^= 0xd2;
		}

		Common::MemoryReadStream msStart(smushHeader, consumed);
		TextSplitter tsStart("", &msStart);

		// extract the length / the start of the following BINK header
		tsStart.scanString("%d", 1, &startBinkPos);

		assert(startBinkPos < sizeof(smushHeader));

		// read the rest (5 bytes less because of the string "SMUSH" at the beginning)
		stream->read(smushHeader+consumed, startBinkPos - consumed - 5);

		// decode the reset
		for (unsigned int i = consumed; i < startBinkPos - 5; i++) {
			smushHeader[i] ^= 0xd2;
		}
		consumed = startBinkPos - 5;

		Common::MemoryReadStream msSmush(smushHeader, consumed);
		TextSplitter tsSmush("", &msSmush);

		// skip the first line which contains the length
		tsSmush.nextLine();

		tsSmush.expectString("BEGINDATA");
		while (!tsSmush.checkString("ENDOFDATA")) {
			unsigned int start, end;
			char textId[256];

			// extract single subtitle entry
			tsSmush.scanString("%d\t%d\t%s", 3, &start, &end, textId);

			Subtitle st(start, end, textId);
			_subtitles.push_back(st);
		}
		tsSmush.expectString("ENDOFDATA");
	}

	// set current subtitle index to the first subtitle
	_subtitleIndex = _subtitles.begin();

	if (!bikCheck(stream, startBinkPos)) {
		warning("BinkPlayer::loadFile(): Could not find BINK header for: %s", _fname.c_str());
		delete stream;
		return false;
	}

	Common::SeekableReadStream *bink = nullptr;
	bink = new Common::SeekableSubReadStream(stream, startBinkPos, stream->size(), DisposeAfterUse::YES);
	_videoDecoder->setDefaultHighColorFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0));
	return _videoDecoder->loadStream(bink);
}