From 2f13a17a39a1c11d31b9e45dd7c37f6a993564f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 May 2014 02:37:20 +0200 Subject: [PATCH] Add some more safety checks to spellcasting --- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 36 +++++++++++-------- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5c2ee30e1..41374c1a3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -29,7 +29,7 @@ namespace const std::string& faction = item.getCellRef().mFaction; bool isFactionOwned = false; - if (!faction.empty()) + if (!faction.empty() && ptr.getClass().isNpc()) { const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); if (factions.find(Misc::StringUtils::lowerCase(faction)) == factions.end()) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 3f6cc4103..0843e3e54 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -140,7 +140,7 @@ namespace MWMechanics float x = (willpower + 0.1 * luck) * stats.getFatigueTerm(); // This makes spells that are easy to cast harder to resist and vice versa - if (spell != NULL && caster.getClass().isActor()) + if (spell != NULL && !caster.isEmpty() && caster.getClass().isActor()) { float castChance = getSpellSuccessChance(spell, caster); if (castChance > 0) @@ -226,6 +226,8 @@ namespace MWMechanics bool firstAppliedEffect = true; bool anyHarmfulEffect = false; + bool castByPlayer = (!caster.isEmpty() && caster.getRefData().getHandle() == "player"); + for (std::vector::const_iterator effectIt (effects.mList.begin()); effectIt!=effects.mList.end(); ++effectIt) { @@ -238,7 +240,7 @@ namespace MWMechanics if (!MWBase::Environment::get().getWorld()->isLevitationEnabled() && effectIt->mEffectID == ESM::MagicEffect::Levitate) { - if (caster.getRefData().getHandle() == "player") + if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sLevitateDisabled}"); continue; } @@ -249,13 +251,13 @@ namespace MWMechanics effectIt->mEffectID == ESM::MagicEffect::Mark || effectIt->mEffectID == ESM::MagicEffect::Recall)) { - if (caster.getRefData().getHandle() == "player") + if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); continue; } // If player is healing someone, show the target's HP bar - if (caster.getRefData().getHandle() == "player" && target != caster + if (castByPlayer && target != caster && effectIt->mEffectID == ESM::MagicEffect::RestoreHealth && target.getClass().isActor()) MWBase::Environment::get().getWindowManager()->setEnemy(target); @@ -266,7 +268,7 @@ namespace MWMechanics anyHarmfulEffect = true; // If player is attempting to cast a harmful spell, show the target's HP bar - if (caster.getRefData().getHandle() == "player" && target != caster) + if (castByPlayer && target != caster) MWBase::Environment::get().getWindowManager()->setEnemy(target); // Try absorbing if it's a spell @@ -342,17 +344,20 @@ namespace MWMechanics // For absorb effects, also apply the effect to the caster - but with a negative // magnitude, since we're transfering stats from the target to the caster - for (int i=0; i<5; ++i) + if (!caster.isEmpty() && caster.getClass().isActor()) { - if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) + for (int i=0; i<5; ++i) { - std::vector effects; - ActiveSpells::ActiveEffect effect_ = effect; - effect_.mMagnitude *= -1; - effects.push_back(effect_); - // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies - caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, - effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); + if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) + { + std::vector effects; + ActiveSpells::ActiveEffect effect_ = effect; + effect_.mMagnitude *= -1; + effects.push_back(effect_); + // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, + effects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); + } } } } @@ -441,7 +446,8 @@ namespace MWMechanics if (target.getCellRef().mLockLevel > 0) { MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f); - MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); + if (!caster.isEmpty() && caster.getClass().isActor()) + MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); } target.getCellRef().mLockLevel = -abs(target.getCellRef().mLockLevel); //unlocks the door } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index a930442fb..dce4b792e 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -62,9 +62,11 @@ namespace MWMechanics bool cast (const std::string& id); /// @note \a target can be any type of object, not just actors. + /// @note \a caster can be any type of object, or even an empty object. void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false, bool exploded=false); + /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); };