1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 09:23:53 +00:00

Added stuck mitigation for AiAvoidDoor

This commit is contained in:
Thomas 2014-05-14 13:38:10 -04:00
parent 993ef1be43
commit 2425d2c2ab
3 changed files with 36 additions and 19 deletions

View file

@ -13,32 +13,45 @@
#include "steering.hpp"
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr)
: AiPackage(), mDoorPtr(doorPtr), mDuration(1)
: AiPackage(), mDoorPtr(doorPtr), mDuration(1), mAdjAngle(0)
{
}
bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration)
{
ESM::Position pos = actor.getRefData().getPosition();
if(mDuration = 1) //If it just started, get the actor position as the stuck detection thing
mLastPos = pos;
mDuration -= duration; //Update timer
if(mDuration < 0)
return true; // We have tried backing up for more than one second, we've probably cleared it
if(mDuration < 0) {
float x = pos.pos[0] - mLastPos.pos[0];
float y = pos.pos[1] - mLastPos.pos[1];
float z = pos.pos[2] - mLastPos.pos[2];
int distance = x * x + y * y + z * z;
if(distance < 10 * 10) { //Got stuck, didn't move
if(mAdjAngle == 0) //Try going in various directions
mAdjAngle = 1.57079632679f; //pi/2
else if (mAdjAngle == 1.57079632679f)
mAdjAngle = -1.57079632679;
else
mAdjAngle = 0;
mDuration = 1; //reset timer
}
else //Not stuck
return true; // We have tried backing up for more than one second, we've probably cleared it
}
if(!MWBase::Environment::get().getWorld()->getIsMovingDoor(mDoorPtr))
return true; //Door is no longer opening
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
float x = pos.pos[0] - tPos.pos[0];
float y = pos.pos[1] - tPos.pos[1];
float z = pos.pos[2] - tPos.pos[2];
int distance = sqrt(x * x + y * y + z * z);
if(distance > 300) //Stop backing up when you're far enough away
return true;
/// TODO: Calculate this from door size, not have it built in
float dirToDoor = std::atan2(x,y) + pos.rot[2]; //Calculates the direction to the door, relative to the direction of the NPC
float dirToDoor = std::atan2(x,y) + pos.rot[2] + mAdjAngle; //Calculates the direction to the door, relative to the direction of the NPC
// For example, if the NPC is directly facing the door this will be pi/2
// Make actor move away from the door
@ -47,7 +60,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration
//Make all nearby actors also avoid the door
std::vector<MWWorld::Ptr> actors;
MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(pos.pos[0],pos.pos[1],pos.pos[2]),50,actors);
MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(pos.pos[0],pos.pos[1],pos.pos[2]),100,actors);
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); it++) {
if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player
MWMechanics::AiSequence& seq = MWWorld::Class::get(*it).getCreatureStats(*it).getAiSequence();

View file

@ -29,7 +29,9 @@ namespace MWMechanics
private:
float mDuration;
const MWWorld::Ptr& mDoorPtr;
const MWWorld::Ptr& mDoorPtr;
ESM::Position mLastPos;
float mAdjAngle;
};
}
#endif

View file

@ -1209,16 +1209,18 @@ namespace MWWorld
for (std::vector<std::string>::iterator cit = collisions.begin(); cit != collisions.end(); ++cit)
{
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
if (MWWorld::Class::get(ptr).isActor() && ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() )
if (MWWorld::Class::get(ptr).isActor())
{
// Collided with actor, ask actor to try to avoid door
MWMechanics::AiSequence& seq = MWWorld::Class::get(ptr).getCreatureStats(ptr).getAiSequence();
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr);
if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) {
MWMechanics::AiSequence& seq = MWWorld::Class::get(ptr).getCreatureStats(ptr).getAiSequence();
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr);
}
// we need to undo the rotation
localRotateObject(it->first, 0, 0, oldRot);
//break; //Removed in case ultiple actors are touching
//break; //Removed in case multiple actors are touching
}
}