mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 18:59:57 +00:00
Validate enchantment records (bug #7654)
Clean up spell validation Fix a flaw in spell effect tooltip code
This commit is contained in:
parent
3baefdf29e
commit
876f6ea2da
3 changed files with 66 additions and 61 deletions
|
@ -90,6 +90,7 @@
|
|||
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
||||
Bug #7642: Items in repair and recharge menus aren't sorted alphabetically
|
||||
Bug #7647: NPC walk cycle bugs after greeting player
|
||||
Bug #7654: Tooltips for enchantments with invalid effects cause crashes
|
||||
Bug #7660: Some inconsistencies regarding Invisibility breaking
|
||||
Feature #3537: Shader-based water ripples
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
|
|
|
@ -355,12 +355,10 @@ namespace MWGui::Widgets
|
|||
|
||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||
|
||||
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().search(mEffectParams.mEffectID);
|
||||
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().find(mEffectParams.mEffectID);
|
||||
const ESM::Attribute* attribute = store.get<ESM::Attribute>().search(mEffectParams.mAttribute);
|
||||
const ESM::Skill* skill = store.get<ESM::Skill>().search(mEffectParams.mSkill);
|
||||
|
||||
assert(magicEffect);
|
||||
|
||||
auto windowManager = MWBase::Environment::get().getWindowManager();
|
||||
|
||||
std::string_view pt = windowManager->getGameSettingString("spoint", {});
|
||||
|
|
|
@ -138,6 +138,59 @@ namespace
|
|||
return npcsToReplace;
|
||||
}
|
||||
|
||||
template <class RecordType>
|
||||
std::vector<RecordType> getSpellsToReplace(
|
||||
const MWWorld::Store<RecordType>& spells, const MWWorld::Store<ESM::MagicEffect>& magicEffects)
|
||||
{
|
||||
std::vector<RecordType> spellsToReplace;
|
||||
|
||||
for (RecordType spell : spells)
|
||||
{
|
||||
if (spell.mEffects.mList.empty())
|
||||
continue;
|
||||
|
||||
bool changed = false;
|
||||
auto iter = spell.mEffects.mList.begin();
|
||||
while (iter != spell.mEffects.mList.end())
|
||||
{
|
||||
const ESM::MagicEffect* mgef = magicEffects.search(iter->mEffectID);
|
||||
if (!mgef)
|
||||
{
|
||||
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
|
||||
<< ": dropping invalid effect (index " << iter->mEffectID << ")";
|
||||
iter = spell.mEffects.mList.erase(iter);
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(mgef->mData.mFlags & ESM::MagicEffect::TargetAttribute) && iter->mAttribute != -1)
|
||||
{
|
||||
iter->mAttribute = -1;
|
||||
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
|
||||
<< ": dropping unexpected attribute argument of "
|
||||
<< ESM::MagicEffect::indexToGmstString(iter->mEffectID) << " effect";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!(mgef->mData.mFlags & ESM::MagicEffect::TargetSkill) && iter->mSkill != -1)
|
||||
{
|
||||
iter->mSkill = -1;
|
||||
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
|
||||
<< ": dropping unexpected skill argument of "
|
||||
<< ESM::MagicEffect::indexToGmstString(iter->mEffectID) << " effect";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
spellsToReplace.emplace_back(spell);
|
||||
}
|
||||
|
||||
return spellsToReplace;
|
||||
}
|
||||
|
||||
// Custom enchanted items can reference scripts that no longer exist, this doesn't necessarily mean the base item no
|
||||
// longer exists however. So instead of removing the item altogether, we're only removing the script.
|
||||
template <class MapT>
|
||||
|
@ -538,71 +591,24 @@ namespace MWWorld
|
|||
|
||||
removeMissingScripts(getWritable<ESM::Script>(), getWritable<ESM::Creature>().mStatic);
|
||||
|
||||
// Validate spell effects for invalid arguments
|
||||
std::vector<ESM::Spell> spellsToReplace;
|
||||
// Validate spell effects and enchantments for invalid arguments
|
||||
auto& spells = getWritable<ESM::Spell>();
|
||||
for (ESM::Spell spell : spells)
|
||||
{
|
||||
if (spell.mEffects.mList.empty())
|
||||
continue;
|
||||
|
||||
bool changed = false;
|
||||
auto iter = spell.mEffects.mList.begin();
|
||||
while (iter != spell.mEffects.mList.end())
|
||||
{
|
||||
const ESM::MagicEffect* mgef = getWritable<ESM::MagicEffect>().search(iter->mEffectID);
|
||||
if (!mgef)
|
||||
{
|
||||
Log(Debug::Verbose) << "Spell '" << spell.mId << "' has an invalid effect (index "
|
||||
<< iter->mEffectID << ") present. Dropping the effect.";
|
||||
iter = spell.mEffects.mList.erase(iter);
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mgef->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||
{
|
||||
if (iter->mAttribute != -1)
|
||||
{
|
||||
iter->mAttribute = -1;
|
||||
Log(Debug::Verbose)
|
||||
<< ESM::MagicEffect::indexToGmstString(iter->mEffectID) << " effect of spell '" << spell.mId
|
||||
<< "' has an attribute argument present. Dropping the argument.";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (mgef->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||
{
|
||||
if (iter->mSkill != -1)
|
||||
{
|
||||
iter->mSkill = -1;
|
||||
Log(Debug::Verbose)
|
||||
<< ESM::MagicEffect::indexToGmstString(iter->mEffectID) << " effect of spell '" << spell.mId
|
||||
<< "' has a skill argument present. Dropping the argument.";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (iter->mSkill != -1 || iter->mAttribute != -1)
|
||||
{
|
||||
iter->mSkill = -1;
|
||||
iter->mAttribute = -1;
|
||||
Log(Debug::Verbose) << ESM::MagicEffect::indexToGmstString(iter->mEffectID) << " effect of spell '"
|
||||
<< spell.mId << "' has argument(s) present. Dropping the argument(s).";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
spellsToReplace.emplace_back(spell);
|
||||
}
|
||||
auto& enchantments = getWritable<ESM::Enchantment>();
|
||||
auto& magicEffects = getWritable<ESM::MagicEffect>();
|
||||
|
||||
std::vector<ESM::Spell> spellsToReplace = getSpellsToReplace(spells, magicEffects);
|
||||
for (const ESM::Spell& spell : spellsToReplace)
|
||||
{
|
||||
spells.eraseStatic(spell.mId);
|
||||
spells.insertStatic(spell);
|
||||
}
|
||||
|
||||
std::vector<ESM::Enchantment> enchantmentsToReplace = getSpellsToReplace(enchantments, magicEffects);
|
||||
for (const ESM::Enchantment& enchantment : enchantmentsToReplace)
|
||||
{
|
||||
enchantments.eraseStatic(enchantment.mId);
|
||||
enchantments.insertStatic(enchantment);
|
||||
}
|
||||
}
|
||||
|
||||
void ESMStore::movePlayerRecord()
|
||||
|
|
Loading…
Reference in a new issue