mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-03 20:45:33 +00:00
Changed implementations of aifollow/pursue/activate slightly, added ability for NPCs to go through unlocked doors (They even try locked ones), and step back from opening doors (Although it still needs some work)
Notes - When the door hits them while it's about to finish closing they will try to walk through the door. - Considerably more works is needed in making the NPC work out troublesome areas where they get stuck
This commit is contained in:
parent
2c74ea381e
commit
cbfa282f8d
14 changed files with 149 additions and 128 deletions
|
@ -67,7 +67,7 @@ add_openmw_dir (mwclass
|
||||||
|
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow
|
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
||||||
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat steering obstacle
|
disease pickpocket levelledlist combat steering obstacle
|
||||||
)
|
)
|
||||||
|
|
|
@ -390,10 +390,14 @@ namespace MWBase
|
||||||
virtual void setupPlayer() = 0;
|
virtual void setupPlayer() = 0;
|
||||||
virtual void renderPlayer() = 0;
|
virtual void renderPlayer() = 0;
|
||||||
|
|
||||||
|
/// if activated, should this door be opened or closed?
|
||||||
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0;
|
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0;
|
||||||
///< if activated, should this door be opened or closed?
|
|
||||||
|
/// activate (open or close) an non-teleport door
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
||||||
///< activate (open or close) an non-teleport door
|
|
||||||
|
/// Is door currently opening/closing?
|
||||||
|
virtual bool getIsMovingDoor(const MWWorld::Ptr& door) = 0;
|
||||||
|
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
||||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
||||||
|
|
|
@ -19,83 +19,27 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
||||||
return new AiActivate(*this);
|
return new AiActivate(*this);
|
||||||
}
|
}
|
||||||
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
|
||||||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
|
||||||
const ESM::Cell *cell = actor.getCell()->getCell();
|
if(target == MWWorld::Ptr())
|
||||||
|
return true; //Target doesn't exist
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
|
||||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
//Set the target desition from the actor
|
||||||
{
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
|
||||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { //Stop when you get close
|
||||||
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||||
{
|
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
||||||
movement.mPosition[1] = 0;
|
return true;
|
||||||
return false;
|
}
|
||||||
}
|
else {
|
||||||
}
|
pathTo(actor, dest, duration); //Go to the destination
|
||||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
{
|
}
|
||||||
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
|
||||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
|
||||||
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
|
||||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr target = world->searchPtr(mObjectId,false);
|
|
||||||
if(target == MWWorld::Ptr()) return true;
|
|
||||||
|
|
||||||
ESM::Position targetPos = target.getRefData().getPosition();
|
|
||||||
|
|
||||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
|
||||||
{
|
|
||||||
mCellX = cell->mData.mX;
|
|
||||||
mCellY = cell->mData.mY;
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
|
||||||
dest.mX = targetPos.pos[0];
|
|
||||||
dest.mY = targetPos.pos[1];
|
|
||||||
dest.mZ = targetPos.pos[2];
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point start;
|
|
||||||
start.mX = pos.pos[0];
|
|
||||||
start.mY = pos.pos[1];
|
|
||||||
start.mZ = pos.pos[2];
|
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
|
|
||||||
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
|
|
||||||
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200)
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
|
||||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
|
||||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
|
||||||
zTurn(actor, Ogre::Degree(zAngle));
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
|
||||||
movement.mPosition[1] = 1;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Causes actor to walk to activatable object and activate it
|
/// \brief Causes actor to walk to activatable object and activate it
|
||||||
|
/** Will actiavte when close to object or path grid complete **/
|
||||||
class AiActivate : public AiPackage
|
class AiActivate : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -21,8 +22,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mObjectId;
|
std::string mObjectId;
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
|
||||||
int mCellX;
|
int mCellX;
|
||||||
int mCellY;
|
int mCellY;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,23 +12,17 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId("")
|
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), AiPackage()
|
||||||
{
|
{
|
||||||
mTimer = 0;
|
|
||||||
mStuckTimer = 0;
|
|
||||||
}
|
}
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId)
|
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), AiPackage()
|
||||||
{
|
{
|
||||||
mTimer = 0;
|
|
||||||
mStuckTimer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
||||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId("")
|
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), AiPackage()
|
||||||
{
|
{
|
||||||
mTimer = 0;
|
|
||||||
mStuckTimer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIFALLOW_H
|
#ifndef GAME_MWMECHANICS_AIFOLLOW_H
|
||||||
#define GAME_MWMECHANICS_AIFALLOW_H
|
#define GAME_MWMECHANICS_AIFOLLOW_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "aipackage.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
#include "../mwworld/action.hpp"
|
||||||
|
|
||||||
#include <OgreMath.h>
|
#include <OgreMath.h>
|
||||||
|
|
||||||
|
@ -15,13 +16,18 @@
|
||||||
|
|
||||||
MWMechanics::AiPackage::~AiPackage() {}
|
MWMechanics::AiPackage::~AiPackage() {}
|
||||||
|
|
||||||
|
MWMechanics::AiPackage::AiPackage() : mLastDoorChecked(NULL), mTimer(0), mStuckTimer(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration)
|
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration)
|
||||||
{
|
{
|
||||||
//Update various Timers
|
//Update various Timers
|
||||||
mTimer = mTimer + duration; //Update timer
|
mTimer += duration; //Update timer
|
||||||
mStuckTimer = mStuckTimer + duration; //Update stuck timer
|
mStuckTimer += duration; //Update stuck timer
|
||||||
mTotalTime = mTotalTime + duration; //Update total time following
|
mTotalTime += duration; //Update total time following
|
||||||
|
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
|
|
||||||
|
@ -78,18 +84,45 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
|
||||||
//************************
|
//************************
|
||||||
/// Checks if you aren't moving; attempts to unstick you
|
/// Checks if you aren't moving; attempts to unstick you
|
||||||
//************************
|
//************************
|
||||||
if(mStuckTimer>0.5) //Checks every half of a second
|
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished?
|
||||||
|
return true;
|
||||||
|
else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something
|
||||||
{
|
{
|
||||||
if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10) //NPC hasn't moved much is half a second, he's stuck
|
/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
//if(mObstacleCheck.check(actor, duration)) {
|
||||||
|
if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10) { //Actually stuck
|
||||||
mStuckTimer = 0;
|
// first check if we're walking into a door
|
||||||
mStuckPos = pos;
|
MWWorld::LiveCellRef<ESM::Door>* door = getNearbyDoor(actor);
|
||||||
|
if(door != NULL) // NOTE: checks interior cells only
|
||||||
|
{
|
||||||
|
if(door->mRef.mTrap.empty() && mLastDoorChecked != door) { //Open the door if untrapped
|
||||||
|
door->mClass->activate(MWBase::Environment::get().getWorld()->getPtr(door->mRef.mRefID,false), actor).get()->execute(actor);
|
||||||
|
mLastDoorChecked = door;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // probably walking into another NPC
|
||||||
|
{
|
||||||
|
// TODO: diagonal should have same animation as walk forward
|
||||||
|
// but doesn't seem to do that?
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f;
|
||||||
|
// change the angle a bit, too
|
||||||
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
||||||
|
}
|
||||||
|
/*else if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10) { //NPC hasn't moved much is half a second, he's stuck
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mStuckTimer = 0;
|
||||||
|
mStuckPos = pos;
|
||||||
|
mLastDoorChecked = NULL; //Resets it, in case he gets stuck behind the door again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Checks if the path isn't over, turn tomards the direction that you're going
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||||
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
|
||||||
{
|
|
||||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
#include "../../../components/esm/defs.hpp"
|
#include "../../../components/esm/defs.hpp"
|
||||||
|
|
||||||
|
#include "obstacle.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -24,9 +26,13 @@ namespace MWMechanics
|
||||||
TypeIdFollow = 3,
|
TypeIdFollow = 3,
|
||||||
TypeIdActivate = 4,
|
TypeIdActivate = 4,
|
||||||
TypeIdCombat = 5,
|
TypeIdCombat = 5,
|
||||||
TypeIdPursue = 6
|
TypeIdPursue = 6,
|
||||||
|
TypeIdAvoidDoor = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///Default constructor
|
||||||
|
AiPackage();
|
||||||
|
|
||||||
///Default Deconstructor
|
///Default Deconstructor
|
||||||
virtual ~AiPackage();
|
virtual ~AiPackage();
|
||||||
|
|
||||||
|
@ -50,10 +56,14 @@ namespace MWMechanics
|
||||||
bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration);
|
bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration);
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
|
ObstacleCheck mObstacleCheck;
|
||||||
|
|
||||||
|
float mDoorCheckDuration;
|
||||||
float mTimer;
|
float mTimer;
|
||||||
float mStuckTimer;
|
float mStuckTimer;
|
||||||
float mTotalTime;
|
float mTotalTime;
|
||||||
|
|
||||||
|
MWWorld::LiveCellRef<ESM::Door>* mLastDoorChecked; //Used to ensure we don't try to CONSTANTLY open a door
|
||||||
|
|
||||||
ESM::Position mStuckPos;
|
ESM::Position mStuckPos;
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,16 +31,15 @@ bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
||||||
//Set the target desition from the actor
|
//Set the target desition from the actor
|
||||||
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
|
|
||||||
pathTo(actor, dest, duration); //Go to the destination
|
|
||||||
|
|
||||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) { //Stop when you get close
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) { //Stop when you get close
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
pathTo(actor, dest, duration); //Go to the destination
|
||||||
|
}
|
||||||
|
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Makes the actor very closely follow the actor
|
/// \brief Makes the actor very closely follow the actor
|
||||||
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them. **/
|
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them.
|
||||||
|
Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the
|
||||||
|
path is completed). **/
|
||||||
class AiPursue : public AiPackage
|
class AiPursue : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -19,11 +19,19 @@ namespace MWMechanics
|
||||||
// Limitation: there can be false detections, and does not test whether the
|
// Limitation: there can be false detections, and does not test whether the
|
||||||
// actor is facing the door.
|
// actor is facing the door.
|
||||||
bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed)
|
bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed)
|
||||||
|
{
|
||||||
|
if(getNearbyDoor(actor, minSqr, closed)!=NULL)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::LiveCellRef<ESM::Door>* getNearbyDoor(const MWWorld::Ptr& actor, float minSqr, bool closed)
|
||||||
{
|
{
|
||||||
MWWorld::CellStore *cell = actor.getCell();
|
MWWorld::CellStore *cell = actor.getCell();
|
||||||
|
|
||||||
if(cell->getCell()->isExterior())
|
if(cell->getCell()->isExterior())
|
||||||
return false; // check interior cells only
|
return NULL; // check interior cells only
|
||||||
|
|
||||||
// Check all the doors in this cell
|
// Check all the doors in this cell
|
||||||
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
||||||
|
@ -31,14 +39,14 @@ namespace MWMechanics
|
||||||
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin();
|
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin();
|
||||||
Ogre::Vector3 pos(actor.getRefData().getPosition().pos);
|
Ogre::Vector3 pos(actor.getRefData().getPosition().pos);
|
||||||
|
|
||||||
// TODO: How to check whether the actor is facing a door? Below code is for
|
/// TODO: How to check whether the actor is facing a door? Below code is for
|
||||||
// the player, perhaps it can be adapted.
|
/// the player, perhaps it can be adapted.
|
||||||
//MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
//MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||||
//if(!ptr.isEmpty())
|
//if(!ptr.isEmpty())
|
||||||
//std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl;
|
//std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl;
|
||||||
|
|
||||||
// TODO: The in-game observation of rot[2] value seems to be the
|
/// TODO: The in-game observation of rot[2] value seems to be the
|
||||||
// opposite of the code in World::activateDoor() ::confused::
|
/// opposite of the code in World::activateDoor() ::confused::
|
||||||
for (; it != refList.end(); ++it)
|
for (; it != refList.end(); ++it)
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
||||||
|
@ -46,10 +54,10 @@ namespace MWMechanics
|
||||||
if((closed && ref.mData.getLocalRotation().rot[2] == 0) ||
|
if((closed && ref.mData.getLocalRotation().rot[2] == 0) ||
|
||||||
(!closed && ref.mData.getLocalRotation().rot[2] >= 1))
|
(!closed && ref.mData.getLocalRotation().rot[2] >= 1))
|
||||||
{
|
{
|
||||||
return true; // found, stop searching
|
return &ref; // found, stop searching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false; // none found
|
return NULL; // none found
|
||||||
}
|
}
|
||||||
|
|
||||||
ObstacleCheck::ObstacleCheck():
|
ObstacleCheck::ObstacleCheck():
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
||||||
#define OPENMW_MECHANICS_OBSTACLE_H
|
#define OPENMW_MECHANICS_OBSTACLE_H
|
||||||
|
|
||||||
|
//#include "../mwbase/world.hpp"
|
||||||
|
//#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -8,14 +12,20 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
// NOTE: determined empirically based on in-game behaviour
|
/// NOTE: determined empirically based on in-game behaviour
|
||||||
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
|
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
|
||||||
|
|
||||||
// tests actor's proximity to a closed door by default
|
/// tests actor's proximity to a closed door by default
|
||||||
bool proximityToDoor(const MWWorld::Ptr& actor,
|
bool proximityToDoor(const MWWorld::Ptr& actor,
|
||||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED,
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED,
|
||||||
bool closed = true);
|
bool closed = true);
|
||||||
|
|
||||||
|
/// Returns door pointer within range. No guarentee is given as too which one
|
||||||
|
/** \return Pointer to the door, or NULL if none exists **/
|
||||||
|
MWWorld::LiveCellRef<ESM::Door>* getNearbyDoor(const MWWorld::Ptr& actor,
|
||||||
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED,
|
||||||
|
bool closed = true);
|
||||||
|
|
||||||
class ObstacleCheck
|
class ObstacleCheck
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/levelledlist.hpp"
|
#include "../mwmechanics/levelledlist.hpp"
|
||||||
#include "../mwmechanics/combat.hpp"
|
#include "../mwmechanics/combat.hpp"
|
||||||
|
#include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors
|
||||||
|
|
||||||
#include "../mwrender/sky.hpp"
|
#include "../mwrender/sky.hpp"
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
@ -1210,7 +1211,11 @@ namespace MWWorld
|
||||||
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
|
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
|
||||||
if (MWWorld::Class::get(ptr).isActor())
|
if (MWWorld::Class::get(ptr).isActor())
|
||||||
{
|
{
|
||||||
// we collided with an actor, we need to undo the rotation
|
// 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);
|
||||||
|
// we need to undo the rotation
|
||||||
localRotateObject(it->first, 0, 0, oldRot);
|
localRotateObject(it->first, 0, 0, oldRot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1853,6 +1858,16 @@ namespace MWWorld
|
||||||
return door.getRefData().getLocalRotation().rot[2] == 0;
|
return door.getRefData().getLocalRotation().rot[2] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::getIsMovingDoor(const Ptr& door)
|
||||||
|
{
|
||||||
|
//This more expensive comparison is needed for some reason
|
||||||
|
// TODO (tluppi#1#): Figure out why comparing Ptr isn't working
|
||||||
|
for(std::map<MWWorld::Ptr, int>::iterator it = mDoorStates.begin(); it != mDoorStates.end(); it++)
|
||||||
|
if(it->first.getCellRef().mRefID == door.getCellRef().mRefID)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool World::getPlayerStandingOn (const MWWorld::Ptr& object)
|
bool World::getPlayerStandingOn (const MWWorld::Ptr& object)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = mPlayer->getPlayer();
|
MWWorld::Ptr player = mPlayer->getPlayer();
|
||||||
|
@ -1919,7 +1934,7 @@ namespace MWWorld
|
||||||
out.push_back(searchPtrViaHandle(*it));
|
out.push_back(searchPtrViaHandle(*it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc)
|
bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc)
|
||||||
{
|
{
|
||||||
if (!targetNpc.getRefData().isEnabled() || !npc.getRefData().isEnabled())
|
if (!targetNpc.getRefData().isEnabled() || !npc.getRefData().isEnabled())
|
||||||
|
|
|
@ -493,10 +493,13 @@ namespace MWWorld
|
||||||
virtual void setupPlayer();
|
virtual void setupPlayer();
|
||||||
virtual void renderPlayer();
|
virtual void renderPlayer();
|
||||||
|
|
||||||
|
/// if activated, should this door be opened or closed?
|
||||||
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door);
|
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door);
|
||||||
///< if activated, should this door be opened or closed?
|
|
||||||
|
/// activate (open or close) an non-teleport door
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door);
|
virtual void activateDoor(const MWWorld::Ptr& door);
|
||||||
///< activate (open or close) an non-teleport door
|
|
||||||
|
virtual bool getIsMovingDoor(const MWWorld::Ptr& door);
|
||||||
|
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object
|
||||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
|
virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
|
||||||
|
|
Loading…
Reference in a new issue