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; }
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()); }
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 }
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; }
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(); }
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(); }
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; }
int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize) { warning("TODO: fadeRead"); stream.read(buf, totalSize); return totalSize; }
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 {
// 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; }
/** * 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; }
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; } }
ASFGUID(Common::SeekableReadStream &stream) { stream.read(id, 16); }
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()); }
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; }
/** * 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); }
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); }