mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 05:56:39 +00:00 
			
		
		
		
	Merge pull request #2655 from Capostrophic/spellcasting
Fix reported spellcasting discrepancies
This commit is contained in:
		
						commit
						70f6e1c81d
					
				
					 5 changed files with 61 additions and 28 deletions
				
			
		| 
						 | 
					@ -188,6 +188,8 @@
 | 
				
			||||||
    Bug #5226: Reputation should be capped
 | 
					    Bug #5226: Reputation should be capped
 | 
				
			||||||
    Bug #5229: Crash if mesh controller node has no data node
 | 
					    Bug #5229: Crash if mesh controller node has no data node
 | 
				
			||||||
    Bug #5239: OpenMW-CS does not support non-ASCII characters in path names
 | 
					    Bug #5239: OpenMW-CS does not support non-ASCII characters in path names
 | 
				
			||||||
 | 
					    Bug #5241: On-self absorb spells cannot be detected
 | 
				
			||||||
 | 
					    Bug #5242: ExplodeSpell behavior differs from Cast behavior
 | 
				
			||||||
    Feature #1774: Handle AvoidNode
 | 
					    Feature #1774: Handle AvoidNode
 | 
				
			||||||
    Feature #2229: Improve pathfinding AI
 | 
					    Feature #2229: Improve pathfinding AI
 | 
				
			||||||
    Feature #3025: Analogue gamepad movement controls
 | 
					    Feature #3025: Analogue gamepad movement controls
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -447,9 +447,9 @@ namespace MWMechanics
 | 
				
			||||||
            if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer))
 | 
					            if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer))
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // caster needs to be an actor that's not the target for linked effects (e.g. Absorb)
 | 
					            // caster needs to be an actor for linked effects (e.g. Absorb)
 | 
				
			||||||
            if (magicEffect->mData.mFlags & ESM::MagicEffect::CasterLinked
 | 
					            if (magicEffect->mData.mFlags & ESM::MagicEffect::CasterLinked
 | 
				
			||||||
                    && (caster.isEmpty() || !caster.getClass().isActor() || caster == target))
 | 
					                    && (caster.isEmpty() || !caster.getClass().isActor()))
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // If player is healing someone, show the target's HP bar
 | 
					            // If player is healing someone, show the target's HP bar
 | 
				
			||||||
| 
						 | 
					@ -552,6 +552,15 @@ namespace MWMechanics
 | 
				
			||||||
                    effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
 | 
					                    effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
 | 
				
			||||||
                    effect.mMagnitude = magnitude;
 | 
					                    effect.mMagnitude = magnitude;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Avoid applying absorb effects if the caster is the target
 | 
				
			||||||
 | 
					                    // We still need the spell to be added
 | 
				
			||||||
 | 
					                    if (caster == target
 | 
				
			||||||
 | 
					                        && effectIt->mEffectID >= ESM::MagicEffect::AbsorbAttribute
 | 
				
			||||||
 | 
					                        && effectIt->mEffectID <= ESM::MagicEffect::AbsorbSkill)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        effect.mMagnitude = 0;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
 | 
					                    bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
 | 
				
			||||||
                    if (hasDuration && effectIt->mDuration == 0)
 | 
					                    if (hasDuration && effectIt->mDuration == 0)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
| 
						 | 
					@ -600,9 +609,8 @@ namespace MWMechanics
 | 
				
			||||||
                        // magnitude, since we're transferring stats from the target to the caster
 | 
					                        // magnitude, since we're transferring stats from the target to the caster
 | 
				
			||||||
                        if (!caster.isEmpty() && caster != target && caster.getClass().isActor())
 | 
					                        if (!caster.isEmpty() && caster != target && caster.getClass().isActor())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            for (int i=0; i<5; ++i)
 | 
					                            if (effectIt->mEffectID >= ESM::MagicEffect::AbsorbAttribute &&
 | 
				
			||||||
                            {
 | 
					                                effectIt->mEffectID <= ESM::MagicEffect::AbsorbSkill)
 | 
				
			||||||
                                if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i)
 | 
					 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                std::vector<ActiveSpells::ActiveEffect> absorbEffects;
 | 
					                                std::vector<ActiveSpells::ActiveEffect> absorbEffects;
 | 
				
			||||||
                                ActiveSpells::ActiveEffect effect_ = effect;
 | 
					                                ActiveSpells::ActiveEffect effect_ = effect;
 | 
				
			||||||
