Example #1
0
bool Console::Cmd_DumpArchive(int argc, const char **argv) {
	if (argc != 2) {
		DebugPrintf("Extract all the files from a game archive.\n");
		DebugPrintf("The destination folder, named 'dump', must exist.\n");
		DebugPrintf("Usage :\n");
		DebugPrintf("dumpArchive [file name]\n");
		return true;
	}

	// Is the archive multi-room
	Common::String temp = Common::String(argv[1]);
	temp.toUppercase();

	bool multiRoom = !temp.hasSuffix(".M3A");
	if (!multiRoom) {
		temp = Common::String(argv[1], 4);
		temp.toUppercase();
	}

	Archive archive;
	if (!archive.open(argv[1], multiRoom ? 0 : temp.c_str())) {
		DebugPrintf("Can't open archive with name '%s'\n", argv[1]);
		return true;
	}

	archive.dumpToFiles();
	archive.close();

	return true;
}
Example #2
0
bool Debugger::Cmd_DumpItems(int argc, const char **argv) {
    InventoryObjects &objects = _vm->_game->_objects;

    Common::DumpFile outFile;
    outFile.open("items.txt");

    for (uint32 i = 0; i < objects.size(); i++) {
        Common::String curId = Common::String::format("%d", i);
        Common::String desc = _vm->_game->_scene.getVocab(objects[i]._descId);
        desc.toUppercase();

        for (uint j = 0; j < desc.size(); j++) {
            if (desc[j] == ' ' || desc[j] == '-')
                desc.setChar('_', j);
        }

        Common::String cur = "\tOBJ_" + desc + " = " + curId + ",\n";

        outFile.writeString(cur.c_str());
    }

    outFile.flush();
    outFile.close();

    debugPrintf("Game items dumped\n");

    return true;
}
Example #3
0
bool Debugger::Cmd_DumpVocab(int argc, const char **argv) {
    Common::DumpFile outFile;
    outFile.open("vocab.txt");

    for (uint32 i = 0; i < _vm->_game->_scene.getVocabStringsCount(); i++) {
        Common::String curId = Common::String::format("%x", i + 1);
        Common::String curVocab = _vm->_game->_scene.getVocab(i + 1);
        curVocab.toUppercase();

        for (uint j = 0; j < curVocab.size(); j++) {
            if (curVocab[j] == ' ' || curVocab[j] == '-')
                curVocab.setChar('_', j);
        }

        Common::String cur = "\tNOUN_" + curVocab + " = 0x" + curId + ",\n";

        outFile.writeString(cur.c_str());
    }

    outFile.flush();
    outFile.close();

    debugPrintf("Game vocab dumped\n");

    return true;
}
Example #4
0
bool Resource::loadPakFile(Common::String filename) {
	filename.toUppercase();

	Common::ArchiveMemberPtr file = _files.getMember(filename);
	if (!file)
		return false;

	return loadPakFile(filename, file);
}
Example #5
0
bool Resource::loadPakFile(Common::String name, Common::ArchiveMemberPtr file) {
	name.toUppercase();

	if (_archiveFiles.hasArchive(name) || _protectedFiles.hasArchive(name))
		return true;

	Common::Archive *archive = loadArchive(name, file);
	if (!archive)
		return false;

	_archiveFiles.add(name, archive, 0, false);

	return true;
}
Example #6
0
ActionCursor::ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line) :
	ResultAction(engine, slotkey) {
	Common::String up = line;
	up.toUppercase();
	_action = 0;

	if (up[0] == 'B')
		_action = 2;
	else if (up[0] == 'I')
		_action = 3;
	else if (up[0] == 'U')
		_action = 0;
	else if (up[0] == 'H')
		_action = 1;
}
Example #7
0
void Resource::unloadPakFile(Common::String filename, bool remFromCache) {
	filename.toUppercase();

	// We do not remove files from '_protectedFiles' here, since
	// those are protected against unloading.
	if (_archiveFiles.hasArchive(filename)) {
		_archiveFiles.remove(filename);
		if (remFromCache) {
			ArchiveMap::iterator iter = _archiveCache.find(filename);
			if (iter != _archiveCache.end()) {
				delete iter->_value;
				_archiveCache.erase(filename);
			}
		}
	}
}
Example #8
0
Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &filename) {
	Common::String upcName = filename;
	upcName.toUppercase();
	Common::SeekableReadStream *file = nullptr;

	// correct slashes
	for (uint32 i = 0; i < upcName.size(); i++) {
		if (upcName[(int32)i] == '/') {
			upcName.setChar('\\', (uint32)i);
		}
	}
	Common::ArchiveMemberPtr entry = _packages.getMember(upcName);
	if (!entry) {
		return nullptr;
	}
	file = entry->createReadStream();
	return file;
}
Example #9
0
bool Console::Cmd_Extract(int argc, const char **argv) {
	if (argc != 5) {
		DebugPrintf("Extract a file from the game's archives\n");
		DebugPrintf("Usage :\n");
		DebugPrintf("extract [room] [node id] [face number] [object type]\n");
		return true;
	}

	// Room names are uppercase
	Common::String room = Common::String(argv[1]);
	room.toUppercase();

	uint16 id = atoi(argv[2]);
	uint16 face = atoi(argv[3]);
	DirectorySubEntry::ResourceType type = (DirectorySubEntry::ResourceType) atoi(argv[4]);

	const DirectorySubEntry *desc = _vm->getFileDescription(room.c_str(), id, face, type);

	if (!desc) {
		DebugPrintf("File with room %s, id %d, face %d and type %d does not exist\n", room.c_str(), id, face, type);
		return true;
	}

	Common::MemoryReadStream *s = desc->getData();
	Common::String filename = Common::String::format("node%s_%d_face%d.%d", room.c_str(), id, face, type);
	Common::DumpFile f;
	f.open(filename);

	uint8 *buf = new uint8[s->size()];

	s->read(buf, s->size());
	f.write(buf, s->size());

	delete[] buf;

	f.close();

	delete s;

	DebugPrintf("File '%s' successfully written\n", filename.c_str());

	return true;
}
Example #10
0
bool Resource::loadFileList(const Common::String &filedata) {
	Common::SeekableReadStream *f = createReadStream(filedata);

	if (!f)
		return false;

	uint32 filenameOffset = 0;
	while ((filenameOffset = f->readUint32LE()) != 0) {
		uint32 offset = f->pos();
		f->seek(filenameOffset, SEEK_SET);

		uint8 buffer[13];
		f->read(buffer, sizeof(buffer)-1);
		buffer[12] = 0;
		f->seek(offset + 16, SEEK_SET);

		Common::String filename = Common::String((char *)buffer);
		filename.toUppercase();

		if (filename.hasSuffix(".PAK")) {
			if (!exists(filename.c_str()) && _vm->gameFlags().isDemo) {
				// the demo version supplied with Kyra3 does not
				// contain all pak files listed in filedata.fdt
				// so we don't do anything here if they are non
				// existant.
			} else if (!loadPakFile(filename)) {
				delete f;
				error("couldn't load file '%s'", filename.c_str());
				return false;	// for compilers that don't support NORETURN
			}
		}
	}

	delete f;
	return true;
}
Example #11
0
/**
 * Search file in Cat file
 */
