mirror of
https://github.com/OpenMW/openmw.git
synced 2026-01-25 12:30:55 +00:00
Merge branch 'Assign-RefIds-to-MagicEffects' into 'master'
Assign StringRefIds to magic effects See merge request OpenMW/openmw!5064
This commit is contained in:
commit
dc022d10d4
58 changed files with 2164 additions and 1947 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include <components/esm3/loaddial.hpp>
|
||||
#include <components/esm3/loadinfo.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/esm3/loadregn.hpp>
|
||||
#include <components/esm3/loadscpt.hpp>
|
||||
#include <components/esm3/loadweap.hpp>
|
||||
|
|
@ -574,7 +575,7 @@ namespace ESM
|
|||
{
|
||||
EffectList record;
|
||||
record.mList.emplace_back(IndexedENAMstruct{ {
|
||||
.mEffectID = 1,
|
||||
.mEffectID = ESM::MagicEffect::SwiftSwim,
|
||||
.mSkill = 2,
|
||||
.mAttribute = 3,
|
||||
.mRange = 4,
|
||||
|
|
|
|||
|
|
@ -153,8 +153,10 @@ namespace
|
|||
int i = 0;
|
||||
for (const ESM::IndexedENAMstruct& effect : effects.mList)
|
||||
{
|
||||
std::cout << " Effect[" << i << "]: " << magicEffectLabel(effect.mData.mEffectID) << " ("
|
||||
<< effect.mData.mEffectID << ")" << std::endl;
|
||||
int effectIdx = ESM::MagicEffect::refIdToIndex(effect.mData.mEffectID);
|
||||
if (effectIdx != -1)
|
||||
std::cout << " Effect[" << i << "]: " << magicEffectLabel(effectIdx) << " (" << effectIdx << ")"
|
||||
<< std::endl;
|
||||
if (effect.mData.mSkill != -1)
|
||||
std::cout << " Skill: " << skillLabel(effect.mData.mSkill) << " (" << (int)effect.mData.mSkill << ")"
|
||||
<< std::endl;
|
||||
|
|
@ -843,11 +845,12 @@ namespace EsmTool
|
|||
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
||||
for (int i = 0; i != 4; i++)
|
||||
{
|
||||
// A value of -1 means no effect
|
||||
if (mData.mData.mEffectID[i] == -1)
|
||||
// A value of EmptyRefId means no effect
|
||||
if (mData.mData.mEffectID[i].empty())
|
||||
continue;
|
||||
std::cout << " Effect: " << magicEffectLabel(mData.mData.mEffectID[i]) << " (" << mData.mData.mEffectID[i]
|
||||
<< ")" << std::endl;
|
||||
|
||||
int effectIdx = ESM::MagicEffect::refIdToIndex(mData.mData.mEffectID[i]);
|
||||
std::cout << " Effect: " << magicEffectLabel(effectIdx) << " (" << effectIdx << ")" << std::endl;
|
||||
std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) << " (" << mData.mData.mSkills[i] << ")"
|
||||
<< std::endl;
|
||||
std::cout << " Attribute: " << attributeLabel(mData.mData.mAttributes[i]) << " ("
|
||||
|
|
@ -973,7 +976,8 @@ namespace EsmTool
|
|||
template <>
|
||||
void Record<ESM::MagicEffect>::print()
|
||||
{
|
||||
std::cout << " Index: " << magicEffectLabel(mData.mIndex) << " (" << mData.mIndex << ")" << std::endl;
|
||||
int effectIdx = ESM::MagicEffect::refIdToIndex(mData.mId);
|
||||
std::cout << " Index: " << magicEffectLabel(effectIdx) << " (" << effectIdx << ")" << std::endl;
|
||||
std::cout << " Description: " << mData.mDescription << std::endl;
|
||||
std::cout << " Icon: " << mData.mIcon << std::endl;
|
||||
std::cout << " Flags: " << magicEffectFlags(mData.mData.mFlags) << std::endl;
|
||||
|
|
|
|||
|
|
@ -128,11 +128,18 @@ void CSMDoc::Document::addOptionalGlobals()
|
|||
|
||||
void CSMDoc::Document::addOptionalMagicEffects()
|
||||
{
|
||||
for (int i = ESM::MagicEffect::SummonFabricant; i <= ESM::MagicEffect::SummonCreature05; ++i)
|
||||
static const std::array<ESM::RefId, 6> optionalMagicEffects{
|
||||
ESM::MagicEffect::SummonFabricant,
|
||||
ESM::MagicEffect::SummonWolf,
|
||||
ESM::MagicEffect::SummonBear,
|
||||
ESM::MagicEffect::SummonBonewolf,
|
||||
ESM::MagicEffect::SummonCreature04,
|
||||
ESM::MagicEffect::SummonCreature05,
|
||||
};
|
||||
for (const auto effectId : optionalMagicEffects)
|
||||
{
|
||||
ESM::MagicEffect effect;
|
||||
effect.mIndex = i;
|
||||
effect.mId = ESM::MagicEffect::indexToRefId(i);
|
||||
effect.mId = effectId;
|
||||
effect.blank();
|
||||
|
||||
addOptionalMagicEffect(effect);
|
||||
|
|
@ -282,10 +289,7 @@ void CSMDoc::Document::createBase()
|
|||
for (int i = 0; i < ESM::MagicEffect::Length; ++i)
|
||||
{
|
||||
ESM::MagicEffect record;
|
||||
|
||||
record.mIndex = i;
|
||||
record.mId = ESM::MagicEffect::indexToRefId(i);
|
||||
|
||||
record.blank();
|
||||
|
||||
getData().getMagicEffects().add(record);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ namespace CSMTools
|
|||
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)
|
||||
int effectIndex = ESM::MagicEffect::refIdToIndex(effect.mData.mEffectID);
|
||||
if (effectIndex < -1 || effectIndex >= ESM::MagicEffect::Length)
|
||||
messages.add(id, "Effect #" + number + ": invalid effect ID", "", CSMDoc::Message::Severity_Error);
|
||||
if (effect.mData.mSkill < -1 || effect.mData.mSkill >= ESM::Skill::Length)
|
||||
messages.add(id, "Effect #" + number + ": invalid skill", "", CSMDoc::Message::Severity_Error);
|
||||
|
|
@ -68,13 +69,14 @@ namespace CSMTools
|
|||
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
if (ingredient.mData.mEffectID[i] == -1)
|
||||
if (ingredient.mData.mEffectID[i].empty())
|
||||
continue;
|
||||
|
||||
hasEffects = true;
|
||||
int effectIndex = ESM::MagicEffect::refIdToIndex(ingredient.mData.mEffectID[i]);
|
||||
|
||||
const std::string number = std::to_string(i + 1);
|
||||
if (ingredient.mData.mEffectID[i] < -1 || ingredient.mData.mEffectID[i] >= ESM::MagicEffect::Length)
|
||||
if (effectIndex < -1 || effectIndex >= ESM::MagicEffect::Length)
|
||||
messages.add(id, "Effect #" + number + ": invalid effect ID", "", CSMDoc::Message::Severity_Error);
|
||||
if (ingredient.mData.mSkills[i] < -1 || ingredient.mData.mSkills[i] >= ESM::Skill::Length)
|
||||
messages.add(id, "Effect #" + number + ": invalid skill", "", CSMDoc::Message::Severity_Error);
|
||||
|
|
|
|||
|
|
@ -73,17 +73,6 @@ namespace CSMWorld
|
|||
return ESM::RefId::stringRefId(Land::createUniqueRecordId(record.mX, record.mY));
|
||||
}
|
||||
|
||||
inline ESM::RefId getRecordId(const ESM::MagicEffect& record)
|
||||
{
|
||||
return ESM::RefId::stringRefId(CSMWorld::getStringId(record.mId));
|
||||
}
|
||||
|
||||
inline void setRecordId(const ESM::RefId& id, ESM::MagicEffect& record)
|
||||
{
|
||||
int index = ESM::MagicEffect::indexNameToIndex(id.getRefIdString());
|
||||
record.mId = ESM::RefId::index(ESM::REC_MGEF, static_cast<std::uint32_t>(index));
|
||||
}
|
||||
|
||||
inline void setRecordId(const ESM::RefId& id, ESM::Skill& record)
|
||||
{
|
||||
if (const auto* skillId = id.getIf<ESM::SkillId>())
|
||||
|
|
|
|||
|
|
@ -25,18 +25,7 @@ namespace CSMWorld
|
|||
|
||||
std::string operator()(ESM::FormId value) const { return value.toString("FormId:"); }
|
||||
|
||||
std::string operator()(ESM::IndexRefId value) const
|
||||
{
|
||||
switch (value.getRecordType())
|
||||
{
|
||||
case ESM::REC_MGEF:
|
||||
return std::string(ESM::MagicEffect::sIndexNames[value.getValue()]);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return value.toDebugString();
|
||||
}
|
||||
std::string operator()(ESM::IndexRefId value) const { return value.toDebugString(); }
|
||||
|
||||
template <class T>
|
||||
std::string operator()(const T& value) const
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ namespace CSMWorld
|
|||
// blank row
|
||||
ESM::IndexedENAMstruct effect;
|
||||
effect.mIndex = position;
|
||||
effect.mData.mEffectID = 0;
|
||||
effect.mData.mEffectID = ESM::MagicEffect::WaterBreathing;
|
||||
effect.mData.mSkill = -1;
|
||||
effect.mData.mAttribute = -1;
|
||||
effect.mData.mRange = 0;
|
||||
|
|
@ -319,34 +319,28 @@ namespace CSMWorld
|
|||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
return effect.mEffectID;
|
||||
return ESM::MagicEffect::refIdToIndex(effect.mEffectID);
|
||||
case 1:
|
||||
{
|
||||
switch (effect.mEffectID)
|
||||
{
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
case ESM::MagicEffect::FortifySkill:
|
||||
case ESM::MagicEffect::AbsorbSkill:
|
||||
return effect.mSkill;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
if (effect.mEffectID == ESM::MagicEffect::DrainSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::DamageSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::RestoreSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifySkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::AbsorbSkill)
|
||||
return effect.mSkill;
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
switch (effect.mEffectID)
|
||||
{
|
||||
case ESM::MagicEffect::DrainAttribute:
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
case ESM::MagicEffect::FortifyAttribute:
|
||||
case ESM::MagicEffect::AbsorbAttribute:
|
||||
return effect.mAttribute;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
if (effect.mEffectID == ESM::MagicEffect::DrainAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::DamageAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::RestoreAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::AbsorbAttribute)
|
||||
return effect.mAttribute;
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
case 3:
|
||||
return effect.mRange;
|
||||
|
|
@ -377,26 +371,23 @@ namespace CSMWorld
|
|||
{
|
||||
case 0:
|
||||
{
|
||||
effect.mEffectID = static_cast<short>(value.toInt());
|
||||
switch (effect.mEffectID)
|
||||
effect.mEffectID = ESM::MagicEffect::indexToRefId(value.toInt());
|
||||
if (effect.mEffectID == ESM::MagicEffect::DrainSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::DamageSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::RestoreSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifySkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::AbsorbSkill)
|
||||
effect.mAttribute = -1;
|
||||
else if (effect.mEffectID == ESM::MagicEffect::DrainAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::DamageAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::RestoreAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::AbsorbAttribute)
|
||||
effect.mSkill = -1;
|
||||
else
|
||||
{
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
case ESM::MagicEffect::FortifySkill:
|
||||
case ESM::MagicEffect::AbsorbSkill:
|
||||
effect.mAttribute = -1;
|
||||
break;
|
||||
case ESM::MagicEffect::DrainAttribute:
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
case ESM::MagicEffect::FortifyAttribute:
|
||||
case ESM::MagicEffect::AbsorbAttribute:
|
||||
effect.mSkill = -1;
|
||||
break;
|
||||
default:
|
||||
effect.mSkill = -1;
|
||||
effect.mAttribute = -1;
|
||||
effect.mSkill = -1;
|
||||
effect.mAttribute = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,37 +144,29 @@ QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData(
|
|||
if (subRowIndex < 0 || subRowIndex >= 4)
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
ESM::RefId effectId = record.get().mData.mEffectID[subRowIndex];
|
||||
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
return record.get().mData.mEffectID[subRowIndex];
|
||||
return ESM::MagicEffect::refIdToIndex(effectId);
|
||||
case 1:
|
||||
{
|
||||
switch (record.get().mData.mEffectID[subRowIndex])
|
||||
{
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
case ESM::MagicEffect::FortifySkill:
|
||||
case ESM::MagicEffect::AbsorbSkill:
|
||||
return record.get().mData.mSkills[subRowIndex];
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
if (effectId == ESM::MagicEffect::DrainSkill || effectId == ESM::MagicEffect::DamageSkill
|
||||
|| effectId == ESM::MagicEffect::RestoreSkill || effectId == ESM::MagicEffect::FortifySkill
|
||||
|| effectId == ESM::MagicEffect::AbsorbSkill)
|
||||
return record.get().mData.mSkills[subRowIndex];
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
switch (record.get().mData.mEffectID[subRowIndex])
|
||||
{
|
||||
case ESM::MagicEffect::DrainAttribute:
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
case ESM::MagicEffect::FortifyAttribute:
|
||||
case ESM::MagicEffect::AbsorbAttribute:
|
||||
return record.get().mData.mAttributes[subRowIndex];
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
if (effectId == ESM::MagicEffect::DrainAttribute || effectId == ESM::MagicEffect::DamageAttribute
|
||||
|| effectId == ESM::MagicEffect::RestoreAttribute || effectId == ESM::MagicEffect::FortifyAttribute
|
||||
|| effectId == ESM::MagicEffect::AbsorbAttribute)
|
||||
return record.get().mData.mAttributes[subRowIndex];
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
||||
|
|
@ -191,29 +183,24 @@ void CSMWorld::IngredEffectRefIdAdapter::setNestedData(
|
|||
if (subRowIndex < 0 || subRowIndex >= 4)
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
ESM::RefId effectId = ESM::MagicEffect::indexToRefId(value.toInt());
|
||||
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
ingredient.mData.mEffectID[subRowIndex] = value.toInt();
|
||||
switch (ingredient.mData.mEffectID[subRowIndex])
|
||||
ingredient.mData.mEffectID[subRowIndex] = effectId;
|
||||
if (effectId == ESM::MagicEffect::DrainSkill || effectId == ESM::MagicEffect::DamageSkill
|
||||
|| effectId == ESM::MagicEffect::RestoreSkill || effectId == ESM::MagicEffect::FortifySkill
|
||||
|| effectId == ESM::MagicEffect::AbsorbSkill)
|
||||
ingredient.mData.mAttributes[subRowIndex] = -1;
|
||||
else if (effectId == ESM::MagicEffect::DrainAttribute || effectId == ESM::MagicEffect::DamageAttribute
|
||||
|| effectId == ESM::MagicEffect::RestoreAttribute || effectId == ESM::MagicEffect::FortifyAttribute
|
||||
|| effectId == ESM::MagicEffect::AbsorbAttribute)
|
||||
ingredient.mData.mSkills[subRowIndex] = -1;
|
||||
else
|
||||
{
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
case ESM::MagicEffect::FortifySkill:
|
||||
case ESM::MagicEffect::AbsorbSkill:
|
||||
ingredient.mData.mAttributes[subRowIndex] = -1;
|
||||
break;
|
||||
case ESM::MagicEffect::DrainAttribute:
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
case ESM::MagicEffect::FortifyAttribute:
|
||||
case ESM::MagicEffect::AbsorbAttribute:
|
||||
ingredient.mData.mSkills[subRowIndex] = -1;
|
||||
break;
|
||||
default:
|
||||
ingredient.mData.mSkills[subRowIndex] = -1;
|
||||
ingredient.mData.mAttributes[subRowIndex] = -1;
|
||||
ingredient.mData.mSkills[subRowIndex] = -1;
|
||||
ingredient.mData.mAttributes[subRowIndex] = -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace MWClass
|
|||
|
||||
std::unique_ptr<MWWorld::Action> Ingredient::use(const MWWorld::Ptr& ptr, bool force) const
|
||||
{
|
||||
if (ptr.get<ESM::Ingredient>()->mBase->mData.mEffectID[0] < 0)
|
||||
if (ptr.get<ESM::Ingredient>()->mBase->mData.mEffectID[0].empty())
|
||||
return std::make_unique<MWWorld::NullAction>();
|
||||
std::unique_ptr<MWWorld::Action> action = std::make_unique<MWWorld::ActionEat>(ptr);
|
||||
|
||||
|
|
@ -131,10 +131,10 @@ namespace MWClass
|
|||
MWGui::Widgets::SpellEffectList list;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (ref->mBase->mData.mEffectID[i] < 0)
|
||||
if (ref->mBase->mData.mEffectID[i].empty())
|
||||
continue;
|
||||
MWGui::Widgets::SpellEffectParams params;
|
||||
params.mEffectID = static_cast<short>(ref->mBase->mData.mEffectID[i]);
|
||||
params.mEffectID = ref->mBase->mData.mEffectID[i];
|
||||
params.mAttribute = ESM::Attribute::indexToRefId(ref->mBase->mData.mAttributes[i]);
|
||||
params.mSkill = ESM::Skill::indexToRefId(ref->mBase->mData.mSkills[i]);
|
||||
params.mKnown = alchemySkill >= fWortChanceValue * (i + 1);
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ namespace MWGui
|
|||
for (const MWMechanics::EffectKey& effectKey : effectIds)
|
||||
{
|
||||
Widgets::SpellEffectParams params;
|
||||
params.mEffectID = static_cast<short>(effectKey.mId);
|
||||
params.mEffectID = effectKey.mId;
|
||||
const ESM::MagicEffect* magicEffect
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effectKey.mId);
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "spellcreationdialog.hpp"
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <MyGUI_Button.h>
|
||||
#include <MyGUI_Gui.h>
|
||||
#include <MyGUI_ImageBox.h>
|
||||
|
|
@ -33,20 +35,20 @@
|
|||
namespace
|
||||
{
|
||||
|
||||
bool sortMagicEffects(short id1, short id2)
|
||||
bool sortMagicEffects(ESM::RefId id1, ESM::RefId id2)
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||
|
||||
return gmst.find(ESM::MagicEffect::indexToGmstString(id1))->mValue.getString()
|
||||
< gmst.find(ESM::MagicEffect::indexToGmstString(id2))->mValue.getString();
|
||||
return gmst.find(ESM::MagicEffect::refIdToGmstString(id1))->mValue.getString()
|
||||
< gmst.find(ESM::MagicEffect::refIdToGmstString(id2))->mValue.getString();
|
||||
}
|
||||
|
||||
void init(ESM::ENAMstruct& effect)
|
||||
{
|
||||
effect.mArea = 0;
|
||||
effect.mDuration = 0;
|
||||
effect.mEffectID = -1;
|
||||
effect.mEffectID = ESM::RefId();
|
||||
effect.mMagnMax = 0;
|
||||
effect.mMagnMin = 0;
|
||||
effect.mRange = 0;
|
||||
|
|
@ -222,9 +224,9 @@ namespace MWGui
|
|||
mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(
|
||||
VFS::Path::toNormalized(effect->mIcon), *MWBase::Environment::get().getResourceSystem()->getVFS()));
|
||||
|
||||
mEffectName->setCaptionWithReplacing("#{" + ESM::MagicEffect::indexToGmstString(effect->mIndex) + "}");
|
||||
mEffectName->setCaptionWithReplacing(std::format("#{{{}}}", ESM::MagicEffect::refIdToGmstString(effect->mId)));
|
||||
|
||||
mEffect.mEffectID = static_cast<int16_t>(effect->mIndex);
|
||||
mEffect.mEffectID = effect->mId;
|
||||
|
||||
mMagicEffect = effect;
|
||||
|
||||
|
|
@ -761,7 +763,7 @@ namespace MWGui
|
|||
, mUsedEffectsView(nullptr)
|
||||
, mAddEffectDialog()
|
||||
, mSelectedEffect(0)
|
||||
, mSelectedKnownEffectId(0)
|
||||
, mSelectedKnownEffectId(ESM::RefId())
|
||||
, mConstantEffect(false)
|
||||
, mType(type)
|
||||
{
|
||||
|
|
@ -782,7 +784,7 @@ namespace MWGui
|
|||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
|
||||
std::vector<short> knownEffects;
|
||||
std::vector<ESM::RefId> knownEffects;
|
||||
|
||||
for (const ESM::Spell* spell : spells)
|
||||
{
|
||||
|
|
@ -792,7 +794,7 @@ namespace MWGui
|
|||
|
||||
for (const ESM::IndexedENAMstruct& effectInfo : spell->mEffects.mList)
|
||||
{
|
||||
int16_t effectId = effectInfo.mData.mEffectID;
|
||||
ESM::RefId effectId = effectInfo.mData.mEffectID;
|
||||
const ESM::MagicEffect* effect
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effectId);
|
||||
|
||||
|
|
@ -812,12 +814,12 @@ namespace MWGui
|
|||
mAvailableEffectsList->clear();
|
||||
|
||||
int i = 0;
|
||||
for (const short effectId : knownEffects)
|
||||
for (const auto effectId : knownEffects)
|
||||
{
|
||||
mAvailableEffectsList->addItem(MWBase::Environment::get()
|
||||
.getESMStore()
|
||||
->get<ESM::GameSetting>()
|
||||
.find(ESM::MagicEffect::indexToGmstString(effectId))
|
||||
.find(ESM::MagicEffect::refIdToGmstString(effectId))
|
||||
->mValue.getString());
|
||||
mButtonMapping[i] = effectId;
|
||||
++i;
|
||||
|
|
@ -826,12 +828,12 @@ namespace MWGui
|
|||
mAvailableEffectsList->scrollToTop();
|
||||
|
||||
mAvailableButtons.clear();
|
||||
for (const short effectId : knownEffects)
|
||||
for (const auto effectId : knownEffects)
|
||||
{
|
||||
const std::string& name = MWBase::Environment::get()
|
||||
.getESMStore()
|
||||
->get<ESM::GameSetting>()
|
||||
.find(ESM::MagicEffect::indexToGmstString(effectId))
|
||||
.find(ESM::MagicEffect::refIdToGmstString(effectId))
|
||||
->mValue.getString();
|
||||
MyGUI::Button* w = mAvailableEffectsList->getItemWidget(name);
|
||||
mAvailableButtons.emplace_back(w);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ namespace MWGui
|
|||
void setConstantEffect(bool constant);
|
||||
|
||||
protected:
|
||||
std::map<int, short> mButtonMapping; // maps button ID to effect ID
|
||||
std::map<int, ESM::RefId> mButtonMapping; // maps button ID to effect ID
|
||||
|
||||
Gui::MWList* mAvailableEffectsList;
|
||||
MyGUI::ScrollView* mUsedEffectsView;
|
||||
|
|
@ -123,7 +123,7 @@ namespace MWGui
|
|||
std::unique_ptr<SelectSkillDialog> mSelectSkillDialog;
|
||||
|
||||
int mSelectedEffect;
|
||||
short mSelectedKnownEffectId;
|
||||
ESM::RefId mSelectedKnownEffectId;
|
||||
|
||||
bool mConstantEffect;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "spellicons.hpp"
|
||||
|
||||
#include <format>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ namespace MWGui
|
|||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
|
||||
std::map<int, std::vector<MagicEffectInfo>> effects;
|
||||
std::map<ESM::RefId, std::vector<MagicEffectInfo>> effects;
|
||||
for (const auto& params : stats.getActiveSpells())
|
||||
{
|
||||
for (const auto& effect : params.getEffects())
|
||||
|
|
@ -154,10 +155,8 @@ namespace MWGui
|
|||
Misc::ResourceHelpers::correctIconPath(VFS::Path::toNormalized(effect->mIcon),
|
||||
*MWBase::Environment::get().getResourceSystem()->getVFS()));
|
||||
|
||||
const std::string& name = ESM::MagicEffect::indexToGmstString(effectId);
|
||||
|
||||
ToolTipInfo tooltipInfo;
|
||||
tooltipInfo.caption = "#{" + name + "}";
|
||||
tooltipInfo.caption = std::format("#{{{}}}", ESM::MagicEffect::refIdToGmstString(effectId));
|
||||
tooltipInfo.icon = effect->mIcon;
|
||||
tooltipInfo.imageSize = 16;
|
||||
tooltipInfo.wordWrap = false;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace MWGui
|
|||
void updateWidgets(MyGUI::Widget* parent, bool adjustSize);
|
||||
|
||||
private:
|
||||
std::map<int, MyGUI::ImageBox*> mWidgetMap;
|
||||
std::map<ESM::RefId, MyGUI::ImageBox*> mWidgetMap;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ namespace MWGui
|
|||
|
||||
for (const auto& effect : effects.mList)
|
||||
{
|
||||
short effectId = effect.mData.mEffectID;
|
||||
ESM::RefId effectId = effect.mData.mEffectID;
|
||||
|
||||
if (effectId != -1)
|
||||
if (!effectId.empty())
|
||||
{
|
||||
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().find(effectId);
|
||||
const ESM::Attribute* attribute
|
||||
|
|
|
|||
|
|
@ -954,11 +954,10 @@ namespace MWGui
|
|||
widget->setUserString("ToolTipLayout", "ClassToolTip");
|
||||
}
|
||||
|
||||
void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id)
|
||||
void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, ESM::RefId effectId)
|
||||
{
|
||||
const auto& store = MWBase::Environment::get().getESMStore();
|
||||
const ESM::MagicEffect* effect = store->get<ESM::MagicEffect>().find(id);
|
||||
const std::string& name = ESM::MagicEffect::indexToGmstString(id);
|
||||
const ESM::MagicEffect* effect = store->get<ESM::MagicEffect>().find(effectId);
|
||||
|
||||
std::string icon = effect->mIcon;
|
||||
icon.insert(icon.rfind('\\') + 1, "b_");
|
||||
|
|
@ -967,7 +966,8 @@ namespace MWGui
|
|||
|
||||
widget->setUserString("ToolTipType", "Layout");
|
||||
widget->setUserString("ToolTipLayout", "MagicEffectToolTip");
|
||||
widget->setUserString("Caption_MagicEffectName", "#{" + name + "}");
|
||||
widget->setUserString(
|
||||
"Caption_MagicEffectName", std::format("#{{{}}}", ESM::MagicEffect::refIdToGmstString(effectId)));
|
||||
widget->setUserString("Caption_MagicEffectDescription", effect->mDescription);
|
||||
widget->setUserString("Caption_MagicEffectSchool",
|
||||
"#{sSchool}: "
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ namespace MWGui
|
|||
static void createBirthsignToolTip(MyGUI::Widget* widget, const ESM::RefId& birthsignId);
|
||||
static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace);
|
||||
static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass);
|
||||
static void createMagicEffectToolTip(MyGUI::Widget* widget, short id);
|
||||
static void createMagicEffectToolTip(MyGUI::Widget* widget, ESM::RefId effectId);
|
||||
|
||||
bool checkOwned();
|
||||
/// Returns True if taking mFocusObject would be crime
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <components/esm/attr.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/effectlist.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
|
||||
namespace MyGUI
|
||||
|
|
@ -40,7 +41,6 @@ namespace MWGui
|
|||
, mIsConstant(false)
|
||||
, mNoMagnitude(false)
|
||||
, mKnown(true)
|
||||
, mEffectID(-1)
|
||||
, mMagnMin(-1)
|
||||
, mMagnMax(-1)
|
||||
, mRange(-1)
|
||||
|
|
@ -55,10 +55,8 @@ namespace MWGui
|
|||
|
||||
bool mKnown; // is this effect known to the player? (If not, will display as a question mark instead)
|
||||
|
||||
// value of -1 here means the effect is unknown to the player
|
||||
short mEffectID;
|
||||
|
||||
ESM::RefId mSkill, mAttribute;
|
||||
// value of EmptyRefId here means the effect is unknown to the player
|
||||
ESM::RefId mEffectID, mSkill, mAttribute;
|
||||
|
||||
// value of -1 here means the value is unavailable
|
||||
int mMagnMin, mMagnMax, mRange, mDuration;
|
||||
|
|
@ -71,16 +69,13 @@ namespace MWGui
|
|||
if (mEffectID != other.mEffectID)
|
||||
return false;
|
||||
|
||||
bool involvesAttribute = (mEffectID == 74 // restore attribute
|
||||
|| mEffectID == 85 // absorb attribute
|
||||
|| mEffectID == 17 // drain attribute
|
||||
|| mEffectID == 79 // fortify attribute
|
||||
|| mEffectID == 22); // damage attribute
|
||||
bool involvesSkill = (mEffectID == 78 // restore skill
|
||||
|| mEffectID == 89 // absorb skill
|
||||
|| mEffectID == 21 // drain skill
|
||||
|| mEffectID == 83 // fortify skill
|
||||
|| mEffectID == 26); // damage skill
|
||||
bool involvesAttribute = (mEffectID == ESM::MagicEffect::RestoreAttribute
|
||||
|| mEffectID == ESM::MagicEffect::AbsorbAttribute || mEffectID == ESM::MagicEffect::DrainAttribute
|
||||
|| mEffectID == ESM::MagicEffect::FortifyAttribute
|
||||
|| mEffectID == ESM::MagicEffect::DamageAttribute);
|
||||
bool involvesSkill = (mEffectID == ESM::MagicEffect::RestoreSkill
|
||||
|| mEffectID == ESM::MagicEffect::AbsorbSkill || mEffectID == ESM::MagicEffect::DrainSkill
|
||||
|| mEffectID == ESM::MagicEffect::FortifySkill || mEffectID == ESM::MagicEffect::DamageSkill);
|
||||
return ((other.mSkill == mSkill) || !involvesSkill)
|
||||
&& ((other.mAttribute == mAttribute) && !involvesAttribute) && (other.mArea == mArea);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "magicbindings.hpp"
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <components/esm3/activespells.hpp>
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadarmo.hpp>
|
||||
|
|
@ -245,9 +247,10 @@ namespace MWLua
|
|||
|
||||
sol::table effect(state, sol::create);
|
||||
magicApi["EFFECT_TYPE"] = LuaUtil::makeStrictReadOnly(effect);
|
||||
for (const auto& name : ESM::MagicEffect::sIndexNames)
|
||||
for (int i = 0; i < ESM::MagicEffect::Length; ++i)
|
||||
{
|
||||
effect[name] = Misc::StringUtils::lowerCase(name);
|
||||
std::string_view name = ESM::MagicEffect::indexToName(i);
|
||||
effect[name] = ESM::MagicEffect::indexToRefId(i).serializeText();
|
||||
}
|
||||
|
||||
// Spell store
|
||||
|
|
@ -262,43 +265,9 @@ namespace MWLua
|
|||
|
||||
// MagicEffect store
|
||||
sol::table magicEffects(state, sol::create);
|
||||
addRecordFunctionBinding<ESM::MagicEffect>(magicEffects, context);
|
||||
magicApi["effects"] = LuaUtil::makeReadOnly(magicEffects);
|
||||
using MagicEffectStore = MWWorld::Store<ESM::MagicEffect>;
|
||||
const MagicEffectStore* magicEffectStore
|
||||
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>();
|
||||
auto magicEffectStoreT = state.new_usertype<MagicEffectStore>("ESM3_MagicEffectStore");
|
||||
magicEffectStoreT[sol::meta_function::to_string] = [](const MagicEffectStore& store) {
|
||||
return "ESM3_MagicEffectStore{" + std::to_string(store.getSize()) + " effects}";
|
||||
};
|
||||
magicEffectStoreT[sol::meta_function::index] = sol::overload(
|
||||
[](const MagicEffectStore& store, int id) -> const ESM::MagicEffect* { return store.search(id); },
|
||||
[](const MagicEffectStore& store, std::string_view id) -> const ESM::MagicEffect* {
|
||||
int index = ESM::MagicEffect::indexNameToIndex(id);
|
||||
return store.search(index);
|
||||
});
|
||||
auto magicEffectsIter = [magicEffectStore](sol::this_state thisState, const sol::object& /*store*/,
|
||||
sol::optional<int> id) -> std::tuple<sol::object, sol::object> {
|
||||
MagicEffectStore::iterator iter;
|
||||
if (id.has_value())
|
||||
{
|
||||
iter = magicEffectStore->findIter(*id);
|
||||
if (iter != magicEffectStore->end())
|
||||
iter++;
|
||||
}
|
||||
else
|
||||
iter = magicEffectStore->begin();
|
||||
if (iter != magicEffectStore->end())
|
||||
return std::make_tuple(
|
||||
sol::make_object(thisState, iter->first), sol::make_object(thisState, &iter->second));
|
||||
else
|
||||
return std::make_tuple(sol::nil, sol::nil);
|
||||
};
|
||||
magicEffectStoreT[sol::meta_function::pairs]
|
||||
= [iter = sol::make_object(state, magicEffectsIter)] { return iter; };
|
||||
magicEffectStoreT[sol::meta_function::ipairs]
|
||||
= [iter = sol::make_object(state, magicEffectsIter)] { return iter; };
|
||||
|
||||
magicEffects["records"] = magicEffectStore;
|
||||
const auto* magicEffectStore = &MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>();
|
||||
|
||||
// Spell record
|
||||
auto spellT = state.new_usertype<ESM::Spell>("ESM3_Spell");
|
||||
|
|
@ -345,16 +314,14 @@ namespace MWLua
|
|||
auto effectParamsT = state.new_usertype<ESM::IndexedENAMstruct>("ESM3_EffectParams");
|
||||
effectParamsT[sol::meta_function::to_string] = [magicEffectStore](const ESM::IndexedENAMstruct& params) {
|
||||
const ESM::MagicEffect* const rec = magicEffectStore->find(params.mData.mEffectID);
|
||||
return "ESM3_EffectParams[" + ESM::MagicEffect::indexToGmstString(rec->mIndex) + "]";
|
||||
return std::format("ESM3_EffectParams[{}]", ESM::MagicEffect::refIdToGmstString(rec->mId));
|
||||
};
|
||||
effectParamsT["effect"] = sol::readonly_property(
|
||||
[magicEffectStore](const ESM::IndexedENAMstruct& params) -> const ESM::MagicEffect* {
|
||||
return magicEffectStore->find(params.mData.mEffectID);
|
||||
});
|
||||
effectParamsT["id"] = sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> std::string {
|
||||
auto name = ESM::MagicEffect::indexToName(params.mData.mEffectID);
|
||||
return Misc::StringUtils::lowerCase(name);
|
||||
});
|
||||
effectParamsT["id"] = sol::readonly_property(
|
||||
[](const ESM::IndexedENAMstruct& params) -> ESM::RefId { return params.mData.mEffectID; });
|
||||
effectParamsT["affectedSkill"]
|
||||
= sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> sol::optional<std::string> {
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(params.mData.mSkill);
|
||||
|
|
@ -386,12 +353,9 @@ namespace MWLua
|
|||
auto magicEffectT = state.new_usertype<ESM::MagicEffect>("ESM3_MagicEffect");
|
||||
|
||||
magicEffectT[sol::meta_function::to_string] = [](const ESM::MagicEffect& rec) {
|
||||
return "ESM3_MagicEffect[" + ESM::MagicEffect::indexToGmstString(rec.mIndex) + "]";
|
||||
return std::format("ESM3_MagicEffect[{}]", ESM::MagicEffect::refIdToGmstString(rec.mId));
|
||||
};
|
||||
magicEffectT["id"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> std::string {
|
||||
auto name = ESM::MagicEffect::indexToName(rec.mIndex);
|
||||
return Misc::StringUtils::lowerCase(name);
|
||||
});
|
||||
magicEffectT["id"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> ESM::RefId { return rec.mId; });
|
||||
magicEffectT["icon"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> std::string {
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
return Misc::ResourceHelpers::correctIconPath(VFS::Path::toNormalized(rec.mIcon), *vfs);
|
||||
|
|
@ -422,7 +386,7 @@ namespace MWLua
|
|||
.getWorld()
|
||||
->getStore()
|
||||
.get<ESM::GameSetting>()
|
||||
.find(ESM::MagicEffect::indexToGmstString(rec.mIndex))
|
||||
.find(ESM::MagicEffect::refIdToGmstString(rec.mId))
|
||||
->mValue.getString();
|
||||
});
|
||||
magicEffectT["school"] = sol::readonly_property(
|
||||
|
|
@ -453,12 +417,10 @@ namespace MWLua
|
|||
|
||||
auto activeSpellEffectT = state.new_usertype<ESM::ActiveEffect>("ActiveSpellEffect");
|
||||
activeSpellEffectT[sol::meta_function::to_string] = [](const ESM::ActiveEffect& self) {
|
||||
return "ActiveSpellEffect[" + ESM::MagicEffect::indexToGmstString(self.mEffectId) + "]";
|
||||
return std::format("ActiveSpellEffect[{}]", ESM::MagicEffect::refIdToGmstString(self.mEffectId));
|
||||
};
|
||||
activeSpellEffectT["id"] = sol::readonly_property([](const ESM::ActiveEffect& self) -> std::string {
|
||||
auto name = ESM::MagicEffect::indexToName(self.mEffectId);
|
||||
return Misc::StringUtils::lowerCase(name);
|
||||
});
|
||||
activeSpellEffectT["id"]
|
||||
= sol::readonly_property([](const ESM::ActiveEffect& self) -> ESM::RefId { return self.mEffectId; });
|
||||
activeSpellEffectT["index"]
|
||||
= sol::readonly_property([](const ESM::ActiveEffect& self) -> int { return self.mEffectIndex; });
|
||||
activeSpellEffectT["name"] = sol::readonly_property([](const ESM::ActiveEffect& self) -> std::string {
|
||||
|
|
@ -588,12 +550,10 @@ namespace MWLua
|
|||
auto activeEffectT = state.new_usertype<ActiveEffect>("ActiveEffect");
|
||||
|
||||
activeEffectT[sol::meta_function::to_string] = [](const ActiveEffect& self) {
|
||||
return "ActiveEffect[" + ESM::MagicEffect::indexToGmstString(self.key.mId) + "]";
|
||||
return std::format("ActiveEffect[{}]", ESM::MagicEffect::refIdToGmstString(self.key.mId));
|
||||
};
|
||||
activeEffectT["id"] = sol::readonly_property([](const ActiveEffect& self) -> std::string {
|
||||
auto name = ESM::MagicEffect::indexToName(self.key.mId);
|
||||
return Misc::StringUtils::lowerCase(name);
|
||||
});
|
||||
activeEffectT["id"]
|
||||
= sol::readonly_property([](const ActiveEffect& self) -> ESM::RefId { return self.key.mId; });
|
||||
activeEffectT["name"]
|
||||
= sol::readonly_property([](const ActiveEffect& self) -> std::string { return self.key.toString(); });
|
||||
|
||||
|
|
@ -1024,7 +984,7 @@ namespace MWLua
|
|||
|
||||
auto getEffectKey
|
||||
= [](std::string_view idStr, sol::optional<std::string_view> argStr) -> MWMechanics::EffectKey {
|
||||
auto id = ESM::MagicEffect::indexNameToIndex(idStr);
|
||||
auto id = ESM::RefId::deserializeText(idStr);
|
||||
auto* rec = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(id);
|
||||
|
||||
MWMechanics::EffectKey key = MWMechanics::EffectKey(id);
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ namespace MWLua
|
|||
sol::table res(lua, sol::create);
|
||||
for (uint32_t i = 0; i < 4; ++i)
|
||||
{
|
||||
if (rec.mData.mEffectID[i] < 0)
|
||||
if (rec.mData.mEffectID[i].empty())
|
||||
continue;
|
||||
ESM::IndexedENAMstruct effect;
|
||||
effect.mData.mEffectID = static_cast<int16_t>(rec.mData.mEffectID[i]);
|
||||
effect.mData.mEffectID = rec.mData.mEffectID[i];
|
||||
effect.mData.mSkill = static_cast<signed char>(rec.mData.mSkills[i]);
|
||||
effect.mData.mAttribute = static_cast<signed char>(rec.mData.mAttributes[i]);
|
||||
effect.mData.mRange = ESM::RT_Self;
|
||||
|
|
@ -63,4 +63,4 @@ namespace MWLua
|
|||
return res;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ namespace MWMechanics
|
|||
|
||||
if (Settings::game().mClassicCalmSpellsBehavior)
|
||||
{
|
||||
ESM::MagicEffect::Effects effect
|
||||
ESM::RefId effect
|
||||
= ptr.getClass().isNpc() ? ESM::MagicEffect::CalmHumanoid : ESM::MagicEffect::CalmCreature;
|
||||
if (creatureStats.getMagicEffects().getOrDefault(effect).getMagnitude() > 0.f)
|
||||
creatureStats.getAiSequence().stopCombat();
|
||||
|
|
@ -426,8 +426,7 @@ namespace MWMechanics
|
|||
{
|
||||
const VFS::Path::Normalized reflectStaticModel
|
||||
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(reflectStatic->mModel));
|
||||
animation->addEffect(
|
||||
reflectStaticModel, ESM::MagicEffect::indexToName(ESM::MagicEffect::Reflect), false);
|
||||
animation->addEffect(reflectStaticModel, ESM::MagicEffect::Reflect.getValue(), false);
|
||||
}
|
||||
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell(*reflected);
|
||||
}
|
||||
|
|
@ -646,7 +645,7 @@ namespace MWMechanics
|
|||
purge([=](const ActiveSpellParams& params) { return params.mActiveSpellId == id; }, ptr);
|
||||
}
|
||||
|
||||
void ActiveSpells::purgeEffect(const MWWorld::Ptr& ptr, int effectId, ESM::RefId effectArg)
|
||||
void ActiveSpells::purgeEffect(const MWWorld::Ptr& ptr, ESM::RefId effectId, ESM::RefId effectArg)
|
||||
{
|
||||
purge(
|
||||
[=](const ActiveSpellParams&, const ESM::ActiveEffect& effect) {
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ namespace MWMechanics
|
|||
void removeEffectsByActiveSpellId(const MWWorld::Ptr& ptr, const ESM::RefId& id);
|
||||
|
||||
/// Remove all active effects with this effect id
|
||||
void purgeEffect(const MWWorld::Ptr& ptr, int effectId, ESM::RefId effectArg = {});
|
||||
void purgeEffect(const MWWorld::Ptr& ptr, ESM::RefId effectId, ESM::RefId effectArg = {});
|
||||
|
||||
void purge(EffectPredicate predicate, const MWWorld::Ptr& ptr);
|
||||
void purge(ParamsPredicate predicate, const MWWorld::Ptr& ptr);
|
||||
|
|
|
|||
|
|
@ -796,7 +796,7 @@ namespace MWMechanics
|
|||
continue;
|
||||
for (const auto& effect : spell.getEffects())
|
||||
{
|
||||
static const std::array<int, 7> damageEffects{
|
||||
static const std::array<ESM::RefId, 7> damageEffects{
|
||||
ESM::MagicEffect::FireDamage,
|
||||
ESM::MagicEffect::ShockDamage,
|
||||
ESM::MagicEffect::FrostDamage,
|
||||
|
|
@ -1817,7 +1817,7 @@ namespace MWMechanics
|
|||
// Make sure spell effects are removed
|
||||
purgeSpellEffects(actor.getPtr().getCellRef().getRefNum());
|
||||
|
||||
stats.getMagicEffects().add(ESM::MagicEffect::Vampirism, vampirism);
|
||||
stats.getMagicEffects().add(EffectKey(ESM::MagicEffect::Vampirism), vampirism);
|
||||
|
||||
if (isPlayer)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <cmath>
|
||||
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ namespace
|
|||
|
||||
std::optional<MWMechanics::EffectKey> toKey(const ESM::Ingredient& ingredient, size_t i)
|
||||
{
|
||||
if (ingredient.mData.mEffectID[i] < 0)
|
||||
if (ingredient.mData.mEffectID[i].empty())
|
||||
return {};
|
||||
ESM::RefId arg = ESM::Skill::indexToRefId(ingredient.mData.mSkills[i]);
|
||||
if (arg.empty())
|
||||
|
|
@ -176,7 +177,7 @@ void MWMechanics::Alchemy::updateEffects()
|
|||
|
||||
if (magicEffect->mData.mBaseCost <= 0)
|
||||
{
|
||||
const std::string os = "invalid base cost for magic effect " + std::to_string(effectKey.mId);
|
||||
const std::string os = std::format("invalid base cost for magic effect {}", effectKey.mId.getRefIdString());
|
||||
throw std::runtime_error(os);
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +218,7 @@ void MWMechanics::Alchemy::updateEffects()
|
|||
if (magnitude > 0 && duration > 0)
|
||||
{
|
||||
ESM::ENAMstruct effect;
|
||||
effect.mEffectID = static_cast<int16_t>(effectKey.mId);
|
||||
effect.mEffectID = effectKey.mId;
|
||||
|
||||
effect.mAttribute = -1;
|
||||
effect.mSkill = -1;
|
||||
|
|
@ -621,7 +622,7 @@ std::vector<std::string> MWMechanics::Alchemy::effectsDescription(
|
|||
if (alchemySkill < fWortChanceValue * static_cast<int>(i + 1))
|
||||
break;
|
||||
|
||||
if (effectID != -1)
|
||||
if (!effectID.empty())
|
||||
{
|
||||
const ESM::Attribute* attribute
|
||||
= store->get<ESM::Attribute>().search(ESM::Attribute::indexToRefId(data.mAttributes[i]));
|
||||
|
|
|
|||
|
|
@ -2803,19 +2803,19 @@ namespace MWMechanics
|
|||
// Stop any effects that are no longer active
|
||||
std::vector<std::string_view> effects = mAnimation->getLoopingEffects();
|
||||
|
||||
for (std::string_view effectId : effects)
|
||||
for (std::string_view effectStr : effects)
|
||||
{
|
||||
auto index = ESM::MagicEffect::indexNameToIndex(effectId);
|
||||
auto effectId = ESM::RefId::deserializeText(effectStr);
|
||||
|
||||
if (index >= 0
|
||||
if (MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().search(effectId)
|
||||
&& (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished()
|
||||
|| mPtr.getClass()
|
||||
.getCreatureStats(mPtr)
|
||||
.getMagicEffects()
|
||||
.getOrDefault(MWMechanics::EffectKey(index))
|
||||
.getOrDefault(MWMechanics::EffectKey(effectId))
|
||||
.getMagnitude()
|
||||
<= 0))
|
||||
mAnimation->removeEffect(effectId);
|
||||
mAnimation->removeEffect(effectStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -350,12 +350,14 @@ namespace MWMechanics
|
|||
if (godmode)
|
||||
return;
|
||||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
static const std::array<ESM::RefId, 3> elementalShieldEffects{ ESM::MagicEffect::FireShield,
|
||||
ESM::MagicEffect::LightningShield, ESM::MagicEffect::FrostShield };
|
||||
for (const auto elementalShieldEffect : elementalShieldEffects)
|
||||
{
|
||||
float magnitude = victim.getClass()
|
||||
.getCreatureStats(victim)
|
||||
.getMagicEffects()
|
||||
.getOrDefault(ESM::MagicEffect::FireShield + i)
|
||||
.getOrDefault(elementalShieldEffect)
|
||||
.getMagnitude();
|
||||
|
||||
if (!magnitude)
|
||||
|
|
@ -375,10 +377,10 @@ namespace MWMechanics
|
|||
|
||||
float x = std::max(0.f, saveTerm - Misc::Rng::roll0to99(prng));
|
||||
|
||||
short element = ESM::MagicEffect::FireDamage;
|
||||
if (i == 1)
|
||||
ESM::RefId element = ESM::MagicEffect::FireDamage;
|
||||
if (elementalShieldEffect == ESM::MagicEffect::LightningShield)
|
||||
element = ESM::MagicEffect::ShockDamage;
|
||||
if (i == 2)
|
||||
if (elementalShieldEffect == ESM::MagicEffect::FrostShield)
|
||||
element = ESM::MagicEffect::FrostDamage;
|
||||
|
||||
float elementResistance
|
||||
|
|
|
|||
|
|
@ -649,7 +649,7 @@ namespace MWMechanics
|
|||
return mTimeOfDeath;
|
||||
}
|
||||
|
||||
std::multimap<int, ESM::RefNum>& CreatureStats::getSummonedCreatureMap()
|
||||
std::multimap<ESM::RefId, ESM::RefNum>& CreatureStats::getSummonedCreatureMap()
|
||||
{
|
||||
return mSummonedCreatures;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ namespace MWMechanics
|
|||
MWWorld::TimeStamp mTimeOfDeath;
|
||||
|
||||
private:
|
||||
std::multimap<int, ESM::RefNum> mSummonedCreatures; // <Effect, Actor>
|
||||
std::multimap<ESM::RefId, ESM::RefNum> mSummonedCreatures; // <Effect, Actor>
|
||||
|
||||
float mAwarenessTimer = 0.f;
|
||||
int mAwarenessRoll = -1;
|
||||
|
|
@ -231,7 +231,7 @@ namespace MWMechanics
|
|||
void setBlock(bool value);
|
||||
bool getBlock() const;
|
||||
|
||||
std::multimap<int, ESM::RefNum>& getSummonedCreatureMap(); // <Effect, summoned creature>
|
||||
std::multimap<ESM::RefId, ESM::RefNum>& getSummonedCreatureMap(); // <Effect, summoned creature>
|
||||
|
||||
enum Flag
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace
|
|||
namespace MWMechanics
|
||||
{
|
||||
EffectKey::EffectKey()
|
||||
: mId(0)
|
||||
: mId(ESM::MagicEffect::WaterWalking)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -55,13 +55,7 @@ namespace MWMechanics
|
|||
|
||||
bool operator<(const EffectKey& left, const EffectKey& right)
|
||||
{
|
||||
if (left.mId < right.mId)
|
||||
return true;
|
||||
|
||||
if (left.mId > right.mId)
|
||||
return false;
|
||||
|
||||
return left.mArg < right.mArg;
|
||||
return std::tie(left.mId, left.mArg) < std::tie(right.mId, right.mArg);
|
||||
}
|
||||
|
||||
bool operator==(const EffectKey& left, const EffectKey& right)
|
||||
|
|
@ -145,6 +139,11 @@ namespace MWMechanics
|
|||
return get(key).value_or(EffectParam());
|
||||
}
|
||||
|
||||
EffectParam MagicEffects::getOrDefault(ESM::RefId effectId) const
|
||||
{
|
||||
return getOrDefault(EffectKey(effectId));
|
||||
}
|
||||
|
||||
std::optional<EffectParam> MagicEffects::get(const EffectKey& key) const
|
||||
{
|
||||
Collection::const_iterator iter = mCollection.find(key);
|
||||
|
|
@ -189,34 +188,21 @@ namespace MWMechanics
|
|||
|
||||
if (targetsSkill || targetsAttribute)
|
||||
{
|
||||
switch (effect.mIndex)
|
||||
{
|
||||
case ESM::MagicEffect::AbsorbAttribute:
|
||||
case ESM::MagicEffect::AbsorbSkill:
|
||||
spellLine = windowManager->getGameSettingString("sAbsorb", {});
|
||||
break;
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
spellLine = windowManager->getGameSettingString("sDamage", {});
|
||||
break;
|
||||
case ESM::MagicEffect::DrainAttribute:
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
spellLine = windowManager->getGameSettingString("sDrain", {});
|
||||
break;
|
||||
case ESM::MagicEffect::FortifyAttribute:
|
||||
case ESM::MagicEffect::FortifySkill:
|
||||
spellLine = windowManager->getGameSettingString("sFortify", {});
|
||||
break;
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
spellLine = windowManager->getGameSettingString("sRestore", {});
|
||||
break;
|
||||
}
|
||||
if (effect.mId == ESM::MagicEffect::AbsorbAttribute || effect.mId == ESM::MagicEffect::AbsorbSkill)
|
||||
spellLine = windowManager->getGameSettingString("sAbsorb", {});
|
||||
else if (effect.mId == ESM::MagicEffect::DamageAttribute || effect.mId == ESM::MagicEffect::DamageSkill)
|
||||
spellLine = windowManager->getGameSettingString("sDamage", {});
|
||||
else if (effect.mId == ESM::MagicEffect::DrainAttribute || effect.mId == ESM::MagicEffect::DrainSkill)
|
||||
spellLine = windowManager->getGameSettingString("sDrain", {});
|
||||
else if (effect.mId == ESM::MagicEffect::FortifyAttribute || effect.mId == ESM::MagicEffect::FortifySkill)
|
||||
spellLine = windowManager->getGameSettingString("sFortify", {});
|
||||
else if (effect.mId == ESM::MagicEffect::RestoreAttribute || effect.mId == ESM::MagicEffect::RestoreSkill)
|
||||
spellLine = windowManager->getGameSettingString("sRestore", {});
|
||||
}
|
||||
|
||||
if (spellLine.empty())
|
||||
{
|
||||
auto& effectIDStr = ESM::MagicEffect::indexToGmstString(effect.mIndex);
|
||||
auto effectIDStr = ESM::MagicEffect::refIdToGmstString(effect.mId);
|
||||
spellLine = windowManager->getGameSettingString(effectIDStr, {});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ namespace MWMechanics
|
|||
{
|
||||
struct EffectKey
|
||||
{
|
||||
int mId;
|
||||
ESM::RefId mId;
|
||||
ESM::RefId mArg; // skill or ability
|
||||
|
||||
EffectKey();
|
||||
|
||||
EffectKey(int id, ESM::RefId arg = {})
|
||||
EffectKey(ESM::RefId id, ESM::RefId arg = {})
|
||||
: mId(id)
|
||||
, mArg(arg)
|
||||
{
|
||||
|
|
@ -107,6 +107,7 @@ namespace MWMechanics
|
|||
void modifyBase(const EffectKey& key, int diff);
|
||||
|
||||
EffectParam getOrDefault(const EffectKey& key) const;
|
||||
EffectParam getOrDefault(ESM::RefId effectId) const;
|
||||
std::optional<EffectParam> get(const EffectKey& key) const;
|
||||
///< This function can safely be used for keys that are not present.
|
||||
};
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ namespace MWMechanics
|
|||
ESM::RefId school = ESM::Skill::Alteration;
|
||||
if (!enchantment->mEffects.mList.empty())
|
||||
{
|
||||
short effectId = enchantment->mEffects.mList.front().mData.mEffectID;
|
||||
ESM::RefId effectId = enchantment->mEffects.mList.front().mData.mEffectID;
|
||||
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().find(effectId);
|
||||
school = magicEffect->mData.mSchool;
|
||||
}
|
||||
|
|
@ -509,8 +509,8 @@ namespace MWMechanics
|
|||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
||||
if (animation)
|
||||
{
|
||||
animation->addEffect(castStaticModel.value(), ESM::MagicEffect::indexToName(effect->mIndex), false, {},
|
||||
effect->mParticle);
|
||||
animation->addEffect(
|
||||
castStaticModel.value(), effect->mId.getRefIdString(), false, {}, effect->mParticle);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -585,8 +585,8 @@ namespace MWMechanics
|
|||
{
|
||||
const VFS::Path::Normalized castStaticModel
|
||||
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(castStatic->mModel));
|
||||
anim->addEffect(castStaticModel.value(), ESM::MagicEffect::indexToName(magicEffect.mIndex), loop, {},
|
||||
magicEffect.mParticle);
|
||||
anim->addEffect(
|
||||
castStaticModel.value(), magicEffect.mId.getRefIdString(), loop, {}, magicEffect.mParticle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -23,7 +23,14 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
int numEffectsToDispel(const MWWorld::Ptr& actor, int effectFilter = -1, bool negative = true)
|
||||
enum Stats
|
||||
{
|
||||
Health = 0,
|
||||
Magicka = 1,
|
||||
Fatigue = 2
|
||||
};
|
||||
|
||||
int numEffectsToDispel(const MWWorld::Ptr& actor, ESM::RefId effectFilter = ESM::RefId(), bool negative = true)
|
||||
{
|
||||
int toCure = 0;
|
||||
const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells();
|
||||
|
|
@ -31,7 +38,7 @@ namespace
|
|||
{
|
||||
// if the effect filter is not specified, take in account only spells effects. Leave potions, enchanted
|
||||
// items etc.
|
||||
if (effectFilter == -1)
|
||||
if (effectFilter.empty())
|
||||
{
|
||||
const ESM::Spell* spell
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::Spell>().search(it->getSourceSpellId());
|
||||
|
|
@ -42,8 +49,8 @@ namespace
|
|||
const MWMechanics::ActiveSpells::ActiveSpellParams& params = *it;
|
||||
for (const auto& effect : params.getEffects())
|
||||
{
|
||||
int effectId = effect.mEffectId;
|
||||
if (effectFilter != -1 && effectId != effectFilter)
|
||||
ESM::RefId effectId = effect.mEffectId;
|
||||
if (!effectFilter.empty() && effectId != effectFilter)
|
||||
continue;
|
||||
const ESM::MagicEffect* magicEffect
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effectId);
|
||||
|
|
@ -207,404 +214,363 @@ namespace MWMechanics
|
|||
// NOTE: enemy may be empty
|
||||
|
||||
float rating = 1;
|
||||
switch (effect.mEffectID)
|
||||
if (effect.mEffectID == ESM::MagicEffect::Soultrap || effect.mEffectID == ESM::MagicEffect::AlmsiviIntervention
|
||||
|| effect.mEffectID == ESM::MagicEffect::DivineIntervention
|
||||
|| effect.mEffectID == ESM::MagicEffect::CalmHumanoid || effect.mEffectID == ESM::MagicEffect::CalmCreature
|
||||
|| effect.mEffectID == ESM::MagicEffect::FrenzyHumanoid
|
||||
|| effect.mEffectID == ESM::MagicEffect::FrenzyCreature
|
||||
|| effect.mEffectID == ESM::MagicEffect::DemoralizeHumanoid
|
||||
|| effect.mEffectID == ESM::MagicEffect::DemoralizeCreature
|
||||
|| effect.mEffectID == ESM::MagicEffect::RallyHumanoid
|
||||
|| effect.mEffectID == ESM::MagicEffect::RallyCreature || effect.mEffectID == ESM::MagicEffect::Charm
|
||||
|| effect.mEffectID == ESM::MagicEffect::DetectAnimal
|
||||
|| effect.mEffectID == ESM::MagicEffect::DetectEnchantment
|
||||
|| effect.mEffectID == ESM::MagicEffect::DetectKey || effect.mEffectID == ESM::MagicEffect::Telekinesis
|
||||
|| effect.mEffectID == ESM::MagicEffect::Mark || effect.mEffectID == ESM::MagicEffect::Recall
|
||||
|| effect.mEffectID == ESM::MagicEffect::Jump || effect.mEffectID == ESM::MagicEffect::WaterBreathing
|
||||
|| effect.mEffectID == ESM::MagicEffect::SwiftSwim || effect.mEffectID == ESM::MagicEffect::WaterWalking
|
||||
|| effect.mEffectID == ESM::MagicEffect::SlowFall || effect.mEffectID == ESM::MagicEffect::Light
|
||||
|| effect.mEffectID == ESM::MagicEffect::Lock || effect.mEffectID == ESM::MagicEffect::Open
|
||||
|| effect.mEffectID == ESM::MagicEffect::TurnUndead
|
||||
|| effect.mEffectID == ESM::MagicEffect::WeaknessToCommonDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::WeaknessToBlightDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::WeaknessToCorprusDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::CureCommonDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::CureBlightDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::CureCorprusDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistBlightDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistCommonDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistCorprusDisease
|
||||
|| effect.mEffectID == ESM::MagicEffect::Invisibility || effect.mEffectID == ESM::MagicEffect::Chameleon
|
||||
|| effect.mEffectID == ESM::MagicEffect::NightEye || effect.mEffectID == ESM::MagicEffect::Vampirism
|
||||
|| effect.mEffectID == ESM::MagicEffect::StuntedMagicka || effect.mEffectID == ESM::MagicEffect::ExtraSpell
|
||||
|| effect.mEffectID == ESM::MagicEffect::RemoveCurse
|
||||
|| effect.mEffectID == ESM::MagicEffect::CommandCreature
|
||||
|| effect.mEffectID == ESM::MagicEffect::CommandHumanoid)
|
||||
return 0.f;
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Blind)
|
||||
{
|
||||
case ESM::MagicEffect::Soultrap:
|
||||
case ESM::MagicEffect::AlmsiviIntervention:
|
||||
case ESM::MagicEffect::DivineIntervention:
|
||||
case ESM::MagicEffect::CalmHumanoid:
|
||||
case ESM::MagicEffect::CalmCreature:
|
||||
case ESM::MagicEffect::FrenzyHumanoid:
|
||||
case ESM::MagicEffect::FrenzyCreature:
|
||||
case ESM::MagicEffect::DemoralizeHumanoid:
|
||||
case ESM::MagicEffect::DemoralizeCreature:
|
||||
case ESM::MagicEffect::RallyHumanoid:
|
||||
case ESM::MagicEffect::RallyCreature:
|
||||
case ESM::MagicEffect::Charm:
|
||||
case ESM::MagicEffect::DetectAnimal:
|
||||
case ESM::MagicEffect::DetectEnchantment:
|
||||
case ESM::MagicEffect::DetectKey:
|
||||
case ESM::MagicEffect::Telekinesis:
|
||||
case ESM::MagicEffect::Mark:
|
||||
case ESM::MagicEffect::Recall:
|
||||
case ESM::MagicEffect::Jump:
|
||||
case ESM::MagicEffect::WaterBreathing:
|
||||
case ESM::MagicEffect::SwiftSwim:
|
||||
case ESM::MagicEffect::WaterWalking:
|
||||
case ESM::MagicEffect::SlowFall:
|
||||
case ESM::MagicEffect::Light:
|
||||
case ESM::MagicEffect::Lock:
|
||||
case ESM::MagicEffect::Open:
|
||||
case ESM::MagicEffect::TurnUndead:
|
||||
case ESM::MagicEffect::WeaknessToCommonDisease:
|
||||
case ESM::MagicEffect::WeaknessToBlightDisease:
|
||||
case ESM::MagicEffect::WeaknessToCorprusDisease:
|
||||
case ESM::MagicEffect::CureCommonDisease:
|
||||
case ESM::MagicEffect::CureBlightDisease:
|
||||
case ESM::MagicEffect::CureCorprusDisease:
|
||||
case ESM::MagicEffect::ResistBlightDisease:
|
||||
case ESM::MagicEffect::ResistCommonDisease:
|
||||
case ESM::MagicEffect::ResistCorprusDisease:
|
||||
case ESM::MagicEffect::Invisibility:
|
||||
case ESM::MagicEffect::Chameleon:
|
||||
case ESM::MagicEffect::NightEye:
|
||||
case ESM::MagicEffect::Vampirism:
|
||||
case ESM::MagicEffect::StuntedMagicka:
|
||||
case ESM::MagicEffect::ExtraSpell:
|
||||
case ESM::MagicEffect::RemoveCurse:
|
||||
case ESM::MagicEffect::CommandCreature:
|
||||
case ESM::MagicEffect::CommandHumanoid:
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
case ESM::MagicEffect::Blind:
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||
|
||||
const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||
|
||||
// Enemy can't attack
|
||||
if (stats.isParalyzed() || stats.getKnockedDown())
|
||||
return 0.f;
|
||||
|
||||
// Enemy doesn't attack
|
||||
if (stats.getDrawState() != MWMechanics::DrawState::Weapon)
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::Sound:
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||
|
||||
// Enemy can't cast spells
|
||||
if (stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Silence).getMagnitude() > 0)
|
||||
return 0.f;
|
||||
|
||||
if (stats.isParalyzed() || stats.getKnockedDown())
|
||||
return 0.f;
|
||||
|
||||
// Enemy doesn't cast spells
|
||||
if (stats.getDrawState() != MWMechanics::DrawState::Spell)
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::Silence:
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||
|
||||
// Enemy can't cast spells
|
||||
if (stats.isParalyzed() || stats.getKnockedDown())
|
||||
return 0.f;
|
||||
|
||||
// Enemy doesn't cast spells
|
||||
if (stats.getDrawState() != MWMechanics::DrawState::Spell)
|
||||
return 0.f;
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
return 0.f; // TODO: implement based on attribute damage
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
return 0.f; // TODO: implement based on skill damage
|
||||
|
||||
case ESM::MagicEffect::ResistFire:
|
||||
case ESM::MagicEffect::ResistFrost:
|
||||
case ESM::MagicEffect::ResistMagicka:
|
||||
case ESM::MagicEffect::ResistNormalWeapons:
|
||||
case ESM::MagicEffect::ResistParalysis:
|
||||
case ESM::MagicEffect::ResistPoison:
|
||||
case ESM::MagicEffect::ResistShock:
|
||||
case ESM::MagicEffect::SpellAbsorption:
|
||||
case ESM::MagicEffect::Reflect:
|
||||
return 0.f; // probably useless since we don't know in advance what the enemy will cast
|
||||
|
||||
// don't cast these for now as they would make the NPC cast the same effect over and over again, especially
|
||||
// when they have potions
|
||||
case ESM::MagicEffect::FortifyAttribute:
|
||||
case ESM::MagicEffect::FortifyHealth:
|
||||
case ESM::MagicEffect::FortifyMagicka:
|
||||
case ESM::MagicEffect::FortifyFatigue:
|
||||
case ESM::MagicEffect::FortifySkill:
|
||||
case ESM::MagicEffect::FortifyMaximumMagicka:
|
||||
case ESM::MagicEffect::FortifyAttack:
|
||||
// Enemy can't attack
|
||||
if (stats.isParalyzed() || stats.getKnockedDown())
|
||||
return 0.f;
|
||||
|
||||
case ESM::MagicEffect::Burden:
|
||||
// Enemy doesn't attack
|
||||
if (stats.getDrawState() != MWMechanics::DrawState::Weapon)
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Sound)
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||
|
||||
// Enemy can't cast spells
|
||||
if (stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Silence).getMagnitude() > 0)
|
||||
return 0.f;
|
||||
|
||||
if (stats.isParalyzed() || stats.getKnockedDown())
|
||||
return 0.f;
|
||||
|
||||
// Enemy doesn't cast spells
|
||||
if (stats.getDrawState() != MWMechanics::DrawState::Spell)
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Silence)
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||
|
||||
// Enemy can't cast spells
|
||||
if (stats.isParalyzed() || stats.getKnockedDown())
|
||||
return 0.f;
|
||||
|
||||
// Enemy doesn't cast spells
|
||||
if (stats.getDrawState() != MWMechanics::DrawState::Spell)
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreAttribute)
|
||||
return 0.f; // TODO: implement based on attribute damage
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreSkill)
|
||||
return 0.f; // TODO: implement based on skill damage
|
||||
else if (effect.mEffectID == ESM::MagicEffect::ResistFire || effect.mEffectID == ESM::MagicEffect::ResistFrost
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistMagicka
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistNormalWeapons
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistParalysis
|
||||
|| effect.mEffectID == ESM::MagicEffect::ResistPoison || effect.mEffectID == ESM::MagicEffect::ResistShock
|
||||
|| effect.mEffectID == ESM::MagicEffect::SpellAbsorption || effect.mEffectID == ESM::MagicEffect::Reflect)
|
||||
return 0.f; // probably useless since we don't know in advance what the enemy will cast
|
||||
|
||||
// don't cast these for now as they would make the NPC cast the same effect over and over again, especially
|
||||
// when they have potions
|
||||
else if (effect.mEffectID == ESM::MagicEffect::FortifyAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyHealth
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyMagicka
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyFatigue
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifySkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyMaximumMagicka
|
||||
|| effect.mEffectID == ESM::MagicEffect::FortifyAttack)
|
||||
return 0.f;
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Burden)
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
// Ignore enemy without inventory
|
||||
if (!enemy.getClass().hasInventoryStore(enemy))
|
||||
return 0.f;
|
||||
|
||||
// burden makes sense only to overburden an enemy
|
||||
float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy);
|
||||
if (burden > 0)
|
||||
return 0.f;
|
||||
|
||||
if ((effect.mMagnMin + effect.mMagnMax) / 2.f > -burden)
|
||||
rating *= 3;
|
||||
else
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Feather)
|
||||
{
|
||||
// Ignore actors without inventory
|
||||
if (!actor.getClass().hasInventoryStore(actor))
|
||||
return 0.f;
|
||||
|
||||
// feather makes sense only for overburden actors
|
||||
float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor);
|
||||
if (burden <= 0)
|
||||
return 0.f;
|
||||
|
||||
if ((effect.mMagnMin + effect.mMagnMax) / 2.f >= burden)
|
||||
rating *= 3;
|
||||
else
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Levitate)
|
||||
return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway
|
||||
else if (effect.mEffectID == ESM::MagicEffect::BoundBoots || effect.mEffectID == ESM::MagicEffect::BoundHelm)
|
||||
{
|
||||
if (actor.getClass().isNpc())
|
||||
{
|
||||
// Beast races can't wear helmets or boots
|
||||
const ESM::RefId& raceid = actor.get<ESM::NPC>()->mBase->mRace;
|
||||
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(raceid);
|
||||
if (race->mData.mFlags & ESM::Race::Beast)
|
||||
return 0.f;
|
||||
}
|
||||
else
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::BoundShield)
|
||||
{
|
||||
if (!actor.getClass().hasInventoryStore(actor))
|
||||
return 0.f;
|
||||
else if (!actor.getClass().isNpc())
|
||||
{
|
||||
// If the actor is an NPC they can benefit from the armor rating, otherwise check if we've got a
|
||||
// one-handed weapon to use with the shield
|
||||
const auto& store = actor.getClass().getInventoryStore(actor);
|
||||
auto oneHanded = std::find_if(store.cbegin(MWWorld::ContainerStore::Type_Weapon), store.cend(),
|
||||
[](const MWWorld::ConstPtr& weapon) {
|
||||
if (weapon.getClass().getItemHealth(weapon) <= 0.f)
|
||||
return false;
|
||||
short type = weapon.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
return !(MWMechanics::getWeaponType(type)->mFlags & ESM::WeaponType::TwoHanded);
|
||||
});
|
||||
if (oneHanded == store.cend())
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
// Creatures cannot wear armor
|
||||
else if (effect.mEffectID == ESM::MagicEffect::BoundCuirass
|
||||
|| effect.mEffectID == ESM::MagicEffect::BoundGloves)
|
||||
{
|
||||
if (!actor.getClass().isNpc())
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::AbsorbMagicka)
|
||||
{
|
||||
if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getMagicka().getCurrent() <= 0.f)
|
||||
{
|
||||
rating = 0.5f;
|
||||
rating *= getRestoreMagickaPriority(actor);
|
||||
}
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreHealth
|
||||
|| effect.mEffectID == ESM::MagicEffect::RestoreMagicka
|
||||
|| effect.mEffectID == ESM::MagicEffect::RestoreFatigue)
|
||||
{
|
||||
if (effect.mRange == ESM::RT_Self)
|
||||
{
|
||||
auto targetStat = Stats::Health;
|
||||
if (effect.mEffectID == ESM::MagicEffect::RestoreMagicka)
|
||||
targetStat = Stats::Magicka;
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreFatigue)
|
||||
targetStat = Stats::Fatigue;
|
||||
|
||||
const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||
const DynamicStat<float>& current = stats.getDynamic(targetStat);
|
||||
// NB: this currently assumes the hardcoded magic effect flags are used
|
||||
const float magnitude = (effect.mMagnMin + effect.mMagnMax) / 2.f;
|
||||
const float toHeal = magnitude * std::max(1, effect.mDuration);
|
||||
const float damage = std::max(current.getModified() - current.getCurrent(), 0.f);
|
||||
float priority = 0.f;
|
||||
if (effect.mEffectID == ESM::MagicEffect::RestoreHealth)
|
||||
priority = 4.f;
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreMagicka)
|
||||
priority = getRestoreMagickaPriority(actor);
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreFatigue)
|
||||
priority = 2.f;
|
||||
float overheal = 0.f;
|
||||
float heal = toHeal;
|
||||
if (damage < toHeal && current.getCurrent() > current.getModified() * 0.5)
|
||||
{
|
||||
overheal = toHeal - damage;
|
||||
heal = damage;
|
||||
}
|
||||
|
||||
priority = (priority - 1.f) / 2.f * std::pow((damage / current.getModified() + 0.6f), priority * 2)
|
||||
+ priority * (heal - 2.f * overheal) / current.getModified() - 0.5f;
|
||||
rating = priority;
|
||||
}
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::Dispel)
|
||||
{
|
||||
int numPositive = 0;
|
||||
int numNegative = 0;
|
||||
int diff = 0;
|
||||
|
||||
if (effect.mRange == ESM::RT_Self)
|
||||
{
|
||||
numPositive = numEffectsToDispel(actor, ESM::RefId(), false);
|
||||
numNegative = numEffectsToDispel(actor);
|
||||
|
||||
diff = numNegative - numPositive;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
// Ignore enemy without inventory
|
||||
if (!enemy.getClass().hasInventoryStore(enemy))
|
||||
return 0.f;
|
||||
numPositive = numEffectsToDispel(enemy, ESM::RefId(), false);
|
||||
numNegative = numEffectsToDispel(enemy);
|
||||
|
||||
// burden makes sense only to overburden an enemy
|
||||
float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy);
|
||||
if (burden > 0)
|
||||
return 0.f;
|
||||
diff = numPositive - numNegative;
|
||||
|
||||
if ((effect.mMagnMin + effect.mMagnMax) / 2.f > -burden)
|
||||
rating *= 3;
|
||||
else
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
// if rating < 0 here, the spell will be considered as negative later
|
||||
rating *= -1;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::Feather:
|
||||
if (diff <= 0)
|
||||
return 0.f;
|
||||
|
||||
rating *= (diff) / 5.f;
|
||||
}
|
||||
|
||||
// Prefer Cure effects over Dispel, because Dispel also removes positive effects
|
||||
else if (effect.mEffectID == ESM::MagicEffect::CureParalyzation)
|
||||
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze);
|
||||
else if (effect.mEffectID == ESM::MagicEffect::CurePoison)
|
||||
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison);
|
||||
else if (effect.mEffectID == ESM::MagicEffect::DisintegrateArmor)
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
// Ignore enemy without inventory
|
||||
if (!enemy.getClass().hasInventoryStore(enemy))
|
||||
return 0.f;
|
||||
|
||||
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
|
||||
|
||||
// According to UESP
|
||||
static const int armorSlots[] = {
|
||||
MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||
MWWorld::InventoryStore::Slot_Cuirass,
|
||||
MWWorld::InventoryStore::Slot_LeftPauldron,
|
||||
MWWorld::InventoryStore::Slot_RightPauldron,
|
||||
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
||||
MWWorld::InventoryStore::Slot_RightGauntlet,
|
||||
MWWorld::InventoryStore::Slot_Helmet,
|
||||
MWWorld::InventoryStore::Slot_Greaves,
|
||||
MWWorld::InventoryStore::Slot_Boots,
|
||||
};
|
||||
|
||||
bool enemyHasArmor = false;
|
||||
|
||||
// Ignore enemy without armor
|
||||
for (unsigned int i = 0; i < sizeof(armorSlots) / sizeof(int); ++i)
|
||||
{
|
||||
// Ignore actors without inventory
|
||||
if (!actor.getClass().hasInventoryStore(actor))
|
||||
return 0.f;
|
||||
MWWorld::ContainerStoreIterator item = inv.getSlot(armorSlots[i]);
|
||||
|
||||
// feather makes sense only for overburden actors
|
||||
float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor);
|
||||
if (burden <= 0)
|
||||
return 0.f;
|
||||
|
||||
if ((effect.mMagnMin + effect.mMagnMax) / 2.f >= burden)
|
||||
rating *= 3;
|
||||
else
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor))
|
||||
{
|
||||
enemyHasArmor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::Levitate:
|
||||
return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway
|
||||
case ESM::MagicEffect::BoundBoots:
|
||||
case ESM::MagicEffect::BoundHelm:
|
||||
if (actor.getClass().isNpc())
|
||||
{
|
||||
// Beast races can't wear helmets or boots
|
||||
const ESM::RefId& raceid = actor.get<ESM::NPC>()->mBase->mRace;
|
||||
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(raceid);
|
||||
if (race->mData.mFlags & ESM::Race::Beast)
|
||||
return 0.f;
|
||||
}
|
||||
else
|
||||
return 0.f;
|
||||
if (!enemyHasArmor)
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::DisintegrateWeapon)
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
case ESM::MagicEffect::BoundShield:
|
||||
if (!actor.getClass().hasInventoryStore(actor))
|
||||
return 0.f;
|
||||
else if (!actor.getClass().isNpc())
|
||||
{
|
||||
// If the actor is an NPC they can benefit from the armor rating, otherwise check if we've got a
|
||||
// one-handed weapon to use with the shield
|
||||
const auto& store = actor.getClass().getInventoryStore(actor);
|
||||
auto oneHanded = std::find_if(store.cbegin(MWWorld::ContainerStore::Type_Weapon), store.cend(),
|
||||
[](const MWWorld::ConstPtr& weapon) {
|
||||
if (weapon.getClass().getItemHealth(weapon) <= 0.f)
|
||||
return false;
|
||||
short type = weapon.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
return !(MWMechanics::getWeaponType(type)->mFlags & ESM::WeaponType::TwoHanded);
|
||||
});
|
||||
if (oneHanded == store.cend())
|
||||
return 0.f;
|
||||
}
|
||||
break;
|
||||
// Creatures can not wear armor
|
||||
case ESM::MagicEffect::BoundCuirass:
|
||||
case ESM::MagicEffect::BoundGloves:
|
||||
if (!actor.getClass().isNpc())
|
||||
return 0.f;
|
||||
break;
|
||||
// Ignore enemy without inventory
|
||||
if (!enemy.getClass().hasInventoryStore(enemy))
|
||||
return 0.f;
|
||||
|
||||
case ESM::MagicEffect::AbsorbMagicka:
|
||||
if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getMagicka().getCurrent() <= 0.f)
|
||||
{
|
||||
rating = 0.5f;
|
||||
rating *= getRestoreMagickaPriority(actor);
|
||||
}
|
||||
break;
|
||||
case ESM::MagicEffect::RestoreHealth:
|
||||
case ESM::MagicEffect::RestoreMagicka:
|
||||
case ESM::MagicEffect::RestoreFatigue:
|
||||
if (effect.mRange == ESM::RT_Self)
|
||||
{
|
||||
const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||
const DynamicStat<float>& current
|
||||
= stats.getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth);
|
||||
// NB: this currently assumes the hardcoded magic effect flags are used
|
||||
const float magnitude = (effect.mMagnMin + effect.mMagnMax) / 2.f;
|
||||
const float toHeal = magnitude * std::max(1, effect.mDuration);
|
||||
const float damage = std::max(current.getModified() - current.getCurrent(), 0.f);
|
||||
float priority = 0.f;
|
||||
if (effect.mEffectID == ESM::MagicEffect::RestoreHealth)
|
||||
priority = 4.f;
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreMagicka)
|
||||
priority = getRestoreMagickaPriority(actor);
|
||||
else if (effect.mEffectID == ESM::MagicEffect::RestoreFatigue)
|
||||
priority = 2.f;
|
||||
float overheal = 0.f;
|
||||
float heal = toHeal;
|
||||
if (damage < toHeal && current.getCurrent() > current.getModified() * 0.5)
|
||||
{
|
||||
overheal = toHeal - damage;
|
||||
heal = damage;
|
||||
}
|
||||
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
|
||||
MWWorld::ContainerStoreIterator item = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
priority = (priority - 1.f) / 2.f * std::pow((damage / current.getModified() + 0.6f), priority * 2)
|
||||
+ priority * (heal - 2.f * overheal) / current.getModified() - 0.5f;
|
||||
rating = priority;
|
||||
}
|
||||
break;
|
||||
|
||||
case ESM::MagicEffect::Dispel:
|
||||
// Ignore enemy without weapons
|
||||
if (item == inv.end() || (item.getType() != MWWorld::ContainerStore::Type_Weapon))
|
||||
return 0.f;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::AbsorbAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::DamageAttribute
|
||||
|| effect.mEffectID == ESM::MagicEffect::DrainAttribute)
|
||||
{
|
||||
if (!enemy.isEmpty()
|
||||
&& enemy.getClass()
|
||||
.getCreatureStats(enemy)
|
||||
.getAttribute(ESM::Attribute::indexToRefId(effect.mAttribute))
|
||||
.getModified()
|
||||
<= 0)
|
||||
return 0.f;
|
||||
{
|
||||
int numPositive = 0;
|
||||
int numNegative = 0;
|
||||
int diff = 0;
|
||||
|
||||
if (effect.mRange == ESM::RT_Self)
|
||||
if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length)
|
||||
{
|
||||
numPositive = numEffectsToDispel(actor, -1, false);
|
||||
numNegative = numEffectsToDispel(actor);
|
||||
|
||||
diff = numNegative - numPositive;
|
||||
const float attributePriorities[ESM::Attribute::Length] = {
|
||||
1.0f, // Strength
|
||||
0.5f, // Intelligence
|
||||
0.6f, // Willpower
|
||||
0.7f, // Agility
|
||||
0.5f, // Speed
|
||||
0.8f, // Endurance
|
||||
0.7f, // Personality
|
||||
0.3f // Luck
|
||||
};
|
||||
rating *= attributePriorities[effect.mAttribute];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
numPositive = numEffectsToDispel(enemy, -1, false);
|
||||
numNegative = numEffectsToDispel(enemy);
|
||||
|
||||
diff = numPositive - numNegative;
|
||||
|
||||
// if rating < 0 here, the spell will be considered as negative later
|
||||
rating *= -1;
|
||||
}
|
||||
|
||||
if (diff <= 0)
|
||||
return 0.f;
|
||||
|
||||
rating *= (diff) / 5.f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Prefer Cure effects over Dispel, because Dispel also removes positive effects
|
||||
case ESM::MagicEffect::CureParalyzation:
|
||||
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze);
|
||||
|
||||
case ESM::MagicEffect::CurePoison:
|
||||
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison);
|
||||
case ESM::MagicEffect::DisintegrateArmor:
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
// Ignore enemy without inventory
|
||||
if (!enemy.getClass().hasInventoryStore(enemy))
|
||||
return 0.f;
|
||||
|
||||
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
|
||||
|
||||
// According to UESP
|
||||
static const int armorSlots[] = {
|
||||
MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||
MWWorld::InventoryStore::Slot_Cuirass,
|
||||
MWWorld::InventoryStore::Slot_LeftPauldron,
|
||||
MWWorld::InventoryStore::Slot_RightPauldron,
|
||||
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
||||
MWWorld::InventoryStore::Slot_RightGauntlet,
|
||||
MWWorld::InventoryStore::Slot_Helmet,
|
||||
MWWorld::InventoryStore::Slot_Greaves,
|
||||
MWWorld::InventoryStore::Slot_Boots,
|
||||
};
|
||||
|
||||
bool enemyHasArmor = false;
|
||||
|
||||
// Ignore enemy without armor
|
||||
for (unsigned int i = 0; i < sizeof(armorSlots) / sizeof(int); ++i)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator item = inv.getSlot(armorSlots[i]);
|
||||
|
||||
if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor))
|
||||
{
|
||||
enemyHasArmor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!enemyHasArmor)
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::DisintegrateWeapon:
|
||||
{
|
||||
if (enemy.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
// Ignore enemy without inventory
|
||||
if (!enemy.getClass().hasInventoryStore(enemy))
|
||||
return 0.f;
|
||||
|
||||
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
|
||||
MWWorld::ContainerStoreIterator item = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
// Ignore enemy without weapons
|
||||
if (item == inv.end() || (item.getType() != MWWorld::ContainerStore::Type_Weapon))
|
||||
return 0.f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::AbsorbAttribute:
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
case ESM::MagicEffect::DrainAttribute:
|
||||
if (!enemy.isEmpty()
|
||||
&& enemy.getClass()
|
||||
.getCreatureStats(enemy)
|
||||
.getAttribute(ESM::Attribute::indexToRefId(effect.mAttribute))
|
||||
.getModified()
|
||||
<= 0)
|
||||
return 0.f;
|
||||
{
|
||||
if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length)
|
||||
{
|
||||
const float attributePriorities[ESM::Attribute::Length] = {
|
||||
1.0f, // Strength
|
||||
0.5f, // Intelligence
|
||||
0.6f, // Willpower
|
||||
0.7f, // Agility
|
||||
0.5f, // Speed
|
||||
0.8f, // Endurance
|
||||
0.7f, // Personality
|
||||
0.3f // Luck
|
||||
};
|
||||
rating *= attributePriorities[effect.mAttribute];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ESM::MagicEffect::AbsorbSkill:
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
if (enemy.isEmpty() || !enemy.getClass().isNpc())
|
||||
return 0.f;
|
||||
if (enemy.getClass().getSkill(enemy, ESM::Skill::indexToRefId(effect.mSkill)) <= 0)
|
||||
return 0.f;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else if (effect.mEffectID == ESM::MagicEffect::AbsorbSkill || effect.mEffectID == ESM::MagicEffect::DamageSkill
|
||||
|| effect.mEffectID == ESM::MagicEffect::DrainSkill)
|
||||
{
|
||||
if (enemy.isEmpty() || !enemy.getClass().isNpc())
|
||||
return 0.f;
|
||||
if (enemy.getClass().getSkill(enemy, ESM::Skill::indexToRefId(effect.mSkill)) <= 0)
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
// Allow only one summoned creature at time
|
||||
|
|
@ -617,7 +583,27 @@ namespace MWMechanics
|
|||
// But rate summons higher than other effects
|
||||
rating = 3.f;
|
||||
}
|
||||
if (effect.mEffectID >= ESM::MagicEffect::BoundDagger && effect.mEffectID <= ESM::MagicEffect::BoundGloves)
|
||||
|
||||
static const std::array<ESM::RefId, 6> boundWeapons{
|
||||
ESM::MagicEffect::BoundDagger,
|
||||
ESM::MagicEffect::BoundLongsword,
|
||||
ESM::MagicEffect::BoundMace,
|
||||
ESM::MagicEffect::BoundBattleAxe,
|
||||
ESM::MagicEffect::BoundSpear,
|
||||
ESM::MagicEffect::BoundLongbow,
|
||||
};
|
||||
|
||||
static const std::array<ESM::RefId, 6> boundArmor{
|
||||
ESM::MagicEffect::ExtraSpell,
|
||||
ESM::MagicEffect::BoundCuirass,
|
||||
ESM::MagicEffect::BoundHelm,
|
||||
ESM::MagicEffect::BoundBoots,
|
||||
ESM::MagicEffect::BoundShield,
|
||||
ESM::MagicEffect::BoundGloves,
|
||||
};
|
||||
|
||||
if (std::ranges::find(boundWeapons, effect.mEffectID) != boundWeapons.end()
|
||||
|| std::ranges::find(boundArmor, effect.mEffectID) != boundArmor.end())
|
||||
{
|
||||
// Prefer casting bound items over other spells
|
||||
rating = 2.f;
|
||||
|
|
@ -627,9 +613,9 @@ namespace MWMechanics
|
|||
// summon another of a different kind unless what we have is a bow and the actor is out of ammo.
|
||||
// FIXME: This code assumes the summoned item is of the usual type (i.e. a mod hasn't changed Bound Bow to
|
||||
// summon an Axe instead)
|
||||
if (effect.mEffectID <= ESM::MagicEffect::BoundLongbow)
|
||||
if (std::ranges::find(boundWeapons, effect.mEffectID) != boundWeapons.end())
|
||||
{
|
||||
for (int e = ESM::MagicEffect::BoundDagger; e <= ESM::MagicEffect::BoundLongbow; ++e)
|
||||
for (const auto e : boundWeapons)
|
||||
if (actor.getClass().getCreatureStats(actor).getMagicEffects().getOrDefault(e).getMagnitude() > 0.f
|
||||
&& (e != ESM::MagicEffect::BoundLongbow || effect.mEffectID == e
|
||||
|| rateAmmo(actor, enemy, getWeaponType(ESM::Weapon::MarksmanBow)->mAmmoType) <= 0.f))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
namespace MWMechanics
|
||||
{
|
||||
|
||||
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
float getEffectMultiplier(ESM::RefId effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
const ESM::Spell* spell, const MagicEffects* effects)
|
||||
{
|
||||
if (!actor.getClass().isActor())
|
||||
|
|
@ -26,11 +26,11 @@ namespace MWMechanics
|
|||
return 1 - resistance / 100.f;
|
||||
}
|
||||
|
||||
float getEffectResistance(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
float getEffectResistance(ESM::RefId effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
const ESM::Spell* spell, const MagicEffects* effects)
|
||||
{
|
||||
// Effects with no resistance attribute belonging to them can not be resisted
|
||||
if (ESM::MagicEffect::getResistanceEffect(effectId) == -1)
|
||||
if (ESM::MagicEffect::getResistanceEffect(effectId).empty())
|
||||
return 0.f;
|
||||
|
||||
const auto magicEffect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effectId);
|
||||
|
|
@ -72,15 +72,16 @@ namespace MWMechanics
|
|||
return x;
|
||||
}
|
||||
|
||||
float getEffectResistanceAttribute(short effectId, const MagicEffects* actorEffects)
|
||||
float getEffectResistanceAttribute(ESM::RefId effectId, const MagicEffects* actorEffects)
|
||||
{
|
||||
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
||||
short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId);
|
||||
|
||||
float resistance = 0;
|
||||
if (resistanceEffect != -1)
|
||||
|
||||
ESM::RefId resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
||||
ESM::RefId weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId);
|
||||
|
||||
if (!resistanceEffect.empty())
|
||||
resistance += actorEffects->getOrDefault(resistanceEffect).getMagnitude();
|
||||
if (weaknessEffect != -1)
|
||||
if (!weaknessEffect.empty())
|
||||
resistance -= actorEffects->getOrDefault(weaknessEffect).getMagnitude();
|
||||
|
||||
if (effectId == ESM::MagicEffect::FireDamage)
|
||||
|
|
@ -92,5 +93,4 @@ namespace MWMechanics
|
|||
|
||||
return resistance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
namespace ESM
|
||||
{
|
||||
struct Spell;
|
||||
class RefId;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
|
@ -19,19 +20,19 @@ namespace MWMechanics
|
|||
/// @return effect multiplier from 0 to 2. (100% net resistance to 100% net weakness)
|
||||
/// @param effects Override the actor's current magicEffects. Useful if there are effects currently
|
||||
/// being applied (but not applied yet) that should also be considered.
|
||||
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
float getEffectMultiplier(ESM::RefId effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr);
|
||||
|
||||
/// Get the effective resistance against an effect casted by the given actor in the given spell (optional).
|
||||
/// @return >=100 for fully resisted. can also return negative value for damage amplification.
|
||||
/// @param effects Override the actor's current magicEffects. Useful if there are effects currently
|
||||
/// being applied (but not applied yet) that should also be considered.
|
||||
float getEffectResistance(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
float getEffectResistance(ESM::RefId effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||
const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr);
|
||||
|
||||
/// Get the resistance attribute against an effect for a given actor. This will add together
|
||||
/// ResistX and Weakness to X effects relevant against the given effect.
|
||||
float getEffectResistanceAttribute(short effectId, const MagicEffects* actorEffects);
|
||||
float getEffectResistanceAttribute(ESM::RefId effectId, const MagicEffects* actorEffects);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ namespace MWMechanics
|
|||
for (const ESM::SpellState::PermanentSpellEffectInfo& info : it->second)
|
||||
{
|
||||
// Applied corprus effects are already in loaded stats modifiers
|
||||
if (info.mId == ESM::MagicEffect::FortifyAttribute)
|
||||
if (info.mId == ESM::MagicEffect::refIdToIndex(ESM::MagicEffect::FortifyAttribute))
|
||||
{
|
||||
auto id = ESM::Attribute::indexToRefId(info.mArg);
|
||||
AttributeValue attr = creatureStats->getAttribute(id);
|
||||
|
|
@ -265,7 +265,7 @@ namespace MWMechanics
|
|||
attr.damage(-info.mMagnitude);
|
||||
creatureStats->setAttribute(id, attr);
|
||||
}
|
||||
else if (info.mId == ESM::MagicEffect::DrainAttribute)
|
||||
else if (info.mId == ESM::MagicEffect::refIdToIndex(ESM::MagicEffect::DrainAttribute))
|
||||
{
|
||||
auto id = ESM::Attribute::indexToRefId(info.mArg);
|
||||
AttributeValue attr = creatureStats->getAttribute(id);
|
||||
|
|
|
|||
|
|
@ -166,13 +166,13 @@ namespace MWMechanics
|
|||
throw std::range_error("Index out of range");
|
||||
|
||||
ESM::ENAMstruct effect;
|
||||
effect.mEffectID = static_cast<int16_t>(ingredient->mData.mEffectID[index]);
|
||||
effect.mEffectID = ingredient->mData.mEffectID[index];
|
||||
effect.mSkill = static_cast<signed char>(ingredient->mData.mSkills[index]);
|
||||
effect.mAttribute = static_cast<signed char>(ingredient->mData.mAttributes[index]);
|
||||
effect.mRange = ESM::RT_Self;
|
||||
effect.mArea = 0;
|
||||
|
||||
if (effect.mEffectID < 0)
|
||||
if (effect.mEffectID.empty())
|
||||
return std::nullopt;
|
||||
|
||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||
|
|
|
|||
|
|
@ -23,21 +23,45 @@
|
|||
namespace MWMechanics
|
||||
{
|
||||
|
||||
bool isSummoningEffect(int effectId)
|
||||
bool isSummoningEffect(ESM::RefId effectId)
|
||||
{
|
||||
return ((effectId >= ESM::MagicEffect::SummonScamp && effectId <= ESM::MagicEffect::SummonStormAtronach)
|
||||
|| (effectId == ESM::MagicEffect::SummonCenturionSphere)
|
||||
|| (effectId >= ESM::MagicEffect::SummonFabricant && effectId <= ESM::MagicEffect::SummonCreature05));
|
||||
if (effectId.empty())
|
||||
return false;
|
||||
static const std::array<ESM::RefId, 22> summonEffects{
|
||||
ESM::MagicEffect::SummonAncestralGhost,
|
||||
ESM::MagicEffect::SummonBonelord,
|
||||
ESM::MagicEffect::SummonBonewalker,
|
||||
ESM::MagicEffect::SummonCenturionSphere,
|
||||
ESM::MagicEffect::SummonClannfear,
|
||||
ESM::MagicEffect::SummonDaedroth,
|
||||
ESM::MagicEffect::SummonDremora,
|
||||
ESM::MagicEffect::SummonFabricant,
|
||||
ESM::MagicEffect::SummonFlameAtronach,
|
||||
ESM::MagicEffect::SummonFrostAtronach,
|
||||
ESM::MagicEffect::SummonGoldenSaint,
|
||||
ESM::MagicEffect::SummonGreaterBonewalker,
|
||||
ESM::MagicEffect::SummonHunger,
|
||||
ESM::MagicEffect::SummonScamp,
|
||||
ESM::MagicEffect::SummonSkeletalMinion,
|
||||
ESM::MagicEffect::SummonStormAtronach,
|
||||
ESM::MagicEffect::SummonWingedTwilight,
|
||||
ESM::MagicEffect::SummonWolf,
|
||||
ESM::MagicEffect::SummonBear,
|
||||
ESM::MagicEffect::SummonBonewolf,
|
||||
ESM::MagicEffect::SummonCreature04,
|
||||
ESM::MagicEffect::SummonCreature05,
|
||||
};
|
||||
return (std::find(summonEffects.begin(), summonEffects.end(), effectId) != summonEffects.end());
|
||||
}
|
||||
|
||||
static const std::map<int, ESM::RefId>& getSummonMap()
|
||||
static const std::map<ESM::RefId, ESM::RefId>& getSummonMap()
|
||||
{
|
||||
static std::map<int, ESM::RefId> summonMap;
|
||||
static std::map<ESM::RefId, ESM::RefId> summonMap;
|
||||
|
||||
if (summonMap.size() > 0)
|
||||
return summonMap;
|
||||
|
||||
const std::map<int, std::string_view> summonMapToGameSetting{
|
||||
const std::map<ESM::RefId, std::string_view> summonMapToGameSetting{
|
||||
{ ESM::MagicEffect::SummonAncestralGhost, "sMagicAncestralGhostID" },
|
||||
{ ESM::MagicEffect::SummonBonelord, "sMagicBonelordID" },
|
||||
{ ESM::MagicEffect::SummonBonewalker, "sMagicLeastBonewalkerID" },
|
||||
|
|
@ -70,7 +94,7 @@ namespace MWMechanics
|
|||
return summonMap;
|
||||
}
|
||||
|
||||
ESM::RefId getSummonedCreature(int effectId)
|
||||
ESM::RefId getSummonedCreature(ESM::RefId effectId)
|
||||
{
|
||||
const auto& summonMap = getSummonMap();
|
||||
auto it = summonMap.find(effectId);
|
||||
|
|
@ -81,7 +105,7 @@ namespace MWMechanics
|
|||
return ESM::RefId();
|
||||
}
|
||||
|
||||
ESM::RefNum summonCreature(int effectId, const MWWorld::Ptr& summoner)
|
||||
ESM::RefNum summonCreature(ESM::RefId effectId, const MWWorld::Ptr& summoner)
|
||||
{
|
||||
const ESM::RefId& creatureID = getSummonedCreature(effectId);
|
||||
ESM::RefNum creature;
|
||||
|
|
@ -152,7 +176,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<int, ESM::RefNum>& summon)
|
||||
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<ESM::RefId, ESM::RefNum>& summon)
|
||||
{
|
||||
auto& creatureStats = summoner.getClass().getCreatureStats(summoner);
|
||||
creatureStats.getActiveSpells().purge(
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ namespace MWWorld
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
bool isSummoningEffect(int effectId);
|
||||
bool isSummoningEffect(ESM::RefId effectId);
|
||||
|
||||
ESM::RefId getSummonedCreature(int effectId);
|
||||
ESM::RefId getSummonedCreature(ESM::RefId effectId);
|
||||
|
||||
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<int, ESM::RefNum>& summon);
|
||||
void purgeSummonEffect(const MWWorld::Ptr& summoner, const std::pair<ESM::RefId, ESM::RefNum>& summon);
|
||||
|
||||
ESM::RefNum summonCreature(int effectId, const MWWorld::Ptr& summoner);
|
||||
ESM::RefNum summonCreature(ESM::RefId effectId, const MWWorld::Ptr& summoner);
|
||||
|
||||
void updateSummons(const MWWorld::Ptr& summoner, bool cleanup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -613,13 +613,13 @@ namespace MWScript
|
|||
return;
|
||||
}
|
||||
|
||||
long key;
|
||||
ESM::RefId key;
|
||||
|
||||
if (const auto k = ::Misc::StringUtils::toNumeric<long>(effectName);
|
||||
k.has_value() && *k >= 0 && *k <= 32767)
|
||||
key = *k;
|
||||
key = ESM::MagicEffect::indexToRefId(*k);
|
||||
else
|
||||
key = ESM::MagicEffect::effectGmstIdToIndex(effectName);
|
||||
key = ESM::MagicEffect::effectGmstIdToRefId(effectName);
|
||||
|
||||
const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
for (const auto& spell : stats.getActiveSpells())
|
||||
|
|
|
|||
|
|
@ -580,7 +580,8 @@ namespace MWScript
|
|||
runtime.pop();
|
||||
|
||||
if (ptr.getClass().isActor())
|
||||
ptr.getClass().getCreatureStats(ptr).getActiveSpells().purgeEffect(ptr, effectId);
|
||||
ptr.getClass().getCreatureStats(ptr).getActiveSpells().purgeEffect(
|
||||
ptr, ESM::MagicEffect::indexToRefId(static_cast<int>(effectId)));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1262,13 +1263,13 @@ namespace MWScript
|
|||
template <class R>
|
||||
class OpGetMagicEffect : public Interpreter::Opcode0
|
||||
{
|
||||
int mPositiveEffect;
|
||||
int mNegativeEffect;
|
||||
ESM::RefId mPositiveEffect;
|
||||
ESM::RefId mNegativeEffect;
|
||||
|
||||
public:
|
||||
OpGetMagicEffect(int positiveEffect, int negativeEffect)
|
||||
: mPositiveEffect(positiveEffect)
|
||||
, mNegativeEffect(negativeEffect)
|
||||
: mPositiveEffect(ESM::MagicEffect::indexToRefId(positiveEffect))
|
||||
, mNegativeEffect(ESM::MagicEffect::indexToRefId(negativeEffect))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1284,7 +1285,7 @@ namespace MWScript
|
|||
|
||||
const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
|
||||
float currentValue = effects.getOrDefault(mPositiveEffect).getMagnitude();
|
||||
if (mNegativeEffect != -1)
|
||||
if (!mNegativeEffect.empty())
|
||||
currentValue -= effects.getOrDefault(mNegativeEffect).getMagnitude();
|
||||
|
||||
// GetResist* should take in account elemental shields
|
||||
|
|
@ -1303,13 +1304,13 @@ namespace MWScript
|
|||
template <class R>
|
||||
class OpSetMagicEffect : public Interpreter::Opcode0
|
||||
{
|
||||
int mPositiveEffect;
|
||||
int mNegativeEffect;
|
||||
ESM::RefId mPositiveEffect;
|
||||
ESM::RefId mNegativeEffect;
|
||||
|
||||
public:
|
||||
OpSetMagicEffect(int positiveEffect, int negativeEffect)
|
||||
: mPositiveEffect(positiveEffect)
|
||||
, mNegativeEffect(negativeEffect)
|
||||
: mPositiveEffect(ESM::MagicEffect::indexToRefId(positiveEffect))
|
||||
, mNegativeEffect(ESM::MagicEffect::indexToRefId(negativeEffect))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1325,7 +1326,7 @@ namespace MWScript
|
|||
|
||||
MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
|
||||
float currentValue = effects.getOrDefault(mPositiveEffect).getMagnitude();
|
||||
if (mNegativeEffect != -1)
|
||||
if (!mNegativeEffect.empty())
|
||||
currentValue -= effects.getOrDefault(mNegativeEffect).getMagnitude();
|
||||
|
||||
// SetResist* should take in account elemental shields
|
||||
|
|
@ -1343,13 +1344,13 @@ namespace MWScript
|
|||
template <class R>
|
||||
class OpModMagicEffect : public Interpreter::Opcode0
|
||||
{
|
||||
int mPositiveEffect;
|
||||
int mNegativeEffect;
|
||||
ESM::RefId mPositiveEffect;
|
||||
ESM::RefId mNegativeEffect;
|
||||
|
||||
public:
|
||||
OpModMagicEffect(int positiveEffect, int negativeEffect)
|
||||
: mPositiveEffect(positiveEffect)
|
||||
, mNegativeEffect(negativeEffect)
|
||||
: mPositiveEffect(ESM::MagicEffect::indexToRefId(positiveEffect))
|
||||
, mNegativeEffect(ESM::MagicEffect::indexToRefId(negativeEffect))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1392,7 +1393,7 @@ namespace MWScript
|
|||
auto& effects = player.getClass().getCreatureStats(player).getMagicEffects();
|
||||
float delta = std::clamp(arg * 100.f, 0.f, 100.f)
|
||||
- effects.getOrDefault(ESM::MagicEffect::NightEye).getMagnitude();
|
||||
effects.modifyBase(ESM::MagicEffect::NightEye, static_cast<int>(delta));
|
||||
effects.modifyBase(MWMechanics::EffectKey(ESM::MagicEffect::NightEye), static_cast<int>(delta));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1409,14 +1410,14 @@ namespace MWScript
|
|||
float newBase = std::clamp(nightEye.getMagnitude() + arg * 100.f, 0.f, 100.f);
|
||||
newBase -= nightEye.getModifier();
|
||||
float delta = std::clamp(newBase, 0.f, 100.f) - nightEye.getMagnitude();
|
||||
effects.modifyBase(ESM::MagicEffect::NightEye, static_cast<int>(delta));
|
||||
effects.modifyBase(MWMechanics::EffectKey(ESM::MagicEffect::NightEye), static_cast<int>(delta));
|
||||
}
|
||||
};
|
||||
|
||||
struct MagicEffect
|
||||
{
|
||||
int mPositiveEffect;
|
||||
int mNegativeEffect;
|
||||
ESM::RefId mPositiveEffect;
|
||||
ESM::RefId mNegativeEffect;
|
||||
};
|
||||
|
||||
void installOpcodes(Interpreter::Interpreter& interpreter)
|
||||
|
|
@ -1577,28 +1578,28 @@ namespace MWScript
|
|||
{ ESM::MagicEffect::ResistBlightDisease, ESM::MagicEffect::WeaknessToBlightDisease },
|
||||
{ ESM::MagicEffect::ResistCorprusDisease, ESM::MagicEffect::WeaknessToCorprusDisease },
|
||||
{ ESM::MagicEffect::ResistPoison, ESM::MagicEffect::WeaknessToPoison },
|
||||
{ ESM::MagicEffect::ResistParalysis, -1 },
|
||||
{ ESM::MagicEffect::ResistParalysis, ESM::RefId() },
|
||||
{ ESM::MagicEffect::ResistNormalWeapons, ESM::MagicEffect::WeaknessToNormalWeapons },
|
||||
{ ESM::MagicEffect::WaterBreathing, -1 },
|
||||
{ ESM::MagicEffect::Chameleon, -1 },
|
||||
{ ESM::MagicEffect::WaterWalking, -1 },
|
||||
{ ESM::MagicEffect::SwiftSwim, -1 },
|
||||
{ ESM::MagicEffect::Jump, -1 },
|
||||
{ ESM::MagicEffect::Levitate, -1 },
|
||||
{ ESM::MagicEffect::Shield, -1 },
|
||||
{ ESM::MagicEffect::Sound, -1 },
|
||||
{ ESM::MagicEffect::Silence, -1 },
|
||||
{ ESM::MagicEffect::Blind, -1 },
|
||||
{ ESM::MagicEffect::Paralyze, -1 },
|
||||
{ ESM::MagicEffect::Invisibility, -1 },
|
||||
{ ESM::MagicEffect::FortifyAttack, -1 },
|
||||
{ ESM::MagicEffect::Sanctuary, -1 },
|
||||
{ ESM::MagicEffect::WaterBreathing, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Chameleon, ESM::RefId() },
|
||||
{ ESM::MagicEffect::WaterWalking, ESM::RefId() },
|
||||
{ ESM::MagicEffect::SwiftSwim, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Jump, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Levitate, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Shield, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Sound, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Silence, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Blind, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Paralyze, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Invisibility, ESM::RefId() },
|
||||
{ ESM::MagicEffect::FortifyAttack, ESM::RefId() },
|
||||
{ ESM::MagicEffect::Sanctuary, ESM::RefId() },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 24; ++i)
|
||||
{
|
||||
int positive = sMagicEffects[i].mPositiveEffect;
|
||||
int negative = sMagicEffects[i].mNegativeEffect;
|
||||
int positive = ESM::MagicEffect::refIdToIndex(sMagicEffects[i].mPositiveEffect);
|
||||
int negative = ESM::MagicEffect::refIdToIndex(sMagicEffects[i].mNegativeEffect);
|
||||
|
||||
interpreter.installSegment5<OpGetMagicEffect<ImplicitRef>>(
|
||||
Compiler::Stats::opcodeGetMagicEffect + i, positive, negative);
|
||||
|
|
|
|||
|
|
@ -185,8 +185,8 @@ namespace
|
|||
{
|
||||
iter->mData.mAttribute = -1;
|
||||
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
|
||||
<< ": dropping unexpected attribute argument of "
|
||||
<< ESM::MagicEffect::indexToGmstString(iter->mData.mEffectID) << " effect";
|
||||
<< ": dropping unexpected attribute argument of " << iter->mData.mEffectID
|
||||
<< " effect";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
|
@ -194,8 +194,8 @@ namespace
|
|||
{
|
||||
iter->mData.mSkill = -1;
|
||||
Log(Debug::Verbose) << RecordType::getRecordType() << " " << spell.mId
|
||||
<< ": dropping unexpected skill argument of "
|
||||
<< ESM::MagicEffect::indexToGmstString(iter->mData.mEffectID) << " effect";
|
||||
<< ": dropping unexpected skill argument of " << iter->mData.mEffectID
|
||||
<< " effect";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,9 +110,6 @@ namespace MWWorld
|
|||
return ptr;
|
||||
}
|
||||
|
||||
// Need to instantiate these before they're used
|
||||
template class IndexedStore<ESM::MagicEffect>;
|
||||
|
||||
template <class T, class Id>
|
||||
TypedDynamicStore<T, Id>::TypedDynamicStore()
|
||||
{
|
||||
|
|
@ -976,10 +973,6 @@ namespace MWWorld
|
|||
TypedDynamicStore<ESM::GameSetting>::setUp();
|
||||
}
|
||||
|
||||
// Magic effect
|
||||
//=========================================================================
|
||||
Store<ESM::MagicEffect>::Store() {}
|
||||
|
||||
// Attribute
|
||||
//=========================================================================
|
||||
|
||||
|
|
@ -1260,7 +1253,7 @@ template class MWWorld::TypedDynamicStore<ESM::ItemLevList>;
|
|||
// template class MWWorld::Store<ESM::LandTexture>;
|
||||
template class MWWorld::TypedDynamicStore<ESM::Light>;
|
||||
template class MWWorld::TypedDynamicStore<ESM::Lockpick>;
|
||||
// template class MWWorld::Store<ESM::MagicEffect>;
|
||||
template class MWWorld::TypedDynamicStore<ESM::MagicEffect>;
|
||||
template class MWWorld::TypedDynamicStore<ESM::Miscellaneous>;
|
||||
template class MWWorld::TypedDynamicStore<ESM::NPC>;
|
||||
// template class MWWorld::Store<ESM::Pathgrid>;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <components/esm3/loadglob.hpp>
|
||||
#include <components/esm3/loadgmst.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/esm3/loadpgrd.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
#include <components/esm4/loadachr.hpp>
|
||||
|
|
@ -31,7 +32,6 @@
|
|||
namespace ESM
|
||||
{
|
||||
struct LandTexture;
|
||||
struct MagicEffect;
|
||||
struct WeaponType;
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
|
@ -452,13 +452,6 @@ namespace MWWorld
|
|||
void setUp(const MWWorld::Store<ESM::GameSetting>& settings);
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM::MagicEffect> : public IndexedStore<ESM::MagicEffect>
|
||||
{
|
||||
public:
|
||||
Store();
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM::Attribute> : public TypedDynamicStore<ESM::Attribute>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3108,7 +3108,7 @@ namespace MWWorld
|
|||
const MWWorld::Class& cls = ptr.getClass();
|
||||
if (cls.isActor())
|
||||
{
|
||||
std::set<int> playing;
|
||||
std::set<ESM::RefId> playing;
|
||||
for (const auto& params : cls.getCreatureStats(ptr).getActiveSpells())
|
||||
{
|
||||
for (const auto& effect : params.getEffects())
|
||||
|
|
|
|||
|
|
@ -447,6 +447,8 @@ namespace
|
|||
refId = ESM::Attribute::Strength;
|
||||
else if constexpr (std::is_same_v<RecordType, ESM::Skill>)
|
||||
refId = ESM::Skill::Block;
|
||||
else if constexpr (std::is_same_v<RecordType, ESM::MagicEffect>)
|
||||
refId = ESM::MagicEffect::WaterBreathing;
|
||||
else
|
||||
refId = ESM::StringRefId(stringId);
|
||||
|
||||
|
|
@ -501,7 +503,6 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
static_assert(ESM::hasIndex<ESM::MagicEffect>);
|
||||
static_assert(ESM::hasStringId<ESM::Dialogue>);
|
||||
|
||||
template <class T, class = std::void_t<>>
|
||||
|
|
|
|||
|
|
@ -13,61 +13,57 @@ namespace ESM
|
|||
{
|
||||
namespace
|
||||
{
|
||||
bool isSummon(int effectId)
|
||||
bool isSummon(ESM::RefId effectId)
|
||||
{
|
||||
switch (effectId)
|
||||
{
|
||||
case MagicEffect::SummonScamp:
|
||||
case MagicEffect::SummonClannfear:
|
||||
case MagicEffect::SummonDaedroth:
|
||||
case MagicEffect::SummonDremora:
|
||||
case MagicEffect::SummonAncestralGhost:
|
||||
case MagicEffect::SummonSkeletalMinion:
|
||||
case MagicEffect::SummonBonewalker:
|
||||
case MagicEffect::SummonGreaterBonewalker:
|
||||
case MagicEffect::SummonBonelord:
|
||||
case MagicEffect::SummonWingedTwilight:
|
||||
case MagicEffect::SummonHunger:
|
||||
case MagicEffect::SummonGoldenSaint:
|
||||
case MagicEffect::SummonFlameAtronach:
|
||||
case MagicEffect::SummonFrostAtronach:
|
||||
case MagicEffect::SummonStormAtronach:
|
||||
case MagicEffect::SummonCenturionSphere:
|
||||
case MagicEffect::SummonFabricant:
|
||||
case MagicEffect::SummonWolf:
|
||||
case MagicEffect::SummonBear:
|
||||
case MagicEffect::SummonBonewolf:
|
||||
case MagicEffect::SummonCreature04:
|
||||
case MagicEffect::SummonCreature05:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
static const std::array summonEffects{
|
||||
MagicEffect::SummonScamp,
|
||||
MagicEffect::SummonClannfear,
|
||||
MagicEffect::SummonDaedroth,
|
||||
MagicEffect::SummonDremora,
|
||||
MagicEffect::SummonAncestralGhost,
|
||||
MagicEffect::SummonSkeletalMinion,
|
||||
MagicEffect::SummonBonewalker,
|
||||
MagicEffect::SummonGreaterBonewalker,
|
||||
MagicEffect::SummonBonelord,
|
||||
MagicEffect::SummonWingedTwilight,
|
||||
MagicEffect::SummonHunger,
|
||||
MagicEffect::SummonGoldenSaint,
|
||||
MagicEffect::SummonFlameAtronach,
|
||||
MagicEffect::SummonFrostAtronach,
|
||||
MagicEffect::SummonStormAtronach,
|
||||
MagicEffect::SummonCenturionSphere,
|
||||
MagicEffect::SummonFabricant,
|
||||
MagicEffect::SummonWolf,
|
||||
MagicEffect::SummonBear,
|
||||
MagicEffect::SummonBonewolf,
|
||||
MagicEffect::SummonCreature04,
|
||||
MagicEffect::SummonCreature05,
|
||||
};
|
||||
return std::find(summonEffects.begin(), summonEffects.end(), effectId) != summonEffects.end();
|
||||
}
|
||||
bool affectsAttribute(int effectId)
|
||||
bool affectsAttribute(ESM::RefId effectId)
|
||||
{
|
||||
switch (effectId)
|
||||
{
|
||||
case MagicEffect::DrainAttribute:
|
||||
case MagicEffect::DamageAttribute:
|
||||
case MagicEffect::RestoreAttribute:
|
||||
case MagicEffect::FortifyAttribute:
|
||||
case MagicEffect::AbsorbAttribute:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
static const std::array affectsAttributeEffects{
|
||||
MagicEffect::DrainAttribute,
|
||||
MagicEffect::DamageAttribute,
|
||||
MagicEffect::RestoreAttribute,
|
||||
MagicEffect::FortifyAttribute,
|
||||
MagicEffect::AbsorbAttribute,
|
||||
};
|
||||
return std::find(affectsAttributeEffects.begin(), affectsAttributeEffects.end(), effectId)
|
||||
!= affectsAttributeEffects.end();
|
||||
}
|
||||
bool affectsSkill(int effectId)
|
||||
bool affectsSkill(ESM::RefId effectId)
|
||||
{
|
||||
switch (effectId)
|
||||
{
|
||||
case MagicEffect::DrainSkill:
|
||||
case MagicEffect::DamageSkill:
|
||||
case MagicEffect::RestoreSkill:
|
||||
case MagicEffect::FortifySkill:
|
||||
case MagicEffect::AbsorbSkill:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
static const std::array affectsSkillEffects{
|
||||
MagicEffect::DrainSkill,
|
||||
MagicEffect::DamageSkill,
|
||||
MagicEffect::RestoreSkill,
|
||||
MagicEffect::FortifySkill,
|
||||
MagicEffect::AbsorbSkill,
|
||||
};
|
||||
return std::find(affectsSkillEffects.begin(), affectsSkillEffects.end(), effectId)
|
||||
!= affectsSkillEffects.end();
|
||||
}
|
||||
|
||||
void saveImpl(ESMWriter& esm, const std::vector<ActiveSpells::ActiveSpellParams>& spells, NAME tag)
|
||||
|
|
@ -90,7 +86,7 @@ namespace ESM
|
|||
|
||||
for (auto& effect : params.mEffects)
|
||||
{
|
||||
esm.writeHNT("MGEF", effect.mEffectId);
|
||||
esm.writeHNT("MGEF", ESM::MagicEffect::refIdToIndex(effect.mEffectId));
|
||||
if (const ESM::RefId* id = std::get_if<ESM::RefId>(&effect.mArg))
|
||||
{
|
||||
if (!id->empty())
|
||||
|
|
@ -175,8 +171,10 @@ namespace ESM
|
|||
|
||||
while (esm.isNextSub("MGEF"))
|
||||
{
|
||||
int32_t effectId;
|
||||
ActiveEffect effect;
|
||||
esm.getHT(effect.mEffectId);
|
||||
esm.getHT(effectId);
|
||||
effect.mEffectId = ESM::MagicEffect::indexToRefId(effectId);
|
||||
if (format <= MaxActorIdSaveGameFormatVersion)
|
||||
{
|
||||
int32_t arg = -1;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace ESM
|
|||
Flag_Invalid = 1 << 5
|
||||
};
|
||||
|
||||
int32_t mEffectId;
|
||||
RefId mEffectId;
|
||||
float mMagnitude;
|
||||
float mMinMagnitude;
|
||||
float mMaxMagnitude;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace ESM
|
||||
|
|
@ -117,9 +119,10 @@ namespace ESM
|
|||
esm.getHNOT(effectIndex, "EIND");
|
||||
int32_t actorId;
|
||||
esm.getHNT(actorId, "ACID");
|
||||
mSummonedCreatureMap[SummonKey(magicEffect, source, effectIndex)] = actorId;
|
||||
mSummonedCreatures.emplace(
|
||||
magicEffect, RefNum{ .mIndex = static_cast<uint32_t>(actorId), .mContentFile = -1 });
|
||||
mSummonedCreatureMap[SummonKey(ESM::MagicEffect::indexToRefId(magicEffect), source, effectIndex)]
|
||||
= actorId;
|
||||
mSummonedCreatures.emplace(ESM::MagicEffect::indexToRefId(magicEffect),
|
||||
RefNum{ .mIndex = static_cast<uint32_t>(actorId), .mContentFile = -1 });
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -133,7 +136,7 @@ namespace ESM
|
|||
esm.getHNT(actor.mIndex, "ACID");
|
||||
else
|
||||
actor = esm.getFormId(true, "ACID");
|
||||
mSummonedCreatures.emplace(magicEffect, actor);
|
||||
mSummonedCreatures.emplace(ESM::MagicEffect::indexToRefId(magicEffect), actor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +251,7 @@ namespace ESM
|
|||
|
||||
for (const auto& [effectId, actor] : mSummonedCreatures)
|
||||
{
|
||||
esm.writeHNT("SUMM", effectId);
|
||||
esm.writeHNT("SUMM", ESM::MagicEffect::refIdToIndex(effectId));
|
||||
esm.writeFormId(actor, true, "ACID");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace ESM
|
|||
std::array<StatState<int>, 4> mAiSettings;
|
||||
|
||||
std::map<SummonKey, int> mSummonedCreatureMap;
|
||||
std::multimap<int, RefNum> mSummonedCreatures;
|
||||
std::multimap<ESM::RefId, RefNum> mSummonedCreatures;
|
||||
std::vector<int> mSummonGraveyard;
|
||||
|
||||
TimeStamp mTradeTime;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,55 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/misc/concepts.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
template <Misc::SameAsWithoutCvref<ENAMstruct> T>
|
||||
namespace
|
||||
{
|
||||
// ENAM format defined by Morrowind.esm
|
||||
struct EsmENAMstruct
|
||||
{
|
||||
int16_t mEffectID;
|
||||
signed char mSkill, mAttribute;
|
||||
int32_t mRange, mArea, mDuration, mMagnMin, mMagnMax;
|
||||
};
|
||||
|
||||
void toBinary(const ENAMstruct& src, EsmENAMstruct& dst)
|
||||
{
|
||||
int16_t index = static_cast<int16_t>(ESM::MagicEffect::refIdToIndex(src.mEffectID));
|
||||
if (index < 0 || index >= ESM::MagicEffect::Length)
|
||||
throw std::runtime_error(std::format("Cannot serialize effect {}", src.mEffectID.toDebugString()));
|
||||
dst.mEffectID = index;
|
||||
dst.mSkill = src.mSkill;
|
||||
dst.mAttribute = src.mAttribute;
|
||||
dst.mRange = src.mRange;
|
||||
dst.mArea = src.mArea;
|
||||
dst.mDuration = src.mDuration;
|
||||
dst.mMagnMin = src.mMagnMin;
|
||||
dst.mMagnMax = src.mMagnMax;
|
||||
}
|
||||
|
||||
void fromBinary(const EsmENAMstruct& src, ENAMstruct& dst)
|
||||
{
|
||||
int16_t index = src.mEffectID;
|
||||
if (index < 0 || index >= ESM::MagicEffect::Length)
|
||||
throw std::runtime_error(std::format("Cannot deserialize effect with index {}", index));
|
||||
dst.mEffectID = ESM::MagicEffect::indexToRefId(index);
|
||||
dst.mSkill = src.mSkill;
|
||||
dst.mAttribute = src.mAttribute;
|
||||
dst.mRange = src.mRange;
|
||||
dst.mArea = src.mArea;
|
||||
dst.mDuration = src.mDuration;
|
||||
dst.mMagnMin = src.mMagnMin;
|
||||
dst.mMagnMax = src.mMagnMax;
|
||||
}
|
||||
}
|
||||
|
||||
template <Misc::SameAsWithoutCvref<EsmENAMstruct> T>
|
||||
void decompose(T&& v, const auto& f)
|
||||
{
|
||||
f(v.mEffectID, v.mSkill, v.mAttribute, v.mRange, v.mArea, v.mDuration, v.mMagnMin, v.mMagnMax);
|
||||
|
|
@ -37,8 +81,11 @@ namespace ESM
|
|||
|
||||
void EffectList::add(ESMReader& esm)
|
||||
{
|
||||
EsmENAMstruct bin;
|
||||
esm.getSubComposite(bin);
|
||||
|
||||
ENAMstruct s;
|
||||
esm.getSubComposite(s);
|
||||
fromBinary(bin, s);
|
||||
mList.push_back({ s, static_cast<uint32_t>(mList.size()) });
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +93,9 @@ namespace ESM
|
|||
{
|
||||
for (const IndexedENAMstruct& enam : mList)
|
||||
{
|
||||
esm.writeNamedComposite("ENAM", enam.mData);
|
||||
EsmENAMstruct bin;
|
||||
toBinary(enam.mData, bin);
|
||||
esm.writeNamedComposite("ENAM", bin);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
|
|
@ -14,8 +16,8 @@ namespace ESM
|
|||
*/
|
||||
struct ENAMstruct
|
||||
{
|
||||
// Magical effect, hard-coded ID
|
||||
int16_t mEffectID;
|
||||
// Magical effect, serialized to int16
|
||||
ESM::RefId mEffectID;
|
||||
|
||||
// Which skills/attributes are affected (for restore/drain spells
|
||||
// etc.)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,46 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/misc/concepts.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
template <Misc::SameAsWithoutCvref<Ingredient::IRDTstruct> T>
|
||||
namespace
|
||||
{
|
||||
// IRDT format defined by Morrowind.esm
|
||||
struct EsmIRDTstruct
|
||||
{
|
||||
float mWeight;
|
||||
int32_t mValue, mEffectID[4], mSkills[4], mAttributes[4];
|
||||
};
|
||||
|
||||
void toBinary(const Ingredient::IRDTstruct& src, EsmIRDTstruct& dst)
|
||||
{
|
||||
dst.mWeight = src.mWeight;
|
||||
dst.mValue = src.mValue;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
dst.mEffectID[i] = ESM::MagicEffect::refIdToIndex(src.mEffectID[i]);
|
||||
dst.mSkills[i] = src.mSkills[i];
|
||||
dst.mAttributes[i] = src.mAttributes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void fromBinary(const EsmIRDTstruct& src, Ingredient::IRDTstruct& dst)
|
||||
{
|
||||
dst.mWeight = src.mWeight;
|
||||
dst.mValue = src.mValue;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
dst.mEffectID[i] = ESM::MagicEffect::indexToRefId(src.mEffectID[i]);
|
||||
dst.mSkills[i] = src.mSkills[i];
|
||||
dst.mAttributes[i] = src.mAttributes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <Misc::SameAsWithoutCvref<EsmIRDTstruct> T>
|
||||
void decompose(T&& v, const auto& f)
|
||||
{
|
||||
f(v.mWeight, v.mValue, v.mEffectID, v.mSkills, v.mAttributes);
|
||||
|
|
@ -36,7 +71,9 @@ namespace ESM
|
|||
mName = esm.getHString();
|
||||
break;
|
||||
case fourCC("IRDT"):
|
||||
esm.getSubComposite(mData);
|
||||
EsmIRDTstruct bin;
|
||||
esm.getSubComposite(bin);
|
||||
fromBinary(bin, mData);
|
||||
hasData = true;
|
||||
break;
|
||||
case fourCC("SCRI"):
|
||||
|
|
@ -63,15 +100,21 @@ namespace ESM
|
|||
// horrible hack to fix broken data in records
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (mData.mEffectID[i] != 85 && mData.mEffectID[i] != 22 && mData.mEffectID[i] != 17
|
||||
&& mData.mEffectID[i] != 79 && mData.mEffectID[i] != 74)
|
||||
if (mData.mEffectID[i] != ESM::MagicEffect::AbsorbAttribute
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::DamageAttribute
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::DrainAttribute
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::FortifyAttribute
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::RestoreAttribute)
|
||||
{
|
||||
mData.mAttributes[i] = -1;
|
||||
}
|
||||
|
||||
// is this relevant in cycle from 0 to 4?
|
||||
if (mData.mEffectID[i] != 89 && mData.mEffectID[i] != 26 && mData.mEffectID[i] != 21
|
||||
&& mData.mEffectID[i] != 83 && mData.mEffectID[i] != 78)
|
||||
if (mData.mEffectID[i] != ESM::MagicEffect::AbsorbSkill
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::DamageSkill
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::DrainSkill
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::FortifySkill
|
||||
&& mData.mEffectID[i] != ESM::MagicEffect::RestoreSkill)
|
||||
{
|
||||
mData.mSkills[i] = -1;
|
||||
}
|
||||
|
|
@ -90,7 +133,9 @@ namespace ESM
|
|||
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeNamedComposite("IRDT", mData);
|
||||
EsmIRDTstruct bin;
|
||||
toBinary(mData, bin);
|
||||
esm.writeNamedComposite("IRDT", bin);
|
||||
esm.writeHNOCRefId("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
|
|
@ -102,7 +147,7 @@ namespace ESM
|
|||
mData.mValue = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
mData.mEffectID[i] = 0;
|
||||
mData.mEffectID[i] = ESM::MagicEffect::WaterBreathing;
|
||||
mData.mSkills[i] = 0;
|
||||
mData.mAttributes[i] = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace ESM
|
|||
{
|
||||
float mWeight;
|
||||
int32_t mValue;
|
||||
int32_t mEffectID[4]; // Effect, -1 means none
|
||||
RefId mEffectID[4]; // Effect, EmptyRefId means none
|
||||
int32_t mSkills[4]; // SkillEnum related to effect
|
||||
int32_t mAttributes[4]; // Attribute related to effect
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,14 +25,165 @@ namespace ESM
|
|||
0x1048, 0x1048, 0x1048, 0x1048 };
|
||||
}
|
||||
|
||||
const StringRefId MagicEffect::WaterBreathing("WaterBreathing");
|
||||
const StringRefId MagicEffect::SwiftSwim("SwiftSwim");
|
||||
const StringRefId MagicEffect::WaterWalking("WaterWalking");
|
||||
const StringRefId MagicEffect::Shield("Shield");
|
||||
const StringRefId MagicEffect::FireShield("FireShield");
|
||||
const StringRefId MagicEffect::LightningShield("LightningShield");
|
||||
const StringRefId MagicEffect::FrostShield("FrostShield");
|
||||
const StringRefId MagicEffect::Burden("Burden");
|
||||
const StringRefId MagicEffect::Feather("Feather");
|
||||
const StringRefId MagicEffect::Jump("Jump");
|
||||
const StringRefId MagicEffect::Levitate("Levitate");
|
||||
const StringRefId MagicEffect::SlowFall("SlowFall");
|
||||
const StringRefId MagicEffect::Lock("Lock");
|
||||
const StringRefId MagicEffect::Open("Open");
|
||||
const StringRefId MagicEffect::FireDamage("FireDamage");
|
||||
const StringRefId MagicEffect::ShockDamage("ShockDamage");
|
||||
const StringRefId MagicEffect::FrostDamage("FrostDamage");
|
||||
const StringRefId MagicEffect::DrainAttribute("DrainAttribute");
|
||||
const StringRefId MagicEffect::DrainHealth("DrainHealth");
|
||||
const StringRefId MagicEffect::DrainMagicka("DrainMagicka");
|
||||
const StringRefId MagicEffect::DrainFatigue("DrainFatigue");
|
||||
const StringRefId MagicEffect::DrainSkill("DrainSkill");
|
||||
const StringRefId MagicEffect::DamageAttribute("DamageAttribute");
|
||||
const StringRefId MagicEffect::DamageHealth("DamageHealth");
|
||||
const StringRefId MagicEffect::DamageMagicka("DamageMagicka");
|
||||
const StringRefId MagicEffect::DamageFatigue("DamageFatigue");
|
||||
const StringRefId MagicEffect::DamageSkill("DamageSkill");
|
||||
const StringRefId MagicEffect::Poison("Poison");
|
||||
const StringRefId MagicEffect::WeaknessToFire("WeaknessToFire");
|
||||
const StringRefId MagicEffect::WeaknessToFrost("WeaknessToFrost");
|
||||
const StringRefId MagicEffect::WeaknessToShock("WeaknessToShock");
|
||||
const StringRefId MagicEffect::WeaknessToMagicka("WeaknessToMagicka");
|
||||
const StringRefId MagicEffect::WeaknessToCommonDisease("WeaknessToCommonDisease");
|
||||
const StringRefId MagicEffect::WeaknessToBlightDisease("WeaknessToBlightDisease");
|
||||
const StringRefId MagicEffect::WeaknessToCorprusDisease("WeaknessToCorprusDisease");
|
||||
const StringRefId MagicEffect::WeaknessToPoison("WeaknessToPoison");
|
||||
const StringRefId MagicEffect::WeaknessToNormalWeapons("WeaknessToNormalWeapons");
|
||||
const StringRefId MagicEffect::DisintegrateWeapon("DisintegrateWeapon");
|
||||
const StringRefId MagicEffect::DisintegrateArmor("DisintegrateArmor");
|
||||
const StringRefId MagicEffect::Invisibility("Invisibility");
|
||||
const StringRefId MagicEffect::Chameleon("Chameleon");
|
||||
const StringRefId MagicEffect::Light("Light");
|
||||
const StringRefId MagicEffect::Sanctuary("Sanctuary");
|
||||
const StringRefId MagicEffect::NightEye("NightEye");
|
||||
const StringRefId MagicEffect::Charm("Charm");
|
||||
const StringRefId MagicEffect::Paralyze("Paralyze");
|
||||
const StringRefId MagicEffect::Silence("Silence");
|
||||
const StringRefId MagicEffect::Blind("Blind");
|
||||
const StringRefId MagicEffect::Sound("Sound");
|
||||
const StringRefId MagicEffect::CalmHumanoid("CalmHumanoid");
|
||||
const StringRefId MagicEffect::CalmCreature("CalmCreature");
|
||||
const StringRefId MagicEffect::FrenzyHumanoid("FrenzyHumanoid");
|
||||
const StringRefId MagicEffect::FrenzyCreature("FrenzyCreature");
|
||||
const StringRefId MagicEffect::DemoralizeHumanoid("DemoralizeHumanoid");
|
||||
const StringRefId MagicEffect::DemoralizeCreature("DemoralizeCreature");
|
||||
const StringRefId MagicEffect::RallyHumanoid("RallyHumanoid");
|
||||
const StringRefId MagicEffect::RallyCreature("RallyCreature");
|
||||
const StringRefId MagicEffect::Dispel("Dispel");
|
||||
const StringRefId MagicEffect::Soultrap("Soultrap");
|
||||
const StringRefId MagicEffect::Telekinesis("Telekinesis");
|
||||
const StringRefId MagicEffect::Mark("Mark");
|
||||
const StringRefId MagicEffect::Recall("Recall");
|
||||
const StringRefId MagicEffect::DivineIntervention("DivineIntervention");
|
||||
const StringRefId MagicEffect::AlmsiviIntervention("AlmsiviIntervention");
|
||||
const StringRefId MagicEffect::DetectAnimal("DetectAnimal");
|
||||
const StringRefId MagicEffect::DetectEnchantment("DetectEnchantment");
|
||||
const StringRefId MagicEffect::DetectKey("DetectKey");
|
||||
const StringRefId MagicEffect::SpellAbsorption("SpellAbsorption");
|
||||
const StringRefId MagicEffect::Reflect("Reflect");
|
||||
const StringRefId MagicEffect::CureCommonDisease("CureCommonDisease");
|
||||
const StringRefId MagicEffect::CureBlightDisease("CureBlightDisease");
|
||||
const StringRefId MagicEffect::CureCorprusDisease("CureCorprusDisease");
|
||||
const StringRefId MagicEffect::CurePoison("CurePoison");
|
||||
const StringRefId MagicEffect::CureParalyzation("CureParalyzation");
|
||||
const StringRefId MagicEffect::RestoreAttribute("RestoreAttribute");
|
||||
const StringRefId MagicEffect::RestoreHealth("RestoreHealth");
|
||||
const StringRefId MagicEffect::RestoreMagicka("RestoreMagicka");
|
||||
const StringRefId MagicEffect::RestoreFatigue("RestoreFatigue");
|
||||
const StringRefId MagicEffect::RestoreSkill("RestoreSkill");
|
||||
const StringRefId MagicEffect::FortifyAttribute("FortifyAttribute");
|
||||
const StringRefId MagicEffect::FortifyHealth("FortifyHealth");
|
||||
const StringRefId MagicEffect::FortifyMagicka("FortifyMagicka");
|
||||
const StringRefId MagicEffect::FortifyFatigue("FortifyFatigue");
|
||||
const StringRefId MagicEffect::FortifySkill("FortifySkill");
|
||||
const StringRefId MagicEffect::FortifyMaximumMagicka("FortifyMaximumMagicka");
|
||||
const StringRefId MagicEffect::AbsorbAttribute("AbsorbAttribute");
|
||||
const StringRefId MagicEffect::AbsorbHealth("AbsorbHealth");
|
||||
const StringRefId MagicEffect::AbsorbMagicka("AbsorbMagicka");
|
||||
const StringRefId MagicEffect::AbsorbFatigue("AbsorbFatigue");
|
||||
const StringRefId MagicEffect::AbsorbSkill("AbsorbSkill");
|
||||
const StringRefId MagicEffect::ResistFire("ResistFire");
|
||||
const StringRefId MagicEffect::ResistFrost("ResistFrost");
|
||||
const StringRefId MagicEffect::ResistShock("ResistShock");
|
||||
const StringRefId MagicEffect::ResistMagicka("ResistMagicka");
|
||||
const StringRefId MagicEffect::ResistCommonDisease("ResistCommonDisease");
|
||||
const StringRefId MagicEffect::ResistBlightDisease("ResistBlightDisease");
|
||||
const StringRefId MagicEffect::ResistCorprusDisease("ResistCorprusDisease");
|
||||
const StringRefId MagicEffect::ResistPoison("ResistPoison");
|
||||
const StringRefId MagicEffect::ResistNormalWeapons("ResistNormalWeapons");
|
||||
const StringRefId MagicEffect::ResistParalysis("ResistParalysis");
|
||||
const StringRefId MagicEffect::RemoveCurse("RemoveCurse");
|
||||
const StringRefId MagicEffect::TurnUndead("TurnUndead");
|
||||
const StringRefId MagicEffect::SummonScamp("SummonScamp");
|
||||
const StringRefId MagicEffect::SummonClannfear("SummonClannfear");
|
||||
const StringRefId MagicEffect::SummonDaedroth("SummonDaedroth");
|
||||
const StringRefId MagicEffect::SummonDremora("SummonDremora");
|
||||
const StringRefId MagicEffect::SummonAncestralGhost("SummonAncestralGhost");
|
||||
const StringRefId MagicEffect::SummonSkeletalMinion("SummonSkeletalMinion");
|
||||
const StringRefId MagicEffect::SummonBonewalker("SummonBonewalker");
|
||||
const StringRefId MagicEffect::SummonGreaterBonewalker("SummonGreaterBonewalker");
|
||||
const StringRefId MagicEffect::SummonBonelord("SummonBonelord");
|
||||
const StringRefId MagicEffect::SummonWingedTwilight("SummonWingedTwilight");
|
||||
const StringRefId MagicEffect::SummonHunger("SummonHunger");
|
||||
const StringRefId MagicEffect::SummonGoldenSaint("SummonGoldenSaint");
|
||||
const StringRefId MagicEffect::SummonFlameAtronach("SummonFlameAtronach");
|
||||
const StringRefId MagicEffect::SummonFrostAtronach("SummonFrostAtronach");
|
||||
const StringRefId MagicEffect::SummonStormAtronach("SummonStormAtronach");
|
||||
const StringRefId MagicEffect::FortifyAttack("FortifyAttack");
|
||||
const StringRefId MagicEffect::CommandCreature("CommandCreature");
|
||||
const StringRefId MagicEffect::CommandHumanoid("CommandHumanoid");
|
||||
const StringRefId MagicEffect::BoundDagger("BoundDagger");
|
||||
const StringRefId MagicEffect::BoundLongsword("BoundLongsword");
|
||||
const StringRefId MagicEffect::BoundMace("BoundMace");
|
||||
const StringRefId MagicEffect::BoundBattleAxe("BoundBattleAxe");
|
||||
const StringRefId MagicEffect::BoundSpear("BoundSpear");
|
||||
const StringRefId MagicEffect::BoundLongbow("BoundLongbow");
|
||||
const StringRefId MagicEffect::ExtraSpell("ExtraSpell");
|
||||
const StringRefId MagicEffect::BoundCuirass("BoundCuirass");
|
||||
const StringRefId MagicEffect::BoundHelm("BoundHelm");
|
||||
const StringRefId MagicEffect::BoundBoots("BoundBoots");
|
||||
const StringRefId MagicEffect::BoundShield("BoundShield");
|
||||
const StringRefId MagicEffect::BoundGloves("BoundGloves");
|
||||
const StringRefId MagicEffect::Corprus("Corprus");
|
||||
const StringRefId MagicEffect::Vampirism("Vampirism");
|
||||
const StringRefId MagicEffect::SummonCenturionSphere("SummonCenturionSphere");
|
||||
const StringRefId MagicEffect::SunDamage("SunDamage");
|
||||
const StringRefId MagicEffect::StuntedMagicka("StuntedMagicka");
|
||||
|
||||
// Tribunal only
|
||||
const StringRefId MagicEffect::SummonFabricant("SummonFabricant");
|
||||
|
||||
// Bloodmoon only
|
||||
const StringRefId MagicEffect::SummonWolf("SummonWolf");
|
||||
const StringRefId MagicEffect::SummonBear("SummonBear");
|
||||
const StringRefId MagicEffect::SummonBonewolf("SummonBonewolf");
|
||||
const StringRefId MagicEffect::SummonCreature04("SummonCreature04");
|
||||
const StringRefId MagicEffect::SummonCreature05("SummonCreature05");
|
||||
|
||||
void MagicEffect::load(ESMReader& esm, bool& isDeleted)
|
||||
{
|
||||
isDeleted = false; // MagicEffect record can't be deleted now (may be changed in the future)
|
||||
mRecordFlags = esm.getRecordFlags();
|
||||
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
int32_t index = -1;
|
||||
esm.getHNT(index, "INDX");
|
||||
if (index < 0 || index >= Length)
|
||||
esm.fail("Invalid Index!");
|
||||
|
||||
mId = indexToRefId(mIndex);
|
||||
mId = indexToRefId(index);
|
||||
|
||||
esm.getSubNameIs("MEDT");
|
||||
esm.getSubHeader();
|
||||
|
|
@ -52,8 +203,8 @@ namespace ESM
|
|||
{
|
||||
// don't allow mods to change fixed flags in the legacy format
|
||||
mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight);
|
||||
if (mIndex >= 0 && mIndex < NumberOfHardcodedFlags)
|
||||
mData.mFlags |= HardcodedFlags[mIndex];
|
||||
if (index >= 0 && index < NumberOfHardcodedFlags)
|
||||
mData.mFlags |= HardcodedFlags[index];
|
||||
}
|
||||
|
||||
// vanilla MW accepts the _SND subrecords before or after DESC... I hope
|
||||
|
|
@ -103,7 +254,7 @@ namespace ESM
|
|||
}
|
||||
void MagicEffect::save(ESMWriter& esm, bool /*isDeleted*/) const
|
||||
{
|
||||
esm.writeHNT("INDX", mIndex);
|
||||
esm.writeHNT("INDX", refIdToIndex(mId));
|
||||
|
||||
esm.startSubRecord("MEDT");
|
||||
esm.writeT(MagicSchool::skillRefIdToIndex(mData.mSchool));
|
||||
|
|
@ -134,109 +285,153 @@ namespace ESM
|
|||
|
||||
namespace
|
||||
{
|
||||
std::map<short, short> makeEffectsMap()
|
||||
std::unordered_map<RefId, RefId> makeResistancesMap()
|
||||
{
|
||||
std::map<short, short> effects;
|
||||
std::unordered_map<RefId, RefId> effects{
|
||||
{ MagicEffect::DisintegrateArmor, MagicEffect::Sanctuary },
|
||||
{ MagicEffect::DisintegrateWeapon, MagicEffect::Sanctuary },
|
||||
|
||||
effects[MagicEffect::Effects::DisintegrateArmor] = MagicEffect::Effects::Sanctuary;
|
||||
effects[MagicEffect::Effects::DisintegrateWeapon] = MagicEffect::Effects::Sanctuary;
|
||||
{ MagicEffect::DrainAttribute, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DrainHealth, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DrainMagicka, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DrainFatigue, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DrainSkill, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DamageAttribute, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DamageHealth, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DamageMagicka, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DamageFatigue, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DamageSkill, MagicEffect::ResistMagicka },
|
||||
|
||||
for (short i = MagicEffect::Effects::DrainAttribute; i <= MagicEffect::Effects::DamageSkill; ++i)
|
||||
effects[i] = MagicEffect::Effects::ResistMagicka;
|
||||
for (short i = MagicEffect::Effects::AbsorbAttribute; i <= MagicEffect::Effects::AbsorbSkill; ++i)
|
||||
effects[i] = MagicEffect::Effects::ResistMagicka;
|
||||
for (short i = MagicEffect::Effects::WeaknessToFire; i <= MagicEffect::Effects::WeaknessToNormalWeapons;
|
||||
++i)
|
||||
effects[i] = MagicEffect::Effects::ResistMagicka;
|
||||
{ MagicEffect::AbsorbAttribute, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::AbsorbHealth, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::AbsorbMagicka, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::AbsorbFatigue, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::AbsorbSkill, MagicEffect::ResistMagicka },
|
||||
|
||||
effects[MagicEffect::Effects::Burden] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::Charm] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::Silence] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::Blind] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::Sound] = MagicEffect::Effects::ResistMagicka;
|
||||
{ MagicEffect::WeaknessToFire, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToFrost, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToShock, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToMagicka, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToCommonDisease, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToBlightDisease, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToCorprusDisease, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToPoison, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::WeaknessToNormalWeapons, MagicEffect::ResistMagicka },
|
||||
|
||||
for (short i = 0; i < 2; ++i)
|
||||
{
|
||||
effects[MagicEffect::Effects::CalmHumanoid + i] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::FrenzyHumanoid + i] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::DemoralizeHumanoid + i] = MagicEffect::Effects::ResistMagicka;
|
||||
effects[MagicEffect::Effects::RallyHumanoid + i] = MagicEffect::Effects::ResistMagicka;
|
||||
}
|
||||
{ MagicEffect::Burden, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::Charm, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::Silence, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::Blind, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::Sound, MagicEffect::ResistMagicka },
|
||||
|
||||
effects[MagicEffect::Effects::TurnUndead] = MagicEffect::Effects::ResistMagicka;
|
||||
{ MagicEffect::CalmHumanoid, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::CalmCreature, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::FrenzyHumanoid, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::FrenzyCreature, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DemoralizeHumanoid, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::DemoralizeCreature, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::RallyHumanoid, MagicEffect::ResistMagicka },
|
||||
{ MagicEffect::RallyCreature, MagicEffect::ResistMagicka },
|
||||
|
||||
effects[MagicEffect::Effects::FireDamage] = MagicEffect::Effects::ResistFire;
|
||||
effects[MagicEffect::Effects::FrostDamage] = MagicEffect::Effects::ResistFrost;
|
||||
effects[MagicEffect::Effects::ShockDamage] = MagicEffect::Effects::ResistShock;
|
||||
effects[MagicEffect::Effects::Vampirism] = MagicEffect::Effects::ResistCommonDisease;
|
||||
effects[MagicEffect::Effects::Corprus] = MagicEffect::Effects::ResistCorprusDisease;
|
||||
effects[MagicEffect::Effects::Poison] = MagicEffect::Effects::ResistPoison;
|
||||
effects[MagicEffect::Effects::Paralyze] = MagicEffect::Effects::ResistParalysis;
|
||||
{ MagicEffect::TurnUndead, MagicEffect::ResistMagicka },
|
||||
|
||||
{ MagicEffect::FireDamage, MagicEffect::ResistFire },
|
||||
{ MagicEffect::FrostDamage, MagicEffect::ResistFrost },
|
||||
{ MagicEffect::ShockDamage, MagicEffect::ResistShock },
|
||||
{ MagicEffect::Vampirism, MagicEffect::ResistCommonDisease },
|
||||
{ MagicEffect::Corprus, MagicEffect::ResistCorprusDisease },
|
||||
{ MagicEffect::Poison, MagicEffect::ResistPoison },
|
||||
{ MagicEffect::Paralyze, MagicEffect::ResistParalysis },
|
||||
};
|
||||
return effects;
|
||||
}
|
||||
}
|
||||
|
||||
short MagicEffect::getResistanceEffect(short effect)
|
||||
RefId MagicEffect::getResistanceEffect(RefId effectId)
|
||||
{
|
||||
// Source https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attribute
|
||||
|
||||
// <Effect, Effect providing resistance against first effect>
|
||||
static const std::map<short, short> effects = makeEffectsMap();
|
||||
static const std::unordered_map<RefId, RefId> effects = makeResistancesMap();
|
||||
|
||||
if (const auto it = effects.find(effect); it != effects.end())
|
||||
if (const auto it = effects.find(effectId); it != effects.end())
|
||||
return it->second;
|
||||
|
||||
return -1;
|
||||
return {};
|
||||
}
|
||||
|
||||
short MagicEffect::getWeaknessEffect(short effect)
|
||||
namespace
|
||||
{
|
||||
static std::map<short, short> effects;
|
||||
if (effects.empty())
|
||||
std::unordered_map<RefId, RefId> makeWeaknessesMap()
|
||||
{
|
||||
for (short i = DrainAttribute; i <= DamageSkill; ++i)
|
||||
effects[i] = WeaknessToMagicka;
|
||||
for (short i = AbsorbAttribute; i <= AbsorbSkill; ++i)
|
||||
effects[i] = WeaknessToMagicka;
|
||||
for (short i = WeaknessToFire; i <= WeaknessToNormalWeapons; ++i)
|
||||
effects[i] = WeaknessToMagicka;
|
||||
std::unordered_map<RefId, RefId> effects{
|
||||
{ MagicEffect::DrainAttribute, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DrainHealth, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DrainMagicka, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DrainFatigue, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DrainSkill, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DamageAttribute, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DamageHealth, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DamageMagicka, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DamageFatigue, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DamageSkill, MagicEffect::WeaknessToMagicka },
|
||||
|
||||
effects[Burden] = WeaknessToMagicka;
|
||||
effects[Charm] = WeaknessToMagicka;
|
||||
effects[Silence] = WeaknessToMagicka;
|
||||
effects[Blind] = WeaknessToMagicka;
|
||||
effects[Sound] = WeaknessToMagicka;
|
||||
{ MagicEffect::AbsorbAttribute, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::AbsorbHealth, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::AbsorbMagicka, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::AbsorbFatigue, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::AbsorbSkill, MagicEffect::WeaknessToMagicka },
|
||||
|
||||
for (short i = 0; i < 2; ++i)
|
||||
{
|
||||
effects[CalmHumanoid + i] = WeaknessToMagicka;
|
||||
effects[FrenzyHumanoid + i] = WeaknessToMagicka;
|
||||
effects[DemoralizeHumanoid + i] = WeaknessToMagicka;
|
||||
effects[RallyHumanoid + i] = WeaknessToMagicka;
|
||||
}
|
||||
{ MagicEffect::WeaknessToFire, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToFrost, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToShock, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToMagicka, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToCommonDisease, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToBlightDisease, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToCorprusDisease, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToPoison, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::WeaknessToNormalWeapons, MagicEffect::WeaknessToMagicka },
|
||||
|
||||
effects[TurnUndead] = WeaknessToMagicka;
|
||||
{ MagicEffect::Burden, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::Charm, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::Silence, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::Blind, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::Sound, MagicEffect::WeaknessToMagicka },
|
||||
|
||||
effects[FireDamage] = WeaknessToFire;
|
||||
effects[FrostDamage] = WeaknessToFrost;
|
||||
effects[ShockDamage] = WeaknessToShock;
|
||||
effects[Vampirism] = WeaknessToCommonDisease;
|
||||
effects[Corprus] = WeaknessToCorprusDisease;
|
||||
effects[Poison] = WeaknessToPoison;
|
||||
{ MagicEffect::CalmHumanoid, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::CalmCreature, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::FrenzyHumanoid, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::FrenzyCreature, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DemoralizeHumanoid, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::DemoralizeCreature, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::RallyHumanoid, MagicEffect::WeaknessToMagicka },
|
||||
{ MagicEffect::RallyCreature, MagicEffect::WeaknessToMagicka },
|
||||
|
||||
effects[Paralyze] = -1;
|
||||
{ MagicEffect::TurnUndead, MagicEffect::WeaknessToMagicka },
|
||||
|
||||
{ MagicEffect::FireDamage, MagicEffect::WeaknessToFire },
|
||||
{ MagicEffect::FrostDamage, MagicEffect::WeaknessToFrost },
|
||||
{ MagicEffect::ShockDamage, MagicEffect::WeaknessToShock },
|
||||
{ MagicEffect::Vampirism, MagicEffect::WeaknessToCommonDisease },
|
||||
{ MagicEffect::Corprus, MagicEffect::WeaknessToCorprusDisease },
|
||||
{ MagicEffect::Poison, MagicEffect::WeaknessToPoison },
|
||||
};
|
||||
return effects;
|
||||
}
|
||||
|
||||
if (effects.find(effect) != effects.end())
|
||||
return effects[effect];
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Map effect ID to GMST name
|
||||
const std::array<std::string, MagicEffect::Length> MagicEffect::sGmstEffectIds = {
|
||||
RefId MagicEffect::getWeaknessEffect(RefId effectId)
|
||||
{
|
||||
static const std::unordered_map<RefId, RefId> effects = makeWeaknessesMap();
|
||||
|
||||
if (const auto it = effects.find(effectId); it != effects.end())
|
||||
return it->second;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Map effect index to GMST name
|
||||
static constexpr std::array<std::string_view, MagicEffect::Length> sGmstEffectIds = {
|
||||
"sEffectWaterBreathing",
|
||||
"sEffectSwiftSwim",
|
||||
"sEffectWaterWalking",
|
||||
|
|
@ -386,203 +581,184 @@ namespace ESM
|
|||
"sEffectSummonCreature05",
|
||||
};
|
||||
|
||||
// Map effect ID to identifying name
|
||||
const std::array<std::string_view, MagicEffect::Length> MagicEffect::sIndexNames = {
|
||||
"WaterBreathing",
|
||||
"SwiftSwim",
|
||||
"WaterWalking",
|
||||
"Shield",
|
||||
"FireShield",
|
||||
"LightningShield",
|
||||
"FrostShield",
|
||||
"Burden",
|
||||
"Feather",
|
||||
"Jump",
|
||||
"Levitate",
|
||||
"SlowFall",
|
||||
"Lock",
|
||||
"Open",
|
||||
"FireDamage",
|
||||
"ShockDamage",
|
||||
"FrostDamage",
|
||||
"DrainAttribute",
|
||||
"DrainHealth",
|
||||
"DrainMagicka",
|
||||
"DrainFatigue",
|
||||
"DrainSkill",
|
||||
"DamageAttribute",
|
||||
"DamageHealth",
|
||||
"DamageMagicka",
|
||||
"DamageFatigue",
|
||||
"DamageSkill",
|
||||
"Poison",
|
||||
"WeaknessToFire",
|
||||
"WeaknessToFrost",
|
||||
"WeaknessToShock",
|
||||
"WeaknessToMagicka",
|
||||
"WeaknessToCommonDisease",
|
||||
"WeaknessToBlightDisease",
|
||||
"WeaknessToCorprusDisease",
|
||||
"WeaknessToPoison",
|
||||
"WeaknessToNormalWeapons",
|
||||
"DisintegrateWeapon",
|
||||
"DisintegrateArmor",
|
||||
"Invisibility",
|
||||
"Chameleon",
|
||||
"Light",
|
||||
"Sanctuary",
|
||||
"NightEye",
|
||||
"Charm",
|
||||
"Paralyze",
|
||||
"Silence",
|
||||
"Blind",
|
||||
"Sound",
|
||||
"CalmHumanoid",
|
||||
"CalmCreature",
|
||||
"FrenzyHumanoid",
|
||||
"FrenzyCreature",
|
||||
"DemoralizeHumanoid",
|
||||
"DemoralizeCreature",
|
||||
"RallyHumanoid",
|
||||
"RallyCreature",
|
||||
"Dispel",
|
||||
"Soultrap",
|
||||
"Telekinesis",
|
||||
"Mark",
|
||||
"Recall",
|
||||
"DivineIntervention",
|
||||
"AlmsiviIntervention",
|
||||
"DetectAnimal",
|
||||
"DetectEnchantment",
|
||||
"DetectKey",
|
||||
"SpellAbsorption",
|
||||
"Reflect",
|
||||
"CureCommonDisease",
|
||||
"CureBlightDisease",
|
||||
"CureCorprusDisease",
|
||||
"CurePoison",
|
||||
"CureParalyzation",
|
||||
"RestoreAttribute",
|
||||
"RestoreHealth",
|
||||
"RestoreMagicka",
|
||||
"RestoreFatigue",
|
||||
"RestoreSkill",
|
||||
"FortifyAttribute",
|
||||
"FortifyHealth",
|
||||
"FortifyMagicka",
|
||||
"FortifyFatigue",
|
||||
"FortifySkill",
|
||||
"FortifyMaximumMagicka",
|
||||
"AbsorbAttribute",
|
||||
"AbsorbHealth",
|
||||
"AbsorbMagicka",
|
||||
"AbsorbFatigue",
|
||||
"AbsorbSkill",
|
||||
"ResistFire",
|
||||
"ResistFrost",
|
||||
"ResistShock",
|
||||
"ResistMagicka",
|
||||
"ResistCommonDisease",
|
||||
"ResistBlightDisease",
|
||||
"ResistCorprusDisease",
|
||||
"ResistPoison",
|
||||
"ResistNormalWeapons",
|
||||
"ResistParalysis",
|
||||
"RemoveCurse",
|
||||
"TurnUndead",
|
||||
"SummonScamp",
|
||||
"SummonClannfear",
|
||||
"SummonDaedroth",
|
||||
"SummonDremora",
|
||||
"SummonAncestralGhost",
|
||||
"SummonSkeletalMinion",
|
||||
"SummonBonewalker",
|
||||
"SummonGreaterBonewalker",
|
||||
"SummonBonelord",
|
||||
"SummonWingedTwilight",
|
||||
"SummonHunger",
|
||||
"SummonGoldenSaint",
|
||||
"SummonFlameAtronach",
|
||||
"SummonFrostAtronach",
|
||||
"SummonStormAtronach",
|
||||
"FortifyAttack",
|
||||
"CommandCreature",
|
||||
"CommandHumanoid",
|
||||
"BoundDagger",
|
||||
"BoundLongsword",
|
||||
"BoundMace",
|
||||
"BoundBattleAxe",
|
||||
"BoundSpear",
|
||||
"BoundLongbow",
|
||||
"ExtraSpell",
|
||||
"BoundCuirass",
|
||||
"BoundHelm",
|
||||
"BoundBoots",
|
||||
"BoundShield",
|
||||
"BoundGloves",
|
||||
"Corprus",
|
||||
"Vampirism",
|
||||
"SummonCenturionSphere",
|
||||
"SunDamage",
|
||||
"StuntedMagicka",
|
||||
static const std::array<RefId, MagicEffect::Length> sMagicEffectIds{
|
||||
MagicEffect::WaterBreathing,
|
||||
MagicEffect::SwiftSwim,
|
||||
MagicEffect::WaterWalking,
|
||||
MagicEffect::Shield,
|
||||
MagicEffect::FireShield,
|
||||
MagicEffect::LightningShield,
|
||||
MagicEffect::FrostShield,
|
||||
MagicEffect::Burden,
|
||||
MagicEffect::Feather,
|
||||
MagicEffect::Jump,
|
||||
MagicEffect::Levitate,
|
||||
MagicEffect::SlowFall,
|
||||
MagicEffect::Lock,
|
||||
MagicEffect::Open,
|
||||
MagicEffect::FireDamage,
|
||||
MagicEffect::ShockDamage,
|
||||
MagicEffect::FrostDamage,
|
||||
MagicEffect::DrainAttribute,
|
||||
MagicEffect::DrainHealth,
|
||||
MagicEffect::DrainMagicka,
|
||||
MagicEffect::DrainFatigue,
|
||||
MagicEffect::DrainSkill,
|
||||
MagicEffect::DamageAttribute,
|
||||
MagicEffect::DamageHealth,
|
||||
MagicEffect::DamageMagicka,
|
||||
MagicEffect::DamageFatigue,
|
||||
MagicEffect::DamageSkill,
|
||||
MagicEffect::Poison,
|
||||
MagicEffect::WeaknessToFire,
|
||||
MagicEffect::WeaknessToFrost,
|
||||
MagicEffect::WeaknessToShock,
|
||||
MagicEffect::WeaknessToMagicka,
|
||||
MagicEffect::WeaknessToCommonDisease,
|
||||
MagicEffect::WeaknessToBlightDisease,
|
||||
MagicEffect::WeaknessToCorprusDisease,
|
||||
MagicEffect::WeaknessToPoison,
|
||||
MagicEffect::WeaknessToNormalWeapons,
|
||||
MagicEffect::DisintegrateWeapon,
|
||||
MagicEffect::DisintegrateArmor,
|
||||
MagicEffect::Invisibility,
|
||||
MagicEffect::Chameleon,
|
||||
MagicEffect::Light,
|
||||
MagicEffect::Sanctuary,
|
||||
MagicEffect::NightEye,
|
||||
MagicEffect::Charm,
|
||||
MagicEffect::Paralyze,
|
||||
MagicEffect::Silence,
|
||||
MagicEffect::Blind,
|
||||
MagicEffect::Sound,
|
||||
MagicEffect::CalmHumanoid,
|
||||
MagicEffect::CalmCreature,
|
||||
MagicEffect::FrenzyHumanoid,
|
||||
MagicEffect::FrenzyCreature,
|
||||
MagicEffect::DemoralizeHumanoid,
|
||||
MagicEffect::DemoralizeCreature,
|
||||
MagicEffect::RallyHumanoid,
|
||||
MagicEffect::RallyCreature,
|
||||
MagicEffect::Dispel,
|
||||
MagicEffect::Soultrap,
|
||||
MagicEffect::Telekinesis,
|
||||
MagicEffect::Mark,
|
||||
MagicEffect::Recall,
|
||||
MagicEffect::DivineIntervention,
|
||||
MagicEffect::AlmsiviIntervention,
|
||||
MagicEffect::DetectAnimal,
|
||||
MagicEffect::DetectEnchantment,
|
||||
MagicEffect::DetectKey,
|
||||
MagicEffect::SpellAbsorption,
|
||||
MagicEffect::Reflect,
|
||||
MagicEffect::CureCommonDisease,
|
||||
MagicEffect::CureBlightDisease,
|
||||
MagicEffect::CureCorprusDisease,
|
||||
MagicEffect::CurePoison,
|
||||
MagicEffect::CureParalyzation,
|
||||
MagicEffect::RestoreAttribute,
|
||||
MagicEffect::RestoreHealth,
|
||||
MagicEffect::RestoreMagicka,
|
||||
MagicEffect::RestoreFatigue,
|
||||
MagicEffect::RestoreSkill,
|
||||
MagicEffect::FortifyAttribute,
|
||||
MagicEffect::FortifyHealth,
|
||||
MagicEffect::FortifyMagicka,
|
||||
MagicEffect::FortifyFatigue,
|
||||
MagicEffect::FortifySkill,
|
||||
MagicEffect::FortifyMaximumMagicka,
|
||||
MagicEffect::AbsorbAttribute,
|
||||
MagicEffect::AbsorbHealth,
|
||||
MagicEffect::AbsorbMagicka,
|
||||
MagicEffect::AbsorbFatigue,
|
||||
MagicEffect::AbsorbSkill,
|
||||
MagicEffect::ResistFire,
|
||||
MagicEffect::ResistFrost,
|
||||
MagicEffect::ResistShock,
|
||||
MagicEffect::ResistMagicka,
|
||||
MagicEffect::ResistCommonDisease,
|
||||
MagicEffect::ResistBlightDisease,
|
||||
MagicEffect::ResistCorprusDisease,
|
||||
MagicEffect::ResistPoison,
|
||||
MagicEffect::ResistNormalWeapons,
|
||||
MagicEffect::ResistParalysis,
|
||||
MagicEffect::RemoveCurse,
|
||||
MagicEffect::TurnUndead,
|
||||
MagicEffect::SummonScamp,
|
||||
MagicEffect::SummonClannfear,
|
||||
MagicEffect::SummonDaedroth,
|
||||
MagicEffect::SummonDremora,
|
||||
MagicEffect::SummonAncestralGhost,
|
||||
MagicEffect::SummonSkeletalMinion,
|
||||
MagicEffect::SummonBonewalker,
|
||||
MagicEffect::SummonGreaterBonewalker,
|
||||
MagicEffect::SummonBonelord,
|
||||
MagicEffect::SummonWingedTwilight,
|
||||
MagicEffect::SummonHunger,
|
||||
MagicEffect::SummonGoldenSaint,
|
||||
MagicEffect::SummonFlameAtronach,
|
||||
MagicEffect::SummonFrostAtronach,
|
||||
MagicEffect::SummonStormAtronach,
|
||||
MagicEffect::FortifyAttack,
|
||||
MagicEffect::CommandCreature,
|
||||
MagicEffect::CommandHumanoid,
|
||||
MagicEffect::BoundDagger,
|
||||
MagicEffect::BoundLongsword,
|
||||
MagicEffect::BoundMace,
|
||||
MagicEffect::BoundBattleAxe,
|
||||
MagicEffect::BoundSpear,
|
||||
MagicEffect::BoundLongbow,
|
||||
MagicEffect::ExtraSpell,
|
||||
MagicEffect::BoundCuirass,
|
||||
MagicEffect::BoundHelm,
|
||||
MagicEffect::BoundBoots,
|
||||
MagicEffect::BoundShield,
|
||||
MagicEffect::BoundGloves,
|
||||
MagicEffect::Corprus,
|
||||
MagicEffect::Vampirism,
|
||||
MagicEffect::SummonCenturionSphere,
|
||||
MagicEffect::SunDamage,
|
||||
MagicEffect::StuntedMagicka,
|
||||
|
||||
// tribunal
|
||||
"SummonFabricant",
|
||||
MagicEffect::SummonFabricant,
|
||||
|
||||
// bloodmoon
|
||||
"SummonWolf",
|
||||
"SummonBear",
|
||||
"SummonBonewolf",
|
||||
"SummonCreature04",
|
||||
"SummonCreature05",
|
||||
MagicEffect::SummonWolf,
|
||||
MagicEffect::SummonBear,
|
||||
MagicEffect::SummonBonewolf,
|
||||
MagicEffect::SummonCreature04,
|
||||
MagicEffect::SummonCreature05,
|
||||
};
|
||||
|
||||
template <typename Collection>
|
||||
static std::map<std::string_view, int, Misc::StringUtils::CiComp> initStringToIntMap(const Collection& strings)
|
||||
template <typename Collection, typename Comparator = std::less<typename Collection::value_type>>
|
||||
static std::map<typename Collection::value_type, int, Comparator> initToIndexMap(
|
||||
const Collection& data, Comparator comp = Comparator())
|
||||
{
|
||||
std::map<std::string_view, int, Misc::StringUtils::CiComp> map;
|
||||
for (size_t i = 0; i < strings.size(); i++)
|
||||
map[strings[i]] = static_cast<int>(i);
|
||||
|
||||
std::map<typename Collection::value_type, int, Comparator> map(comp);
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
map[data[i]] = static_cast<int>(i);
|
||||
return map;
|
||||
}
|
||||
|
||||
const std::map<std::string_view, int, Misc::StringUtils::CiComp> MagicEffect::sGmstEffectIdToIndexMap
|
||||
= initStringToIntMap(MagicEffect::sGmstEffectIds);
|
||||
const std::map<std::string_view, int, Misc::StringUtils::CiComp> sGmstEffectIdToIndexMap
|
||||
= initToIndexMap(sGmstEffectIds, Misc::StringUtils::CiComp());
|
||||
|
||||
const std::map<std::string_view, int, Misc::StringUtils::CiComp> MagicEffect::sIndexNameToIndexMap
|
||||
= initStringToIntMap(MagicEffect::sIndexNames);
|
||||
|
||||
class FindSecond
|
||||
{
|
||||
std::string_view mName;
|
||||
|
||||
public:
|
||||
FindSecond(std::string_view name)
|
||||
: mName(name)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(const std::pair<short, std::string>& item) const
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(item.second, mName))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const std::map<RefId, int> sMagicEffectIdToIndexMap = initToIndexMap(sMagicEffectIds);
|
||||
|
||||
MagicEffect::MagnitudeDisplayType MagicEffect::getMagnitudeDisplayType() const
|
||||
{
|
||||
int index = refIdToIndex(mId);
|
||||
if (mData.mFlags & NoMagnitude)
|
||||
return MDT_None;
|
||||
if (mIndex == 84)
|
||||
if (index == 84)
|
||||
return MDT_TimesInt;
|
||||
if (mIndex == 59 || (mIndex >= 64 && mIndex <= 66))
|
||||
if (index == 59 || (index >= 64 && index <= 66))
|
||||
return MDT_Feet;
|
||||
if (mIndex == 118 || mIndex == 119)
|
||||
if (index == 118 || index == 119)
|
||||
return MDT_Level;
|
||||
if ((mIndex >= 28 && mIndex <= 36) || (mIndex >= 90 && mIndex <= 99) || mIndex == 40 || mIndex == 47
|
||||
|| mIndex == 57 || mIndex == 68)
|
||||
if ((index >= 28 && index <= 36) || (index >= 90 && index <= 99) || index == 40 || index == 47 || index == 57
|
||||
|| index == 68)
|
||||
return MDT_Percentage;
|
||||
|
||||
return MDT_Points;
|
||||
|
|
@ -620,44 +796,41 @@ namespace ESM
|
|||
return color;
|
||||
}
|
||||
|
||||
const std::string& MagicEffect::indexToGmstString(int effectID)
|
||||
std::string_view MagicEffect::refIdToGmstString(RefId effectId)
|
||||
{
|
||||
if (effectID < 0 || static_cast<std::size_t>(effectID) >= sGmstEffectIds.size())
|
||||
throw std::runtime_error(std::string("Unimplemented effect ID ") + std::to_string(effectID));
|
||||
|
||||
return sGmstEffectIds[effectID];
|
||||
int index = refIdToIndex(effectId);
|
||||
if (index < 0 || index >= Length)
|
||||
return {};
|
||||
return sGmstEffectIds[index];
|
||||
}
|
||||
|
||||
std::string_view MagicEffect::indexToName(int effectID)
|
||||
RefId MagicEffect::effectGmstIdToRefId(std::string_view gmstId)
|
||||
{
|
||||
if (effectID < 0 || static_cast<std::size_t>(effectID) >= sIndexNames.size())
|
||||
throw std::runtime_error(std::string("Unimplemented effect ID ") + std::to_string(effectID));
|
||||
|
||||
return sIndexNames[effectID];
|
||||
}
|
||||
|
||||
int MagicEffect::indexNameToIndex(std::string_view effect)
|
||||
{
|
||||
auto name = sIndexNameToIndexMap.find(effect);
|
||||
if (name == sIndexNameToIndexMap.end())
|
||||
return -1;
|
||||
|
||||
return name->second;
|
||||
}
|
||||
|
||||
int MagicEffect::effectGmstIdToIndex(std::string_view gmstId)
|
||||
{
|
||||
auto name = sGmstEffectIdToIndexMap.find(gmstId);
|
||||
if (name == sGmstEffectIdToIndexMap.end())
|
||||
throw std::runtime_error("Unimplemented effect " + std::string(gmstId));
|
||||
|
||||
return name->second;
|
||||
auto it = sGmstEffectIdToIndexMap.find(gmstId);
|
||||
if (it == sGmstEffectIdToIndexMap.end())
|
||||
return {};
|
||||
return sMagicEffectIds[it->second];
|
||||
}
|
||||
|
||||
RefId MagicEffect::indexToRefId(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
return RefId();
|
||||
return RefId::index(sRecordId, static_cast<std::uint32_t>(index));
|
||||
if (index < 0 || index >= Length)
|
||||
return {};
|
||||
return sMagicEffectIds[index];
|
||||
}
|
||||
|
||||
int MagicEffect::refIdToIndex(RefId effectId)
|
||||
{
|
||||
const auto it = sMagicEffectIdToIndexMap.find(effectId);
|
||||
if (it != sMagicEffectIdToIndexMap.end())
|
||||
return it->second;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string_view MagicEffect::indexToName(int index)
|
||||
{
|
||||
if (index < 0 || index >= Length)
|
||||
return {};
|
||||
return sMagicEffectIds[index].getRefIdString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,10 +83,10 @@ namespace ESM
|
|||
float mUnknown2; // Called "Size Cap" in CS
|
||||
}; // 36 bytes
|
||||
|
||||
/// Returns the effect that provides resistance against \a effect (or -1 if there's none)
|
||||
static short getResistanceEffect(short effect);
|
||||
/// Returns the effect that induces weakness against \a effect (or -1 if there's none)
|
||||
static short getWeaknessEffect(short effect);
|
||||
/// Returns the effect that provides resistance against \a effect (or empty RefId if there's none)
|
||||
static RefId getResistanceEffect(RefId effect);
|
||||
/// Returns the effect that induces weakness against \a effect (or empty RefId if there's none)
|
||||
static RefId getWeaknessEffect(RefId effect);
|
||||
|
||||
MagnitudeDisplayType getMagnitudeDisplayType() const;
|
||||
|
||||
|
|
@ -98,17 +98,6 @@ namespace ESM
|
|||
ESM::RefId mCastSound, mBoltSound, mHitSound, mAreaSound; // Sounds
|
||||
std::string mDescription;
|
||||
|
||||
// Index of this magical effect. Corresponds to one of the
|
||||
// hard-coded effects in the original engine:
|
||||
// 0-136 in Morrowind
|
||||
// 137 in Tribunal
|
||||
// 138-140 in Bloodmoon (also changes 64?)
|
||||
// 141-142 are summon effects introduced in bloodmoon, but not used
|
||||
// there. They can be redefined in mods by setting the name in GMST
|
||||
// sEffectSummonCreature04/05 creature id in
|
||||
// sMagicCreature04ID/05ID.
|
||||
int32_t mIndex;
|
||||
|
||||
void load(ESMReader& esm, bool& isDeleted);
|
||||
void save(ESMWriter& esm, bool isDeleted = false) const;
|
||||
|
||||
|
|
@ -117,170 +106,163 @@ namespace ESM
|
|||
|
||||
osg::Vec4f getColor() const;
|
||||
|
||||
enum Effects : short
|
||||
{
|
||||
WaterBreathing = 0,
|
||||
SwiftSwim = 1,
|
||||
WaterWalking = 2,
|
||||
Shield = 3,
|
||||
FireShield = 4,
|
||||
LightningShield = 5,
|
||||
FrostShield = 6,
|
||||
Burden = 7,
|
||||
Feather = 8,
|
||||
Jump = 9,
|
||||
Levitate = 10,
|
||||
SlowFall = 11,
|
||||
Lock = 12,
|
||||
Open = 13,
|
||||
FireDamage = 14,
|
||||
ShockDamage = 15,
|
||||
FrostDamage = 16,
|
||||
DrainAttribute = 17,
|
||||
DrainHealth = 18,
|
||||
DrainMagicka = 19,
|
||||
DrainFatigue = 20,
|
||||
DrainSkill = 21,
|
||||
DamageAttribute = 22,
|
||||
DamageHealth = 23,
|
||||
DamageMagicka = 24,
|
||||
DamageFatigue = 25,
|
||||
DamageSkill = 26,
|
||||
Poison = 27,
|
||||
WeaknessToFire = 28,
|
||||
WeaknessToFrost = 29,
|
||||
WeaknessToShock = 30,
|
||||
WeaknessToMagicka = 31,
|
||||
WeaknessToCommonDisease = 32,
|
||||
WeaknessToBlightDisease = 33,
|
||||
WeaknessToCorprusDisease = 34,
|
||||
WeaknessToPoison = 35,
|
||||
WeaknessToNormalWeapons = 36,
|
||||
DisintegrateWeapon = 37,
|
||||
DisintegrateArmor = 38,
|
||||
Invisibility = 39,
|
||||
Chameleon = 40,
|
||||
Light = 41,
|
||||
Sanctuary = 42,
|
||||
NightEye = 43,
|
||||
Charm = 44,
|
||||
Paralyze = 45,
|
||||
Silence = 46,
|
||||
Blind = 47,
|
||||
Sound = 48,
|
||||
CalmHumanoid = 49,
|
||||
CalmCreature = 50,
|
||||
FrenzyHumanoid = 51,
|
||||
FrenzyCreature = 52,
|
||||
DemoralizeHumanoid = 53,
|
||||
DemoralizeCreature = 54,
|
||||
RallyHumanoid = 55,
|
||||
RallyCreature = 56,
|
||||
Dispel = 57,
|
||||
Soultrap = 58,
|
||||
Telekinesis = 59,
|
||||
Mark = 60,
|
||||
Recall = 61,
|
||||
DivineIntervention = 62,
|
||||
AlmsiviIntervention = 63,
|
||||
DetectAnimal = 64,
|
||||
DetectEnchantment = 65,
|
||||
DetectKey = 66,
|
||||
SpellAbsorption = 67,
|
||||
Reflect = 68,
|
||||
CureCommonDisease = 69,
|
||||
CureBlightDisease = 70,
|
||||
CureCorprusDisease = 71,
|
||||
CurePoison = 72,
|
||||
CureParalyzation = 73,
|
||||
RestoreAttribute = 74,
|
||||
RestoreHealth = 75,
|
||||
RestoreMagicka = 76,
|
||||
RestoreFatigue = 77,
|
||||
RestoreSkill = 78,
|
||||
FortifyAttribute = 79,
|
||||
FortifyHealth = 80,
|
||||
FortifyMagicka = 81,
|
||||
FortifyFatigue = 82,
|
||||
FortifySkill = 83,
|
||||
FortifyMaximumMagicka = 84,
|
||||
AbsorbAttribute = 85,
|
||||
AbsorbHealth = 86,
|
||||
AbsorbMagicka = 87,
|
||||
AbsorbFatigue = 88,
|
||||
AbsorbSkill = 89,
|
||||
ResistFire = 90,
|
||||
ResistFrost = 91,
|
||||
ResistShock = 92,
|
||||
ResistMagicka = 93,
|
||||
ResistCommonDisease = 94,
|
||||
ResistBlightDisease = 95,
|
||||
ResistCorprusDisease = 96,
|
||||
ResistPoison = 97,
|
||||
ResistNormalWeapons = 98,
|
||||
ResistParalysis = 99,
|
||||
RemoveCurse = 100,
|
||||
TurnUndead = 101,
|
||||
SummonScamp = 102,
|
||||
SummonClannfear = 103,
|
||||
SummonDaedroth = 104,
|
||||
SummonDremora = 105,
|
||||
SummonAncestralGhost = 106,
|
||||
SummonSkeletalMinion = 107,
|
||||
SummonBonewalker = 108,
|
||||
SummonGreaterBonewalker = 109,
|
||||
SummonBonelord = 110,
|
||||
SummonWingedTwilight = 111,
|
||||
SummonHunger = 112,
|
||||
SummonGoldenSaint = 113,
|
||||
SummonFlameAtronach = 114,
|
||||
SummonFrostAtronach = 115,
|
||||
SummonStormAtronach = 116,
|
||||
FortifyAttack = 117,
|
||||
CommandCreature = 118,
|
||||
CommandHumanoid = 119,
|
||||
BoundDagger = 120,
|
||||
BoundLongsword = 121,
|
||||
BoundMace = 122,
|
||||
BoundBattleAxe = 123,
|
||||
BoundSpear = 124,
|
||||
BoundLongbow = 125,
|
||||
ExtraSpell = 126,
|
||||
BoundCuirass = 127,
|
||||
BoundHelm = 128,
|
||||
BoundBoots = 129,
|
||||
BoundShield = 130,
|
||||
BoundGloves = 131,
|
||||
Corprus = 132,
|
||||
Vampirism = 133,
|
||||
SummonCenturionSphere = 134,
|
||||
SunDamage = 135,
|
||||
StuntedMagicka = 136,
|
||||
static const StringRefId WaterBreathing;
|
||||
static const StringRefId SwiftSwim;
|
||||
static const StringRefId WaterWalking;
|
||||
static const StringRefId Shield;
|
||||
static const StringRefId FireShield;
|
||||
static const StringRefId LightningShield;
|
||||
static const StringRefId FrostShield;
|
||||
static const StringRefId Burden;
|
||||
static const StringRefId Feather;
|
||||
static const StringRefId Jump;
|
||||
static const StringRefId Levitate;
|
||||
static const StringRefId SlowFall;
|
||||
static const StringRefId Lock;
|
||||
static const StringRefId Open;
|
||||
static const StringRefId FireDamage;
|
||||
static const StringRefId ShockDamage;
|
||||
static const StringRefId FrostDamage;
|
||||
static const StringRefId DrainAttribute;
|
||||
static const StringRefId DrainHealth;
|
||||
static const StringRefId DrainMagicka;
|
||||
static const StringRefId DrainFatigue;
|
||||
static const StringRefId DrainSkill;
|
||||
static const StringRefId DamageAttribute;
|
||||
static const StringRefId DamageHealth;
|
||||
static const StringRefId DamageMagicka;
|
||||
static const StringRefId DamageFatigue;
|
||||
static const StringRefId DamageSkill;
|
||||
static const StringRefId Poison;
|
||||
static const StringRefId WeaknessToFire;
|
||||
static const StringRefId WeaknessToFrost;
|
||||
static const StringRefId WeaknessToShock;
|
||||
static const StringRefId WeaknessToMagicka;
|
||||
static const StringRefId WeaknessToCommonDisease;
|
||||
static const StringRefId WeaknessToBlightDisease;
|
||||
static const StringRefId WeaknessToCorprusDisease;
|
||||
static const StringRefId WeaknessToPoison;
|
||||
static const StringRefId WeaknessToNormalWeapons;
|
||||
static const StringRefId DisintegrateWeapon;
|
||||
static const StringRefId DisintegrateArmor;
|
||||
static const StringRefId Invisibility;
|
||||
static const StringRefId Chameleon;
|
||||
static const StringRefId Light;
|
||||
static const StringRefId Sanctuary;
|
||||
static const StringRefId NightEye;
|
||||
static const StringRefId Charm;
|
||||
static const StringRefId Paralyze;
|
||||
static const StringRefId Silence;
|
||||
static const StringRefId Blind;
|
||||
static const StringRefId Sound;
|
||||
static const StringRefId CalmHumanoid;
|
||||
static const StringRefId CalmCreature;
|
||||
static const StringRefId FrenzyHumanoid;
|
||||
static const StringRefId FrenzyCreature;
|
||||
static const StringRefId DemoralizeHumanoid;
|
||||
static const StringRefId DemoralizeCreature;
|
||||
static const StringRefId RallyHumanoid;
|
||||
static const StringRefId RallyCreature;
|
||||
static const StringRefId Dispel;
|
||||
static const StringRefId Soultrap;
|
||||
static const StringRefId Telekinesis;
|
||||
static const StringRefId Mark;
|
||||
static const StringRefId Recall;
|
||||
static const StringRefId DivineIntervention;
|
||||
static const StringRefId AlmsiviIntervention;
|
||||
static const StringRefId DetectAnimal;
|
||||
static const StringRefId DetectEnchantment;
|
||||
static const StringRefId DetectKey;
|
||||
static const StringRefId SpellAbsorption;
|
||||
static const StringRefId Reflect;
|
||||
static const StringRefId CureCommonDisease;
|
||||
static const StringRefId CureBlightDisease;
|
||||
static const StringRefId CureCorprusDisease;
|
||||
static const StringRefId CurePoison;
|
||||
static const StringRefId CureParalyzation;
|
||||
static const StringRefId RestoreAttribute;
|
||||
static const StringRefId RestoreHealth;
|
||||
static const StringRefId RestoreMagicka;
|
||||
static const StringRefId RestoreFatigue;
|
||||
static const StringRefId RestoreSkill;
|
||||
static const StringRefId FortifyAttribute;
|
||||
static const StringRefId FortifyHealth;
|
||||
static const StringRefId FortifyMagicka;
|
||||
static const StringRefId FortifyFatigue;
|
||||
static const StringRefId FortifySkill;
|
||||
static const StringRefId FortifyMaximumMagicka;
|
||||
static const StringRefId AbsorbAttribute;
|
||||
static const StringRefId AbsorbHealth;
|
||||
static const StringRefId AbsorbMagicka;
|
||||
static const StringRefId AbsorbFatigue;
|
||||
static const StringRefId AbsorbSkill;
|
||||
static const StringRefId ResistFire;
|
||||
static const StringRefId ResistFrost;
|
||||
static const StringRefId ResistShock;
|
||||
static const StringRefId ResistMagicka;
|
||||
static const StringRefId ResistCommonDisease;
|
||||
static const StringRefId ResistBlightDisease;
|
||||
static const StringRefId ResistCorprusDisease;
|
||||
static const StringRefId ResistPoison;
|
||||
static const StringRefId ResistNormalWeapons;
|
||||
static const StringRefId ResistParalysis;
|
||||
static const StringRefId RemoveCurse;
|
||||
static const StringRefId TurnUndead;
|
||||
static const StringRefId SummonScamp;
|
||||
static const StringRefId SummonClannfear;
|
||||
static const StringRefId SummonDaedroth;
|
||||
static const StringRefId SummonDremora;
|
||||
static const StringRefId SummonAncestralGhost;
|
||||
static const StringRefId SummonSkeletalMinion;
|
||||
static const StringRefId SummonBonewalker;
|
||||
static const StringRefId SummonGreaterBonewalker;
|
||||
static const StringRefId SummonBonelord;
|
||||
static const StringRefId SummonWingedTwilight;
|
||||
static const StringRefId SummonHunger;
|
||||
static const StringRefId SummonGoldenSaint;
|
||||
static const StringRefId SummonFlameAtronach;
|
||||
static const StringRefId SummonFrostAtronach;
|
||||
static const StringRefId SummonStormAtronach;
|
||||
static const StringRefId FortifyAttack;
|
||||
static const StringRefId CommandCreature;
|
||||
static const StringRefId CommandHumanoid;
|
||||
static const StringRefId BoundDagger;
|
||||
static const StringRefId BoundLongsword;
|
||||
static const StringRefId BoundMace;
|
||||
static const StringRefId BoundBattleAxe;
|
||||
static const StringRefId BoundSpear;
|
||||
static const StringRefId BoundLongbow;
|
||||
static const StringRefId ExtraSpell;
|
||||
static const StringRefId BoundCuirass;
|
||||
static const StringRefId BoundHelm;
|
||||
static const StringRefId BoundBoots;
|
||||
static const StringRefId BoundShield;
|
||||
static const StringRefId BoundGloves;
|
||||
static const StringRefId Corprus;
|
||||
static const StringRefId Vampirism;
|
||||
static const StringRefId SummonCenturionSphere;
|
||||
static const StringRefId SunDamage;
|
||||
static const StringRefId StuntedMagicka;
|
||||
|
||||
// Tribunal only
|
||||
SummonFabricant = 137,
|
||||
// Tribunal only
|
||||
static const StringRefId SummonFabricant;
|
||||
|
||||
// Bloodmoon only
|
||||
SummonWolf = 138,
|
||||
SummonBear = 139,
|
||||
SummonBonewolf = 140,
|
||||
SummonCreature04 = 141,
|
||||
SummonCreature05 = 142,
|
||||
// Bloodmoon only
|
||||
static const StringRefId SummonWolf;
|
||||
static const StringRefId SummonBear;
|
||||
static const StringRefId SummonBonewolf;
|
||||
static const StringRefId SummonCreature04;
|
||||
static const StringRefId SummonCreature05;
|
||||
|
||||
Length
|
||||
};
|
||||
static constexpr int Length = 143;
|
||||
|
||||
static const std::array<std::string, Length> sGmstEffectIds;
|
||||
static const std::array<std::string_view, Length> sIndexNames;
|
||||
static const std::map<std::string_view, int, Misc::StringUtils::CiComp> sGmstEffectIdToIndexMap;
|
||||
static const std::map<std::string_view, int, Misc::StringUtils::CiComp> sIndexNameToIndexMap;
|
||||
|
||||
static const std::string& indexToGmstString(int effectID);
|
||||
static std::string_view indexToName(int effectID);
|
||||
static int indexNameToIndex(std::string_view effect);
|
||||
static int effectGmstIdToIndex(std::string_view gmstId);
|
||||
static std::string_view refIdToGmstString(RefId effectId);
|
||||
static RefId effectGmstIdToRefId(std::string_view gmstId);
|
||||
|
||||
static RefId indexToRefId(int index);
|
||||
static int refIdToIndex(RefId effectId);
|
||||
|
||||
static std::string_view indexToName(int index);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
|
|
@ -10,7 +12,7 @@ namespace ESM
|
|||
{
|
||||
for (const auto& [key, params] : mEffects)
|
||||
{
|
||||
esm.writeHNT("EFID", key);
|
||||
esm.writeHNT("EFID", ESM::MagicEffect::refIdToIndex(key));
|
||||
esm.writeHNT("BASE", params.first);
|
||||
esm.writeHNT("MODI", params.second);
|
||||
}
|
||||
|
|
@ -28,7 +30,7 @@ namespace ESM
|
|||
params.second = 0.f;
|
||||
else
|
||||
esm.getHNT(params.second, "MODI");
|
||||
mEffects.emplace(id, params);
|
||||
mEffects.emplace(ESM::MagicEffect::indexToRefId(id), params);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace ESM
|
|||
struct MagicEffects
|
||||
{
|
||||
// <Effect Id, Base value, Modifier>
|
||||
std::map<int32_t, std::pair<int32_t, float>> mEffects;
|
||||
std::map<ESM::RefId, std::pair<int32_t, float>> mEffects;
|
||||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
|
|
@ -24,14 +24,14 @@ namespace ESM
|
|||
|
||||
struct SummonKey
|
||||
{
|
||||
SummonKey(int32_t effectId, const ESM::RefId& sourceId, int32_t index)
|
||||
SummonKey(ESM::RefId effectId, const ESM::RefId& sourceId, int32_t index)
|
||||
: mEffectId(effectId)
|
||||
, mSourceId(sourceId)
|
||||
, mEffectIndex(index)
|
||||
{
|
||||
}
|
||||
|
||||
int32_t mEffectId;
|
||||
ESM::RefId mEffectId;
|
||||
ESM::RefId mSourceId;
|
||||
int32_t mEffectIndex;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue