Example #1
0
Common::Error CineEngine::saveGameState(int slot, const Common::String &desc) {
	// Load savegame descriptions from index file
	loadSaveDirectory();

	// Set description for selected slot making sure it ends with a trailing zero
	strncpy(currentSaveName[slot], desc.c_str(), 20);
	currentSaveName[slot][sizeof(CommandeType) - 1] = 0;

	// Update savegame descriptions
	Common::String indexFile = _targetName + ".dir";

	Common::OutSaveFile *fHandle = _saveFileMan->openForSaving(indexFile);
	if (!fHandle) {
		warning("Unable to open file %s for saving", indexFile.c_str());
		return Common::kUnknownError;
	}

	fHandle->write(currentSaveName, 10 * 20);
	delete fHandle;

	// Save game
	char saveFileName[256];
	sprintf(saveFileName, "%s.%1d", _targetName.c_str(), slot);
	makeSave(saveFileName);

	checkDataDisk(-1);

	return Common::kNoError;
}
Example #2
0
void loadRel(char *pRelName) {
	uint16 numEntry;
	uint16 i;
	byte *ptr;

	checkDataDisk(-1);

	for (i = 0; i < NUM_MAX_REL; i++) {
		if (relTable[i].data) {
			free(relTable[i].data);
			relTable[i].data = NULL;
			relTable[i].size = 0;
		}
	}

	ptr = readBundleFile(findFileInBundle(pRelName));

	setMouseCursor(MOUSE_CURSOR_DISK);

	numEntry = READ_BE_UINT16(ptr); ptr += 2;

	assert(numEntry <= NUM_MAX_REL);

	for (i = 0; i < numEntry; i++) {
		relTable[i].size = READ_BE_UINT16(ptr); ptr += 2;
		relTable[i].obj1Param1 = READ_BE_UINT16(ptr); ptr += 2;
		relTable[i].obj1Param2 = READ_BE_UINT16(ptr); ptr += 2;
		relTable[i].obj2Param = READ_BE_UINT16(ptr); ptr += 2;
	}

	for (i = 0; i < numEntry; i++) {
		if (relTable[i].size) {
			relTable[i].data = (byte *)malloc(relTable[i].size);

			assert(relTable[i].data);

			memcpy(relTable[i].data, ptr, relTable[i].size);
			ptr += relTable[i].size;
		}
	}

#ifdef DUMP_SCRIPTS

	{
		uint16 s;
		char buffer[256];

		for (s = 0; s < numEntry; s++) {
			if (relTable[s].size) {
				sprintf(buffer, "%s_%03d.txt", pRelName, s);

				decompileScript(relTable[s].data, NULL, relTable[s].size, s);
				dumpScript(buffer);
			}
		}
	}
#endif
}
Example #3
0
/*! \todo Is script size of 0 valid?
 * \todo Fix script dump code
 */
