/** * 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 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(); for(int resourceIndex=0; resourceIndex<NUM_MAX_ANIMDATA; resourceIndex++) { // Seek to the start of the current animation's entry fHandle.seek(fileStartPos + resourceIndex * 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(); int16 frameIndex = 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) { //resourceIndex++; // Jump over the invalid entry continue; } // Alright, the animation entry looks to be valid so let's start handling it... if (strcmp(currentPartName, name) != 0) { closePart(); loadPart(name); } animName = g_cine->_partBuffer[foundFileIdx].partName; loadRelatedPalette(animName); // Is this for Future Wars only? loadResource(animName, resourceIndex, frameIndex); } loadPart(part); // Make sure we jump over all the animation entries fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize); }
void IFFDecoder::loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size) { PaletteRange range; range.timer = stream.readSint16BE(); range.step = stream.readSint16BE(); range.flags = stream.readSint16BE(); range.first = stream.readByte(); range.last = stream.readByte(); _paletteRanges.push_back(range); }
bool loadObjectTable(Common::SeekableReadStream &in) { in.readUint16BE(); // Entry count in.readUint16BE(); // Entry size for (int i = 0; i < NUM_MAX_OBJECT; i++) { g_cine->_objectTable[i].x = in.readSint16BE(); g_cine->_objectTable[i].y = in.readSint16BE(); g_cine->_objectTable[i].mask = in.readUint16BE(); g_cine->_objectTable[i].frame = in.readSint16BE(); g_cine->_objectTable[i].costume = in.readSint16BE(); in.read(g_cine->_objectTable[i].name, 20); g_cine->_objectTable[i].part = in.readUint16BE(); } return !(in.eos() || in.err()); }
/** * Restore overlay sprites from savefile * @param fHandle Savefile open for reading */ void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { overlay tmp; fHandle.readUint32BE(); fHandle.readUint32BE(); tmp.objIdx = fHandle.readUint16BE(); tmp.type = fHandle.readUint16BE(); tmp.x = fHandle.readSint16BE(); tmp.y = fHandle.readSint16BE(); tmp.width = fHandle.readSint16BE(); tmp.color = fHandle.readSint16BE(); g_cine->_overlayList.push_back(tmp); }
bool loadOverlayList(Common::SeekableReadStream &in) { int size = in.readSint16BE(); for (int i = 0; i < size; i++) { loadOverlayFromSave(in); } return !(in.eos() || in.err()); }
bool loadObjectScripts(Common::SeekableReadStream &in) { int size = in.readSint16BE(); for (int i = 0; i < size; i++) { loadScriptFromSave(in, false); } return !(in.eos() || in.err()); }
/** * Restore incrust list from savefile * @param fHandle Savefile open for reading */ void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) { BGIncrust tmp; int size = fHandle.readSint16BE(); for (int i = 0; i < size; i++) { fHandle.readUint32BE(); fHandle.readUint32BE(); tmp.unkPtr = 0; tmp.objIdx = fHandle.readUint16BE(); tmp.param = fHandle.readUint16BE(); tmp.x = fHandle.readUint16BE(); tmp.y = fHandle.readUint16BE(); tmp.frame = fHandle.readUint16BE(); tmp.part = fHandle.readUint16BE(); g_cine->_bgIncrustList.push_back(tmp); if (tmp.param == 0) { renderer->incrustSprite(g_cine->_objectTable[tmp.objIdx]); } else { renderer->incrustMask(g_cine->_objectTable[tmp.objIdx]); } } }
void parseOpcodeDefault(Instruction &instr, Common::SeekableReadStream &ncs) { instr.argCount = getDirectArgumentCount(instr.opcode); const OpcodeArgument * const args = getDirectArguments(instr.opcode); for (size_t i = 0; i < instr.argCount; i++) { instr.argTypes[i] = args[i]; switch (instr.argTypes[i]) { case kOpcodeArgUint8: instr.args[i] = ncs.readByte(); break; case kOpcodeArgUint16: instr.args[i] = ncs.readUint16BE(); break; case kOpcodeArgSint16: instr.args[i] = ncs.readSint16BE(); break; case kOpcodeArgSint32: instr.args[i] = ncs.readSint32BE(); break; case kOpcodeArgUint32: instr.args[i] = (int32)ncs.readUint32BE(); break; default: break; } } }
void CSTimeModule::cursorMoveProc(Feature *feature) { uint16 cursor = _vm->getView()->getBitmapCursor(); if (!cursor) return; Common::Point pos = _vm->getEventManager()->getMousePos(); // FIXME: shouldn't be hardcoded uint16 compoundSHAPIndex = 200; // FIXME: stupid REGS stuff.. Common::SeekableReadStream *regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex); regsStream->seek(cursor * 2); feature->_data.bounds.left = pos.x - regsStream->readSint16BE(); delete regsStream; regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex + 1); regsStream->seek(cursor * 2); feature->_data.bounds.top = pos.y - regsStream->readSint16BE(); delete regsStream; }
/** * Read _invent from Hugo.dat */ void InventoryHandler::loadInvent(Common::SeekableReadStream &in) { for (int varnt = 0; varnt < _vm->_numVariant; varnt++) { int16 numElem = in.readUint16BE(); if (varnt == _vm->_gameVariant) { _maxInvent = numElem; _invent = (int16 *)malloc(sizeof(int16) * numElem); for (int i = 0; i < numElem; i++) _invent[i] = in.readSint16BE(); } else { in.skip(numElem * sizeof(int16)); } } }
bool StaticResource::loadButtonDefs(Common::SeekableReadStream &stream, void *&ptr, int &size) { size = stream.size() / 18; LoLButtonDef *r = new LoLButtonDef[size]; for (int i = 0; i < size; i++) { r[i].buttonflags = stream.readUint16BE(); r[i].keyCode = stream.readUint16BE(); r[i].keyCode2 = stream.readUint16BE(); r[i].x = stream.readSint16BE(); r[i].y = stream.readSint16BE(); r[i].w = stream.readUint16BE(); r[i].h = stream.readUint16BE(); r[i].index = stream.readUint16BE(); r[i].screenDim = stream.readUint16BE(); } ptr = r; return true; }
Common::String *World::loadStringFromDITL(Common::MacResManager *resMan, int resourceId, int itemIndex) { Common::SeekableReadStream *res = resMan->getResource(MKTAG('D','I','T','L'), resourceId); if (res) { int itemCount = res->readSint16BE(); for (int i = 0; i <= itemCount; i++) { // int placeholder; short rect[4]; byte flags; pstring str; res->skip(13); Common::String message = readPascalString(res); if (i == itemIndex) { Common::String *msg = new Common::String(message); delete res; return msg; } } delete res; } return NULL; }
void MohawkEngine_Riven::loadHotspots(uint16 id) { // Clear old hotspots delete[] _hotspots; // NOTE: The hotspot scripts are cleared by the RivenScriptManager automatically. Common::SeekableReadStream *inStream = getResource(ID_HSPT, id); _hotspotCount = inStream->readUint16BE(); _hotspots = new RivenHotspot[_hotspotCount]; for (uint16 i = 0; i < _hotspotCount; i++) { _hotspots[i].enabled = true; _hotspots[i].blstID = inStream->readUint16BE(); _hotspots[i].name_resource = inStream->readSint16BE(); int16 left = inStream->readSint16BE(); int16 top = inStream->readSint16BE(); int16 right = inStream->readSint16BE(); int16 bottom = inStream->readSint16BE(); // Riven has some invalid rects, disable them here // Known weird hotspots: // - tspit 371 (DVD: 377), hotspot 4 if (left >= right || top >= bottom) { warning("%s %d hotspot %d is invalid: (%d, %d, %d, %d)", getStackName(_curStack).c_str(), _curCard, i, left, top, right, bottom); left = top = right = bottom = 0; _hotspots[i].enabled = 0; } _hotspots[i].rect = Common::Rect(left, top, right, bottom); _hotspots[i].u0 = inStream->readUint16BE(); _hotspots[i].mouse_cursor = inStream->readUint16BE(); _hotspots[i].index = inStream->readUint16BE(); _hotspots[i].u1 = inStream->readSint16BE(); _hotspots[i].zipModeHotspot = inStream->readUint16BE(); // Read in the scripts now _hotspots[i].scripts = _scriptMan->readScripts(inStream); } delete inStream; updateZipMode(); }
void MohawkEngine_Riven::loadCard(uint16 id) { // NOTE: The card scripts are cleared by the RivenScriptManager automatically. Common::SeekableReadStream* inStream = getResource(ID_CARD, id); _cardData.name = inStream->readSint16BE(); _cardData.zipModePlace = inStream->readUint16BE(); _cardData.scripts = _scriptMan->readScripts(inStream); _cardData.hasData = true; delete inStream; if (_cardData.zipModePlace) { Common::String cardName = getName(CardNames, _cardData.name); if (cardName.empty()) return; ZipMode zip; zip.name = cardName; zip.id = id; if (!(Common::find(_zipModeData.begin(), _zipModeData.end(), zip) != _zipModeData.end())) _zipModeData.push_back(zip); } }
bool loadSeqList(Common::SeekableReadStream &in) { uint size = in.readUint16BE(); SeqListElement tmp; for (uint i = 0; i < size; i++) { tmp.var4 = in.readSint16BE(); tmp.objIdx = in.readUint16BE(); tmp.var8 = in.readSint16BE(); tmp.frame = in.readSint16BE(); tmp.varC = in.readSint16BE(); tmp.varE = in.readSint16BE(); tmp.var10 = in.readSint16BE(); tmp.var12 = in.readSint16BE(); tmp.var14 = in.readSint16BE(); tmp.var16 = in.readSint16BE(); tmp.var18 = in.readSint16BE(); tmp.var1A = in.readSint16BE(); tmp.var1C = in.readSint16BE(); tmp.var1E = in.readSint16BE(); g_cine->_seqList.push_back(tmp); } return !(in.eos() || in.err()); }
void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in) { int numBytes = in.readSint16BE(); int y1 = in.readSint16BE(); int x1 = in.readSint16BE(); int y2 = in.readSint16BE(); int x2 = in.readSint16BE(); int w = x2 - x1; int h = y2 - y1; Graphics::ManagedSurface tmp; tmp.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); numBytes -= 10; int x = 0, y = 0; while (numBytes > 0 && y < h) { int n = in.readSByte(); int count; int b = 0; int state = 0; numBytes--; if ((n >= 0) && (n <= 127)) { // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. count = n + 1; state = 1; } else if ((n >= -127) && (n <= -1)) { // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. b = in.readByte(); numBytes--; count = -n + 1; state = 2; } else { // Else if n is -128, noop. count = 0; } for (int i = 0; i < count && y < h; i++) { byte color = 0; if (state == 1) { color = in.readByte(); numBytes--; } else if (state == 2) color = b; for (int c = 0; c < 8; c++) { if (_boundsCalculationMode) { adjustBounds(x1 + x, y1 + y); } else if (x1 + x >= 0 && x1 + x < surface->w && y1 + y >= 0 && y1 + y < surface->h) *((byte *)tmp.getBasePtr(x, y)) = (color & (1 << (7 - c % 8))) ? kColorBlack : kColorWhite; x++; if (x == w) { y++; x = 0; break; } } } } in.skip(numBytes); if (_boundsCalculationMode) return; FloodFill ff(&tmp, kColorWhite, kColorGreen); for (int yy = 0; yy < h; yy++) { ff.addSeed(0, yy); ff.addSeed(w - 1, yy); } for (int xx = 0; xx < w; xx++) { ff.addSeed(xx, 0); ff.addSeed(xx, h - 1); } ff.fill(); for (y = 0; y < h && y1 + y < surface->h; y++) { byte *src = (byte *)tmp.getBasePtr(0, y); byte *dst = (byte *)surface->getBasePtr(x1, y1 + y); for (x = 0; x < w; x++) { if (*src != kColorGreen) *dst = *src; src++; dst++; } } tmp.free(); }
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()); }
/** * Savegame format detector * @param fHandle Savefile to check * @return Savegame format on success, ANIMSIZE_UNKNOWN on failure * * This function seeks through the savefile and tries to determine the * savegame format it uses. There's a miniscule chance that the detection * algorithm could get confused and think that the file uses both the older * and the newer format but that is such a remote possibility that I wouldn't * worry about it at all. * * Also detects the temporary Operation Stealth savegame format now. */ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) { const uint32 prevStreamPos = fHandle.pos(); // First check for the temporary Operation Stealth savegame format. fHandle.seek(0); ChunkHeader hdr; loadChunkHeader(fHandle, hdr); fHandle.seek(prevStreamPos); if (hdr.id == TEMP_OS_FORMAT_ID) { return TEMP_OS_FORMAT; } // Ok, so the savegame isn't using the temporary Operation Stealth savegame format. // Let's check for the plain Future Wars savegame format and its different versions then. // The animDataTable begins at savefile position 0x2315. // Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443) // and 30 bytes in the save format after that (Revision 31444 and onwards). // There are 255 entries in the animDataTable in both of the savefile formats. static const uint animDataTableStart = 0x2315; static const uint animEntriesCount = 255; static const uint oldAnimEntrySize = 23; static const uint newAnimEntrySize = 30; static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; Common::Array<uint> animEntrySizeMatches; // Try to walk through the savefile using different animDataTable entry sizes // and make a list of all the successful entry sizes. for (uint i = 0; i < ARRAYSIZE(animEntrySizeChoices); i++) { // 206 = 2 * 50 * 2 + 2 * 3 (Size of global and object script entries) // 20 = 4 * 2 + 2 * 6 (Size of overlay and background incrust entries) static const uint sizeofScreenParams = 2 * 6; static const uint globalScriptEntrySize = 206; static const uint objectScriptEntrySize = 206; static const uint overlayEntrySize = 20; static const uint bgIncrustEntrySize = 20; static const uint chainEntrySizes[] = { globalScriptEntrySize, objectScriptEntrySize, overlayEntrySize, bgIncrustEntrySize }; uint animEntrySize = animEntrySizeChoices[i]; // Jump over the animDataTable entries and the screen parameters int32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams; // Check that there's data left after the point we're going to jump to if (newPos >= fHandle.size()) { continue; } fHandle.seek(newPos); // Jump over the remaining items in the savegame file // (i.e. the global scripts, object scripts, overlays and background incrusts). bool chainWalkSuccess = true; for (uint chainIndex = 0; chainIndex < ARRAYSIZE(chainEntrySizes); chainIndex++) { // Read entry count and jump over the entries int entryCount = fHandle.readSint16BE(); newPos = fHandle.pos() + chainEntrySizes[chainIndex] * entryCount; // Check that we didn't go past the end of file. // Note that getting exactly to the end of file is acceptable. if (newPos > fHandle.size()) { chainWalkSuccess = false; break; } fHandle.seek(newPos); } // If we could walk the chain successfully and // got exactly to the end of file then we've got a match. if (chainWalkSuccess && fHandle.pos() == fHandle.size()) { // We found a match, let's save it animEntrySizeMatches.push_back(animEntrySize); } } // Check that we got only one entry size match. // If we didn't, then return an error. enum CineSaveGameFormat result = ANIMSIZE_UNKNOWN; if (animEntrySizeMatches.size() == 1) { const uint animEntrySize = animEntrySizeMatches[0]; assert(animEntrySize == oldAnimEntrySize || animEntrySize == newAnimEntrySize); if (animEntrySize == oldAnimEntrySize) { result = ANIMSIZE_23; } else { // animEntrySize == newAnimEntrySize // Check data and mask pointers in all of the animDataTable entries // to see whether we've got the version with the broken data and mask pointers or not. // In the broken format all data and mask pointers were always zero. static const uint relativeDataPos = 2 * 4; bool pointersIntact = false; for (uint i = 0; i < animEntriesCount; i++) { fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos); uint32 data = fHandle.readUint32BE(); uint32 mask = fHandle.readUint32BE(); if ((data != 0) || (mask != 0)) { pointersIntact = true; break; } } result = (pointersIntact ? ANIMSIZE_30_PTRS_INTACT : ANIMSIZE_30_PTRS_BROKEN); } } else if (animEntrySizeMatches.size() > 1) { warning("Savegame format detector got confused by input data. Detecting savegame to be using an unknown format"); } else { // animEtrySizeMatches.size() == 0 debug(3, "Savegame format detector was unable to detect savegame's format"); } fHandle.seek(prevStreamPos); return result; }
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()); }
void CSTimeModule::defaultMoveProc(Feature *feature) { if (feature->_data.paused > 0) return; if (!feature->_data.enabled) return; if (feature->_timeProc && !(this->*(feature->_timeProc))(feature)) return; if (feature->_needsReset) { feature->resetFeatureScript(1, feature->_scrbId); if ((feature->_flags & kFeatureNewDisable) || (feature->_flags & kFeatureNewDisableOnReset)) { feature->_data.enabled = 0; } feature->_dirty = 1; if (feature->_flags & kFeatureInternalRegion) { // TODO: create region [+140] (if not already done) } } else { if (!(feature->_flags & kFeatureNewClip)) { if (feature->_data.useClipRect) { // TODO: or clip with _unknown228 } else if (feature->_region) { // TODO: or clip with region } else { // TODO: or clip with bounds } } feature->_dirty = 1; if (feature->_flags & kFeatureNewInternalTiming) { feature->_nextTime += feature->_delayTime; } else { feature->_nextTime = _vm->getView()->_lastIdleTime + feature->_delayTime; } if (feature->_done) { if (feature->_flags & kFeatureNewNoLoop) { // FIXME: sync channel reset uint16 unknown184 = 1, unknown186 = 1; // FIXME: XXX if (feature->_flags & kFeatureDisableOnEnd || (unknown184 != 0 && unknown186 != 0)) { // FIXME: XXX feature->_data.enabled = 0; if (feature->_doneProc) { (this->*(feature->_doneProc))(feature); // TODO: with -2 } } return; } feature->_data.currOffset = 26; feature->_done = 0; } if (feature->_flags & kFeatureNewDisable) feature->_data.enabled = 0; } int xOffset = feature->_data.currentPos.x + feature->_data.nextPos.x; int yOffset = feature->_data.currentPos.y + feature->_data.nextPos.y; Common::SeekableReadStream *ourSCRB = _vm->getView()->getSCRB(feature->_data.scrbIndex); ourSCRB->seek(feature->_data.currOffset); bool setBitmap = false; uint bitmapId = 0; bool done = false; while (!done) { byte opcode = ourSCRB->readByte(); byte size = ourSCRB->readByte(); switch (opcode) { case 1: ourSCRB->skip(size - 2); opcode = ourSCRB->readByte(); size = ourSCRB->readByte(); if (opcode != 0) { ourSCRB->seek(-2, SEEK_CUR); done = true; break; } case 0: // TODO: set ptr +176 to 1 feature->_done = 1; if (feature->_doneProc) { (this->*(feature->_doneProc))(feature); // TODO: with -1 } done = true; break; case 3: { int32 pos = ourSCRB->pos(); ourSCRB->seek(2); uint16 base = ourSCRB->readUint16BE(); ourSCRB->seek(pos); base += ourSCRB->readUint16BE(); if (base) { // FIXME: sound? } ourSCRB->skip(size - 4); } warning("saw feature opcode 0x3 (size %d)", size); break; case 4: // FIXME if (false /* TODO: !+72 */) { ourSCRB->skip(size - 2); } else { uint16 time = ourSCRB->readUint16BE(); // FIXME: not right feature->_delayTime = time; ourSCRB->skip(size - 4); } warning("saw feature opcode 0x4 (size %d)", size); break; case 9: // FIXME ourSCRB->skip(size - 2); warning("ignoring feature opcode 0x9 (size %d)", size); break; case 0xf: // FIXME ourSCRB->skip(size - 2); warning("ignoring feature opcode 0xf (size %d)", size); break; case 0x10: while (bitmapId < 48) { if (!size) break; size--; feature->_data.bitmapIds[bitmapId] = ourSCRB->readUint16BE() & 0xFFF; feature->_data.bitmapPos[bitmapId].x = ourSCRB->readUint16BE() + xOffset; feature->_data.bitmapPos[bitmapId].y = ourSCRB->readUint16BE() + yOffset; bitmapId++; } feature->_data.bitmapIds[bitmapId] = 0; setBitmap = true; break; default: warning("unknown new feature opcode %d", opcode); ourSCRB->skip(size - 2); break; } } feature->_data.currOffset = ourSCRB->pos(); if (!setBitmap) { // TODO: set fail flag return; } if (feature->_frameProc) { (this->*(feature->_frameProc))(feature); } // TODO: set palette if needed // TODO: adjust for regs if needed Common::Array<int16> regsX, regsY; Common::SeekableReadStream *regsStream; uint16 compoundSHAPIndex = _vm->getView()->getCompoundSHAPId(feature->_data.compoundSHAPIndex); regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex); while (regsStream->pos() != regsStream->size()) regsX.push_back(regsStream->readSint16BE()); delete regsStream; regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex + 1); while (regsStream->pos() != regsStream->size()) regsY.push_back(regsStream->readSint16BE()); delete regsStream; for (uint i = 0; i < 48; i++) { uint16 thisBitmapId = feature->_data.bitmapIds[i]; if (!thisBitmapId) break; feature->_data.bitmapPos[i].x -= regsX[thisBitmapId]; feature->_data.bitmapPos[i].y -= regsY[thisBitmapId]; } // TODO: set bounds // TODO: unset fail flag }