예제 #1
0
 virtual void write(ESM::ESMWriter& esm)
 {
     for (typename std::map<std::string, T>::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it)
     {
         esm.startRecord(T::sRecordId);
         it->second.save(esm);
         esm.endRecord(T::sRecordId);
     }
 }
예제 #2
0
 void Globals::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
 {
     for (Collection::const_iterator iter (mVariables.begin()); iter!=mVariables.end(); ++iter)
     {
         writer.startRecord (ESM::REC_GLOB);
         iter->second.save (writer);
         writer.endRecord (ESM::REC_GLOB);
     }
 }
예제 #3
0
 virtual void write(ESM::ESMWriter &esm)
 {
     for (std::vector<ESM::GlobalScript>::const_iterator it = mScripts.begin(); it != mScripts.end(); ++it)
     {
         esm.startRecord(ESM::REC_GSCR);
         it->save(esm);
         esm.endRecord(ESM::REC_GSCR);
     }
 }
예제 #4
0
 virtual void write(ESM::ESMWriter &esm)
 {
     esm.startRecord(ESM::REC_DCOU);
     for (std::map<std::string, int>::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it)
     {
         esm.writeHNString("ID__", it->first);
         esm.writeHNT ("COUN", it->second);
     }
     esm.endRecord(ESM::REC_DCOU);
 }
예제 #5
0
 virtual void write(ESM::ESMWriter &esm)
 {
     for (std::map<std::string, DIAL>::const_iterator it = mDials.begin(); it != mDials.end(); ++it)
     {
         esm.startRecord(ESM::REC_QUES);
         ESM::QuestState state;
         state.mFinished = 0;
         state.mState = it->second.mIndex;
         state.mTopic = Misc::StringUtils::lowerCase(it->first);
         state.save(esm);
         esm.endRecord(ESM::REC_QUES);
     }
 }
예제 #6
0
파일: cells.cpp 프로젝트: AAlderman/openmw
void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const
{
    if (cell.getState()!=CellStore::State_Loaded)
        cell.load (mStore, mReader);

    ESM::CellState cellState;

    cell.saveState (cellState);

    writer.startRecord (ESM::REC_CSTA);
    cellState.mId.save (writer);
    cellState.save (writer);
    cell.writeFog(writer);
    cell.writeReferences (writer);
    writer.endRecord (ESM::REC_CSTA);
}
예제 #7
0
    void RefIdDataContainer<RecordT>::save (int index, ESM::ESMWriter& writer) const
    {
        CSMWorld::RecordBase::State state = mContainer.at (index).mState;

        if (state==CSMWorld::RecordBase::State_Modified ||
            state==CSMWorld::RecordBase::State_ModifiedOnly)
        {
            writer.startRecord (mContainer.at (index).mModified.sRecordId);
            writer.writeHNCString ("NAME", getId (index));
            mContainer.at (index).mModified.save (writer);
            writer.endRecord (mContainer.at (index).mModified.sRecordId);
        }
        else if (state==CSMWorld::RecordBase::State_Deleted)
        {
            /// \todo write record with delete flag
        }
    }
