forked from mirror/openmw-tes3mp
Add NPC validation to esmstore (bug #2772)
This commit is contained in:
parent
ccfc07e7e3
commit
49ba00a3ec
4 changed files with 63 additions and 3 deletions
|
@ -4,6 +4,7 @@
|
|||
Bug #1990: Sunrise/sunset not set correct
|
||||
Bug #2222: Fatigue's effect on selling price is backwards
|
||||
Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped
|
||||
Bug #2772: Non-existing class or faction freezes the game
|
||||
Bug #2835: Player able to slowly move when overencumbered
|
||||
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
||||
Bug #3374: Touch spells not hitting kwama foragers
|
||||
|
|
|
@ -120,7 +120,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
|
|||
}
|
||||
}
|
||||
|
||||
void ESMStore::setUp()
|
||||
void ESMStore::setUp(bool validateRecords)
|
||||
{
|
||||
mIds.clear();
|
||||
|
||||
|
@ -142,6 +142,62 @@ void ESMStore::setUp()
|
|||
mAttributes.setUp();
|
||||
mDialogs.setUp();
|
||||
mStatics.setUp();
|
||||
|
||||
if (validateRecords)
|
||||
validate();
|
||||
}
|
||||
|
||||
void ESMStore::validate()
|
||||
{
|
||||
// Cache first class from store - we will use it if current class is not found
|
||||
std::string defaultCls = "";
|
||||
Store<ESM::Class>::iterator it = mClasses.begin();
|
||||
if (it != mClasses.end())
|
||||
defaultCls = it->mId;
|
||||
else
|
||||
throw std::runtime_error("List of NPC classes is empty!");
|
||||
|
||||
// Validate NPCs for non-existing class and faction.
|
||||
// We will replace invalid entries by fixed ones
|
||||
std::vector<ESM::NPC> entitiesToReplace;
|
||||
for (ESM::NPC npc : mNpcs)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
const std::string npcFaction = npc.mFaction;
|
||||
if (!npcFaction.empty())
|
||||
{
|
||||
const ESM::Faction *fact = mFactions.search(npcFaction);
|
||||
if (!fact)
|
||||
{
|
||||
std::cerr << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it." << std::endl;
|
||||
npc.mFaction = "";
|
||||
npc.mNpdt.mRank = -1;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string npcClass = npc.mClass;
|
||||
if (!npcClass.empty())
|
||||
{
|
||||
const ESM::Class *cls = mClasses.search(npcClass);
|
||||
if (!cls)
|
||||
{
|
||||
std::cerr << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent class '" << npc.mClass << "', using '" << defaultCls << "' class as replacement." << std::endl;
|
||||
npc.mClass = defaultCls;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
entitiesToReplace.push_back(npc);
|
||||
}
|
||||
|
||||
for (const ESM::NPC &npc : entitiesToReplace)
|
||||
{
|
||||
mNpcs.eraseStatic(npc.mId);
|
||||
mNpcs.insertStatic(npc);
|
||||
}
|
||||
}
|
||||
|
||||
int ESMStore::countSavedGameRecords() const
|
||||
|
|
|
@ -74,6 +74,9 @@ namespace MWWorld
|
|||
|
||||
unsigned int mDynamicCount;
|
||||
|
||||
/// Validate entries in store after setup
|
||||
void validate();
|
||||
|
||||
public:
|
||||
/// \todo replace with SharedIterator<StoreBase>
|
||||
typedef std::map<int, StoreBase *>::const_iterator iterator;
|
||||
|
@ -228,7 +231,7 @@ namespace MWWorld
|
|||
|
||||
// This method must be called once, after loading all master/plugin files. This can only be done
|
||||
// from the outside, so it must be public.
|
||||
void setUp();
|
||||
void setUp(bool validateRecords = false);
|
||||
|
||||
int countSavedGameRecords() const;
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ namespace MWWorld
|
|||
|
||||
fillGlobalVariables();
|
||||
|
||||
mStore.setUp();
|
||||
mStore.setUp(true);
|
||||
mStore.movePlayerRecord();
|
||||
|
||||
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->getFloat();
|
||||
|
|
Loading…
Reference in a new issue