mirror of
https://github.com/OpenMW/openmw.git
synced 2026-01-20 16:30:54 +00:00
- Changed reverse lookup map constructor for gmsts, names, and ESM::MagicEffectIds to be more generic. - Changed refIdToIndex to use map instead of array traversal. - Removed redundant check from refIdToGmstString. - Removed sMagicEffectNames and associated map. Removed dead code from loadmgef.cpp/hpp. - Changed return types of magic effect bindings to RefId. - Reverted ESMStore search to find. - Changed std::map to std::unordered_map for faster lookups in resistance and weakness functions. - Changed loadmgef To methods to pass RefId by value. - Removed StringRefId alias MagicEffectId. - Changed all effectId arguments in PR to pass-by-value. - Removed ESM::MagicEffect::refIdToName function. - Changed effect key type from long to ESM::RefId in OpGetEffect of mwscript. - Removed superfluous MWWorld::Store<ESM::GameSettings> argument to MagicEffect store's setUp method. - Removed transformation code from decompose for ENAM and IRDT structs. - Changed resistance and weakness maps to initialization to use initialization instead of assignment. - Changed sGmstEffectIds to constexpr array since all parameters are known at compile time. - Changed getBoundItemsMap to use an unordered_map and have string_view values. - MagicEffect store definition removed (uses standard template class TypedDynamicStore). - Fixed bug in calculating sun damage that would have made vampires daywalkers in Mournhold. - Removed polymorphic EffectKey constructor and added overload to getOrDefault. - Placed ESM spec IRDT and ENAM structs in anonymous namespace. - Added exception if attempting to serialize ENAM subrecords with out of bounds index. - Added include format statements to satisfy Ubuntu CI linker.
836 lines
36 KiB
C++
836 lines
36 KiB
C++
#include "loadmgef.hpp"
|
|
|
|
#include "esmreader.hpp"
|
|
#include "esmwriter.hpp"
|
|
#include "loadskil.hpp"
|
|
|
|
#include <components/misc/strings/algorithm.hpp>
|
|
|
|
namespace ESM
|
|
{
|
|
namespace
|
|
{
|
|
const int NumberOfHardcodedFlags = 143;
|
|
const int HardcodedFlags[NumberOfHardcodedFlags] = { 0x11c8, 0x11c0, 0x11c8, 0x11e0, 0x11e0, 0x11e0, 0x11e0,
|
|
0x11d0, 0x11c0, 0x11c0, 0x11e0, 0x11c0, 0x11184, 0x11184, 0x1f0, 0x1f0, 0x1f0, 0x11d2, 0x11f0, 0x11d0,
|
|
0x11d0, 0x11d1, 0x1d2, 0x1f0, 0x1d0, 0x1d0, 0x1d1, 0x1f0, 0x11d0, 0x11d0, 0x11d0, 0x11d0, 0x11d0, 0x11d0,
|
|
0x11d0, 0x11d0, 0x11d0, 0x1d0, 0x1d0, 0x11c8, 0x31c0, 0x11c0, 0x11c0, 0x11c0, 0x1180, 0x11d8, 0x11d8,
|
|
0x11d0, 0x11d0, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, 0x11c4, 0x111b8,
|
|
0x1040, 0x104c, 0x104c, 0x104c, 0x104c, 0x1040, 0x1040, 0x1040, 0x11c0, 0x11c0, 0x1cc, 0x1cc, 0x1cc, 0x1cc,
|
|
0x1cc, 0x1c2, 0x1c0, 0x1c0, 0x1c0, 0x1c1, 0x11c2, 0x11c0, 0x11c0, 0x11c0, 0x11c1, 0x11c0, 0x21192, 0x20190,
|
|
0x20190, 0x20190, 0x21191, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0,
|
|
0x1c0, 0x11190, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048,
|
|
0x9048, 0x9048, 0x9048, 0x9048, 0x11c0, 0x1180, 0x1180, 0x5048, 0x5048, 0x5048, 0x5048, 0x5048, 0x5048,
|
|
0x1188, 0x5048, 0x5048, 0x5048, 0x5048, 0x5048, 0x1048, 0x104c, 0x1048, 0x40, 0x11c8, 0x1048, 0x1048,
|
|
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();
|
|
|
|
int32_t index = -1;
|
|
esm.getHNT(index, "INDX");
|
|
if (index < 0 || index >= Length)
|
|
esm.fail("Invalid Index!");
|
|
|
|
mId = indexToRefId(index);
|
|
|
|
esm.getSubNameIs("MEDT");
|
|
esm.getSubHeader();
|
|
int32_t school;
|
|
esm.getT(school);
|
|
mData.mSchool = MagicSchool::indexToSkillRefId(school);
|
|
esm.getT(mData.mBaseCost);
|
|
esm.getT(mData.mFlags);
|
|
esm.getT(mData.mRed);
|
|
esm.getT(mData.mGreen);
|
|
esm.getT(mData.mBlue);
|
|
esm.getT(mData.mUnknown1);
|
|
esm.getT(mData.mSpeed);
|
|
esm.getT(mData.mUnknown2);
|
|
|
|
if (esm.getFormatVersion() == DefaultFormatVersion)
|
|
{
|
|
// don't allow mods to change fixed flags in the legacy format
|
|
mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight);
|
|
if (index >= 0 && index < NumberOfHardcodedFlags)
|
|
mData.mFlags |= HardcodedFlags[index];
|
|
}
|
|
|
|
// vanilla MW accepts the _SND subrecords before or after DESC... I hope
|
|
// this isn't true for other records, or we have to do a mass-refactor
|
|
while (esm.hasMoreSubs())
|
|
{
|
|
esm.getSubName();
|
|
switch (esm.retSubName().toInt())
|
|
{
|
|
case fourCC("ITEX"):
|
|
mIcon = esm.getHString();
|
|
break;
|
|
case fourCC("PTEX"):
|
|
mParticle = esm.getHString();
|
|
break;
|
|
case fourCC("BSND"):
|
|
mBoltSound = esm.getRefId();
|
|
break;
|
|
case fourCC("CSND"):
|
|
mCastSound = esm.getRefId();
|
|
break;
|
|
case fourCC("HSND"):
|
|
mHitSound = esm.getRefId();
|
|
break;
|
|
case fourCC("ASND"):
|
|
mAreaSound = esm.getRefId();
|
|
break;
|
|
case fourCC("CVFX"):
|
|
mCasting = esm.getRefId();
|
|
break;
|
|
case fourCC("BVFX"):
|
|
mBolt = esm.getRefId();
|
|
break;
|
|
case fourCC("HVFX"):
|
|
mHit = esm.getRefId();
|
|
break;
|
|
case fourCC("AVFX"):
|
|
mArea = esm.getRefId();
|
|
break;
|
|
case fourCC("DESC"):
|
|
mDescription = esm.getHString();
|
|
break;
|
|
default:
|
|
esm.fail("Unknown subrecord");
|
|
}
|
|
}
|
|
}
|
|
void MagicEffect::save(ESMWriter& esm, bool /*isDeleted*/) const
|
|
{
|
|
esm.writeHNT("INDX", refIdToIndex(mId));
|
|
|
|
esm.startSubRecord("MEDT");
|
|
esm.writeT(MagicSchool::skillRefIdToIndex(mData.mSchool));
|
|
esm.writeT(mData.mBaseCost);
|
|
esm.writeT(mData.mFlags);
|
|
esm.writeT(mData.mRed);
|
|
esm.writeT(mData.mGreen);
|
|
esm.writeT(mData.mBlue);
|
|
esm.writeT(mData.mUnknown1);
|
|
esm.writeT(mData.mSpeed);
|
|
esm.writeT(mData.mUnknown2);
|
|
esm.endRecord("MEDT");
|
|
|
|
esm.writeHNOCString("ITEX", mIcon);
|
|
esm.writeHNOCString("PTEX", mParticle);
|
|
esm.writeHNOCRefId("BSND", mBoltSound);
|
|
esm.writeHNOCRefId("CSND", mCastSound);
|
|
esm.writeHNOCRefId("HSND", mHitSound);
|
|
esm.writeHNOCRefId("ASND", mAreaSound);
|
|
|
|
esm.writeHNOCRefId("CVFX", mCasting);
|
|
esm.writeHNOCRefId("BVFX", mBolt);
|
|
esm.writeHNOCRefId("HVFX", mHit);
|
|
esm.writeHNOCRefId("AVFX", mArea);
|
|
|
|
esm.writeHNOString("DESC", mDescription);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
std::unordered_map<RefId, RefId> makeResistancesMap()
|
|
{
|
|
std::unordered_map<RefId, RefId> effects{
|
|
{ MagicEffect::DisintegrateArmor, MagicEffect::Sanctuary },
|
|
{ MagicEffect::DisintegrateWeapon, MagicEffect::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 },
|
|
|
|
{ MagicEffect::AbsorbAttribute, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::AbsorbHealth, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::AbsorbMagicka, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::AbsorbFatigue, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::AbsorbSkill, MagicEffect::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 },
|
|
|
|
{ MagicEffect::Burden, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::Charm, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::Silence, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::Blind, MagicEffect::ResistMagicka },
|
|
{ MagicEffect::Sound, MagicEffect::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 },
|
|
|
|
{ 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;
|
|
}
|
|
}
|
|
|
|
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::unordered_map<RefId, RefId> effects = makeResistancesMap();
|
|
|
|
if (const auto it = effects.find(effectId); it != effects.end())
|
|
return it->second;
|
|
|
|
return {};
|
|
}
|
|
|
|
namespace
|
|
{
|
|
std::unordered_map<RefId, RefId> makeWeaknessesMap()
|
|
{
|
|
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 },
|
|
|
|
{ MagicEffect::AbsorbAttribute, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::AbsorbHealth, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::AbsorbMagicka, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::AbsorbFatigue, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::AbsorbSkill, MagicEffect::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 },
|
|
|
|
{ MagicEffect::Burden, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::Charm, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::Silence, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::Blind, MagicEffect::WeaknessToMagicka },
|
|
{ MagicEffect::Sound, MagicEffect::WeaknessToMagicka },
|
|
|
|
{ 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 },
|
|
|
|
{ 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;
|
|
}
|
|
}
|
|
|
|
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",
|
|
"sEffectShield",
|
|
"sEffectFireShield",
|
|
"sEffectLightningShield",
|
|
"sEffectFrostShield",
|
|
"sEffectBurden",
|
|
"sEffectFeather",
|
|
"sEffectJump",
|
|
"sEffectLevitate",
|
|
"sEffectSlowFall",
|
|
"sEffectLock",
|
|
"sEffectOpen",
|
|
"sEffectFireDamage",
|
|
"sEffectShockDamage",
|
|
"sEffectFrostDamage",
|
|
"sEffectDrainAttribute",
|
|
"sEffectDrainHealth",
|
|
"sEffectDrainSpellpoints",
|
|
"sEffectDrainFatigue",
|
|
"sEffectDrainSkill",
|
|
"sEffectDamageAttribute",
|
|
"sEffectDamageHealth",
|
|
"sEffectDamageMagicka",
|
|
"sEffectDamageFatigue",
|
|
"sEffectDamageSkill",
|
|
"sEffectPoison",
|
|
"sEffectWeaknesstoFire",
|
|
"sEffectWeaknesstoFrost",
|
|
"sEffectWeaknesstoShock",
|
|
"sEffectWeaknesstoMagicka",
|
|
"sEffectWeaknesstoCommonDisease",
|
|
"sEffectWeaknesstoBlightDisease",
|
|
"sEffectWeaknesstoCorprusDisease",
|
|
"sEffectWeaknesstoPoison",
|
|
"sEffectWeaknesstoNormalWeapons",
|
|
"sEffectDisintegrateWeapon",
|
|
"sEffectDisintegrateArmor",
|
|
"sEffectInvisibility",
|
|
"sEffectChameleon",
|
|
"sEffectLight",
|
|
"sEffectSanctuary",
|
|
"sEffectNightEye",
|
|
"sEffectCharm",
|
|
"sEffectParalyze",
|
|
"sEffectSilence",
|
|
"sEffectBlind",
|
|
"sEffectSound",
|
|
"sEffectCalmHumanoid",
|
|
"sEffectCalmCreature",
|
|
"sEffectFrenzyHumanoid",
|
|
"sEffectFrenzyCreature",
|
|
"sEffectDemoralizeHumanoid",
|
|
"sEffectDemoralizeCreature",
|
|
"sEffectRallyHumanoid",
|
|
"sEffectRallyCreature",
|
|
"sEffectDispel",
|
|
"sEffectSoultrap",
|
|
"sEffectTelekinesis",
|
|
"sEffectMark",
|
|
"sEffectRecall",
|
|
"sEffectDivineIntervention",
|
|
"sEffectAlmsiviIntervention",
|
|
"sEffectDetectAnimal",
|
|
"sEffectDetectEnchantment",
|
|
"sEffectDetectKey",
|
|
"sEffectSpellAbsorption",
|
|
"sEffectReflect",
|
|
"sEffectCureCommonDisease",
|
|
"sEffectCureBlightDisease",
|
|
"sEffectCureCorprusDisease",
|
|
"sEffectCurePoison",
|
|
"sEffectCureParalyzation",
|
|
"sEffectRestoreAttribute",
|
|
"sEffectRestoreHealth",
|
|
"sEffectRestoreSpellPoints",
|
|
"sEffectRestoreFatigue",
|
|
"sEffectRestoreSkill",
|
|
"sEffectFortifyAttribute",
|
|
"sEffectFortifyHealth",
|
|
"sEffectFortifySpellpoints",
|
|
"sEffectFortifyFatigue",
|
|
"sEffectFortifySkill",
|
|
"sEffectFortifyMagickaMultiplier",
|
|
"sEffectAbsorbAttribute",
|
|
"sEffectAbsorbHealth",
|
|
"sEffectAbsorbSpellPoints",
|
|
"sEffectAbsorbFatigue",
|
|
"sEffectAbsorbSkill",
|
|
"sEffectResistFire",
|
|
"sEffectResistFrost",
|
|
"sEffectResistShock",
|
|
"sEffectResistMagicka",
|
|
"sEffectResistCommonDisease",
|
|
"sEffectResistBlightDisease",
|
|
"sEffectResistCorprusDisease",
|
|
"sEffectResistPoison",
|
|
"sEffectResistNormalWeapons",
|
|
"sEffectResistParalysis",
|
|
"sEffectRemoveCurse",
|
|
"sEffectTurnUndead",
|
|
"sEffectSummonScamp",
|
|
"sEffectSummonClannfear",
|
|
"sEffectSummonDaedroth",
|
|
"sEffectSummonDremora",
|
|
"sEffectSummonAncestralGhost",
|
|
"sEffectSummonSkeletalMinion",
|
|
"sEffectSummonLeastBonewalker",
|
|
"sEffectSummonGreaterBonewalker",
|
|
"sEffectSummonBonelord",
|
|
"sEffectSummonWingedTwilight",
|
|
"sEffectSummonHunger",
|
|
"sEffectSummonGoldenSaint",
|
|
"sEffectSummonFlameAtronach",
|
|
"sEffectSummonFrostAtronach",
|
|
"sEffectSummonStormAtronach",
|
|
"sEffectFortifyAttackBonus",
|
|
"sEffectCommandCreatures",
|
|
"sEffectCommandHumanoids",
|
|
"sEffectBoundDagger",
|
|
"sEffectBoundLongsword",
|
|
"sEffectBoundMace",
|
|
"sEffectBoundBattleAxe",
|
|
"sEffectBoundSpear",
|
|
"sEffectBoundLongbow",
|
|
"sEffectExtraSpell",
|
|
"sEffectBoundCuirass",
|
|
"sEffectBoundHelm",
|
|
"sEffectBoundBoots",
|
|
"sEffectBoundShield",
|
|
"sEffectBoundGloves",
|
|
"sEffectCorpus", // NB this typo. (bethesda made it)
|
|
"sEffectVampirism",
|
|
"sEffectSummonCenturionSphere",
|
|
"sEffectSunDamage",
|
|
"sEffectStuntedMagicka",
|
|
|
|
// tribunal
|
|
"sEffectSummonFabricant",
|
|
|
|
// bloodmoon
|
|
"sEffectSummonCreature01",
|
|
"sEffectSummonCreature02",
|
|
"sEffectSummonCreature03",
|
|
"sEffectSummonCreature04",
|
|
"sEffectSummonCreature05",
|
|
};
|
|
|
|
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
|
|
MagicEffect::SummonFabricant,
|
|
|
|
// bloodmoon
|
|
MagicEffect::SummonWolf,
|
|
MagicEffect::SummonBear,
|
|
MagicEffect::SummonBonewolf,
|
|
MagicEffect::SummonCreature04,
|
|
MagicEffect::SummonCreature05,
|
|
};
|
|
|
|
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<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> sGmstEffectIdToIndexMap
|
|
= initToIndexMap(sGmstEffectIds, Misc::StringUtils::CiComp());
|
|
|
|
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 (index == 84)
|
|
return MDT_TimesInt;
|
|
if (index == 59 || (index >= 64 && index <= 66))
|
|
return MDT_Feet;
|
|
if (index == 118 || index == 119)
|
|
return MDT_Level;
|
|
if ((index >= 28 && index <= 36) || (index >= 90 && index <= 99) || index == 40 || index == 47 || index == 57
|
|
|| index == 68)
|
|
return MDT_Percentage;
|
|
|
|
return MDT_Points;
|
|
}
|
|
|
|
void MagicEffect::blank()
|
|
{
|
|
mRecordFlags = 0;
|
|
mData.mSchool = ESM::Skill::Alteration;
|
|
mData.mBaseCost = 0;
|
|
mData.mFlags = 0;
|
|
mData.mRed = 0;
|
|
mData.mGreen = 0;
|
|
mData.mBlue = 0;
|
|
mData.mSpeed = 1;
|
|
|
|
mIcon.clear();
|
|
mParticle.clear();
|
|
mCasting = ESM::RefId();
|
|
mHit = ESM::RefId();
|
|
mArea = ESM::RefId();
|
|
mBolt = ESM::RefId();
|
|
mCastSound = ESM::RefId();
|
|
mBoltSound = ESM::RefId();
|
|
mHitSound = ESM::RefId();
|
|
mAreaSound = ESM::RefId();
|
|
mDescription.clear();
|
|
}
|
|
|
|
osg::Vec4f MagicEffect::getColor() const
|
|
{
|
|
osg::Vec4f color{ mData.mRed / 255.f, mData.mGreen / 255.f, mData.mBlue / 255.f, 1.f };
|
|
if (mData.mFlags & NegativeLight)
|
|
return osg::Vec4f(1.f, 1.f, 1.f, 2.f) - color;
|
|
return color;
|
|
}
|
|
|
|
std::string_view MagicEffect::refIdToGmstString(RefId effectId)
|
|
{
|
|
int index = refIdToIndex(effectId);
|
|
if (index < 0 || index >= Length)
|
|
return {};
|
|
return sGmstEffectIds[index];
|
|
}
|
|
|
|
RefId MagicEffect::effectGmstIdToRefId(std::string_view gmstId)
|
|
{
|
|
auto it = sGmstEffectIdToIndexMap.find(gmstId);
|
|
if (it == sGmstEffectIdToIndexMap.end())
|
|
return {};
|
|
return sMagicEffectIds[it->second];
|
|
}
|
|
|
|
RefId MagicEffect::indexToRefId(int 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();
|
|
}
|
|
}
|