forked from mirror/openmw-tes3mp
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;
|
||||
}
|
||||
|
||||
/// 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…
Reference in a new issue