Пример #1
0
void OldFeature::resetScript() {
	Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId);
	_data.endFrame = ourSCRB->readUint16BE() - 1;
	delete ourSCRB;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) {
	char bgName[13];

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

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

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

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

	checkDataDisk(currentDisk);

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

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

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

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

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

	// At 0x005F:
	loadObjectTable(in);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	strcpy(part, currentPartName);

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

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

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

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

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

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

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

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

	loadPart(part);

	// Make sure we jump over all the animation entries
	fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize);
}
Пример #6
0
bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) {
	char musicName[13];
	char bgNames[8][13];

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

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

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

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

	in.read(currentCtName, 13);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	disableSystemMenu = in.readUint16BE();

	// TODO: adBgVar1 = 1 here

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

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

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

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

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

	return !(in.eos() || in.err());
}
Пример #7
0
bool loadZoneQuery(Common::SeekableReadStream &in) {
	for (int i = 0; i < 16; i++) {
		g_cine->_zoneQuery[i] = in.readUint16BE();
	}
	return !(in.eos() || in.err());
}
Пример #8
0
bool loadCommandVariables(Common::SeekableReadStream &in) {
	for (int i = 0; i < 4; i++) {
		commandVar3[i] = in.readUint16BE();
	}
	return !(in.eos() || in.err());
}
Пример #9
0
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
}
Пример #10
0
void AGOSEngine::loadGamePcFile() {
	Common::SeekableReadStream *in;
	int fileSize;

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

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

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

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

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

		fileSize = in->size();

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

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

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

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

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

		_numRoomStates = in->size() / 8;

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

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

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

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

		fileSize = in->size();

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

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

		fileSize = in->size();

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

		/* Remember the current state */
		_xsubroutineListOrg = _subroutineList;
		_xtablesHeapPtrOrg = _tablesHeapPtr;
		_xtablesHeapCurPosOrg = _tablesHeapCurPos;
	}
}