예제 #8
0
    void ProjectileManager::write(ESM::ESMWriter &writer, Loading::Listener &progress) const
    {
        for (std::vector<ProjectileState>::const_iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it)
        {
            writer.startRecord(ESM::REC_PROJ);

            ESM::ProjectileState state;
            state.mId = it->mId;
            state.mPosition = it->mNode->getPosition();
            state.mOrientation = it->mNode->getOrientation();
            state.mActorId = it->mActorId;

            state.mBowId = it->mBowId;
            state.mVelocity = it->mVelocity;

            state.save(writer);

            writer.endRecord(ESM::REC_PROJ);

            progress.increaseProgress();
        }

        for (std::vector<MagicBoltState>::const_iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
        {
            writer.startRecord(ESM::REC_MPRJ);

            ESM::MagicBoltState state;
            state.mId = it->mId;
            state.mPosition = it->mNode->getPosition();
            state.mOrientation = it->mNode->getOrientation();
            state.mActorId = it->mActorId;

            state.mSpellId = it->mSpellId;
            state.mEffects = it->mEffects;
            state.mSound = it->mSoundId;
            state.mSourceName = it->mSourceName;
            state.mSpeed = it->mSpeed;
            state.mStack = it->mStack;

            state.save(writer);

            writer.endRecord(ESM::REC_MPRJ);

            progress.increaseProgress();
        }
    }
예제 #9
0
 virtual void write(ESM::ESMWriter &esm)
 {
     if (!mHasGame)
         return;
     esm.startRecord(ESM::REC_WTHR);
     ESM::WeatherState weather;
     weather.mTimePassed = 0.0f;
     weather.mFastForward = false;
     weather.mWeatherUpdateTime = mGame.mGMDT.mTimeOfNextTransition - mContext->mHour;
     weather.mTransitionFactor = 1 - (mGame.mGMDT.mWeatherTransition / 100.0f);
     weather.mCurrentWeather = validateWeatherID(mGame.mGMDT.mCurrentWeather);
     weather.mNextWeather = validateWeatherID(mGame.mGMDT.mNextWeather);
     weather.mQueuedWeather = -1;
     // TODO: Determine how ModRegion modifiers are saved in Morrowind.
     weather.save(esm);
     esm.endRecord(ESM::REC_WTHR);
 }
예제 #10
0
    void GlobalScripts::write (ESM::ESMWriter& writer) const
    {
        for (std::map<std::string, std::pair<bool, Locals> >::const_iterator iter (mScripts.begin());
            iter!=mScripts.end(); ++iter)
        {
            ESM::GlobalScript script;

            script.mId = iter->first;

            iter->second.second.write (script.mLocals, iter->first);

            script.mRunning = iter->second.first ? 1 : 0;

            writer.startRecord (ESM::REC_GSCR);
            script.save (writer);
            writer.endRecord (ESM::REC_GSCR);
        }
    }
예제 #11
0
    void Journal::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
    {
        for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
        {
            const Quest& quest = iter->second;

            ESM::QuestState state;
            quest.write (state);
            writer.startRecord (ESM::REC_QUES);
            state.save (writer);
            writer.endRecord (ESM::REC_QUES);
            progress.increaseProgress();

            for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter)
            {
                ESM::JournalEntry entry;
                entry.mType = ESM::JournalEntry::Type_Quest;
                entry.mTopic = quest.getTopic();
                iter->write (entry);
                writer.startRecord (ESM::REC_JOUR);
                entry.save (writer);
                writer.endRecord (ESM::REC_JOUR);
                progress.increaseProgress();
            }
        }

        for (TEntryIter iter (mJournal.begin()); iter!=mJournal.end(); ++iter)
        {
            ESM::JournalEntry entry;
            entry.mType = ESM::JournalEntry::Type_Journal;
            iter->write (entry);
            writer.startRecord (ESM::REC_JOUR);
            entry.save (writer);
            writer.endRecord (ESM::REC_JOUR);
            progress.increaseProgress();
        }

        for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
        {
            const Topic& topic = iter->second;

            for (Topic::TEntryIter iter (topic.begin()); iter!=topic.end(); ++iter)
            {
                ESM::JournalEntry entry;
                entry.mType = ESM::JournalEntry::Type_Topic;
                entry.mTopic = topic.getTopic();
                iter->write (entry);
                writer.startRecord (ESM::REC_JOUR);
                entry.save (writer);
                writer.endRecord (ESM::REC_JOUR);
                progress.increaseProgress();
            }
        }
    }
