You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwdialogue/journalimp.cpp

321 lines
9.3 KiB
C++

#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/class.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwgui/messagebox.hpp"
namespace MWDialogue
{
Quest& Journal::getQuest (const std::string& id)
{
TQuestContainer::iterator iter = mQuests.find (id);
if (iter==mQuests.end())
{
std::pair<TQuestContainer::iterator, bool> result =
mQuests.insert (std::make_pair (id, Quest (id)));
iter = result.first;
}
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;
}
bool Journal::isThere (const std::string& topicId, const std::string& infoId) const
{
if (const ESM::Dialogue *dialogue =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().search (topicId))
{
if (infoId.empty())
return true;
for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin());
iter!=dialogue->mInfo.end(); ++iter)
if (iter->mId == infoId)
return true;
}
return false;
}
Journal::Journal()
{}
void Journal::clear()
{
mJournal.clear();
mQuests.clear();
mTopics.clear();
}
/*
Start of tes3mp addition
Make it possible to check whether a journal entry already exists from elsewhere in the code
*/
bool Journal::hasEntry(const std::string& id, int index)
{
std::string infoId = JournalEntry::idFromIndex(id, index);
for (TEntryIter i = mJournal.begin(); i != mJournal.end(); ++i)
if (i->mTopic == id && i->mInfoId == infoId)
return true;
return false;
}
/*
End of tes3mp addition
*/
/*
Start of tes3mp change (minor)
Make it possible to override current time when adding journal entries, by adding
optional timestamp override arguments
*/
void Journal::addEntry (const std::string& id, int index, const MWWorld::Ptr& actor, int daysPassed, int month, int day)
/*
End of tes3mp change (major)
*/
{
// bail out if we already have heard this...
std::string infoId = JournalEntry::idFromIndex (id, index);
for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i)
if (i->mTopic == id && i->mInfoId == infoId)
{
if (getJournalIndex(id) < index)
{
setJournalIndex(id, index);
MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}");
}
return;
}
StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index, actor);
/*
Start of tes3mp addition
Override the entry's timestamp if provided with valid time arguments
*/
if (daysPassed != -1 && month != -1 && day != -1)
{
entry.mDay = daysPassed;
entry.mMonth = month;
entry.mDayOfMonth = day;
}
/*
End of tes3mp addition
*/
Quest& quest = getQuest (id);
quest.addEntry (entry); // we are doing slicing on purpose here
// there is no need to show empty entries in journal
if (!entry.getText().empty())
{
mJournal.push_back (entry);
MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}");
}
}
void Journal::setJournalIndex (const std::string& id, int index)
{
Quest& quest = getQuest (id);
quest.setIndex (index);
}
void Journal::addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor)
{
Topic& topic = getTopic (topicId);
JournalEntry entry(topicId, infoId, actor);
entry.mActorName = actor.getClass().getName(actor);
topic.addEntry (entry);
}
void Journal::removeLastAddedTopicResponse(const std::string &topicId, const std::string &actorName)
{
Topic& topic = getTopic (topicId);
topic.removeLastAddedResponse(actorName);
if (topic.begin() == topic.end())
mTopics.erase(mTopics.find(topicId)); // All responses removed -> remove topic
}
int Journal::getJournalIndex (const std::string& id) const
{
TQuestContainer::const_iterator iter = mQuests.find (id);
if (iter==mQuests.end())
return 0;
return iter->second.getIndex();
}
Journal::TEntryIter Journal::begin() const
{
return mJournal.begin();
}
Journal::TEntryIter Journal::end() const
{
return mJournal.end();
}
Journal::TQuestIter Journal::questBegin() const
{
return mQuests.begin();
}
Journal::TQuestIter Journal::questEnd() const
{
return mQuests.end();
}
Journal::TTopicIter Journal::topicBegin() const
{
return mTopics.begin();
}
Journal::TTopicIter Journal::topicEnd() const
{
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, 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);
for (Topic::TEntryIter entryIter (quest.begin()); entryIter!=quest.end(); ++entryIter)
{
ESM::JournalEntry entry;
entry.mType = ESM::JournalEntry::Type_Quest;
entry.mTopic = quest.getTopic();
entryIter->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 entryIter (topic.begin()); entryIter!=topic.end(); ++entryIter)
{
ESM::JournalEntry entry;
entry.mType = ESM::JournalEntry::Type_Topic;
entry.mTopic = topic.getTopic();
entryIter->write (entry);
writer.startRecord (ESM::REC_JOUR);
entry.save (writer);
writer.endRecord (ESM::REC_JOUR);
}
}
}
void Journal::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY)
{
ESM::JournalEntry record;
record.load (reader);
if (isThere (record.mTopic, record.mInfo))
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);
if (isThere (record.mTopic))
{
std::pair<TQuestContainer::iterator, bool> result = mQuests.insert (std::make_pair (record.mTopic, record));
// reapply quest index, this is to handle users upgrading from only
// Morrowind.esm (no quest states) to Morrowind.esm + Tribunal.esm
result.first->second.setIndex(record.mState);
}
}
}
}