storing and loading the journal

actorid
Marc Zinnschlag 11 years ago
parent 7d8e3ac651
commit 2293b92efe

@ -5,10 +5,18 @@
#include <deque>
#include <map>
#include <libs/platform/stdint.h>
#include "../mwdialogue/journalentry.hpp"
#include "../mwdialogue/topic.hpp"
#include "../mwdialogue/quest.hpp"
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase
{
/// \brief Interface for the player's journal (implemented in MWDialogue)
@ -69,6 +77,12 @@ namespace MWBase
virtual TTopicIter topicEnd() const = 0;
///< Iterator pointing past the last topic.
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
};
}

@ -3,6 +3,8 @@
#include <stdexcept>
#include <components/esm/journalentry.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -30,11 +32,19 @@ namespace MWDialogue
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + topic);
}
Entry::Entry (const ESM::JournalEntry& record) : mInfoId (record.mInfo), mText (record.mText) {}
std::string Entry::getText() const
{
return mText;
}
void Entry::write (ESM::JournalEntry& entry) const
{
entry.mInfo = mInfoId;
entry.mText = mText;
}
JournalEntry::JournalEntry() {}
@ -42,6 +52,16 @@ namespace MWDialogue
: Entry (topic, infoId), mTopic (topic)
{}
JournalEntry::JournalEntry (const ESM::JournalEntry& record)
: Entry (record), mTopic (record.mTopic)
{}
void JournalEntry::write (ESM::JournalEntry& entry) const
{
Entry::write (entry);
entry.mTopic = mTopic;
}
JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index)
{
return JournalEntry (topic, idFromIndex (topic, index));
@ -72,6 +92,19 @@ namespace MWDialogue
: JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth)
{}
StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record)
: JournalEntry (record), mDay (record.mDay), mMonth (record.mMonth),
mDayOfMonth (record.mDayOfMonth)
{}
void StampedJournalEntry::write (ESM::JournalEntry& entry) const
{
JournalEntry::write (entry);
entry.mDay = mDay;
entry.mMonth = mMonth;
entry.mDayOfMonth = mDayOfMonth;
}
StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
{
int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed");

@ -3,6 +3,11 @@
#include <string>
namespace ESM
{
struct JournalEntry;
}
namespace MWDialogue
{
/// \brief Basic quest/dialogue/topic entry
@ -15,7 +20,11 @@ namespace MWDialogue
Entry (const std::string& topic, const std::string& infoId);
Entry (const ESM::JournalEntry& record);
std::string getText() const;
void write (ESM::JournalEntry& entry) const;
};
/// \brief A dialogue entry
@ -29,6 +38,10 @@ namespace MWDialogue
JournalEntry (const std::string& topic, const std::string& infoId);
JournalEntry (const ESM::JournalEntry& record);
void write (ESM::JournalEntry& entry) const;
static JournalEntry makeFromQuest (const std::string& topic, int index);
static std::string idFromIndex (const std::string& topic, int index);
@ -46,6 +59,10 @@ namespace MWDialogue
StampedJournalEntry (const std::string& topic, const std::string& infoId,
int day, int month, int dayOfMonth);
StampedJournalEntry (const ESM::JournalEntry& record);
void write (ESM::JournalEntry& entry) const;
static StampedJournalEntry makeFromQuest (const std::string& topic, int index);
};
}

@ -1,6 +1,13 @@
#include "journalimp.hpp"
#include <iterator>
#include <components/esm/esmwriter.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/queststate.hpp>
#include <components/esm/journalentry.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
@ -26,6 +33,22 @@ namespace MWDialogue
return iter->second;
}
Topic& Journal::getTopic (const std::string& id)
{
TTopicContainer::iterator iter = mTopics.find (id);
if (iter==mTopics.end())
{
std::pair<TTopicContainer::iterator, bool> result
= mTopics.insert (std::make_pair (id, Topic (id)));
iter = result.first;
}
return iter->second;
}
Journal::Journal()
{}
@ -66,17 +89,9 @@ namespace MWDialogue
void Journal::addTopic (const std::string& topicId, const std::string& infoId)
{
TTopicContainer::iterator iter = mTopics.find (topicId);
Topic& topic = getTopic (topicId);
if (iter==mTopics.end())
{
std::pair<TTopicContainer::iterator, bool> result
= mTopics.insert (std::make_pair (topicId, Topic (topicId)));
iter = result.first;
}
iter->second.addEntry (JournalEntry (topicId, infoId));
topic.addEntry (JournalEntry (topicId, infoId));
}
int Journal::getJournalIndex (const std::string& id) const
@ -118,4 +133,104 @@ namespace MWDialogue
{
return mTopics.end();
}
int Journal::countSavedGameRecords() const
{
int count = static_cast<int> (mQuests.size());
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
count += std::distance (iter->second.begin(), iter->second.end());
count += std::distance (mJournal.begin(), mJournal.end());
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
count += std::distance (iter->second.begin(), iter->second.end());
return count;
}
void Journal::write (ESM::ESMWriter& writer) 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);
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);
}
}
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);
}
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);
}
}
}
void Journal::readRecord (ESM::ESMReader& reader, int32_t type)
{
if (type==ESM::REC_JOUR)
{
ESM::JournalEntry record;
record.load (reader);
switch (record.mType)
{
case ESM::JournalEntry::Type_Quest:
getQuest (record.mTopic).insertEntry (record);
break;
case ESM::JournalEntry::Type_Journal:
mJournal.push_back (record);
break;
case ESM::JournalEntry::Type_Topic:
getTopic (record.mTopic).insertEntry (record);
break;
}
}
else if (type==ESM::REC_QUES)
{
ESM::QuestState record;
record.load (reader);
mQuests.insert (std::make_pair (record.mTopic, record));
}
}
}

