Пример #1
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 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);
}
Пример #2
0
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);
}
Пример #3
0
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());
}
Пример #4
0
/**
 * 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);
}
Пример #5
0
bool loadOverlayList(Common::SeekableReadStream &in) {
    int size = in.readSint16BE();
    for (int i = 0; i < size; i++) {
        loadOverlayFromSave(in);
    }
    return !(in.eos() || in.err());
}
Пример #6
0
bool loadObjectScripts(Common::SeekableReadStream &in) {
    int size = in.readSint16BE();
    for (int i = 0; i < size; i++) {
        loadScriptFromSave(in, false);
    }
    return !(in.eos() || in.err());
}
Пример #7
0
/**
 * 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]);
        }
    }
}
Пример #8
0
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;
		}
	}
}
Пример #9
0
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;
}
Пример #10
0
/**
 * 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));
		}
	}
}
Пример #11
0
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;
}
Пример #12
0
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;
}
Пример #13
0
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();
}
Пример #14
0
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);
	}
}
Пример #15
0
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());
}
Пример #16
0
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();
}
Пример #17
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());
}
Пример #18
0
/**
 * 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;
}
Пример #19
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());
}
Пример #20
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 = 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
}