예제 #12
0
    void ProjectileManager::write(ESM::ESMWriter &writer, Loading::Listener &progress) const
    {
        for (std::vector<ProjectileState>::const_iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it)
        {
            writer.startRecord(ESM::REC_PROJ);

            ESM::ProjectileState state;
            state.mId = it->mIdArrow;
            state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
            state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
            state.mActorId = it->mActorId;

            state.mBowId = it->mBowId;
            state.mVelocity = it->mVelocity;
            state.mAttackStrength = it->mAttackStrength;

            state.save(writer);

            writer.endRecord(ESM::REC_PROJ);
        }

        for (std::vector<MagicBoltState>::const_iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
        {
            writer.startRecord(ESM::REC_MPRJ);

            ESM::MagicBoltState state;
            state.mId = it->mIdMagic.at(0);
            state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
            state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
            state.mActorId = it->mActorId;

            state.mSpellId = it->mSpellId;
            state.mEffects = it->mEffects;
            state.mSound = it->mSoundIds.at(0);
            state.mSourceName = it->mSourceName;
            state.mSpeed = it->mSpeed;
            state.mStack = it->mStack;

            state.save(writer);

            writer.endRecord(ESM::REC_MPRJ);
        }
    }
예제 #13
0
    void GlobalScripts::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
    {
        for (std::map<std::string, GlobalScriptDesc>::const_iterator iter (mScripts.begin());
            iter!=mScripts.end(); ++iter)
        {
            ESM::GlobalScript script;

            script.mId = iter->first;

            iter->second.mLocals.write (script.mLocals, iter->first);

            script.mRunning = iter->second.mRunning ? 1 : 0;

            script.mTargetId = iter->second.mId;

            writer.startRecord (ESM::REC_GSCR);
            script.save (writer);
            writer.endRecord (ESM::REC_GSCR);
        }
    }
예제 #14
0
    void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
    {
        writer.startRecord(ESM::REC_DYNA);
        writer.startSubRecord("COUN");
        writer.writeT(mDynamicCount);
        writer.endRecord("COUN");
        writer.endRecord(ESM::REC_DYNA);

        mPotions.write (writer, progress);
        mArmors.write (writer, progress);
        mBooks.write (writer, progress);
        mClasses.write (writer, progress);
        mClothes.write (writer, progress);
        mEnchants.write (writer, progress);
        mSpells.write (writer, progress);
        mWeapons.write (writer, progress);
        mNpcs.write (writer, progress);
        mItemLists.write (writer, progress);
        mCreatureLists.write (writer, progress);
    }
예제 #15
0
    virtual void write(ESM::ESMWriter &esm)
    {
        ESM::StolenItems items;
        for (std::map<std::string, std::set<Owner> >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
        {
            std::map<std::pair<std::string, bool>, int> owners;
            for (std::set<Owner>::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt)
            {
                owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second)
                                             // Since OpenMW doesn't suffer from the owner contamination bug,
                                             // it needs a count argument. But for legacy savegames, we don't know
                                             // this count, so must assume all items of that ID are stolen,
                                             // like vanilla MW did.
                                             ,std::numeric_limits<int>::max()));
            }

            items.mStolenItems.insert(std::make_pair(it->first, owners));
        }

        esm.startRecord(ESM::REC_STLN);
        items.write(esm);
        esm.endRecord(ESM::REC_STLN);
    }
예제 #16
0
파일: player.cpp 프로젝트: MiroslavR/openmw
    void Player::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
    {
        ESM::Player player;

        mPlayer.save (player.mObject);
        player.mCellId = mCellStore->getCell()->getCellId();

        player.mCurrentCrimeId = mCurrentCrimeId;
        player.mPaidCrimeId = mPaidCrimeId;

        player.mBirthsign = mSign;

        player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x();
        player.mLastKnownExteriorPosition[1] = mLastKnownExteriorPosition.y();
        player.mLastKnownExteriorPosition[2] = mLastKnownExteriorPosition.z();

        if (mMarkedCell)
        {
            player.mHasMark = true;
            player.mMarkedPosition = mMarkedPosition;
            player.mMarkedCell = mMarkedCell->getCell()->getCellId();
        }
        else
            player.mHasMark = false;

        player.mAutoMove = mAutoMove ? 1 : 0;

        for (int i=0; i<ESM::Attribute::Length; ++i)
            mSaveAttributes[i].writeState(player.mSaveAttributes[i]);
        for (int i=0; i<ESM::Skill::Length; ++i)
            mSaveSkills[i].writeState(player.mSaveSkills[i]);

        writer.startRecord (ESM::REC_PLAY);
        player.save (writer);
        writer.endRecord (ESM::REC_PLAY);
    }