@ -15,8 +15,12 @@ namespace MWDialogue
TQuestContainer mQuests;
TTopicContainer mTopics;
private:
Quest& getQuest (const std::string& id);
Topic& getTopic (const std::string& id);
public:
Journal();
@ -55,6 +59,12 @@ namespace MWDialogue
virtual TTopicIter topicEnd() const;
///< Iterator pointing past the last topic.
virtual int countSavedGameRecords() const;
virtual void write (ESM::ESMWriter& writer) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
};
}

@ -1,6 +1,8 @@
#include "quest.hpp"
#include <components/esm/queststate.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
@ -16,6 +18,10 @@ namespace MWDialogue
: Topic (topic), mIndex (0), mFinished (false)
{}
Quest::Quest (const ESM::QuestState& state)
: Topic (state.mTopic), mIndex (state.mState), mFinished (state.mFinished!=0)
{}
std::string Quest::getName() const
{
const ESM::Dialogue *dialogue =
@ -87,4 +93,11 @@ namespace MWDialogue
mEntries.push_back (entry); // we want slicing here
}
void Quest::write (ESM::QuestState& state) const
{
state.mTopic = getTopic();
state.mState = mIndex;
state.mFinished = mFinished;
}
}

@ -3,6 +3,11 @@
#include "topic.hpp"
namespace ESM
{
struct QuestState;
}
namespace MWDialogue
{
/// \brief A quest in progress or a completed quest
@ -17,6 +22,8 @@ namespace MWDialogue
Quest (const std::string& topic);
Quest (const ESM::QuestState& state);
virtual std::string getName() const;
///< May be an empty string
@ -31,6 +38,8 @@ namespace MWDialogue
///< Add entry and adjust index accordingly.
///
/// \note Redundant entries are ignored, but the index is still adjusted.
void write (ESM::QuestState& state) const;
};
}

@ -27,6 +27,16 @@ namespace MWDialogue
mEntries.push_back (entry); // we want slicing here
}
void Topic::insertEntry (const ESM::JournalEntry& entry)
{
mEntries.push_back (entry);
}
std::string Topic::getTopic() const
{
return mTopic;
}
std::string Topic::getName() const
{
return mName;

@ -6,6 +6,11 @@
#include "journalentry.hpp"
namespace ESM
{
struct JournalEntry;
}
namespace MWDialogue
{
/// \brief Collection of seen responses for a topic
@ -35,7 +40,13 @@ namespace MWDialogue
///
/// \note Redundant entries are ignored.
virtual std::string getName () const;
void insertEntry (const ESM::JournalEntry& entry);
///< Add entry without checking for redundant entries or modifying the state of the
/// topic otherwise
std::string getTopic() const;
virtual std::string getName() const;
TEntryIter begin() const;
///< Iterator pointing to the begin of the journal for this topic.

@ -99,11 +99,17 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
std::ofstream stream (slot->mPath.string().c_str());
ESM::ESMWriter writer;
writer.setFormat (ESM::Header::CurrentFormat);
writer.setRecordCount (
1+ // saved game header
MWBase::Environment::get().getJournal()->countSavedGameRecords());
writer.save (stream);
writer.startRecord ("SAVE");
writer.startRecord (ESM::REC_SAVE);
slot->mProfile.save (writer);
writer.endRecord ("SAVE");
writer.endRecord (ESM::REC_SAVE);
MWBase::Environment::get().getJournal()->write (writer);
/// \todo write saved game data
writer.close();
@ -121,10 +127,32 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
ESM::ESMReader reader;
reader.open (slot->mPath.string());
reader.getRecName(); // don't need to read that here
reader.getRecHeader();
while (reader.hasMoreRecs())
{
ESM::NAME n = reader.getRecName();
reader.getRecHeader();
switch (n.val)
{
case ESM::REC_SAVE:
// don't need to read that here
reader.skipRecord();
break;
/// \todo read saved game data
case ESM::REC_JOUR:
case ESM::REC_QUES:
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
break;
default:
// ignore invalid records
/// \todo log error
reader.skipRecord();
}
}
mCharacterManager.setCurrentCharacter(character);

Loading…
Cancel
Save