Merge pull request #1131 from Allofich/waterwalking

Make water walking mechanics closer to original MW
pull/107/head
scrawl 8 years ago committed by GitHub
commit 385db50f2d

@ -223,7 +223,7 @@ namespace MWMechanics
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)
{
switch (effectId)

@ -59,6 +59,8 @@ namespace MWMechanics
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
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);
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
{
const Actor* physactor = getActor(actor);
@ -1326,25 +1338,10 @@ namespace MWPhysics
{
if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
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 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);
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->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
}
}
physicActor->setCanWaterWalk(waterCollision);

@ -123,6 +123,8 @@ namespace MWPhysics
bool isOnGround (const MWWorld::Ptr& actor);
bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
/// Get physical half extents (scaled) of the given actor.
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 (
effectIt->mEffectID);
// Fully resisted?
if (params[i].mMultiplier == 0)
// Fully resisted or can't be applied to target?
if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer()))
continue;
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());
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];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier;

@ -2084,11 +2084,16 @@ namespace MWWorld
if (!cell->getCell()->hasWater())
return true;
// Based on observations from the original engine, the depth
// limit at which water walking can still be cast on a target
// in water appears to be the same as what the highest swimmable
// z position would be with SwimHeightScale + 1.
return !isUnderwater(target, mSwimHeightScale + 1);
float waterlevel = cell->getWaterLevel();
// SwimHeightScale affects the upper z position an actor can swim to
// while in water. Based on observation from the original engine,
// 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

Loading…
Cancel
Save