storing and loading the journal

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

@ -5,10 +5,18 @@
#include <deque> #include <deque>
#include <map> #include <map>
#include <libs/platform/stdint.h>
#include "../mwdialogue/journalentry.hpp" #include "../mwdialogue/journalentry.hpp"
#include "../mwdialogue/topic.hpp" #include "../mwdialogue/topic.hpp"
#include "../mwdialogue/quest.hpp" #include "../mwdialogue/quest.hpp"
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase namespace MWBase
{ {
/// \brief Interface for the player's journal (implemented in MWDialogue) /// \brief Interface for the player's journal (implemented in MWDialogue)
@ -69,6 +77,12 @@ namespace MWBase
virtual TTopicIter topicEnd() const = 0; virtual TTopicIter topicEnd() const = 0;
///< Iterator pointing past the last topic. ///< 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 <stdexcept>
#include <components/esm/journalentry.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -30,11 +32,19 @@ namespace MWDialogue
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + topic); 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 std::string Entry::getText() const
{ {
return mText; return mText;
} }
void Entry::write (ESM::JournalEntry& entry) const
{
entry.mInfo = mInfoId;
entry.mText = mText;
}
JournalEntry::JournalEntry() {} JournalEntry::JournalEntry() {}
@ -42,6 +52,16 @@ namespace MWDialogue
: Entry (topic, infoId), mTopic (topic) : 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) JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index)
{ {
return JournalEntry (topic, idFromIndex (topic, index)); return JournalEntry (topic, idFromIndex (topic, index));
@ -72,6 +92,19 @@ namespace MWDialogue
: JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) : 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) StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
{ {
int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed"); int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed");

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

@ -1,6 +1,13 @@
#include "journalimp.hpp" #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 "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -26,6 +33,22 @@ namespace MWDialogue
return iter->second; 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() Journal::Journal()
{} {}
@ -66,17 +89,9 @@ namespace MWDialogue
void Journal::addTopic (const std::string& topicId, const std::string& infoId) 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()) topic.addEntry (JournalEntry (topicId, infoId));
{
std::pair<TTopicContainer::iterator, bool> result
= mTopics.insert (std::make_pair (topicId, Topic (topicId)));
iter = result.first;
}
iter->second.addEntry (JournalEntry (topicId, infoId));
} }
int Journal::getJournalIndex (const std::string& id) const int Journal::getJournalIndex (const std::string& id) const
@ -118,4 +133,104 @@ namespace MWDialogue
{ {
return mTopics.end(); 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; TQuestContainer mQuests;
TTopicContainer mTopics; TTopicContainer mTopics;
private:
Quest& getQuest (const std::string& id); Quest& getQuest (const std::string& id);
Topic& getTopic (const std::string& id);
public: public:
Journal(); Journal();
@ -55,6 +59,12 @@ namespace MWDialogue
virtual TTopicIter topicEnd() const; virtual TTopicIter topicEnd() const;
///< Iterator pointing past the last topic. ///< 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 "quest.hpp"
#include <components/esm/queststate.hpp>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -16,6 +18,10 @@ namespace MWDialogue
: Topic (topic), mIndex (0), mFinished (false) : 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 std::string Quest::getName() const
{ {
const ESM::Dialogue *dialogue = const ESM::Dialogue *dialogue =
@ -87,4 +93,11 @@ namespace MWDialogue
mEntries.push_back (entry); // we want slicing here 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" #include "topic.hpp"
namespace ESM
{
struct QuestState;
}
namespace MWDialogue namespace MWDialogue
{ {
/// \brief A quest in progress or a completed quest /// \brief A quest in progress or a completed quest
@ -17,6 +22,8 @@ namespace MWDialogue
Quest (const std::string& topic); Quest (const std::string& topic);
Quest (const ESM::QuestState& state);
virtual std::string getName() const; virtual std::string getName() const;
///< May be an empty string ///< May be an empty string
@ -31,6 +38,8 @@ namespace MWDialogue
///< Add entry and adjust index accordingly. ///< Add entry and adjust index accordingly.
/// ///
/// \note Redundant entries are ignored, but the index is still adjusted. /// \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 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 std::string Topic::getName() const
{ {
return mName; return mName;

@ -6,6 +6,11 @@
#include "journalentry.hpp" #include "journalentry.hpp"
namespace ESM
{
struct JournalEntry;
}
namespace MWDialogue namespace MWDialogue
{ {
/// \brief Collection of seen responses for a topic /// \brief Collection of seen responses for a topic
@ -35,7 +40,13 @@ namespace MWDialogue
/// ///
/// \note Redundant entries are ignored. /// \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; TEntryIter begin() const;
///< Iterator pointing to the begin of the journal for this topic. ///< 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()); std::ofstream stream (slot->mPath.string().c_str());
ESM::ESMWriter writer; ESM::ESMWriter writer;
writer.setFormat (ESM::Header::CurrentFormat); writer.setFormat (ESM::Header::CurrentFormat);
writer.setRecordCount (
1+ // saved game header
MWBase::Environment::get().getJournal()->countSavedGameRecords());
writer.save (stream); writer.save (stream);
writer.startRecord ("SAVE");
writer.startRecord (ESM::REC_SAVE);
slot->mProfile.save (writer); slot->mProfile.save (writer);
writer.endRecord ("SAVE"); writer.endRecord (ESM::REC_SAVE);
MWBase::Environment::get().getJournal()->write (writer);
/// \todo write saved game data /// \todo write saved game data
writer.close(); writer.close();
@ -121,10 +127,32 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
ESM::ESMReader reader; ESM::ESMReader reader;
reader.open (slot->mPath.string()); reader.open (slot->mPath.string());
reader.getRecName(); // don't need to read that here while (reader.hasMoreRecs())
reader.getRecHeader(); {
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); mCharacterManager.setCurrentCharacter(character);

Loading…
Cancel
Save