예제 #17
0
void MWState::StateManager::saveGame (const std::string& description, const Slot *slot)
{
    try
    {
        ESM::SavedGame profile;

        MWBase::World& world = *MWBase::Environment::get().getWorld();

        MWWorld::Ptr player = world.getPlayerPtr();

        profile.mContentFiles = world.getContentFiles();

        profile.mPlayerName = player.get<ESM::NPC>()->mBase->mName;
        profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel();

        std::string classId = player.get<ESM::NPC>()->mBase->mClass;
        if (world.getStore().get<ESM::Class>().isDynamic(classId))
            profile.mPlayerClassName = world.getStore().get<ESM::Class>().find(classId)->mName;
        else
            profile.mPlayerClassId = classId;

        profile.mPlayerCell = world.getCellName();

        profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
        profile.mInGameTime.mDay = world.getDay();
        profile.mInGameTime.mMonth = world.getMonth();
        profile.mInGameTime.mYear = world.getYear();
        profile.mTimePlayed = mTimePlayed;
        profile.mDescription = description;

        writeScreenshot(profile.mScreenshot);

        if (!slot)
            slot = getCurrentCharacter()->createSlot (profile);
        else
            slot = getCurrentCharacter()->updateSlot (slot, profile);

        // Write to a memory stream first. If there is an exception during the save process, we don't want to trash the
        // existing save file we are overwriting.
        std::stringstream stream;

        ESM::ESMWriter writer;

        const std::vector<std::string>& current =
            MWBase::Environment::get().getWorld()->getContentFiles();

        for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end();
            ++iter)
            writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0

        writer.setFormat (ESM::SavedGame::sCurrentFormat);

        // all unused
        writer.setVersion(0);
        writer.setType(0);
        writer.setAuthor("");
        writer.setDescription("");

        int recordCount =         1 // saved game header
                +MWBase::Environment::get().getJournal()->countSavedGameRecords()
                +MWBase::Environment::get().getWorld()->countSavedGameRecords()
                +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
                +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
                +MWBase::Environment::get().getWindowManager()->countSavedGameRecords()
                +MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords();
        writer.setRecordCount (recordCount);

        writer.save (stream);

        Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen();
        // Using only Cells for progress information, since they typically have the largest records by far
        listener.setProgressRange(MWBase::Environment::get().getWorld()->countSavedGameCells());
        listener.setLabel("#{sNotifyMessage4}", true);

        Loading::ScopedLoad load(&listener);

        writer.startRecord (ESM::REC_SAVE);
        slot->mProfile.save (writer);
        writer.endRecord (ESM::REC_SAVE);

        MWBase::Environment::get().getJournal()->write (writer, listener);
        MWBase::Environment::get().getDialogueManager()->write (writer, listener);
        MWBase::Environment::get().getWorld()->write (writer, listener);
        MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
        MWBase::Environment::get().getWindowManager()->write(writer, listener);
        MWBase::Environment::get().getMechanicsManager()->write(writer, listener);

        // Ensure we have written the number of records that was estimated
        if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
            std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl;

        writer.close();

        if (stream.fail())
            throw std::runtime_error("Write operation failed (memory stream)");

        // All good, write to file
        boost::filesystem::ofstream filestream (slot->mPath, std::ios::binary);
        filestream << stream.rdbuf();

        if (filestream.fail())
            throw std::runtime_error("Write operation failed (file stream)");

        Settings::Manager::setString ("character", "Saves",
            slot->mPath.parent_path().filename().string());
    }
    catch (const std::exception& e)
    {
        std::stringstream error;
        error << "Failed to save game: " << e.what();

        std::cerr << error.str() << std::endl;

        std::vector<std::string> buttons;
        buttons.push_back("#{sOk}");
        MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons);

        // If no file was written, clean up the slot
        if (slot && !boost::filesystem::exists(slot->mPath))
            getCurrentCharacter()->deleteSlot(slot);
    }
}
예제 #18
0
void MWState::StateManager::saveGame (const std::string& description, const Slot *slot)
{
    ESM::SavedGame profile;

    MWBase::World& world = *MWBase::Environment::get().getWorld();

    MWWorld::Ptr player = world.getPlayer().getPlayer();

    profile.mContentFiles = world.getContentFiles();

    profile.mPlayerName = player.getClass().getName (player);
    profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel();
    profile.mPlayerClass = player.get<ESM::NPC>()->mBase->mClass;

    profile.mPlayerCell = world.getCellName();

    profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
    profile.mInGameTime.mDay = world.getDay();
    profile.mInGameTime.mMonth = world.getMonth();
    profile.mInGameTime.mYear = world.getYear();
    profile.mTimePlayed = mTimePlayed;
    profile.mDescription = description;

    int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing
    Ogre::Image screenshot;
    world.screenshot(screenshot, screenshotW, screenshotH);
    Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
    profile.mScreenshot.resize(encoded->size());
    encoded->read(&profile.mScreenshot[0], encoded->size());

    if (!slot)
        slot = mCharacterManager.getCurrentCharacter()->createSlot (profile);
    else
        slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile);

    std::ofstream stream (slot->mPath.string().c_str());

    ESM::ESMWriter writer;

    const std::vector<std::string>& current =
        MWBase::Environment::get().getWorld()->getContentFiles();

    for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end();
        ++iter)
        writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0

    writer.setFormat (ESM::Header::CurrentFormat);
    writer.setRecordCount (
        1 // saved game header
        +MWBase::Environment::get().getJournal()->countSavedGameRecords()
        +MWBase::Environment::get().getWorld()->countSavedGameRecords()
        +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
                + 1 // global map
        );

    writer.save (stream);

    writer.startRecord (ESM::REC_SAVE);
    slot->mProfile.save (writer);
    writer.endRecord (ESM::REC_SAVE);

    MWBase::Environment::get().getJournal()->write (writer);
    MWBase::Environment::get().getWorld()->write (writer);
    MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
    MWBase::Environment::get().getWindowManager()->write(writer);

    writer.close();

    Settings::Manager::setString ("character", "Saves",
        slot->mPath.parent_path().filename().string());
}
예제 #19
0
 void CreatureStats::writeActorIdCounter (ESM::ESMWriter& esm)
 {
     esm.startRecord(ESM::REC_ACTC);
     esm.writeHNT("COUN", sActorId);
     esm.endRecord(ESM::REC_ACTC);
 }
