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 |     mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck | ||||||
|     birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck |     birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck | ||||||
|     startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck |     startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck | ||||||
|     mergestages gmstcheck |     mergestages gmstcheck topicinfocheck | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| opencs_hdrs_noqt (model/tools | opencs_hdrs_noqt (model/tools | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ | ||||||
| #include "magiceffectcheck.hpp" | #include "magiceffectcheck.hpp" | ||||||
| #include "mergeoperation.hpp" | #include "mergeoperation.hpp" | ||||||
| #include "gmstcheck.hpp" | #include "gmstcheck.hpp" | ||||||
|  | #include "topicinfocheck.hpp" | ||||||
| 
 | 
 | ||||||
| CSMDoc::OperationHolder *CSMTools::Tools::get (int type) | 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 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); |         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 | bool CSMWorld::ConstInfoSelectWrapper::variantTypeIsValid() const | ||||||
| { | { | ||||||
|     return (mConstSelect.mValue.getType() == ESM::VT_Int || mConstSelect.mValue.getType() == ESM::VT_Short || |     return (mConstSelect.mValue.getType() == ESM::VT_Int || mConstSelect.mValue.getType() == ESM::VT_Float); | ||||||
|         mConstSelect.mValue.getType() == ESM::VT_Long || mConstSelect.mValue.getType() == ESM::VT_Float); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const | const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const | ||||||
|  | @ -235,6 +234,40 @@ const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const | ||||||
|     return mConstSelect.mValue; |     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() | void CSMWorld::ConstInfoSelectWrapper::readRule() | ||||||
| { | { | ||||||
|     if (mConstSelect.mSelectRule.size() < RuleMinSize) |     if (mConstSelect.mSelectRule.size() < RuleMinSize) | ||||||
|  | @ -554,9 +587,9 @@ std::pair<int, int> CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const | ||||||
|         case Function_RankHigh: |         case Function_RankHigh: | ||||||
|         case Function_Reputation: |         case Function_Reputation: | ||||||
|         case Function_PcReputation: |         case Function_PcReputation: | ||||||
|  |         case Function_Journal: | ||||||
|             return std::pair<int, int>(IntMin, IntMax); |             return std::pair<int, int>(IntMin, IntMax); | ||||||
| 
 | 
 | ||||||
|         case Function_Journal: |  | ||||||
|         case Function_Item: |         case Function_Item: | ||||||
|         case Function_Dead: |         case Function_Dead: | ||||||
|         case Function_PcLevel: |         case Function_PcLevel: | ||||||
|  | @ -736,7 +769,7 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue(std::pair<T1,T1> con | ||||||
| 
 | 
 | ||||||
|         case Relation_NotEqual: |         case Relation_NotEqual: | ||||||
|             // If the value is the only value withing the range, it will never be true
 |             // If the value is the only value withing the range, it will never be true
 | ||||||
|             return rangesOverlap(conditionRange, validRange); |             return rangesMatch(conditionRange, validRange); | ||||||
| 
 | 
 | ||||||
|         default: |         default: | ||||||
|             throw std::logic_error("InfoCondition: operator can not be used to compare"); |             throw std::logic_error("InfoCondition: operator can not be used to compare"); | ||||||
|  |  | ||||||
|  | @ -165,6 +165,8 @@ namespace CSMWorld | ||||||
| 
 | 
 | ||||||
|         const ESM::Variant& getVariant() const; |         const ESM::Variant& getVariant() const; | ||||||
|          |          | ||||||
|  |         std::string toString() const; | ||||||
|  | 
 | ||||||
|     protected: |     protected: | ||||||
| 
 | 
 | ||||||
|         void readRule(); |         void readRule(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue