merge master, resolve conflicts
commit
aa5647b45e
@ -0,0 +1,90 @@
|
||||
#include "aiavoiddoor.hpp"
|
||||
#include <iostream>
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "mechanicsmanagerimp.hpp"
|
||||
|
||||
#include <OgreMath.h>
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr)
|
||||
: 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) {
|
||||
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 (!mDoorPtr.getClass().getDoorState(mDoorPtr))
|
||||
return true; //Door is no longer opening
|
||||
|
||||
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 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
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = -1 * std::sin(dirToDoor); //I knew I'd use trig someday
|
||||
actor.getClass().getMovementSettings(actor).mPosition[0] = -1 * std::cos(dirToDoor);
|
||||
|
||||
//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]),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();
|
||||
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) { //Only add it once
|
||||
seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string MWMechanics::AiAvoidDoor::getAvoidedDoor()
|
||||
{
|
||||
return mDoorPtr.getCellRef().mRefID;
|
||||
}
|
||||
|
||||
MWMechanics::AiAvoidDoor *MWMechanics::AiAvoidDoor::clone() const
|
||||
{
|
||||
return new AiAvoidDoor(*this);
|
||||
}
|
||||
|
||||
int MWMechanics::AiAvoidDoor::getTypeId() const
|
||||
{
|
||||
return TypeIdAvoidDoor;
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
#ifndef GAME_MWMECHANICS_AIAVOIDDOOR_H
|
||||
#define GAME_MWMECHANICS_AIAVOIDDOOR_H
|
||||
|
||||
#include "aipackage.hpp"
|
||||
#include <string>
|
||||
#include "pathfinding.hpp"
|
||||
#include <components/esm/defs.hpp>
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
/// \brief AiPackage to have an actor avoid an opening door
|
||||
/** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
|
||||
**/
|
||||
class AiAvoidDoor : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Avoid door until the door is fully open
|
||||
AiAvoidDoor(const MWWorld::Ptr& doorPtr);
|
||||
|
||||
virtual AiAvoidDoor *clone() const;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||
|
||||
virtual int getTypeId() const;
|
||||
|
||||
/// Returns the door being avoided
|
||||
std::string getAvoidedDoor();
|
||||
|
||||
private:
|
||||
float mDuration;
|
||||
MWWorld::Ptr mDoorPtr;
|
||||
ESM::Position mLastPos;
|
||||
float mAdjAngle;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,43 +1,45 @@
|
||||
#ifndef GAME_MWMECHANICS_AIFALLOW_H
|
||||
#define GAME_MWMECHANICS_AIFALLOW_H
|
||||
#ifndef GAME_MWMECHANICS_AIFOLLOW_H
|
||||
#define GAME_MWMECHANICS_AIFOLLOW_H
|
||||
|
||||
#include "aipackage.hpp"
|
||||
#include <string>
|
||||
#include "pathfinding.hpp"
|
||||
#include "../../../components/esm/defs.hpp"
|
||||
#include <components/esm/defs.hpp>
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
class AiFollow : public AiPackage
|
||||
{
|
||||
/// \brief AiPackage for an actor to follow another actor/the PC
|
||||
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
||||
**/
|
||||
class AiFollow : public AiPackage
|
||||
{
|
||||
public:
|
||||
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
|
||||
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||
AiFollow(const std::string &ActorId);
|
||||
/// Follow Actor for duration or until you arrive at a world position
|
||||
AiFollow(const MWWorld::Ptr& actor,float duration, float X, float Y, float Z);
|
||||
/// Follow Actor for duration or until you arrive at a position in a cell
|
||||
AiFollow(const MWWorld::Ptr& actor,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||
/// Follow Actor indefinitively
|
||||
AiFollow(const MWWorld::Ptr& actor);
|
||||
|
||||
virtual AiFollow *clone() const;
|
||||
|
||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||
///< \return Package completed?
|
||||
|
||||
virtual int getTypeId() const;
|
||||
|
||||
/// Returns the actor being followed
|
||||
std::string getFollowedActor();
|
||||
|
||||
private:
|
||||
bool mAlwaysFollow; //this will make the actor always follow, thus ignoring mDuration and mX,mY,mZ (used for summoned creatures).
|
||||
/// This will make the actor always follow.
|
||||
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
||||
bool mAlwaysFollow;
|
||||
float mDuration;
|
||||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
std::string mActorId;
|
||||
std::string mCellId;
|
||||
|
||||
float mTimer;
|
||||
float mStuckTimer;
|
||||
float mTotalTime;
|
||||
|
||||
ESM::Position mStuckPos;
|
||||
|
||||
PathFinder mPathFinder;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
int mActorId; // The actor we should follow
|
||||
std::string mCellId;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,4 +1,131 @@
|
||||
|
||||
#include "aipackage.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "../mwworld/action.hpp"
|
||||
|
||||
#include <OgreMath.h>
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
MWMechanics::AiPackage::~AiPackage() {}
|
||||
|
||||
MWMechanics::AiPackage::AiPackage() : mLastDoorChecked(MWWorld::Ptr()), mTimer(.26), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration)
|
||||
{
|
||||
//Update various Timers
|
||||
mTimer += duration; //Update timer
|
||||
mStuckTimer += duration; //Update stuck timer
|
||||
mTotalTime += duration; //Update total time following
|
||||
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||
|
||||
/// Stops the actor when it gets too close to a unloaded cell
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
const ESM::Cell *cell = actor.getCell()->getCell();
|
||||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
||||
|
||||
//Ensure pursuer doesn't leave loaded cells
|
||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
||||
{
|
||||
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(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
{
|
||||
movement.mPosition[1] = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Start position
|
||||
ESM::Pathgrid::Point start = pos.pos;
|
||||
|
||||
//***********************
|
||||
/// Checks if you can't get to the end position at all, adds end position to end of path
|
||||
/// Rebuilds path every quarter of a second, in case the target has moved
|
||||
//***********************
|
||||
if(mTimer > 0.25)
|
||||
{
|
||||
if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
|
||||
mPrevDest = dest;
|
||||
}
|
||||
|
||||
if(!mPathFinder.getPath().empty()) //Path has points in it
|
||||
{
|
||||
ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
|
||||
|
||||
if(distance(dest, lastPos) > 100) //End of the path is far from the destination
|
||||
mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
|
||||
}
|
||||
|
||||
mTimer = 0;
|
||||
}
|
||||
|
||||
//************************
|
||||
/// Checks if you aren't moving; attempts to unstick you
|
||||
//************************
|
||||
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
|
||||
{
|
||||
/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason
|
||||
//if(mObstacleCheck.check(actor, duration)) {
|
||||
if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care
|
||||
// first check if we're walking into a door
|
||||
MWWorld::Ptr door = getNearbyDoor(actor);
|
||||
if(door != MWWorld::Ptr()) // NOTE: checks interior cells only
|
||||
{
|
||||
if(door.getCellRef().mTrap.empty() && mLastDoorChecked != door) { //Open the door if untrapped
|
||||
door.getClass().activate(door, 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 { //Not stuck, so reset things
|
||||
mStuckTimer = 0;
|
||||
mStuckPos = pos;
|
||||
mLastDoorChecked = MWWorld::Ptr(); //Resets it, in case he gets stuck behind the door again
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward
|
||||
}
|
||||
}
|
||||
else {
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
|
||||
}
|
||||
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue