Merge remote-tracking branch 'cc9cii/Slaughterfish-fix'

actorid
Marc Zinnschlag 11 years ago
commit 8b36de6c67

@ -525,7 +525,7 @@ namespace MWClass
float moveSpeed; float moveSpeed;
if(normalizedEncumbrance >= 1.0f) if(normalizedEncumbrance >= 1.0f)
moveSpeed = 0.0f; moveSpeed = 0.0f;
else if(isFlying(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 && else if(canFly(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
world->isLevitationEnabled())) world->isLevitationEnabled()))
{ {
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() + float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
@ -678,7 +678,15 @@ namespace MWClass
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell); return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell);
} }
bool Creature::isFlying(const MWWorld::Ptr &ptr) const bool Creature::isBipedal(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Bipedal;
}
bool Creature::canFly(const MWWorld::Ptr &ptr) const
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref = MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>(); ptr.get<ESM::Creature>();
@ -686,6 +694,22 @@ namespace MWClass
return ref->mBase->mFlags & ESM::Creature::Flies; return ref->mBase->mFlags & ESM::Creature::Flies;
} }
bool Creature::canSwim(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Swims;
}
bool Creature::canWalk(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Walks;
}
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name) int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
{ {
if(name == "left") if(name == "left")

@ -124,7 +124,10 @@ namespace MWClass
return true; return true;
} }
virtual bool isFlying (const MWWorld::Ptr &ptr) const; virtual bool isBipedal (const MWWorld::Ptr &ptr) const;
virtual bool canFly (const MWWorld::Ptr &ptr) const;
virtual bool canSwim (const MWWorld::Ptr &ptr) const;
virtual bool canWalk (const MWWorld::Ptr &ptr) const;
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;

@ -363,7 +363,22 @@ namespace MWWorld
return newPtr; return newPtr;
} }
bool Class::isFlying(const Ptr &ptr) const bool Class::isBipedal(const Ptr &ptr) const
{
return false;
}
bool Class::canFly(const Ptr &ptr) const
{
return false;
}
bool Class::canSwim(const Ptr &ptr) const
{
return false;
}
bool Class::canWalk(const Ptr &ptr) const
{ {
return false; return false;
} }

@ -307,7 +307,10 @@ namespace MWWorld
return false; return false;
} }
virtual bool isFlying(const MWWorld::Ptr& ptr) const; virtual bool isBipedal(const MWWorld::Ptr& ptr) const;
virtual bool canFly(const MWWorld::Ptr& ptr) const;
virtual bool canSwim(const MWWorld::Ptr& ptr) const;
virtual bool canWalk(const MWWorld::Ptr& ptr) const;
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;

