mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-03 23:56:43 +00:00 
			
		
		
		
	Merge pull request #1131 from Allofich/waterwalking
Make water walking mechanics closer to original MW
This commit is contained in:
		
						commit
						385db50f2d
					
				
					 6 changed files with 34 additions and 25 deletions
				
			
		| 
						 | 
					@ -223,7 +223,7 @@ namespace MWMechanics
 | 
				
			||||||
        return 1 - resistance / 100.f;
 | 
					        return 1 - resistance / 100.f;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Check if the given affect can be applied to the target. If \a castByPlayer, emits a message box on failure.
 | 
					    /// Check if the given effect can be applied to the target. If \a castByPlayer, emits a message box on failure.
 | 
				
			||||||
    bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer)
 | 
					    bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        switch (effectId)
 | 
					        switch (effectId)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,8 @@ namespace MWMechanics
 | 
				
			||||||
    float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
 | 
					    float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
 | 
				
			||||||
                              const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL);
 | 
					                              const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
 | 
					    int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
 | 
					    void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -985,6 +985,18 @@ namespace MWPhysics
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const Actor* physicActor = getActor(actor);
 | 
				
			||||||
 | 
					        const float halfZ = physicActor->getHalfExtents().z();
 | 
				
			||||||
 | 
					        const osg::Vec3f actorPosition = physicActor->getPosition();
 | 
				
			||||||
 | 
					        const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
 | 
				
			||||||
 | 
					        const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
 | 
				
			||||||
 | 
					        ActorTracer tracer;
 | 
				
			||||||
 | 
					        tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld);
 | 
				
			||||||
 | 
					        return (tracer.mFraction >= 1.0f);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
 | 
					    osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        const Actor* physactor = getActor(actor);
 | 
					        const Actor* physactor = getActor(actor);
 | 
				
			||||||
| 
						 | 
					@ -1326,25 +1338,10 @@ namespace MWPhysics
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
 | 
					                if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
 | 
				
			||||||
                    waterCollision = true;
 | 
					                    waterCollision = true;
 | 
				
			||||||
                else if (physicActor->getCollisionMode())
 | 
					                else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    const float halfZ = physicActor->getHalfExtents().z();
 | 
					 | 
				
			||||||
                    const osg::Vec3f actorPosition = physicActor->getPosition();
 | 
					                    const osg::Vec3f actorPosition = physicActor->getPosition();
 | 
				
			||||||
                    const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
 | 
					                    physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));            
 | 
				
			||||||
                    const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
 | 
					 | 
				
			||||||
                    ActorTracer tracer;
 | 
					 | 
				
			||||||
                    tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld);
 | 
					 | 
				
			||||||
                    if (tracer.mFraction >= 1.0f)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        waterCollision = true;
 | 
					 | 
				
			||||||
                        physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        //Remove the effect to remove the performance hit of casting in a weird spot
 | 
					 | 
				
			||||||
                        //probably makes that Tribunal quest where the water rises a bit safer
 | 
					 | 
				
			||||||
                        iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().purgeEffect(ESM::MagicEffect::WaterWalking);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            physicActor->setCanWaterWalk(waterCollision);
 | 
					            physicActor->setCanWaterWalk(waterCollision);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,6 +123,8 @@ namespace MWPhysics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool isOnGround (const MWWorld::Ptr& actor);
 | 
					            bool isOnGround (const MWWorld::Ptr& actor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// Get physical half extents (scaled) of the given actor.
 | 
					            /// Get physical half extents (scaled) of the given actor.
 | 
				
			||||||
            osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;
 | 
					            osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -515,8 +515,8 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
 | 
				
			||||||
                    MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
 | 
					                    MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
 | 
				
			||||||
                    effectIt->mEffectID);
 | 
					                    effectIt->mEffectID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Fully resisted?
 | 
					                // Fully resisted or can't be applied to target?
 | 
				
			||||||
                if (params[i].mMultiplier == 0)
 | 
					                if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer()))
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
 | 
					                float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
 | 
				
			||||||
| 
						 | 
					@ -770,6 +770,9 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
 | 
				
			||||||
        for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
 | 
					        for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
 | 
				
			||||||
            effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
 | 
					            effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            // Don't get spell icon display information for enchantments that weren't actually applied
 | 
				
			||||||
 | 
					            if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0)
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
            const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i];
 | 
					            const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i];
 | 
				
			||||||
            float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
 | 
					            float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
 | 
				
			||||||
            magnitude *= params.mMultiplier;
 | 
					            magnitude *= params.mMultiplier;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2084,11 +2084,16 @@ namespace MWWorld
 | 
				
			||||||
        if (!cell->getCell()->hasWater())
 | 
					        if (!cell->getCell()->hasWater())
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Based on observations from the original engine, the depth
 | 
					        float waterlevel = cell->getWaterLevel();
 | 
				
			||||||
        // limit at which water walking can still be cast on a target
 | 
					
 | 
				
			||||||
        // in water appears to be the same as what the highest swimmable
 | 
					        // SwimHeightScale affects the upper z position an actor can swim to 
 | 
				
			||||||
        // z position would be with SwimHeightScale + 1.
 | 
					        // while in water. Based on observation from the original engine,
 | 
				
			||||||
        return !isUnderwater(target, mSwimHeightScale + 1);
 | 
					        // the upper z position you get with a +1 SwimHeightScale is the depth
 | 
				
			||||||
 | 
					        // limit for being able to cast water walking on an underwater target.
 | 
				
			||||||
 | 
					        if (isUnderwater(target, mSwimHeightScale + 1) || (isUnderwater(cell, target.getRefData().getPosition().asVec3()) && !mPhysics->canMoveToWaterSurface(target, waterlevel)))
 | 
				
			||||||
 | 
					            return false; // not castable if too deep or if not enough room to move actor to surface
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool World::isOnGround(const MWWorld::Ptr &ptr) const
 | 
					    bool World::isOnGround(const MWWorld::Ptr &ptr) const
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue