1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 12:35:46 +00:00

Editor: Verify magic effects for enchantments, ingredients and potions

Use constants for known magic effect/skill/attribute range
This commit is contained in:
Alexei Kotov 2024-06-07 11:12:38 +03:00
parent 89eccffbf6
commit 2fdbd6287d
3 changed files with 105 additions and 11 deletions

View File

@ -10,6 +10,7 @@
#include <apps/opencs/model/world/idcollection.hpp> #include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <components/esm/attr.hpp>
#include <components/esm3/effectlist.hpp> #include <components/esm3/effectlist.hpp>
#include <components/esm3/loadench.hpp> #include <components/esm3/loadench.hpp>
@ -65,18 +66,13 @@ void CSMTools::EnchantmentCheckStage::perform(int stage, CSMDoc::Messages& messa
for (size_t i = 1; i <= enchantment.mEffects.mList.size(); i++) for (size_t i = 1; i <= enchantment.mEffects.mList.size(); i++)
{ {
const std::string number = std::to_string(i); const std::string number = std::to_string(i);
// At the time of writing this effects, attributes and skills are hardcoded // At the time of writing this effects, attributes and skills are mostly hardcoded
if (effect->mData.mEffectID < 0 || effect->mData.mEffectID > 142) if (effect->mData.mEffectID < 0 || effect->mData.mEffectID > ESM::MagicEffect::Length)
{
messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error); messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error);
++effect; if (effect->mData.mSkill < -1 || effect->mData.mSkill > ESM::Skill::Length)
continue;
}
if (effect->mData.mSkill < -1 || effect->mData.mSkill > 26)
messages.add( messages.add(
id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error); id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mAttribute < -1 || effect->mData.mAttribute > 7) if (effect->mData.mAttribute < -1 || effect->mData.mAttribute > ESM::Attribute::Length)
messages.add( messages.add(
id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error); id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mRange < 0 || effect->mData.mRange > 2) if (effect->mData.mRange < 0 || effect->mData.mRange > 2)

View File

@ -330,7 +330,45 @@ void CSMTools::ReferenceableCheckStage::potionCheck(
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId);
inventoryItemCheck<ESM::Potion>(potion, messages, id.toString()); inventoryItemCheck<ESM::Potion>(potion, messages, id.toString());
/// \todo Check magic effects for validity
if (potion.mEffects.mList.empty())
{
messages.add(id, "Potion doesn't have any magic effects", "", CSMDoc::Message::Severity_Warning);
}
else
{
std::vector<ESM::IndexedENAMstruct>::const_iterator effect = potion.mEffects.mList.begin();
for (size_t i = 1; i <= potion.mEffects.mList.size(); i++)
{
const std::string number = std::to_string(i);
// At the time of writing this effects, attributes and skills are mostly hardcoded
if (effect->mData.mEffectID < 0 || effect->mData.mEffectID > ESM::MagicEffect::Length)
messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mSkill < -1 || effect->mData.mSkill > ESM::Skill::Length)
messages.add(
id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mAttribute < -1 || effect->mData.mAttribute > ESM::Attribute::Length)
messages.add(
id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mRange != ESM::RT_Self)
messages.add(id, "Effect #" + number + " range is not Self", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mArea < 0)
messages.add(id, "Effect #" + number + " area is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mDuration < 0)
messages.add(id, "Effect #" + number + " duration is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mMagnMin < 0)
messages.add(
id, "Effect #" + number + " minimum magnitude is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mMagnMax < 0)
messages.add(
id, "Effect #" + number + " maximum magnitude is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mMagnMin > effect->mData.mMagnMax)
messages.add(id, "Effect #" + number + " minimum magnitude is higher than maximum magnitude", "",
CSMDoc::Message::Severity_Error);
++effect;
}
}
// Check that mentioned scripts exist // Check that mentioned scripts exist
scriptCheck<ESM::Potion>(potion, messages, id.toString()); scriptCheck<ESM::Potion>(potion, messages, id.toString());
@ -565,6 +603,28 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck(
// Check that mentioned scripts exist // Check that mentioned scripts exist
scriptCheck<ESM::Ingredient>(ingredient, messages, id.toString()); scriptCheck<ESM::Ingredient>(ingredient, messages, id.toString());
bool hasEffects = false;
for (size_t i = 0; i < 4; i++)
{
if (ingredient.mData.mEffectID[i] == -1)
continue;
hasEffects = true;
const std::string number = std::to_string(i + 1);
// At the time of writing this effects, attributes and skills are mostly hardcoded
if (ingredient.mData.mEffectID[i] < -1 || ingredient.mData.mEffectID[i] > ESM::MagicEffect::Length)
messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error);
if (ingredient.mData.mSkills[i] < -1 || ingredient.mData.mSkills[i] > ESM::Skill::Length)
messages.add(id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error);
if (ingredient.mData.mAttributes[i] < -1 || ingredient.mData.mAttributes[i] > ESM::Attribute::Length)
messages.add(
id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error);
}
if (!hasEffects)
messages.add(id, "Ingredient doesn't have any magic effects", "", CSMDoc::Message::Severity_Warning);
} }
void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( void CSMTools::ReferenceableCheckStage::creaturesLevListCheck(

View File

@ -9,6 +9,7 @@
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/model/world/universalid.hpp> #include <apps/opencs/model/world/universalid.hpp>
#include <components/esm/attr.hpp>
#include <components/esm3/loadspel.hpp> #include <components/esm3/loadspel.hpp>
#include "../prefs/state.hpp" #include "../prefs/state.hpp"
@ -46,5 +47,42 @@ void CSMTools::SpellCheckStage::perform(int stage, CSMDoc::Messages& messages)
if (spell.mData.mCost < 0) if (spell.mData.mCost < 0)
messages.add(id, "Spell cost is negative", "", CSMDoc::Message::Severity_Error); messages.add(id, "Spell cost is negative", "", CSMDoc::Message::Severity_Error);
/// \todo check data members that can't be edited in the table view if (spell.mEffects.mList.empty())
{
messages.add(id, "Spell doesn't have any magic effects", "", CSMDoc::Message::Severity_Warning);
}
else
{
std::vector<ESM::IndexedENAMstruct>::const_iterator effect = spell.mEffects.mList.begin();
for (size_t i = 1; i <= spell.mEffects.mList.size(); i++)
{
const std::string number = std::to_string(i);
// At the time of writing this effects, attributes and skills are mostly hardcoded
if (effect->mData.mEffectID < 0 || effect->mData.mEffectID > ESM::MagicEffect::Length)
messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mSkill < -1 || effect->mData.mSkill > ESM::Skill::Length)
messages.add(
id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mAttribute < -1 || effect->mData.mAttribute > ESM::Attribute::Length)
messages.add(
id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mRange < 0 || effect->mData.mRange > 2)
messages.add(id, "Effect #" + number + " range is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mArea < 0)
messages.add(id, "Effect #" + number + " area is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mDuration < 0)
messages.add(id, "Effect #" + number + " duration is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mMagnMin < 0)
messages.add(
id, "Effect #" + number + " minimum magnitude is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mMagnMax < 0)
messages.add(
id, "Effect #" + number + " maximum magnitude is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mData.mMagnMin > effect->mData.mMagnMax)
messages.add(id, "Effect #" + number + " minimum magnitude is higher than maximum magnitude", "",
CSMDoc::Message::Severity_Error);
++effect;
}
}
} }