mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 11:26:37 +00:00 
			
		
		
		
	Topic Info verifier with fixes to InfoSelectWrapper class
This commit is contained in:
		
							parent
							
								
									e89609e5b0
								
							
						
					
					
						commit
						8668eccd0b
					
				
					 6 changed files with 591 additions and 6 deletions
				
			
		|  | @ -42,7 +42,7 @@ opencs_units_noqt (model/tools | |||
|     mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck | ||||
|     birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck | ||||
|     startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck | ||||
|     mergestages gmstcheck | ||||
|     mergestages gmstcheck topicinfocheck | ||||
|     ) | ||||
| 
 | ||||
| opencs_hdrs_noqt (model/tools | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ | |||
| #include "magiceffectcheck.hpp" | ||||
| #include "mergeoperation.hpp" | ||||
| #include "gmstcheck.hpp" | ||||
| #include "topicinfocheck.hpp" | ||||
| 
 | ||||
| CSMDoc::OperationHolder *CSMTools::Tools::get (int type) | ||||
| { | ||||
|  | @ -114,6 +115,19 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() | |||
| 
 | ||||
|         mVerifierOperation->appendStage (new GmstCheckStage (mData.getGmsts())); | ||||
| 
 | ||||
|         mVerifierOperation->appendStage (new TopicInfoCheckStage (mData.getTopicInfos(), | ||||
|                                                                   mData.getCells(), | ||||
|                                                                   mData.getClasses(), | ||||
|                                                                   mData.getFactions(), | ||||
|                                                                   mData.getGmsts(), | ||||
|                                                                   mData.getGlobals(), | ||||
|                                                                   mData.getJournals(), | ||||
|                                                                   mData.getRaces(), | ||||
|                                                                   mData.getRegions(), | ||||
|                                                                   mData.getTopics(), | ||||
|                                                                   mData.getReferenceables().getDataSet(), | ||||
|                                                                   mData.getResources (CSMWorld::UniversalId::Type_SoundsRes))); | ||||
| 
 | ||||
|         mVerifier.setOperation (mVerifierOperation); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										441
									
								
								apps/opencs/model/tools/topicinfocheck.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										441
									
								
								apps/opencs/model/tools/topicinfocheck.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,441 @@ | |||
| #include "topicinfocheck.hpp" | ||||
| 
 | ||||
| #include <sstream> | ||||
| 
 | ||||
| #include "../world/infoselectwrapper.hpp" | ||||
| 
 | ||||
| CSMTools::TopicInfoCheckStage::TopicInfoCheckStage( | ||||
|     const CSMWorld::InfoCollection& topicInfos, | ||||
|     const CSMWorld::IdCollection<CSMWorld::Cell>& cells, | ||||
|     const CSMWorld::IdCollection<ESM::Class>& classes, | ||||
|     const CSMWorld::IdCollection<ESM::Faction>& factions, | ||||
|     const CSMWorld::IdCollection<ESM::GameSetting>& gmsts, | ||||
|     const CSMWorld::IdCollection<ESM::Global>& globals, | ||||
|     const CSMWorld::IdCollection<ESM::Dialogue>& journals, | ||||
|     const CSMWorld::IdCollection<ESM::Race>& races, | ||||
|     const CSMWorld::IdCollection<ESM::Region>& regions, | ||||
|     const CSMWorld::IdCollection<ESM::Dialogue> &topics, | ||||
|     const CSMWorld::RefIdData& referencables, | ||||
|     const CSMWorld::Resources& soundFiles) | ||||
|     : mTopicInfos(topicInfos), | ||||
|       mCells(cells), | ||||
|       mClasses(classes), | ||||
|       mFactions(factions), | ||||
|       mGameSettings(gmsts), | ||||
|       mGlobals(globals), | ||||
|       mJournals(journals), | ||||
|       mRaces(races), | ||||
|       mRegions(regions), | ||||
|       mTopics(topics), | ||||
|       mReferencables(referencables), | ||||
|       mSoundFiles(soundFiles) | ||||
| {} | ||||
| 
 | ||||
| int CSMTools::TopicInfoCheckStage::setup() | ||||
| { | ||||
|     // Generate list of cell names for reference checking
 | ||||
| 
 | ||||
|     mCellNames.clear(); | ||||
|     for (int i = 0; i < mCells.getSize(); ++i) | ||||
|     { | ||||
|         const CSMWorld::Record<CSMWorld::Cell>& cellRecord = mCells.getRecord(i); | ||||
| 
 | ||||
|         if (cellRecord.isDeleted()) | ||||
|             continue; | ||||
| 
 | ||||
|         mCellNames.insert(cellRecord.get().mName); | ||||
|     } | ||||
|     // Cell names can also include region names
 | ||||
|     for (int i = 0; i < mRegions.getSize(); ++i) | ||||
|     { | ||||
|         const CSMWorld::Record<ESM::Region>& regionRecord = mRegions.getRecord(i); | ||||
| 
 | ||||
|         if (regionRecord.isDeleted()) | ||||
|             continue; | ||||
| 
 | ||||
|         mCellNames.insert(regionRecord.get().mName); | ||||
|     } | ||||
|     // Default cell name
 | ||||
|     int index = mGameSettings.searchId("sDefaultCellname"); | ||||
|     if (index != -1) | ||||
|     { | ||||
|         const CSMWorld::Record<ESM::GameSetting>& gmstRecord = mGameSettings.getRecord(index); | ||||
| 
 | ||||
|         if (!gmstRecord.isDeleted() && gmstRecord.get().mValue.getType() == ESM::VT_String) | ||||
|         { | ||||
|             mCellNames.insert(gmstRecord.get().mValue.getString()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return mTopicInfos.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<CSMWorld::Info>& infoRecord = mTopicInfos.getRecord(stage); | ||||
| 
 | ||||
|     if (infoRecord.isDeleted()) | ||||
|         return; | ||||
| 
 | ||||
|     const CSMWorld::Info& topicInfo = infoRecord.get(); | ||||
| 
 | ||||
|     // There should always be a topic that matches
 | ||||
|     int topicIndex = mTopics.searchId(topicInfo.mTopicId); | ||||
| 
 | ||||
|     const CSMWorld::Record<ESM::Dialogue>& topicRecord = mTopics.getRecord(topicIndex); | ||||
| 
 | ||||
|     if (topicRecord.isDeleted()) | ||||
|         return; | ||||
| 
 | ||||
|     const ESM::Dialogue& topic = topicRecord.get(); | ||||
| 
 | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_TopicInfo, topicInfo.mId); | ||||
| 
 | ||||
|     // Check fields
 | ||||
| 
 | ||||
|     if (!topicInfo.mActor.empty()) | ||||
|     { | ||||
|         verifyActor(topicInfo.mActor, id, messages); | ||||
|     } | ||||
| 
 | ||||
|     if (!topicInfo.mClass.empty()) | ||||
|     { | ||||
|         verifyId(topicInfo.mClass, mClasses, id, messages); | ||||
|     } | ||||
| 
 | ||||
|     if (!topicInfo.mCell.empty()) | ||||
|     { | ||||
|         verifyCell(topicInfo.mCell, id, messages); | ||||
|     } | ||||
| 
 | ||||
|     if (!topicInfo.mFaction.empty()) | ||||
|     { | ||||
|         if (verifyId(topicInfo.mFaction, mFactions, id, messages)) | ||||
|         { | ||||
|             verifyFactionRank(topicInfo.mFaction, topicInfo.mData.mRank, id, messages); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!topicInfo.mPcFaction.empty()) | ||||
|     { | ||||
|         if (verifyId(topicInfo.mPcFaction, mFactions, id, messages)) | ||||
|         { | ||||
|             verifyFactionRank(topicInfo.mPcFaction, topicInfo.mData.mPCrank, id, messages); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (topicInfo.mData.mGender < -1 || topicInfo.mData.mGender > 1) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
|         messages.add(id, "Gender: Value is invalid", "", CSMDoc::Message::Severity_Error); | ||||
|     } | ||||
| 
 | ||||
|     if (!topicInfo.mRace.empty()) | ||||
|     { | ||||
|         verifyId(topicInfo.mRace, mRaces, id, messages); | ||||
|     } | ||||
| 
 | ||||
|     if (!topicInfo.mSound.empty()) | ||||
|     { | ||||
|         verifySound(topicInfo.mSound, id, messages); | ||||
|     } | ||||
| 
 | ||||
|     if (topicInfo.mResponse.empty() && topic.mType != ESM::Dialogue::Voice) | ||||
|     { | ||||
|         messages.add(id, "Response is empty", "", CSMDoc::Message::Severity_Warning); | ||||
|     } | ||||
| 
 | ||||
|     // Check info conditions
 | ||||
| 
 | ||||
|     for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator it = topicInfo.mSelects.begin(); | ||||
|          it != topicInfo.mSelects.end(); ++it) | ||||
|     { | ||||
|         verifySelectStruct((*it), id, messages); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Verification functions
 | ||||
| 
 | ||||
| bool CSMTools::TopicInfoCheckStage::verifyActor(const std::string& actor, const CSMWorld::UniversalId& id, | ||||
|     CSMDoc::Messages& messages) | ||||
| { | ||||
|     const std::string specifier = "Actor"; | ||||
| 
 | ||||
|     CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(actor); | ||||
| 
 | ||||
|     if (index.first == -1) | ||||
|     { | ||||
|         writeMissingIdError(specifier, actor, id, messages); | ||||
|         return false; | ||||
|     } | ||||
|     else if (mReferencables.getRecord(index).isDeleted()) | ||||
|     { | ||||
|         writeDeletedRecordError(specifier, actor, id, messages); | ||||
|         return false; | ||||
|     } | ||||
|     else if (index.second != CSMWorld::UniversalId::Type_Npc && index.second != CSMWorld::UniversalId::Type_Creature) | ||||
|     { | ||||
|         writeInvalidTypeError(specifier, actor, index.second, "NPC or Creature", id, messages); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CSMTools::TopicInfoCheckStage::verifyCell(const std::string& cell, const CSMWorld::UniversalId& id, | ||||
|     CSMDoc::Messages& messages) | ||||
| { | ||||
|     const std::string specifier = "Cell"; | ||||
| 
 | ||||
|     if (mCellNames.find(cell) == mCellNames.end()) | ||||
|     { | ||||
|         writeMissingIdError(specifier, cell, id, messages); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CSMTools::TopicInfoCheckStage::verifyFactionRank(const std::string& factionName, int rank, const CSMWorld::UniversalId& id, | ||||
|     CSMDoc::Messages& messages) | ||||
| { | ||||
|     if (rank < -1) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
|         stream << "Rank or PC Rank is set to " << rank << ", but should be set to -1 if no rank is required"; | ||||
| 
 | ||||
|         messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     int index = mFactions.searchId(factionName); | ||||
| 
 | ||||
|     const ESM::Faction &faction = mFactions.getRecord(index).get(); | ||||
| 
 | ||||
|     int limit = 0; | ||||
|     for (; limit < 10; ++limit) | ||||
|     { | ||||
|         if (faction.mRanks[limit].empty()) | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     if (rank >= limit) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
|         stream << "Rank or PC Rank is set to " << rank << " which is more than the maximum of " << limit - 1 | ||||
|                << " for the " << factionName << " faction"; | ||||
| 
 | ||||
|         messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CSMTools::TopicInfoCheckStage::verifyItem(const std::string& item, const CSMWorld::UniversalId& id, | ||||
|     CSMDoc::Messages& messages) | ||||
| { | ||||
|     const std::string specifier = "Item"; | ||||
| 
 | ||||
|     CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(item); | ||||
| 
 | ||||
|     if (index.first == -1) | ||||
|     { | ||||
|         writeMissingIdError(specifier, item, id, messages); | ||||
|         return false; | ||||
|     } | ||||
|     else if (mReferencables.getRecord(index).isDeleted()) | ||||
|     { | ||||
|         writeDeletedRecordError(specifier, item, id, messages); | ||||
|         return false; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         switch (index.second) | ||||
|         { | ||||
|             case CSMWorld::UniversalId::Type_Potion: | ||||
|             case CSMWorld::UniversalId::Type_Apparatus: | ||||
|             case CSMWorld::UniversalId::Type_Armor: | ||||
|             case CSMWorld::UniversalId::Type_Book: | ||||
|             case CSMWorld::UniversalId::Type_Clothing: | ||||
|             case CSMWorld::UniversalId::Type_Ingredient: | ||||
|             case CSMWorld::UniversalId::Type_Light: | ||||
|             case CSMWorld::UniversalId::Type_Lockpick: | ||||
|             case CSMWorld::UniversalId::Type_Miscellaneous: | ||||
|             case CSMWorld::UniversalId::Type_Probe: | ||||
|             case CSMWorld::UniversalId::Type_Repair: | ||||
|             case CSMWorld::UniversalId::Type_Weapon: | ||||
|             case CSMWorld::UniversalId::Type_ItemLevelledList: | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 writeInvalidTypeError(specifier, item, index.second, "Potion, Armor, Book, etc.", id, messages); | ||||
|                 return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::SelectStruct& select, | ||||
|     const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) | ||||
| { | ||||
|     CSMWorld::ConstInfoSelectWrapper infoCondition(select); | ||||
| 
 | ||||
|     if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_None) | ||||
|     { | ||||
|         messages.add(id, "Invalid Info Condition: " + infoCondition.toString(), "", CSMDoc::Message::Severity_Error); | ||||
|         return false; | ||||
|     } | ||||
|     else if (!infoCondition.variantTypeIsValid()) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
|         stream << "Info Condition: Value for \"" << infoCondition.toString() << "\" has a type of "; | ||||
| 
 | ||||
|         switch (select.mValue.getType()) | ||||
|         { | ||||
|             case ESM::VT_None:   stream << "None"; break; | ||||
|             case ESM::VT_Short:  stream << "Short"; break; | ||||
|             case ESM::VT_Int:    stream << "Int"; break; | ||||
|             case ESM::VT_Long:   stream << "Long"; break; | ||||
|             case ESM::VT_Float:  stream << "Float"; break; | ||||
|             case ESM::VT_String: stream << "String"; break; | ||||
|             default:             stream << "Unknown"; break; | ||||
|         } | ||||
| 
 | ||||
|         messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.conditionIsAlwaysTrue()) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
|         stream << "Info Condition: " << infoCondition.toString() << " is always true"; | ||||
| 
 | ||||
|         messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.conditionIsNeverTrue()) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
|         stream << "Info Condition: " << infoCondition.toString() << " is never true"; | ||||
| 
 | ||||
|         messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Id checks
 | ||||
|     if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Global && | ||||
|         !verifyId(infoCondition.getVariableName(), mGlobals, id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Journal && | ||||
|         !verifyId(infoCondition.getVariableName(), mJournals, id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Item && | ||||
|         !verifyItem(infoCondition.getVariableName(), id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Dead && | ||||
|         !verifyActor(infoCondition.getVariableName(), id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotId && | ||||
|         !verifyActor(infoCondition.getVariableName(), id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotFaction && | ||||
|         !verifyId(infoCondition.getVariableName(), mFactions, id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotClass && | ||||
|         !verifyId(infoCondition.getVariableName(), mClasses, id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotRace && | ||||
|         !verifyId(infoCondition.getVariableName(), mRaces, id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotCell && | ||||
|         !verifyCell(infoCondition.getVariableName(), id, messages)) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool CSMTools::TopicInfoCheckStage::verifySound(const std::string& sound, const CSMWorld::UniversalId& id, | ||||
|     CSMDoc::Messages& messages) | ||||
| { | ||||
|     const std::string specifier = "Sound File"; | ||||
| 
 | ||||
|     if (mSoundFiles.searchId(sound) == -1) | ||||
|     { | ||||
|         writeMissingIdError(specifier, sound, id, messages); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| bool CSMTools::TopicInfoCheckStage::verifyId(const std::string& name, const CSMWorld::IdCollection<T>& collection, | ||||
|     const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) | ||||
| { | ||||
|     int index = collection.searchId(name); | ||||
| 
 | ||||
|     if (index == -1) | ||||
|     { | ||||
|         writeMissingIdError(T::getRecordType(), name, id, messages); | ||||
|         return false; | ||||
|     } | ||||
|     else if (collection.getRecord(index).isDeleted()) | ||||
|     { | ||||
|         writeDeletedRecordError(T::getRecordType(), name, id, messages); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // Error functions
 | ||||
| 
 | ||||
| void CSMTools::TopicInfoCheckStage::writeMissingIdError(const std::string& specifier, const std::string& missingId, | ||||
|     const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) | ||||
| { | ||||
|     std::ostringstream stream; | ||||
|     stream << specifier << ": ID or name \"" << missingId << "\" could not be found"; | ||||
| 
 | ||||
|     messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::TopicInfoCheckStage::writeDeletedRecordError(const std::string& specifier, const std::string& recordId, | ||||
|     const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) | ||||
| { | ||||
|     std::ostringstream stream; | ||||
|     stream << specifier << ": Deleted record with ID \"" << recordId << "\" is being referenced"; | ||||
| 
 | ||||
|     messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::TopicInfoCheckStage::writeInvalidTypeError(const std::string& specifier, const std::string& invalidId, | ||||
|     CSMWorld::UniversalId::Type invalidType, const std::string& expectedType, const CSMWorld::UniversalId& id, | ||||
|     CSMDoc::Messages& messages) | ||||
| { | ||||
|     CSMWorld::UniversalId tempId(invalidType, invalidId); | ||||
| 
 | ||||
|     std::ostringstream stream; | ||||
|     stream << specifier << ": invalid type of " << tempId.getTypeName() << " was found for referencable \"" | ||||
|            << invalidId << "\" (can be of type " << expectedType << ")"; | ||||
| 
 | ||||
|     messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); | ||||
| } | ||||
							
								
								
									
										95
									
								
								apps/opencs/model/tools/topicinfocheck.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								apps/opencs/model/tools/topicinfocheck.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| #ifndef CSM_TOOLS_TOPICINFOCHECK_HPP | ||||
| #define CSM_TOOLS_TOPICINFOCHECK_HPP | ||||
| 
 | ||||
| #include <set> | ||||
| 
 | ||||
| #include <components/esm/loadclas.hpp> | ||||
| #include <components/esm/loaddial.hpp> | ||||
| #include <components/esm/loadfact.hpp> | ||||
| #include <components/esm/loadglob.hpp> | ||||
| #include <components/esm/loadgmst.hpp> | ||||
| #include <components/esm/loadrace.hpp> | ||||
| #include <components/esm/loadregn.hpp> | ||||
| 
 | ||||
| #include "../world/cell.hpp" | ||||
| #include "../world/idcollection.hpp" | ||||
| #include "../world/infocollection.hpp" | ||||
| #include "../world/refiddata.hpp" | ||||
| #include "../world/resources.hpp" | ||||
| 
 | ||||
| #include "../doc/stage.hpp" | ||||
| 
 | ||||
| namespace CSMTools | ||||
| { | ||||
|     /// \brief VerifyStage: check topics
 | ||||
|     class TopicInfoCheckStage : public CSMDoc::Stage | ||||
|     { | ||||
|     public: | ||||
| 
 | ||||
|         TopicInfoCheckStage( | ||||
|             const CSMWorld::InfoCollection& topicInfos, | ||||
|             const CSMWorld::IdCollection<CSMWorld::Cell>& cells, | ||||
|             const CSMWorld::IdCollection<ESM::Class>& classes, | ||||
|             const CSMWorld::IdCollection<ESM::Faction>& factions, | ||||
|             const CSMWorld::IdCollection<ESM::GameSetting>& gmsts, | ||||
|             const CSMWorld::IdCollection<ESM::Global>& globals, | ||||
|             const CSMWorld::IdCollection<ESM::Dialogue>& journals, | ||||
|             const CSMWorld::IdCollection<ESM::Race>& races, | ||||
|             const CSMWorld::IdCollection<ESM::Region>& regions, | ||||
|             const CSMWorld::IdCollection<ESM::Dialogue>& topics, | ||||
|             const CSMWorld::RefIdData& referencables, | ||||
|             const CSMWorld::Resources& soundFiles); | ||||
| 
 | ||||
|         virtual int setup(); | ||||
|         ///< \return number of steps
 | ||||
| 
 | ||||
|         virtual void perform(int step, CSMDoc::Messages& messages); | ||||
|         ///< Messages resulting from this stage will be appended to \a messages
 | ||||
| 
 | ||||
|     private: | ||||
| 
 | ||||
|         const CSMWorld::InfoCollection& mTopicInfos; | ||||
| 
 | ||||
|         const CSMWorld::IdCollection<CSMWorld::Cell>& mCells; | ||||
|         const CSMWorld::IdCollection<ESM::Class>& mClasses; | ||||
|         const CSMWorld::IdCollection<ESM::Faction>& mFactions; | ||||
|         const CSMWorld::IdCollection<ESM::GameSetting>& mGameSettings; | ||||
|         const CSMWorld::IdCollection<ESM::Global>& mGlobals; | ||||
|         const CSMWorld::IdCollection<ESM::Dialogue>& mJournals; | ||||
|         const CSMWorld::IdCollection<ESM::Race>& mRaces; | ||||
|         const CSMWorld::IdCollection<ESM::Region>& mRegions; | ||||
|         const CSMWorld::IdCollection<ESM::Dialogue>& mTopics; | ||||
| 
 | ||||
|         const CSMWorld::RefIdData& mReferencables; | ||||
|         const CSMWorld::Resources& mSoundFiles; | ||||
| 
 | ||||
|         std::set<std::string> mCellNames; | ||||
| 
 | ||||
|         // These return false when not successful and write an error
 | ||||
|         bool verifyActor(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
|         bool verifyCell(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
|         bool verifyFactionRank(const std::string& name, int rank, const CSMWorld::UniversalId& id, | ||||
|             CSMDoc::Messages& messages); | ||||
|         bool verifyItem(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
|         bool verifySelectStruct(const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, | ||||
|             CSMDoc::Messages& messages); | ||||
|         bool verifySound(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
| 
 | ||||
|         template <typename T> | ||||
|         bool verifyId(const std::string& name, const CSMWorld::IdCollection<T>& collection, | ||||
|             const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
| 
 | ||||
|         // Common error messages
 | ||||
|         void writeMissingIdError(const std::string& specifier, const std::string& missingId, | ||||
|             const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
| 
 | ||||
|         void writeDeletedRecordError(const std::string& specifier, const std::string& recordId, | ||||
|             const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
| 
 | ||||
|         void writeInvalidTypeError(const std::string& specifier, const std::string& invalidId, | ||||
|             CSMWorld::UniversalId::Type invalidType, const std::string& expectedType, | ||||
|             const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -226,8 +226,7 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue() const | |||
| 
 | ||||
| bool CSMWorld::ConstInfoSelectWrapper::variantTypeIsValid() const | ||||
| { | ||||
|     return (mConstSelect.mValue.getType() == ESM::VT_Int || mConstSelect.mValue.getType() == ESM::VT_Short || | ||||
|         mConstSelect.mValue.getType() == ESM::VT_Long || mConstSelect.mValue.getType() == ESM::VT_Float); | ||||
|     return (mConstSelect.mValue.getType() == ESM::VT_Int || mConstSelect.mValue.getType() == ESM::VT_Float); | ||||
| } | ||||
| 
 | ||||
| const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const | ||||
|  | @ -235,6 +234,40 @@ const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const | |||
|     return mConstSelect.mValue; | ||||
| } | ||||
| 
 | ||||
| std::string CSMWorld::ConstInfoSelectWrapper::toString() const | ||||
| { | ||||
|     std::ostringstream stream; | ||||
|     stream << convertToString(mFunctionName) << " "; | ||||
|      | ||||
|     if (mHasVariable) | ||||
|         stream << mVariableName << " "; | ||||
|      | ||||
|     stream << convertToString(mRelationType) << " "; | ||||
|      | ||||
|     switch (mConstSelect.mValue.getType()) | ||||
|     { | ||||
|         case ESM::VT_Short: | ||||
|         case ESM::VT_Long: | ||||
|         case ESM::VT_Int: | ||||
|             stream << mConstSelect.mValue.getInteger(); | ||||
|             break; | ||||
|              | ||||
|         case ESM::VT_Float: | ||||
|             stream << mConstSelect.mValue.getFloat(); | ||||
|             break; | ||||
|              | ||||
|         case ESM::VT_String: | ||||
|             stream << mConstSelect.mValue.getString(); | ||||
|             break; | ||||
|              | ||||
|         default: | ||||
|             stream << "(Invalid value type)"; | ||||
|             break; | ||||
|     } | ||||
|      | ||||
|     return stream.str(); | ||||
| } | ||||
| 
 | ||||
| void CSMWorld::ConstInfoSelectWrapper::readRule() | ||||
| { | ||||
|     if (mConstSelect.mSelectRule.size() < RuleMinSize) | ||||
|  | @ -554,9 +587,9 @@ std::pair<int, int> CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const | |||
|         case Function_RankHigh: | ||||
|         case Function_Reputation: | ||||
|         case Function_PcReputation: | ||||
|         case Function_Journal: | ||||
|             return std::pair<int, int>(IntMin, IntMax); | ||||
| 
 | ||||
|         case Function_Journal: | ||||
|         case Function_Item: | ||||
|         case Function_Dead: | ||||
|         case Function_PcLevel: | ||||
|  | @ -736,7 +769,7 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue(std::pair<T1,T1> con | |||
| 
 | ||||
|         case Relation_NotEqual: | ||||
|             // If the value is the only value withing the range, it will never be true
 | ||||
|             return rangesOverlap(conditionRange, validRange); | ||||
|             return rangesMatch(conditionRange, validRange); | ||||
| 
 | ||||
|         default: | ||||
|             throw std::logic_error("InfoCondition: operator can not be used to compare"); | ||||
|  |  | |||
|  | @ -165,6 +165,8 @@ namespace CSMWorld | |||
| 
 | ||||
|         const ESM::Variant& getVariant() const; | ||||
|          | ||||
|         std::string toString() const; | ||||
| 
 | ||||
|     protected: | ||||
| 
 | ||||
|         void readRule(); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue