diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 3f32485def..d7645a6989 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -32,41 +32,23 @@ namespace MWMechanics { ESM::Skill::SkillEnum spellSchoolToSkill(int school) { - static std::map schoolSkillMap; // maps spell school to skill id - if (schoolSkillMap.empty()) + static const std::map schoolSkillMap { - 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().find(effect.mEffectID); - return calcEffectCost(effect, magicEffect); + {0, ESM::Skill::Alteration}, {1, ESM::Skill::Conjuration}, {2, ESM::Skill::Destruction}, + {3, ESM::Skill::Illusion}, {4, ESM::Skill::Mysticism}, {5, ESM::Skill::Restoration} + }; + return schoolSkillMap.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().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().find("fEffectCostMult")->mValue.getFloat(); @@ -84,19 +66,18 @@ namespace MWMechanics float y = std::numeric_limits::max(); float lowestSkill = 0; - for (std::vector::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(it->mDuration); - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( - it->mEffectID); + float x = static_cast(effect.mDuration); + const auto magicEffect = MWBase::Environment::get().getWorld()->getStore().get().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().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().find(spellId); - return getSpellSuccessChance(spell, actor, effectiveSchool, cap, checkMagicka); + if (const auto spell = MWBase::Environment::get().getWorld()->getStore().get().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().find(spellId); - return spellIncreasesSkill(spell); + const auto spell = MWBase::Environment::get().getWorld()->getStore().get().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::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(effectIt->mDuration); + effect.mDuration = hasDuration ? static_cast(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().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().find(spellid); - playSpellCastingEffects(spell->mEffects.mList); - + if (const auto spell = store.get().search(spellid)) + playSpellCastingEffects(spell->mEffects.mList); } else { - const ESM::Spell *spell = store.get().find(spellid); - playSpellCastingEffects(spell->mEffects.mList); + if (const auto spell = store.get().search(spellid)) + playSpellCastingEffects(spell->mEffects.mList); } } @@ -1080,12 +1039,9 @@ namespace MWMechanics { const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); std::vector addedEffects; - for (std::vector::const_iterator iter = effects.begin(); iter != effects.end(); ++iter) + for (const ESM::ENAMstruct& effectData : effects) { - const ESM::MagicEffect *effect; - effect = store.get().find(iter->mEffectID); - - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); + const auto effect = store.get().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(disintegrate), - charge); + charge -= std::min(static_cast(disintegrate), charge); item->getCellRef().setCharge(charge); if (charge == 0) @@ -1366,58 +1314,52 @@ namespace MWMechanics std::string getSummonedCreature(int effectId) { - static std::map summonMap; - if (summonMap.empty()) + static const std::map 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"; - } + {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"} + }; - std::map::const_iterator it = summonMap.find(effectId); - if (it == summonMap.end()) - return std::string(); - else + auto it = summonMap.find(effectId); + if (it != summonMap.end()) return MWBase::Environment::get().getWorld()->getStore().get().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().find(key.mId); - + const auto magicEffect = MWBase::Environment::get().getWorld()->getStore().get().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().find (magicEffect->mHit); else castStatic = MWBase::Environment::get().getWorld()->getStore().get().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); } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 5f0e4a1cf7..85e732e03d 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -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& 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.)