Merge pull request #2808 from Capostrophic/spellcleanup

Clean up spellcasting
pull/2810/head
Roman Siromakha 5 years ago committed by GitHub
commit 4f75211e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -32,41 +32,23 @@ namespace MWMechanics
{
ESM::Skill::SkillEnum spellSchoolToSkill(int school)
{
static std::map<int, ESM::Skill::SkillEnum> schoolSkillMap; // maps spell school to skill id
if (schoolSkillMap.empty())
static const std::array<ESM::Skill::SkillEnum, 6> schoolSkillArray
{
schoolSkillMap[0] = ESM::Skill::Alteration;
schoolSkillMap[1] = ESM::Skill::Conjuration;
schoolSkillMap[3] = ESM::Skill::Illusion;
schoolSkillMap[2] = ESM::Skill::Destruction;
schoolSkillMap[4] = ESM::Skill::Mysticism;
schoolSkillMap[5] = ESM::Skill::Restoration;
}
assert(schoolSkillMap.find(school) != schoolSkillMap.end());
return schoolSkillMap[school];
}
float calcEffectCost(const ESM::ENAMstruct& effect)
{
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
return calcEffectCost(effect, magicEffect);
ESM::Skill::Alteration, ESM::Skill::Conjuration, ESM::Skill::Destruction,
ESM::Skill::Illusion, ESM::Skill::Mysticism, ESM::Skill::Restoration
};
return schoolSkillArray.at(school);
}
float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect)
{
int minMagn = 1;
int maxMagn = 1;
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
{
minMagn = effect.mMagnMin;
maxMagn = effect.mMagnMax;
}
int duration = 1;
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
duration = effect.mDuration;
if (!magicEffect)
magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
bool hasMagnitude = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude);
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
int minMagn = hasMagnitude ? effect.mMagnMin : 1;
int maxMagn = hasMagnitude ? effect.mMagnMax : 1;
int duration = hasDuration ? effect.mDuration : 1;
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat();
@ -84,19 +66,18 @@ namespace MWMechanics
float y = std::numeric_limits<float>::max();
float lowestSkill = 0;
for (std::vector<ESM::ENAMstruct>::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it)
for (const ESM::ENAMstruct& effect : spell->mEffects.mList)
{
float x = static_cast<float>(it->mDuration);
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
it->mEffectID);
float x = static_cast<float>(effect.mDuration);
const auto magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce))
x = std::max(1.f, x);
x *= 0.1f * magicEffect->mData.mBaseCost;
x *= 0.5f * (it->mMagnMin + it->mMagnMax);
x *= it->mArea * 0.05f * magicEffect->mData.mBaseCost;
if (it->mRange == ESM::RT_Target)
x *= 0.5f * (effect.mMagnMin + effect.mMagnMax);
x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost;
if (effect.mRange == ESM::RT_Target)
x *= 1.5f;
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"fEffectCostMult")->mValue.getFloat();
@ -149,24 +130,18 @@ namespace MWMechanics
return 100;
if (godmode)
{
return 100;
}
if (!cap)
return std::max(0.f, castChance);
else
return std::max(0.f, std::min(100.f, castChance));
return std::max(0.f, cap ? std::min(100.f, castChance) : castChance);
}
float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka)
{
const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
return getSpellSuccessChance(spell, actor, effectiveSchool, cap, checkMagicka);
if (const auto spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(spellId))
return getSpellSuccessChance(spell, actor, effectiveSchool, cap, checkMagicka);
return 0.f;
}
int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor)
{
int school = 0;
@ -183,16 +158,13 @@ namespace MWMechanics
bool spellIncreasesSkill(const ESM::Spell *spell)
{
if (spell->mData.mType == ESM::Spell::ST_Spell && !(spell->mData.mFlags & ESM::Spell::F_Always))
return true;
return false;
return spell->mData.mType == ESM::Spell::ST_Spell && !(spell->mData.mFlags & ESM::Spell::F_Always);
}
bool spellIncreasesSkill(const std::string &spellId)
{
const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
return spellIncreasesSkill(spell);
const auto spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(spellId);
return spell && spellIncreasesSkill(spell);
}
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects)
@ -314,10 +286,9 @@ namespace MWMechanics
class GetAbsorptionProbability : public MWMechanics::EffectSourceVisitor
{
public:
float mProbability;
float mProbability{0.f};
GetAbsorptionProbability(const MWWorld::Ptr& actor)
: mProbability(0.f){}
GetAbsorptionProbability() = default;
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, const std::string& sourceId, int casterActorId,
@ -342,9 +313,6 @@ namespace MWMechanics
CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target, const bool fromProjectile, const bool manualSpell)
: mCaster(caster)
, mTarget(target)
, mStack(false)
, mHitPosition(0,0,0)
, mAlwaysSucceed(false)
, mFromProjectile(fromProjectile)
, mManualSpell(manualSpell)
{
@ -375,10 +343,9 @@ namespace MWMechanics
// If none of the effects need to apply, we can early-out
bool found = false;
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
iter!=effects.mList.end(); ++iter)
for (const ESM::ENAMstruct& effect : effects.mList)
{
if (iter->mRange == range)
if (effect.mRange == range)
{
found = true;
break;
@ -441,8 +408,7 @@ namespace MWMechanics
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCannotRecast}");
continue;
}
else
canCastAnEffect = true;
canCastAnEffect = true;
if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer))
continue;
@ -466,7 +432,7 @@ namespace MWMechanics
CreatureStats& stats = target.getClass().getCreatureStats(target);
if (stats.getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude() > 0.f)
{
GetAbsorptionProbability check(target);
GetAbsorptionProbability check;
stats.getActiveSpells().visitEffectSources(check);
stats.getSpells().visitEffectSources(check);
if (target.getClass().hasInventoryStore(target))
@ -578,11 +544,7 @@ namespace MWMechanics
}
else
{
if (!hasDuration)
effect.mDuration = 1.0f;
else
effect.mDuration = static_cast<float>(effectIt->mDuration);
effect.mDuration = hasDuration ? static_cast<float>(effectIt->mDuration) : 1.f;
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
@ -658,13 +620,11 @@ namespace MWMechanics
else
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_DefaultHit");
std::string texture = magicEffect->mParticle;
bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0;
// Note: in case of non actor, a free effect should be fine as well
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
if (anim)
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", texture);
if (anim && !castStatic->mModel.empty())
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", magicEffect->mParticle);
}
}
}
@ -985,7 +945,7 @@ namespace MWMechanics
// A non-actor doesn't play its spell cast effects from a character controller, so play them here
if (!mCaster.getClass().isActor())
playSpellCastingEffects(mId, false);
playSpellCastingEffects(spell->mEffects.mList);
inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self);
@ -1065,14 +1025,13 @@ namespace MWMechanics
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
if (enchantment)
{
const ESM::Enchantment *spell = store.get<ESM::Enchantment>().find(spellid);
playSpellCastingEffects(spell->mEffects.mList);
if (const auto spell = store.get<ESM::Enchantment>().search(spellid))
playSpellCastingEffects(spell->mEffects.mList);
}
else
{
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
playSpellCastingEffects(spell->mEffects.mList);
if (const auto spell = store.get<ESM::Spell>().search(spellid))
playSpellCastingEffects(spell->mEffects.mList);
}
}
@ -1080,12 +1039,9 @@ namespace MWMechanics
{
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
std::vector<std::string> addedEffects;
for (std::vector<ESM::ENAMstruct>::const_iterator iter = effects.begin(); iter != effects.end(); ++iter)
for (const ESM::ENAMstruct& effectData : effects)
{
const ESM::MagicEffect *effect;
effect = store.get<ESM::MagicEffect>().find(iter->mEffectID);
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
const auto effect = store.get<ESM::MagicEffect>().find(effectData.mEffectID);
const ESM::Static* castStatic;
@ -1098,13 +1054,10 @@ namespace MWMechanics
if (std::find(addedEffects.begin(), addedEffects.end(), "meshes\\" + castStatic->mModel) != addedEffects.end())
continue;
std::string texture = effect->mParticle;
osg::Vec3f pos (mCaster.getRefData().getPosition().asVec3());
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
if (animation)
{
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", effect->mParticle);
}
else
{
@ -1113,6 +1066,7 @@ namespace MWMechanics
osg::Vec3f bounds (MWBase::Environment::get().getWorld()->getHalfExtents(mCaster) * 2.f / Constants::UnitsPerFoot);
float scale = std::max({ bounds.x()/3.f, bounds.y()/3.f, bounds.z()/6.f });
float meshScale = !mCaster.getClass().isActor() ? mCaster.getCellRef().getScale() : 1.0f;
osg::Vec3f pos (mCaster.getRefData().getPosition().asVec3());
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + castStatic->mModel, effect->mParticle, pos, scale * meshScale);
}
@ -1135,10 +1089,7 @@ namespace MWMechanics
bool CastSpell::spellIncreasesSkill()
{
if (mManualSpell)
return false;
return MWMechanics::spellIncreasesSkill(mId);
return !mManualSpell && MWMechanics::spellIncreasesSkill(mId);
}
int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor)
@ -1167,8 +1118,7 @@ namespace MWMechanics
if (ptr.getClass().hasInventoryStore(ptr))
{
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
MWWorld::ContainerStoreIterator item =
inv.getSlot(slot);
MWWorld::ContainerStoreIterator item = inv.getSlot(slot);
if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor || item.getType() == MWWorld::ContainerStore::Type_Weapon))
{
@ -1183,9 +1133,7 @@ namespace MWMechanics
item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate));
charge = item->getClass().getItemHealth(*item);
charge -=
std::min(static_cast<int>(disintegrate),
charge);
charge -= std::min(static_cast<int>(disintegrate), charge);
item->getCellRef().setCharge(charge);
if (charge == 0)
@ -1366,58 +1314,52 @@ namespace MWMechanics
std::string getSummonedCreature(int effectId)
{
static std::map<int, std::string> summonMap;
if (summonMap.empty())
static const std::map<int, std::string> summonMap
{
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
}
std::map<int, std::string>::const_iterator it = summonMap.find(effectId);
if (it == summonMap.end())
return std::string();
else
{ESM::MagicEffect::SummonAncestralGhost, "sMagicAncestralGhostID"},
{ESM::MagicEffect::SummonBonelord, "sMagicBonelordID"},
{ESM::MagicEffect::SummonBonewalker, "sMagicLeastBonewalkerID"},
{ESM::MagicEffect::SummonCenturionSphere, "sMagicCenturionSphereID"},
{ESM::MagicEffect::SummonClannfear, "sMagicClannfearID"},
{ESM::MagicEffect::SummonDaedroth, "sMagicDaedrothID"},
{ESM::MagicEffect::SummonDremora, "sMagicDremoraID"},
{ESM::MagicEffect::SummonFabricant, "sMagicFabricantID"},
{ESM::MagicEffect::SummonFlameAtronach, "sMagicFlameAtronachID"},
{ESM::MagicEffect::SummonFrostAtronach, "sMagicFrostAtronachID"},
{ESM::MagicEffect::SummonGoldenSaint, "sMagicGoldenSaintID"},
{ESM::MagicEffect::SummonGreaterBonewalker, "sMagicGreaterBonewalkerID"},
{ESM::MagicEffect::SummonHunger, "sMagicHungerID"},
{ESM::MagicEffect::SummonScamp, "sMagicScampID"},
{ESM::MagicEffect::SummonSkeletalMinion, "sMagicSkeletalMinionID"},
{ESM::MagicEffect::SummonStormAtronach, "sMagicStormAtronachID"},
{ESM::MagicEffect::SummonWingedTwilight, "sMagicWingedTwilightID"},
{ESM::MagicEffect::SummonWolf, "sMagicCreature01ID"},
{ESM::MagicEffect::SummonBear, "sMagicCreature02ID"},
{ESM::MagicEffect::SummonBonewolf, "sMagicCreature03ID"},
{ESM::MagicEffect::SummonCreature04, "sMagicCreature04ID"},
{ESM::MagicEffect::SummonCreature05, "sMagicCreature05ID"}
};
auto it = summonMap.find(effectId);
if (it != summonMap.end())
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->mValue.getString();
return std::string();
}
void ApplyLoopingParticlesVisitor::visit (MWMechanics::EffectKey key,
const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/,
float /*magnitude*/, float /*remainingTime*/, float /*totalTime*/)
{
const ESM::MagicEffect *magicEffect =
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(key.mId);
const auto magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(key.mId);
if ((magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) == 0)
return;
const ESM::Static* castStatic;
if (!magicEffect->mHit.empty())
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
else
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_DefaultHit");
std::string texture = magicEffect->mParticle;
bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0;
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mActor);
if (anim && loop)
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", texture);
if (anim && !castStatic->mModel.empty())
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, /*loop*/true, "", magicEffect->mParticle);
}
}

@ -25,8 +25,7 @@ namespace MWMechanics
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
float calcEffectCost(const ESM::ENAMstruct& effect);
float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect);
float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect = nullptr);
bool isSummoningEffect(int effectId);
@ -87,11 +86,11 @@ namespace MWMechanics
void playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects);
public:
bool mStack;
bool mStack{false};
std::string mId; // ID of spell, potion, item etc
std::string mSourceName; // Display name for spell, potion, etc
osg::Vec3f mHitPosition; // Used for spawning area orb
bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false)
osg::Vec3f mHitPosition{0,0,0}; // Used for spawning area orb
bool mAlwaysSucceed{false}; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false)
bool mFromProjectile; // True if spell is cast by enchantment of some projectile (arrow, bolt or thrown weapon)
bool mManualSpell; // True if spell is casted from script and ignores some checks (mana level, success chance, etc.)

Loading…
Cancel
Save