diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 25b2a45050..fd4b97acb9 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -651,7 +651,7 @@ void Record::print() // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? - std::vector::iterator iit; + ESM::Dialogue::InfoContainer::iterator iit; for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++) std::cout << "INFO!" << iit->mId << std::endl; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 323b450647..fe37f37ff7 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -289,7 +289,7 @@ namespace MWDialogue // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. - for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) { if (iter->mId == info->mId) @@ -467,7 +467,7 @@ namespace MWDialogue // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. - for (std::vector::const_iterator iter = mDialogueMap[mLastTopic].mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = mDialogueMap[mLastTopic].mInfo.begin(); iter!=mDialogueMap[mLastTopic].mInfo.end(); ++iter) { if (iter->mId == info->mId) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index b1c700e315..8b9ee9184f 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -621,7 +621,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue bool infoRefusal = false; // Iterate over topic responses to find a matching one - for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) @@ -646,7 +646,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue const ESM::Dialogue& infoRefusalDialogue = *dialogues.find ("Info Refusal"); - for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter, invertDisposition)) { infos.push_back(&*iter); @@ -660,7 +660,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const { - for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 9463e4c45b..55574bf3eb 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -20,7 +20,7 @@ namespace MWDialogue const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (topic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == mInfoId) { @@ -73,7 +73,7 @@ namespace MWDialogue const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (topic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mData.mDisposition==index) /// \todo cleanup info structure { diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 724d531cfb..04aa0534dd 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -56,7 +56,7 @@ namespace MWDialogue if (infoId.empty()) return true; - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == infoId) return true; diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 8ecb4bd13a..a699286a15 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -27,7 +27,7 @@ namespace MWDialogue const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mQuestStatus==ESM::DialInfo::QS_Name) return iter->mResponse; @@ -45,7 +45,7 @@ namespace MWDialogue const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mData.mDisposition==index && iter->mQuestStatus!=ESM::DialInfo::QS_Name) { @@ -53,8 +53,6 @@ namespace MWDialogue mFinished = true; else if (iter->mQuestStatus==ESM::DialInfo::QS_Restart) mFinished = false; - - // Don't return here. Quest status may actually be in a different info record, since we don't merge these (yet?) } // The index must be set even if no related journal entry was found @@ -73,7 +71,7 @@ namespace MWDialogue const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (entry.mTopic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == entry.mInfoId) { diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index ed140434b5..1fdf3c5a50 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -27,8 +27,6 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) { listener->setProgressRange(1000); - std::set missing; - ESM::Dialogue *dialogue = 0; /// \todo Move this to somewhere else. ESMReader? @@ -72,9 +70,10 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) if (n.val == ESM::REC_INFO) { std::string id = esm.getHNOString("INAM"); if (dialogue) { - dialogue->mInfo.push_back(ESM::DialInfo()); - dialogue->mInfo.back().mId = id; - dialogue->mInfo.back().load(esm); + ESM::DialInfo info; + info.mId = id; + info.load(esm); + dialogue->addInfo(info, esm.getIndex() != 0); } else { std::cerr << "error: info record without dialog" << std::endl; esm.skipRecord(); @@ -84,9 +83,9 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } else if (n.val == ESM::REC_SKIL) { mSkills.load (esm); } else { - // Not found (this would be an error later) - esm.skipRecord(); - missing.insert(n.toString()); + std::stringstream error; + error << "Unknown record: " << n.toString(); + throw std::runtime_error(error.str()); } } else { // Load it @@ -113,19 +112,6 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000); } - - /* This information isn't needed on screen. But keep the code around - for debugging purposes later. - - cout << "\n" << mStores.size() << " record types:\n"; - for(RecListList::iterator it = mStores.begin(); it != mStores.end(); it++) - cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; - cout << "\nNot implemented yet: "; - for(set::iterator it = missing.begin(); - it != missing.end(); it++ ) - cout << *it << " "; - cout << endl; - */ } void ESMStore::setUp() diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index fb43ee8586..5adf409bba 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -1,5 +1,7 @@ #include "loaddial.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -43,4 +45,49 @@ void Dialogue::save(ESMWriter &esm) const mInfo.clear(); } +void Dialogue::addInfo(const ESM::DialInfo& info, bool merge) +{ + if (!merge || mInfo.empty() || info.mNext.empty()) + { + mLookup[info.mId] = mInfo.insert(mInfo.end(), info); + return; + } + if (info.mPrev.empty()) + { + mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); + return; + } + + ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); + + std::map::iterator lookup; + lookup = mLookup.find(info.mPrev); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[info.mId] = mInfo.insert(++it, info); + return; + } + + lookup = mLookup.find(info.mNext); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[info.mId] = mInfo.insert(it, info); + return; + } + + lookup = mLookup.find(info.mId); + if (lookup != mLookup.end()) + { + it = lookup->second; + *it = info; + return; + } + + std::cerr << "Failed to insert info " << info.mId << std::endl; +} + } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 63d78833e1..6ec5527f9f 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -2,7 +2,8 @@ #define OPENMW_ESM_DIAL_H #include -#include +#include +#include #include "loadinfo.hpp" @@ -33,11 +34,22 @@ struct Dialogue std::string mId; signed char mType; - std::vector mInfo; + + typedef std::list InfoContainer; + + typedef std::map LookupMap; + + InfoContainer mInfo; + + // This is only used during the loading phase to speed up DialInfo merging. + LookupMap mLookup; void load(ESMReader &esm); void save(ESMWriter &esm) const; + /// @param merge Merge with existing list, or just push each record to the end of the list? + void addInfo (const ESM::DialInfo& info, bool merge); + void blank(); ///< Set record to default state (does not touch the ID and does not change the type). };