void OldFeature::resetScript() { Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId); _data.endFrame = ourSCRB->readUint16BE() - 1; delete ourSCRB; }
void Cursor::loadCursorImage(CursorInfo &cursorInfo) { if (cursorInfo.surface) return; cursorInfo.surface = new Graphics::Surface(); PegasusEngine *vm = (PegasusEngine *)g_engine; Common::SeekableReadStream *cicnStream = vm->_resFork->getResource(MKTAG('c', 'i', 'c', 'n'), cursorInfo.tag); if (!cicnStream) error("Failed to find color icon %d", cursorInfo.tag); // PixMap section Graphics::PICTDecoder::PixMap pixMap = Graphics::PICTDecoder::readPixMap(*cicnStream); // Mask section cicnStream->readUint32BE(); // mask baseAddr uint16 maskRowBytes = cicnStream->readUint16BE(); // mask rowBytes cicnStream->skip(3 * 2); // mask rect /* uint16 maskHeight = */ cicnStream->readUint16BE(); // Bitmap section cicnStream->readUint32BE(); // baseAddr uint16 rowBytes = cicnStream->readUint16BE(); cicnStream->readUint16BE(); // top cicnStream->readUint16BE(); // left uint16 height = cicnStream->readUint16BE(); // bottom cicnStream->readUint16BE(); // right // Data section cicnStream->readUint32BE(); // icon handle cicnStream->skip(maskRowBytes * height); // FIXME: maskHeight doesn't work here, though the specs say it should cicnStream->skip(rowBytes * height); // Palette section cicnStream->readUint32BE(); // always 0 cicnStream->readUint16BE(); // always 0 cursorInfo.colorCount = cicnStream->readUint16BE() + 1; cursorInfo.palette = new byte[cursorInfo.colorCount * 3]; for (uint16 i = 0; i < cursorInfo.colorCount; i++) { cicnStream->readUint16BE(); cursorInfo.palette[i * 3] = cicnStream->readUint16BE() >> 8; cursorInfo.palette[i * 3 + 1] = cicnStream->readUint16BE() >> 8; cursorInfo.palette[i * 3 + 2] = cicnStream->readUint16BE() >> 8; } // PixMap data if (pixMap.pixelSize == 8) { cursorInfo.surface->create(pixMap.rowBytes, pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8()); cicnStream->read(cursorInfo.surface->pixels, pixMap.rowBytes * pixMap.bounds.height()); // While this looks sensible, it actually doesn't work for some cursors // (ie. the 'can grab' hand) //cursorInfo.surface->w = pixMap.bounds.width(); } else if (pixMap.pixelSize == 1) { cursorInfo.surface->create(pixMap.bounds.width(), pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8()); for (int y = 0; y < pixMap.bounds.height(); y++) { byte *line = (byte *)cursorInfo.surface->getBasePtr(0, y); for (int x = 0; x < pixMap.bounds.width();) { byte b = cicnStream->readByte(); for (int i = 0; i < 8; i++) { *line++ = ((b & (1 << (7 - i))) != 0) ? 1 : 0; if (++x == pixMap.bounds.width()) break; } } } } else { error("Unhandled %dbpp cicn images", pixMap.pixelSize); } delete cicnStream; }
bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) { if (argc < 4) { debugPrintf("Usage: dumpScript <stack> <CARD or HSPT> <card>\n"); return true; } uint16 oldStack = _vm->getStack()->getId(); uint newStack = RivenStacks::getId(argv[1]); if (newStack == kStackUnknown) { debugPrintf("\'%s\' is not a stack name!\n", argv[1]); return true; } _vm->changeToStack(newStack); // Get CARD/HSPT data and dump their scripts if (!scumm_stricmp(argv[2], "CARD")) { // Use debugN to print these because the scripts can get very large and would // really be useless if the the text console is not used. A DumpFile could also // theoretically be used, but I (clone2727) typically use this dynamically and // don't want countless files laying around without game context. If one would // want a file of a script they could just redirect stdout to a file or use // deriven. debugN("\n\nDumping scripts for %s\'s card %d!\n", argv[1], (uint16)atoi(argv[3])); debugN("==================================\n\n"); Common::SeekableReadStream *cardStream = _vm->getResource(MKTAG('C','A','R','D'), (uint16)atoi(argv[3])); cardStream->seek(4); RivenScriptList scriptList = _vm->_scriptMan->readScripts(cardStream); for (uint32 i = 0; i < scriptList.size(); i++) { debugN("Stream Type %d:\n", scriptList[i].type); scriptList[i].script->dumpScript(0); } delete cardStream; } else if (!scumm_stricmp(argv[2], "HSPT")) { // See above for why this is printed via debugN debugN("\n\nDumping scripts for %s\'s card %d hotspots!\n", argv[1], (uint16)atoi(argv[3])); debugN("===========================================\n\n"); Common::SeekableReadStream *hsptStream = _vm->getResource(MKTAG('H','S','P','T'), (uint16)atoi(argv[3])); uint16 hotspotCount = hsptStream->readUint16BE(); for (uint16 i = 0; i < hotspotCount; i++) { debugN("Hotspot %d:\n", i); hsptStream->seek(22, SEEK_CUR); // Skip non-script related stuff RivenScriptList scriptList = _vm->_scriptMan->readScripts(hsptStream); for (uint32 j = 0; j < scriptList.size(); j++) { debugN("\tStream Type %d:\n", scriptList[j].type); scriptList[j].script->dumpScript(1); } } delete hsptStream; } else { debugPrintf("%s doesn't have any scripts!\n", argv[2]); } // See above for why this is printed via debugN debugN("\n\n"); _vm->changeToStack(oldStack); debugPrintf("Script dump complete.\n"); return true; }
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()); }
/** * 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 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()); }
bool loadZoneQuery(Common::SeekableReadStream &in) { for (int i = 0; i < 16; i++) { g_cine->_zoneQuery[i] = in.readUint16BE(); } return !(in.eos() || in.err()); }
bool loadCommandVariables(Common::SeekableReadStream &in) { for (int i = 0; i < 4; i++) { commandVar3[i] = in.readUint16BE(); } 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 = true; 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 = true; 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 = false; } 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 = true; 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 }
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; } }