| 
						 | 
					@ -618,7 +626,6 @@ namespace MWMechanics
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Re-casting a summon effect will remove the creature from previous castings of that effect.
 | 
					                // Re-casting a summon effect will remove the creature from previous castings of that effect.
 | 
				
			||||||
                if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
 | 
					                if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1109,18 +1109,9 @@ namespace MWScript
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    runtime.getContext().report("spellcasting failed: you can only cast spells and powers.");
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (ptr == MWMechanics::getPlayer())
 | 
					                if (ptr == MWMechanics::getPlayer())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
 | 
					                    MWBase::Environment::get().getWorld()->getPlayer().setSelectedSpell(spellId);
 | 
				
			||||||
                    store.setSelectedEnchantItem(store.end());
 | 
					 | 
				
			||||||
                    MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, ptr)));
 | 
					 | 
				
			||||||
                    MWBase::Environment::get().getWindowManager()->updateSpellWindow();
 | 
					 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1128,7 +1119,6 @@ namespace MWScript
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    MWMechanics::AiCast castPackage(targetId, spellId, true);
 | 
					                    MWMechanics::AiCast castPackage(targetId, spellId, true);
 | 
				
			||||||
                    ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(castPackage, ptr);
 | 
					                    ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(castPackage, ptr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1152,9 +1142,29 @@ namespace MWScript
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                MWWorld::Ptr ptr = R()(runtime);
 | 
					                MWWorld::Ptr ptr = R()(runtime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std::string spell = runtime.getStringLiteral (runtime[0].mInteger);
 | 
					                std::string spellId = runtime.getStringLiteral (runtime[0].mInteger);
 | 
				
			||||||
                runtime.pop();
 | 
					                runtime.pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(spellId);
 | 
				
			||||||
 | 
					                if (!spell)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    runtime.getContext().report("spellcasting failed: cannot find spell \""+spellId+"\"");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (ptr == MWMechanics::getPlayer())
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    MWBase::Environment::get().getWorld()->getPlayer().setSelectedSpell(spellId);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (ptr.getClass().isActor())
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    MWMechanics::AiCast castPackage(ptr.getCellRef().getRefId(), spellId, true);
 | 
				
			||||||
 | 
					                    ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(castPackage, ptr);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                MWMechanics::CastSpell cast(ptr, ptr, false, true);
 | 
					                MWMechanics::CastSpell cast(ptr, ptr, false, true);
 | 
				
			||||||
                cast.mHitPosition = ptr.getRefData().getPosition().asVec3();
 | 
					                cast.mHitPosition = ptr.getRefData().getPosition().asVec3();
 | 
				
			||||||
                cast.mAlwaysSucceed = true;
 | 
					                cast.mAlwaysSucceed = true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
#include <components/esm/loadbsgn.hpp>
 | 
					#include <components/esm/loadbsgn.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwworld/esmstore.hpp"
 | 
					#include "../mwworld/esmstore.hpp"
 | 
				
			||||||
 | 
					#include "../mwworld/inventorystore.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwbase/environment.hpp"
 | 
					#include "../mwbase/environment.hpp"
 | 
				
			||||||
#include "../mwbase/world.hpp"
 | 
					#include "../mwbase/world.hpp"
 | 
				
			||||||
| 
						 | 
					@ -19,6 +20,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../mwmechanics/movement.hpp"
 | 
					#include "../mwmechanics/movement.hpp"
 | 
				
			||||||
#include "../mwmechanics/npcstats.hpp"
 | 
					#include "../mwmechanics/npcstats.hpp"
 | 
				
			||||||
 | 
					#include "../mwmechanics/spellcasting.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "class.hpp"
 | 
					#include "class.hpp"
 | 
				
			||||||
#include "ptr.hpp"
 | 
					#include "ptr.hpp"
 | 
				
			||||||
| 
						 | 
					@ -492,4 +494,14 @@ namespace MWWorld
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        mPreviousItems.erase(boundItemId);
 | 
					        mPreviousItems.erase(boundItemId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Player::setSelectedSpell(const std::string& spellId)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Ptr player = getPlayer();
 | 
				
			||||||
 | 
					        InventoryStore& store = player.getClass().getInventoryStore(player);
 | 
				
			||||||
 | 
					        store.setSelectedEnchantItem(store.end());
 | 
				
			||||||
 | 
					        int castChance = int(MWMechanics::getSpellSuccessChance(spellId, player));
 | 
				
			||||||
 | 
					        MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, castChance);
 | 
				
			||||||
 | 
					        MWBase::Environment::get().getWindowManager()->updateSpellWindow();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,8 @@ namespace MWWorld
 | 
				
			||||||
        void setPreviousItem(const std::string& boundItemId, const std::string& previousItemId);
 | 
					        void setPreviousItem(const std::string& boundItemId, const std::string& previousItemId);
 | 
				
			||||||
        std::string getPreviousItem(const std::string& boundItemId);
 | 
					        std::string getPreviousItem(const std::string& boundItemId);
 | 
				
			||||||
        void erasePreviousItem(const std::string& boundItemId);
 | 
					        void erasePreviousItem(const std::string& boundItemId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void setSelectedSpell(const std::string& spellId);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue