diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb45..d29546208 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck spellcheck referenceablecheck scriptcheck bodypartcheck + birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck ) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp new file mode 100644 index 000000000..eb97645eb --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -0,0 +1,103 @@ +#include "referencecheck.hpp" + +#include + +CSMTools::ReferenceCheckStage::ReferenceCheckStage( + const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions) + : + mReferences(references), + mReferencables(referencables), + mCells(cells), + mFactions(factions) +{ +} + +void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + const CSMWorld::Record& record = mReferences.getRecord(stage); + + if (record.isDeleted()) + return; + + const CSMWorld::CellRef& cellRef = record.get(); + const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); + + // Check for empty reference id + if (cellRef.mRefID.empty()) + messages.push_back(std::make_pair(id, " is an empty reference")); + + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + + // Check if referenced object is in valid cell + if (mCells.searchId(cellRef.mCell) == -1) + messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); + + // If object have owner, check if that owner reference is valid + if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); + + // If object have creature soul trapped, check if that creature reference is valid + if (!cellRef.mSoul.empty()) + if (mReferencables.searchId(cellRef.mSoul) == -1) + messages.push_back(std::make_pair(id, " has non existing trapped soul " + cellRef.mSoul)); + + bool hasFaction = !cellRef.mFaction.empty(); + + // If object have faction, check if that faction reference is valid + if (hasFaction) + if (mFactions.searchId(cellRef.mFaction) == -1) + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + + // Check item's faction rank + if (hasFaction && cellRef.mFactionRank < -1) + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + else if (!hasFaction && cellRef.mFactionRank != -2) + messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + + // If door have destination cell, check if that reference is valid + if (!cellRef.mDestCell.empty()) + if (mCells.searchId(cellRef.mDestCell) == -1) + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + + // Check if scale isn't negative + if (cellRef.mScale < 0) + { + std::string str = " has negative scale "; + str += boost::lexical_cast(cellRef.mScale); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if charge isn't negative + if (cellRef.mChargeFloat < 0) + { + std::string str = " has negative charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if enchantement points aren't negative or are at full (-1) + if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) + { + std::string str = " has negative enchantment points "; + str += boost::lexical_cast(cellRef.mEnchantmentCharge); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if gold value isn't negative + if (cellRef.mGoldValue < 0) + { + std::string str = " has negative gold value "; + str += cellRef.mGoldValue; + messages.push_back(std::make_pair(id, id.getId() + str)); + } +} + +int CSMTools::ReferenceCheckStage::setup() +{ + return mReferences.getSize(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp new file mode 100644 index 000000000..d1eacb5b5 --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_REFERENCECHECK_H +#define CSM_TOOLS_REFERENCECHECK_H + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +namespace CSMTools +{ + class ReferenceCheckStage : public CSMDoc::Stage + { + public: + ReferenceCheckStage (const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + + private: + const CSMWorld::RefCollection& mReferences; + const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::IdCollection& mCells; + const CSMWorld::IdCollection& mFactions; + }; +} + +#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 6e157f664..0c20bd17b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -23,6 +23,7 @@ #include "referenceablecheck.hpp" #include "scriptcheck.hpp" #include "bodypartcheck.hpp" +#include "referencecheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -82,6 +83,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifier->appendStage (new ScriptCheckStage (mDocument)); mVerifier->appendStage(