예제 #20
0
 virtual void write(ESM::ESMWriter &esm)
 {
     esm.startRecord(ESM::REC_CAM_);
     esm.writeHNT("FIRS", mFirstPersonCam);
     esm.endRecord(ESM::REC_CAM_);
 }
예제 #21
0
 virtual void write(ESM::ESMWriter& esm)
 {
     esm.startRecord(ESM::REC_ASPL);
     esm.writeHNString("ID__", mSelectedSpell);
     esm.endRecord(ESM::REC_ASPL);
 }
예제 #22
0
파일: metadata.cpp 프로젝트: ace13/openmw
void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const
{
    esm.setFormat (mFormat);
    esm.setAuthor (mAuthor);
    esm.setDescription (mDescription);
}
예제 #23
0
void MWState::StateManager::saveGame (const std::string& description, const Slot *slot)
{
    try
    {
        ESM::SavedGame profile;

        MWBase::World& world = *MWBase::Environment::get().getWorld();

        MWWorld::Ptr player = world.getPlayerPtr();

        profile.mContentFiles = world.getContentFiles();

        profile.mPlayerName = player.getClass().getName (player);
        profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel();

        std::string classId = player.get<ESM::NPC>()->mBase->mClass;
        if (world.getStore().get<ESM::Class>().isDynamic(classId))
            profile.mPlayerClassName = world.getStore().get<ESM::Class>().find(classId)->mName;
        else
            profile.mPlayerClassId = classId;

        profile.mPlayerCell = world.getCellName();

        profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
        profile.mInGameTime.mDay = world.getDay();
        profile.mInGameTime.mMonth = world.getMonth();
        profile.mInGameTime.mYear = world.getYear();
        profile.mTimePlayed = mTimePlayed;
        profile.mDescription = description;

        int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing
        Ogre::Image screenshot;
        world.screenshot(screenshot, screenshotW, screenshotH);
        Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
        profile.mScreenshot.resize(encoded->size());
        encoded->read(&profile.mScreenshot[0], encoded->size());

        if (!slot)
            slot = getCurrentCharacter()->createSlot (profile);
        else
            slot = getCurrentCharacter()->updateSlot (slot, profile);

        boost::filesystem::ofstream stream (slot->mPath, std::ios::binary);

        ESM::ESMWriter writer;

        const std::vector<std::string>& current =
            MWBase::Environment::get().getWorld()->getContentFiles();

        for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end();
            ++iter)
            writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0

        writer.setFormat (ESM::Header::CurrentFormat);
        int recordCount =         1 // saved game header
                +MWBase::Environment::get().getJournal()->countSavedGameRecords()
                +MWBase::Environment::get().getWorld()->countSavedGameRecords()
                +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
                +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
                +MWBase::Environment::get().getWindowManager()->countSavedGameRecords();
        writer.setRecordCount (recordCount);

        writer.save (stream);

        Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen();
        listener.setProgressRange(recordCount);
        listener.setLabel("#{sNotifyMessage4}");

        Loading::ScopedLoad load(&listener);

        writer.startRecord (ESM::REC_SAVE);
        slot->mProfile.save (writer);
        writer.endRecord (ESM::REC_SAVE);
        listener.increaseProgress();

        MWBase::Environment::get().getJournal()->write (writer, listener);
        MWBase::Environment::get().getDialogueManager()->write (writer, listener);
        MWBase::Environment::get().getWorld()->write (writer, listener);
        MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
        MWBase::Environment::get().getWindowManager()->write(writer, listener);

        // Ensure we have written the number of records that was estimated
        if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
            std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl;

        writer.close();

        if (stream.fail())
            throw std::runtime_error("Write operation failed");

        Settings::Manager::setString ("character", "Saves",
            slot->mPath.parent_path().filename().string());
    }
    catch (const std::exception& e)
    {
        std::stringstream error;
        error << "Failed to save game: " << e.what();

        std::cerr << error.str() << std::endl;

        std::vector<std::string> buttons;
        buttons.push_back("#{sOk}");
        MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons);

        // If no file was written, clean up the slot
        if (slot && !boost::filesystem::exists(slot->mPath))
            getCurrentCharacter()->deleteSlot(slot);
    }
}