void loadRel(char *pRelName) {
	uint16 numEntry;
	uint16 i;
	uint16 size, p1, p2, p3;
	byte *ptr, *dataPtr;

	checkDataDisk(-1);

	objectScripts.clear();
	relTable.clear();

	ptr = dataPtr = readBundleFile(findFileInBundle(pRelName));

	setMouseCursor(MOUSE_CURSOR_DISK);

	numEntry = READ_BE_UINT16(ptr); ptr += 2;

	for (i = 0; i < numEntry; i++) {
		size = READ_BE_UINT16(ptr); ptr += 2;
		p1 = READ_BE_UINT16(ptr); ptr += 2;
		p2 = READ_BE_UINT16(ptr); ptr += 2;
		p3 = READ_BE_UINT16(ptr); ptr += 2;
		RawObjectScriptPtr tmp(new RawObjectScript(size, p1, p2, p3));
		assert(tmp);
		relTable.push_back(tmp);
	}

	for (i = 0; i < numEntry; i++) {
		size = relTable[i]->_size;
		// TODO: delete the test?
		if (size) {
			relTable[i]->setData(*scriptInfo, ptr);
			ptr += size;
		}
	}

	free(dataPtr);

#ifdef DUMP_SCRIPTS

	{
		uint16 s;
		char buffer[256];

		for (s = 0; s < numEntry; s++) {
			if (relTable[s]->_size) {
				sprintf(buffer, "%s_%03d.txt", pRelName, s);

				decompileScript((const byte *)relTable[s]->getString(0), relTable[s]->_size, s);
				dumpScript(buffer);
			}
		}
	}
#endif
}
Example #4
0
void loadObject(char *pObjectName) {
	debug(5, "loadObject(\"%s\")", pObjectName);
	uint16 numEntry;
	uint16 entrySize;
	uint16 i;
	byte *ptr, *dataPtr;

	checkDataDisk(-1);

	ptr = dataPtr = readBundleFile(findFileInBundle(pObjectName));

	setMouseCursor(MOUSE_CURSOR_DISK);

	numEntry = READ_BE_UINT16(ptr); ptr += 2;

	entrySize = READ_BE_UINT16(ptr); ptr += 2;

	assert(numEntry <= NUM_MAX_OBJECT);

	for (i = 0; i < numEntry; i++) {
		if (g_cine->_objectTable[i].costume != -2 && g_cine->_objectTable[i].costume != -3) { // flag is keep?
			Common::MemoryReadStream readS(ptr, entrySize);

			g_cine->_objectTable[i].x = readS.readSint16BE();
			g_cine->_objectTable[i].y = readS.readSint16BE();
			g_cine->_objectTable[i].mask = readS.readUint16BE();
			g_cine->_objectTable[i].frame = readS.readSint16BE();
			g_cine->_objectTable[i].costume = readS.readSint16BE();
			readS.read(g_cine->_objectTable[i].name, 20);
			g_cine->_objectTable[i].part = readS.readUint16BE();
		}
		ptr += entrySize;
	}

	if (!strcmp(pObjectName, "INTRO.OBJ")) {
		for (i = 0; i < 10; i++) {
			g_cine->_objectTable[i].costume = 0;
		}
	}

	free(dataPtr);
}
Example #5
0
void CineEngine::makeSave(char *saveFileName) {
    Common::SharedPtr<Common::OutSaveFile> fHandle(_saveFileMan->openForSaving(saveFileName));

    setMouseCursor(MOUSE_CURSOR_DISK);

    if (!fHandle) {
        renderer->drawString(otherMessages[1], 0);
        waitPlayerInput();
        // restoreScreen();
        checkDataDisk(-1);
    } else {
        if (getGameType() == GType_FW) {
            makeSaveFW(*fHandle);
        } else {
            makeSaveOS(*fHandle);
        }
    }

    setMouseCursor(MOUSE_CURSOR_NORMAL);
}
Example #6
0
File: msg.cpp Project: 33d/scummvm
void loadMsg(char *pMsgName) {
	uint32 sourceSize;

	checkDataDisk(-1);
	g_cine->_messageTable.clear();
	byte *dataPtr = readBundleFile(findFileInBundle(pMsgName), &sourceSize);

	setMouseCursor(MOUSE_CURSOR_DISK);

	uint count = READ_BE_UINT16(dataPtr);
	uint messageLenPos = 2;
	uint messageDataPos = messageLenPos + 2 * count;

	// Read in the messages
	for (uint i = 0; i < count; i++) {
		// Read message's length
		uint messageLen = READ_BE_UINT16(dataPtr + messageLenPos);
		messageLenPos += 2;

		// Store the read message.
		// This code works around input data that has empty strings residing outside the input
		// buffer (e.g. message indexes 58-254 in BATEAU.MSG in PROCS08 in Operation Stealth).
		if (messageDataPos < sourceSize) {
			g_cine->_messageTable.push_back((const char *)(dataPtr + messageDataPos));
		} else {
			if (messageLen > 0) { // Only warn about overflowing non-empty strings
				warning("loadMsg(%s): message (%d. / %d) is overflowing the input buffer. Replacing it with an empty string", pMsgName, i + 1, count);
			} else {
				debugC(5, kCineDebugPart, "loadMsg(%s): empty message (%d. / %d) resides outside input buffer", pMsgName, i + 1, count);
			}
			// Message resides outside the input buffer so we replace it with an empty string
			g_cine->_messageTable.push_back("");
		}
		// Jump to the next message
		messageDataPos += messageLen;
	}

	free(dataPtr);
}
Example #7
0
/**
 * @todo Is script size of 0 valid?
 * @todo Fix script dump code
 * @return Was the loading successful?
 */
