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 #1990: Sunrise/sunset not set correct
|
||||||
Bug #2222: Fatigue's effect on selling price is backwards
|
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 #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 #2835: Player able to slowly move when overencumbered
|
||||||
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
||||||
Bug #3374: Touch spells not hitting kwama foragers
|
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();
|
mIds.clear();
|
||||||
|
|
||||||
|
@ -142,6 +142,62 @@ void ESMStore::setUp()
|
||||||
mAttributes.setUp();
|
mAttributes.setUp();
|
||||||
mDialogs.setUp();
|
mDialogs.setUp();
|
||||||
mStatics.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
|
int ESMStore::countSavedGameRecords() const
|
||||||
|
|
|
@ -74,6 +74,9 @@ namespace MWWorld
|
||||||
|
|
||||||
unsigned int mDynamicCount;
|
unsigned int mDynamicCount;
|
||||||
|
|
||||||
|
/// Validate entries in store after setup
|
||||||
|
void validate();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \todo replace with SharedIterator<StoreBase>
|
/// \todo replace with SharedIterator<StoreBase>
|
||||||
typedef std::map<int, StoreBase *>::const_iterator iterator;
|
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
|
// 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.
|
// from the outside, so it must be public.
|
||||||
void setUp();
|
void setUp(bool validateRecords = false);
|
||||||
|
|
||||||
int countSavedGameRecords() const;
|
int countSavedGameRecords() const;
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ namespace MWWorld
|
||||||
|
|
||||||
fillGlobalVariables();
|
fillGlobalVariables();
|
||||||
|
|
||||||
mStore.setUp();
|
mStore.setUp(true);
|
||||||
mStore.movePlayerRecord();
|
mStore.movePlayerRecord();
|
||||||
|
|
||||||
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->getFloat();
|
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->getFloat();
|
||||||
|
|
Loading…
Reference in a new issue