@ -130,31 +130,52 @@ namespace MWWorld
position.z += halfExtents.z; position.z += halfExtents.z;
waterlevel -= halfExtents.z * 0.5; waterlevel -= halfExtents.z * 0.5;
/*
* A 3/4 submerged example
*
* +---+
* | |
* | | <- (original waterlevel)
* | |
* | | <- position <- waterlevel
* | |
* | |
* | |
* +---+ <- (original position)
*/
OEngine::Physic::ActorTracer tracer; OEngine::Physic::ActorTracer tracer;
bool wasOnGround = false; bool wasOnGround = false;
bool isOnGround = false; bool isOnGround = false;
Ogre::Vector3 inertia(0.0f); Ogre::Vector3 inertia(0.0f);
Ogre::Vector3 velocity; Ogre::Vector3 velocity;
if(position.z < waterlevel || isFlying)
bool canWalk = ptr.getClass().canWalk(ptr);
bool isBipedal = ptr.getClass().isBipedal(ptr);
bool isNpc = ptr.getClass().isNpc();
if(position.z < waterlevel || isFlying) // under water by 3/4 or can fly
{ {
// TODO: Shouldn't water have higher drag in calculating velocity?
velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)*
Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement;
} }
else else
{ {
velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement;
// not in water nor can fly, so need to deal with gravity
if(!physicActor->getOnGround()) if(!physicActor->getOnGround())
{ {
// If falling, add part of the incoming velocity with the current inertia // If falling, add part of the incoming velocity with the current inertia
velocity = velocity*time + physicActor->getInertialForce(); velocity = velocity * time + physicActor->getInertialForce();
} }
inertia = velocity; inertia = velocity; // REM velocity is for z axis only in this code block
if(!(movement.z > 0.0f)) if(!(movement.z > 0.0f))
{ {
wasOnGround = physicActor->getOnGround(); wasOnGround = physicActor->getOnGround();
tracer.doTrace(colobj, position, position-Ogre::Vector3(0,0,2), engine); // TODO: Find out if there is a significance with the value 2 used here
tracer.doTrace(colobj, position, position - Ogre::Vector3(0,0,2), engine);
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope) if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
isOnGround = true; isOnGround = true;
} }
@ -163,24 +184,38 @@ namespace MWWorld
if(isOnGround) if(isOnGround)
{ {
// if we're on the ground, don't try to fall // if we're on the ground, don't try to fall
velocity.z = std::max(0.0f, velocity.z); velocity.z = std::max(0.0f, velocity.z); // NOTE: two different velocity assignments above
} }
Ogre::Vector3 newPosition = position; Ogre::Vector3 newPosition = position;
/*
* A loop to find newPosition using tracer, if successful different from the starting position.
* nextpos is the local variable used to find potential newPosition, using velocity and remainingTime
* The initial velocity was set earlier (see above).
*/
float remainingTime = time; float remainingTime = time;
for(int iterations = 0;iterations < sMaxIterations && remainingTime > 0.01f;++iterations) for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations)
{ {
Ogre::Vector3 nextpos = newPosition + velocity*remainingTime; Ogre::Vector3 nextpos = newPosition + velocity * remainingTime;
if(newPosition.z < waterlevel && !isFlying && // If not able to fly, walk or bipedal don't allow to move out of water
nextpos.z > waterlevel && newPosition.z <= waterlevel) // TODO: this if condition may not work for large creatures or situations
// where the creature gets above the waterline for some reason
if(newPosition.z < waterlevel && // started 3/4 under water
!isFlying && // can't fly
!canWalk && // can't walk
!isBipedal && // not bipedal (assume bipedals can walk)
!isNpc && // FIXME: shouldn't really need this
nextpos.z > waterlevel && // but about to go above water
newPosition.z <= waterlevel)
{ {
const Ogre::Vector3 down(0,0,-1); const Ogre::Vector3 down(0,0,-1);
Ogre::Real movelen = velocity.normalise(); Ogre::Real movelen = velocity.normalise();
Ogre::Vector3 reflectdir = velocity.reflect(down); Ogre::Vector3 reflectdir = velocity.reflect(down);
reflectdir.normalise(); reflectdir.normalise();
velocity = slide(reflectdir, down)*movelen; velocity = slide(reflectdir, down)*movelen;
continue; // NOTE: remainingTime is unchanged before the loop continues
continue; // velocity updated, calculate nextpos again
} }
// trace to where character would go if there were no obstructions // trace to where character would go if there were no obstructions
@ -189,13 +224,14 @@ namespace MWWorld
// check for obstructions // check for obstructions
if(tracer.mFraction >= 1.0f) if(tracer.mFraction >= 1.0f)
{ {
newPosition = tracer.mEndPos; newPosition = tracer.mEndPos; // ok to move, so set newPosition
remainingTime *= (1.0f-tracer.mFraction); remainingTime *= (1.0f-tracer.mFraction); // FIXME: remainingTime is no longer used so don't set it?
break; break;
} }
// We hit something. Try to step up onto it. // We hit something. Try to step up onto it.
if(stepMove(colobj, newPosition, velocity, remainingTime, engine)) // NOTE: May need to stop slaughterfish step out of the water.
if((canWalk || isBipedal || isNpc) && stepMove(colobj, newPosition, velocity, remainingTime, engine))
isOnGround = !(newPosition.z < waterlevel || isFlying); // Only on the ground if there's gravity isOnGround = !(newPosition.z < waterlevel || isFlying); // Only on the ground if there's gravity
else else
{ {
@ -214,7 +250,7 @@ namespace MWWorld
if(isOnGround || wasOnGround) if(isOnGround || wasOnGround)
{ {
tracer.doTrace(colobj, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+2.0f), engine); tracer.doTrace(colobj, newPosition, newPosition - Ogre::Vector3(0,0,sStepSize+2.0f), engine);
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope) if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
{ {
newPosition.z = tracer.mEndPos.z + 1.0f; newPosition.z = tracer.mEndPos.z + 1.0f;
@ -236,7 +272,7 @@ namespace MWWorld
} }
physicActor->setOnGround(isOnGround); physicActor->setOnGround(isOnGround);
newPosition.z -= halfExtents.z; newPosition.z -= halfExtents.z; // remove what was added at the beggining
return newPosition; return newPosition;
} }
}; };

@ -1649,7 +1649,7 @@ namespace MWWorld
if (ptr.getClass().getCreatureStats(ptr).isDead()) if (ptr.getClass().getCreatureStats(ptr).isDead())
return false; return false;
if (ptr.getClass().isFlying(ptr)) if (ptr.getClass().canFly(ptr))
return true; return true;
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);

Loading…
Cancel
Save