bool loadPrc(const char *pPrcName) {
	byte i;
	uint16 numScripts;
	byte *scriptPtr, *dataPtr;

	assert(pPrcName);

	g_cine->_globalScripts.clear();
	g_cine->_scriptTable.clear();

	// This is copy protection. Used to hang the machine
	if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) {
		Common::Event event;
		event.type = Common::EVENT_RTL;
		g_system->getEventManager()->pushEvent(event);
		return false;
	}

	checkDataDisk(-1);
	if ((g_cine->getGameType() == Cine::GType_FW) &&
		(!scumm_stricmp(pPrcName, BOOT_PRC_NAME) || !scumm_stricmp(pPrcName, "demo.prc"))) {
		scriptPtr = dataPtr = readFile(pPrcName, (g_cine->getFeatures() & GF_CRYPTED_BOOT_PRC) != 0);
	} else {
		scriptPtr = dataPtr = readBundleFile(findFileInBundle(pPrcName));
	}

	assert(scriptPtr);

	setMouseCursor(MOUSE_CURSOR_DISK);

	numScripts = READ_BE_UINT16(scriptPtr);
	scriptPtr += 2;
	assert(numScripts <= NUM_MAX_SCRIPT);

	for (i = 0; i < numScripts; i++) {
		RawScriptPtr tmp(new RawScript(READ_BE_UINT16(scriptPtr)));
		scriptPtr += 2;
		assert(tmp);
		g_cine->_scriptTable.push_back(tmp);
	}

	for (i = 0; i < numScripts; i++) {
		uint16 size = g_cine->_scriptTable[i]->_size;
		// TODO: delete the test?
		if (size) {
			g_cine->_scriptTable[i]->setData(*scriptInfo, scriptPtr);
			scriptPtr += size;
		}
	}

	free(dataPtr);

#ifdef DUMP_SCRIPTS

	{
		uint16 s;
		char buffer[256];

		for (s = 0; s < numScripts; s++) {
			if (scriptTable[s]->_size) {
				sprintf(buffer, "%s_%03d.txt", pPrcName, s);

				decompileScript((const byte *)scriptTable[s]->getString(0), scriptTable[s]->_size, s);
				dumpScript(buffer);
			}
		}
	}
#endif

	return true;
}
Example #8
0
bool CineEngine::makeLoad(const Common::String &saveName) {
    Common::SharedPtr<Common::InSaveFile> saveFile(_saveFileMan->openForLoading(saveName));

    if (!saveFile) {
        renderer->drawString(otherMessages[0], 0);
        waitPlayerInput();
        // restoreScreen();
        checkDataDisk(-1);
        return false;
    }

    setMouseCursor(MOUSE_CURSOR_DISK);

    uint32 saveSize = saveFile->size();
    // TODO: Evaluate the maximum savegame size for the temporary Operation Stealth savegame format.
    if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it
        // Can't get information about the savefile's size so let's try
        // reading as much as we can from the file up to a predefined upper limit.
        //
        // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each):
        // With 256 global scripts, object scripts, overlays and background incrusts:
        // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB
        // With 512 global scripts, object scripts, overlays and background incrusts:
        // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB
        //
        // I think it extremely unlikely that there would be over 512 global scripts, object scripts,
        // overlays and background incrusts so 256kB seems like quite a safe upper limit.
        // NOTE: If the savegame format is changed then this value might have to be re-evaluated!
        // Hopefully devices with more limited memory can also cope with this memory allocation.
        saveSize = 256 * 1024;
    }
    Common::SharedPtr<Common::SeekableReadStream> in(saveFile->readStream(saveSize));

    // Try to detect the used savegame format
    enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*in);

    // Handle problematic savegame formats
    bool load = true; // Should we try to load the savegame?
    bool result = false;
    if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) {
        // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but
        // that's not implemented here because it was never used in a stable
        // release of ScummVM but only during development (From revision 31453,
        // which introduced the problem, until revision 32073, which fixed it).
        // Therefore we bail out if we detect this particular savegame format.
        warning("Detected a known broken savegame format, not loading savegame");
        load = false; // Don't load the savegame
    } else if (saveGameFormat == ANIMSIZE_UNKNOWN) {
        // If we can't detect the savegame format
        // then let's try the default format and hope for the best.
        warning("Couldn't detect the used savegame format, trying default savegame format. Things may break");
        saveGameFormat = ANIMSIZE_30_PTRS_INTACT;
    }

    if (load) {
        // Reset the engine's state
        resetEngine();

        if (saveGameFormat == TEMP_OS_FORMAT) {
            // Load the temporary Operation Stealth savegame format
            result = loadTempSaveOS(*in);
        } else {
            // Load the plain Future Wars savegame format
            result = loadPlainSaveFW(*in, saveGameFormat);
        }
    }

    setMouseCursor(MOUSE_CURSOR_NORMAL);

    return result;
}
Example #9
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());
}
Example #10
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());
}