forked from mirror/openmw-tes3mp
storing and loading the journal
This commit is contained in:
parent
7d8e3ac651
commit
2293b92efe
10 changed files with 278 additions and 18 deletions
|
@ -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.save (stream);
|
||||
writer.startRecord ("SAVE");
|
||||
slot->mProfile.save (writer);
|
||||
writer.endRecord ("SAVE");
|
||||
writer.setRecordCount (
|
||||
1+ // saved game header
|
||||
MWBase::Environment::get().getJournal()->countSavedGameRecords());
|
||||
|
||||
writer.save (stream);
|
||||
|
||||
writer.startRecord (ESM::REC_SAVE);
|
||||
slot->mProfile.save (writer);
|
||||
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();
|
||||
|
||||
/// \todo read saved game data
|
||||
switch (n.val)
|
||||
{
|
||||
case ESM::REC_SAVE:
|
||||
|
||||
// don't need to read that here
|
||||
reader.skipRecord();
|
||||
break;
|
||||
|
||||
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…
Reference in a new issue