byte *FileManager::searchCat(const Common::String &file, CatMode mode, bool &fileFoundFl) {
	byte *ptr = NULL;
	fileFoundFl = true;
	Common::File f;

	Common::String filename = file;
	Common::String secondaryFilename = "";
	filename.toUppercase();

	switch (mode) {
	case RES_INI:
		if (!f.exists("RES_INI.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_INI.CAT");
		secondaryFilename = "RES_INI.RES";
		break;

	case RES_REP:
		if (!f.exists("RES_REP.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_REP.CAT");
		secondaryFilename = "RES_REP.RES";
		break;

	case RES_LIN:
		if (!f.exists("RES_LIN.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_LIN.CAT");
		secondaryFilename = "RES_LIN.RES";
		break;

	case RES_PER:
		if (!f.exists("RES_PER.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_PER.CAT");
		secondaryFilename = "RES_PER.RES";
		break;

	case RES_PIC:
		if (!f.exists("PIC.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("PIC.CAT");
		break;

	case RES_SAN:
		if (!f.exists("RES_SAN.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_SAN.CAT");
		break;

	case RES_SLI:
		if (!f.exists("RES_SLI.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_SLI.CAT");
		break;

	case RES_VOI: {
		Common::String tmpFilename;
		if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
			tmpFilename = "ENG_VOI.CAT";
		// Win95 and Linux versions uses another set of names
		else {
			switch (_vm->_globals->_language) {
			case LANG_EN:
				tmpFilename = "RES_VAN.CAT";
				break;
			case LANG_FR:
				tmpFilename = "RES_VFR.CAT";
				break;
			case LANG_SP:
				tmpFilename = "RES_VES.CAT";
				break;
			}
		}

		if (!f.exists(tmpFilename)) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile(tmpFilename);
		break;
		}

	default:
		break;
	}

	// Scan for an entry in the catalogue
	byte *result;
	bool matchFlag = false;
	int offsetVal = 0;

	while (!matchFlag) {
		Common::String name = (const char *)ptr + offsetVal;

		if (name == filename) {
			// Found entry for file, so get it's details from the catalogue entry
			const byte *pData = ptr + offsetVal;
			_catalogPos = READ_LE_UINT32(pData + 15);
			_catalogSize = READ_LE_UINT32(pData + 19);
			matchFlag = true;
		}

		if (name == "FINIS") {
			_vm->_globals->freeMemory(ptr);
			fileFoundFl = false;
			return NULL;
		}

		offsetVal += 23;
	}

	_vm->_globals->freeMemory(ptr);

	if (secondaryFilename != "") {
		if (!f.open(secondaryFilename))
			error("CHARGE_FICHIER");

		f.seek(_catalogPos);

		byte *catData = _vm->_globals->allocMemory(_catalogSize);
		if (catData == g_PTRNUL)
			error("CHARGE_FICHIER");

		readStream(f, catData, _catalogSize);
		f.close();
		result = catData;
	} else {
		result = NULL;
	}

	return result;
}
Example #12
0
bool Resource::reset() {
	unloadAllPakFiles();

	Common::FSNode dir(ConfMan.get("path"));

	if (!dir.exists() || !dir.isDirectory())
		error("invalid game path '%s'", dir.getPath().c_str());

	if (_vm->game() == GI_KYRA1) {
		// We only need kyra.dat for the demo.
		if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie)
			return true;

		if (!_vm->gameFlags().isDemo && _vm->gameFlags().isTalkie) {
			// List of files in the talkie version, which can never be unload.
			static const char * const list[] = {
				"ADL.PAK", "CHAPTER1.VRM", "COL.PAK", "FINALE.PAK", "INTRO1.PAK", "INTRO2.PAK",
				"INTRO3.PAK", "INTRO4.PAK", "MISC.PAK", "SND.PAK", "STARTUP.PAK", "XMI.PAK",
				"CAVE.APK", "DRAGON1.APK", "DRAGON2.APK", "LAGOON.APK", 0
			};

			loadProtectedFiles(list);
		} else {
			Common::ArchiveMemberList files;

			_files.listMatchingMembers(files, "*.PAK");
			_files.listMatchingMembers(files, "*.APK");

			for (Common::ArchiveMemberList::const_iterator i = files.begin(); i != files.end(); ++i) {
				Common::String name = (*i)->getName();
				name.toUppercase();

				// No PAK file
				if (name == "TWMUSIC.PAK")
					continue;

				// We need to only load the script archive for the language the user specified
				if (name == ((_vm->gameFlags().lang == Common::EN_ANY) ? "JMC.PAK" : "EMC.PAK"))
					continue;

				Common::Archive *archive = loadArchive(name, *i);
				if (archive)
					_files.add(name, archive, 0, false);
				else
					error("Couldn't load PAK file '%s'", name.c_str());
			}
		}
	} else if (_vm->game() == GI_KYRA2) {
		if (_vm->gameFlags().useInstallerPackage)
			_files.add("installer", loadInstallerArchive("WESTWOOD", "%03d", 6), 2, false);

		// mouse pointer, fonts, etc. required for initialization
		if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
			loadPakFile("GENERAL.PAK");
		} else {
			loadPakFile("INTROGEN.PAK");
			loadPakFile("OTHER.PAK");
		}
	} else if (_vm->game() == GI_KYRA3) {
		if (_vm->gameFlags().useInstallerPackage) {
			if (!loadPakFile("WESTWOOD.001"))
				error("Couldn't load file: 'WESTWOOD.001'");
		}

		if (!loadFileList("FILEDATA.FDT"))
			error("Couldn't load file: 'FILEDATA.FDT'");
	} else if (_vm->game() == GI_LOL) {
		if (_vm->gameFlags().useInstallerPackage)
			_files.add("installer", loadInstallerArchive("WESTWOOD", "%d", 0), 2, false);

		if (!_vm->gameFlags().isTalkie && !_vm->gameFlags().isDemo) {
			static const char * const list[] = {
				"GENERAL.PAK", 0
			};

			loadProtectedFiles(list);
		}
	} else {
		error("Unknown game id: %d", _vm->game());
		return false;	// for compilers that don't support NORETURN
	}

	return true;
}
Example #13
0
bool Resource::isInCacheList(Common::String name) {
	name.toUppercase();
	return (_archiveCache.find(name) != _archiveCache.end());
}
Example #14
0
bool Resource::isInPakList(Common::String filename) {
	filename.toUppercase();
	return (_archiveFiles.hasArchive(filename) || _protectedFiles.hasArchive(filename));
}
Example #15
0
void ShaderRenderer::draw2DText(const Common::String &text, const Common::Point &position) {
	OpenGLTexture *glFont = static_cast<OpenGLTexture *>(_font);

	// The font only has uppercase letters
	Common::String textToDraw = text;
	textToDraw.toUppercase();

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glDisable(GL_DEPTH_TEST);
	glDepthMask(GL_FALSE);

	if (_prevText != textToDraw || _prevTextPosition != position) {
		_prevText = textToDraw;
		_prevTextPosition = position;

		float x = position.x / (float) _currentViewport.width();
		float y = position.y / (float) _currentViewport.height();

		float *bufData = new float[16 * textToDraw.size()];
		float *cur = bufData;

		for (uint i = 0; i < textToDraw.size(); i++) {
			Common::Rect textureRect = getFontCharacterRect(textToDraw[i]);
			float w = textureRect.width() / (float) _currentViewport.width();
			float h = textureRect.height() / (float) _currentViewport.height();

			float cw = textureRect.width() / (float)glFont->internalWidth;
			float ch = textureRect.height() / (float)glFont->internalHeight;
			float cx = textureRect.left / (float)glFont->internalWidth;
			float cy = textureRect.top / (float)glFont->internalHeight;

			const float charData[] = {
				cx,      cy + ch, x,     y,    
				cx + cw, cy + ch, x + w, y,    
				cx + cw, cy,      x + w, y + h,
				cx,      cy,      x,     y + h,
			};

			memcpy(cur, charData, 16 * sizeof(float));
			cur += 16;

			x += (textureRect.width() - 3) / (float) _currentViewport.width();
		}

		glBindBuffer(GL_ARRAY_BUFFER, _textVBO);
		glBufferSubData(GL_ARRAY_BUFFER, 0, textToDraw.size() * 16 * sizeof(float), bufData);
		delete[] bufData;
	}

	_textShader->use();
	glBindTexture(GL_TEXTURE_2D, glFont->id);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
	glDrawElements(GL_TRIANGLES, 6 * textToDraw.size(), GL_UNSIGNED_SHORT, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);
}
Example #16
0
Common::Error EoBCoreEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) {
	Common::String saveNameTmp;
	const char *fileName = 0;

	// Special slot id -1 to create final save for party transfer
	if (slot == -1) {
		_savegameFilename = _targetName + Common::String(".fin");
		fileName = _savegameFilename.c_str();
		saveNameTmp = _targetName + Common::String(" final");
		saveNameTmp.toUppercase();
		saveName = saveNameTmp.c_str();
	} else {
		fileName = getSavegameFilename(slot);
	}

	Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail);
	if (!out)
		return _saveFileMan->getError();

	completeDoorOperations();
	generateTempData();
	advanceTimers(_restPartyElapsedTime);
	_restPartyElapsedTime = 0;

	for (int i = 0; i < 6; i++)
		timerSpecialCharacterUpdate(0x30 + i);

	for (int i = 0; i < 6; i++) {
		EoBCharacter *c = &_characters[i];

		out->writeByte(c->id);
		out->writeByte(c->flags);
		out->write(c->name, 11);
		out->writeSByte(c->strengthCur);
		out->writeSByte(c->strengthMax);
		out->writeSByte(c->strengthExtCur);
		out->writeSByte(c->strengthExtMax);
		out->writeSByte(c->intelligenceCur);
		out->writeSByte(c->intelligenceMax);
		out->writeSByte(c->wisdomCur);
		out->writeSByte(c->wisdomMax);
		out->writeSByte(c->dexterityCur);
		out->writeSByte(c->dexterityMax);
		out->writeSByte(c->constitutionCur);
		out->writeSByte(c->constitutionMax);
		out->writeSByte(c->charismaCur);
		out->writeSByte(c->charismaMax);
		out->writeSint16BE(c->hitPointsCur);
		out->writeSint16BE(c->hitPointsMax);
		out->writeSByte(c->armorClass);
		out->writeByte(c->disabledSlots);
		out->writeByte(c->raceSex);
		out->writeByte(c->cClass);
		out->writeByte(c->alignment);
		out->writeByte(c->portrait);
		out->writeByte(c->food);
		out->write(c->level, 3);
		for (int ii = 0; ii < 3; ii++)
			out->writeUint32BE(c->experience[ii]);
		out->write(c->mageSpells, 80);
		out->write(c->clericSpells, 80);
		out->writeUint32BE(c->mageSpellsAvailableFlags);
		for (int ii = 0; ii < 27; ii++)
			out->writeSint16BE(c->inventory[ii]);
		uint32 ct = _system->getMillis();
		for (int ii = 0; ii < 10; ii++)
			out->writeUint32BE((c->timers[ii] && c->timers[ii] > ct) ? c->timers[ii] - ct : 0);

		out->write(c->events, 10);
		out->write(c->effectsRemainder, 4);
		out->writeUint32BE(c->effectFlags);
		out->writeByte(c->damageTaken);
		out->write(c->slotStatus, 5);
	}

	out->writeByte(_currentLevel);
	out->writeSByte(_currentSub);
	out->writeUint16BE(_currentBlock);
	out->writeUint16BE(_currentDirection);
	out->writeSint16BE(_itemInHand);
	out->writeUint32BE(_hasTempDataFlags);
	out->writeUint32BE(_partyEffectFlags);

	out->writeUint16BE(_updateFlags);
	out->writeUint16BE(_compassDirection);
	out->writeUint16BE(_currentControlMode);
	out->writeSint16BE(_updateCharNum);
	out->writeSByte(_openBookSpellLevel);
	out->writeSByte(_openBookSpellSelectedItem);
	out->writeSByte(_openBookSpellListOffset);
	out->writeByte(_openBookChar);
	out->writeByte(_openBookType);
	out->writeByte(_openBookCharBackup);
	out->writeByte(_openBookTypeBackup);
	out->writeByte(_activeSpellCharId);
	out->writeByte(_activeSpellCharacterPos);
	out->writeByte(_activeSpell);
	out->writeByte(_returnAfterSpellCallback ? 1 : 0);

	_inf->saveState(out);

	for (int i = 0; i < 600; i++) {
		EoBItem *t = &_items[i];
		out->writeByte(t->nameUnid);
		out->writeByte(t->nameId);
		out->writeByte(t->flags);
		out->writeSByte(t->icon);
		out->writeSByte(t->type);
		out->writeSByte(t->pos);
		out->writeSint16BE(t->block);
		out->writeSint16BE(t->next);
		out->writeSint16BE(t->prev);
		out->writeByte(t->level);
		out->writeSByte(t->value);
	}

	for (int i = 51; i < 65; i++) {
		EoBItemType *t = &_itemTypes[i];
		out->writeUint16BE(t->invFlags);
		out->writeUint16BE(t->handFlags);
		out->writeSByte(t->armorClass);
		out->writeSByte(t->allowedClasses);
		out->writeSByte(t->requiredHands);
		out->writeSByte(t->dmgNumDiceS);
		out->writeSByte(t->dmgNumPipsS);
		out->writeSByte(t->dmgIncS);
		out->writeSByte(t->dmgNumDiceL);
		out->writeSByte(t->dmgNumPipsL);
		out->writeSByte(t->dmgIncL);
		out->writeByte(t->unk1);
		out->writeUint16BE(t->extraProperties);
	}

	for (int i = 0; i < 18; i++) {
		LevelTempData *l = _lvlTempData[i];
		if (!l || !(_hasTempDataFlags & (1 << i)))
			continue;

		out->write(l->wallsXorData, 4096);
		for (int ii = 0; ii < 1024; ii++)
			out->writeByte(l->flags[ii] & 0xff);

		EoBMonsterInPlay *lm = (EoBMonsterInPlay *)_lvlTempData[i]->monsters;
		EoBFlyingObject *lf = (EoBFlyingObject *)_lvlTempData[i]->flyingObjects;
		WallOfForce *lw = (WallOfForce *)_lvlTempData[i]->wallsOfForce;

		for (int ii = 0; ii < 30; ii++) {
			EoBMonsterInPlay *m = &lm[ii];
			out->writeByte(m->type);
			out->writeByte(m->unit);
			out->writeUint16BE(m->block);
			out->writeByte(m->pos);
			out->writeSByte(m->dir);
			out->writeByte(m->animStep);
			out->writeByte(m->shpIndex);
			out->writeSByte(m->mode);
			out->writeSByte(m->f_9);
			out->writeSByte(m->curAttackFrame);
			out->writeSByte(m->spellStatusLeft);
			out->writeSint16BE(m->hitPointsMax);
			out->writeSint16BE(m->hitPointsCur);
			out->writeUint16BE(m->dest);
			out->writeUint16BE(m->randItem);
			out->writeUint16BE(m->fixedItem);
			out->writeByte(m->flags);
			out->writeByte(m->idleAnimState);
			out->writeByte(m->curRemoteWeapon);
			out->writeByte(m->numRemoteAttacks);
			out->writeSByte(m->palette);
			out->writeByte(m->directionChanged);
			out->writeByte(m->stepsTillRemoteAttack);
			out->writeByte(m->sub);
		}

		for (int ii = 0; ii < _numFlyingObjects; ii++) {
			EoBFlyingObject *m = &lf[ii];
			out->writeByte(m->enable);
			out->writeByte(m->objectType);
			out->writeSint16BE(m->attackerId);
			out->writeSint16BE(m->item);
			out->writeUint16BE(m->curBlock);
			out->writeUint16BE(m->starting);
			out->writeByte(m->u1);
			out->writeByte(m->direction);
			out->writeByte(m->distance);
			out->writeSByte(m->callBackIndex);
			out->writeByte(m->curPos);
			out->writeByte(m->flags);
			out->writeByte(m->unused);
		}

		for (int ii = 0; ii < 5; ii++) {
			WallOfForce *w = &lw[ii];
			out->writeUint16BE(w->block);
			out->writeUint32BE(w->duration);
		}
	}

	out->finalize();

	// check for errors
	if (out->err()) {
		warning("Can't write file '%s'. (Disk full?)", fileName);
		return Common::kUnknownError;
	} else {
		debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName);
	}

	delete out;

	_gui->notifyUpdateSaveSlotsList();

	return Common::kNoError;
}