mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 09:45:36 +00:00
Moved pathfinding code to aiPackage, implemented it's use with aiFollow and aiPursue
This commit is contained in:
parent
645d174a96
commit
2c74ea381e
10 changed files with 181 additions and 171 deletions
|
@ -12,17 +12,23 @@
|
|||
#include "steering.hpp"
|
||||
|
||||
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(""), mTimer(0), mStuckTimer(0)
|
||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId("")
|
||||
{
|
||||
mTimer = 0;
|
||||
mStuckTimer = 0;
|
||||
}
|
||||
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), mTimer(0), mStuckTimer(0)
|
||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId)
|
||||
{
|
||||
mTimer = 0;
|
||||
mStuckTimer = 0;
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId("")
|
||||
{
|
||||
mTimer = 0;
|
||||
mStuckTimer = 0;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||
|
@ -31,10 +37,6 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||
|
||||
if(target == MWWorld::Ptr()) return true; //Target doesn't exist
|
||||
|
||||
mTimer = mTimer + duration; //Update timer
|
||||
mStuckTimer = mStuckTimer + duration; //Update stuck timer
|
||||
mTotalTime = mTotalTime + duration; //Update total time following
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||
|
||||
if(!mAlwaysFollow) //Update if you only follow for a bit
|
||||
|
@ -60,74 +62,19 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||
}
|
||||
|
||||
//Set the target desition from the actor
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = target.getRefData().getPosition().pos[0];
|
||||
dest.mY = target.getRefData().getPosition().pos[1];
|
||||
dest.mZ = target.getRefData().getPosition().pos[2];
|
||||
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||
|
||||
//Current position, for pathfilding stuff
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
pathTo(actor, dest, duration); //Go to the destination
|
||||
|
||||
//Build the path to get to the destination
|
||||
if(mPathFinder.getPath().empty())
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||
|
||||
//***********************
|
||||
// Checks if you can't get to the end position at all
|
||||
//***********************
|
||||
if(mTimer > 0.25)
|
||||
{
|
||||
if(!mPathFinder.getPath().empty()) //Path has points in it
|
||||
{
|
||||
ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
|
||||
|
||||
if((dest.mX - lastPos.mX)*(dest.mX - lastPos.mX)
|
||||
+(dest.mY - lastPos.mY)*(dest.mY - lastPos.mY)
|
||||
+(dest.mZ - lastPos.mZ)*(dest.mZ - lastPos.mZ)
|
||||
> 100*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; you're stuck
|
||||
//************************
|
||||
if(mStuckTimer>0.5) //Checks every half of a second
|
||||
{
|
||||
if((mStuckPos.pos[0] - pos.pos[0])*(mStuckPos.pos[0] - pos.pos[0])
|
||||
+(mStuckPos.pos[1] - pos.pos[1])*(mStuckPos.pos[1] - pos.pos[1])
|
||||
+(mStuckPos.pos[2] - pos.pos[2])*(mStuckPos.pos[2] - pos.pos[2]) < 100) //NPC is stuck
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||
|
||||
mStuckTimer = 0;
|
||||
mStuckPos = pos;
|
||||
}
|
||||
|
||||
//Checks if the path isn't over, turn tomards the direction that you're going
|
||||
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
}
|
||||
|
||||
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
||||
< 100*100)
|
||||
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;
|
||||
else
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
//Check if you're far away
|
||||
if((dest.mX - start.mX)*(dest.mX - start.mX)
|
||||
+(dest.mY - start.mY)*(dest.mY - start.mY)
|
||||
+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) > 1000*1000)
|
||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) > 1000)
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||
else if((dest.mX - start.mX)*(dest.mX - start.mX) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
||||
+(dest.mY - start.mY)*(dest.mY - start.mY)
|
||||
+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) < 800*800)
|
||||
else if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 800) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||
|
||||
return false;
|
||||
|
|
|
@ -40,14 +40,6 @@ namespace MWMechanics
|
|||
float mZ;
|
||||
std::string mActorId;
|
||||
std::string mCellId;
|
||||
|
||||
float mTimer;
|
||||
float mStuckTimer;
|
||||
float mTotalTime;
|
||||
|
||||
ESM::Position mStuckPos;
|
||||
|
||||
PathFinder mPathFinder;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,95 @@
|
|||
|
||||
#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 <OgreMath.h>
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
MWMechanics::AiPackage::~AiPackage() {}
|
||||
|
||||
|
||||
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration)
|
||||
{
|
||||
//Update various Timers
|
||||
mTimer = mTimer + duration; //Update timer
|
||||
mStuckTimer = mStuckTimer + duration; //Update stuck timer
|
||||
mTotalTime = 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)
|
||||
{
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
|
||||
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(mStuckTimer>0.5) //Checks every half of a second
|
||||
{
|
||||
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
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||
|
||||
mStuckTimer = 0;
|
||||
mStuckPos = pos;
|
||||
}
|
||||
|
||||
//Checks if the path isn't over, turn tomards the direction that you're going
|
||||
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef GAME_MWMECHANICS_AIPACKAGE_H
|
||||
#define GAME_MWMECHANICS_AIPACKAGE_H
|
||||
|
||||
#include "pathfinding.hpp"
|
||||
#include "../../../components/esm/defs.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
|
@ -38,8 +41,21 @@ namespace MWMechanics
|
|||
/// \see enum TypeId
|
||||
virtual int getTypeId() const = 0;
|
||||
|
||||
/// Higher number is higher priority (0 beeing the lowest)
|
||||
/// Higher number is higher priority (0 being the lowest)
|
||||
virtual unsigned int getPriority() const {return 0;}
|
||||
|
||||
protected:
|
||||
/// Causes the actor to attempt to walk to the specified location
|
||||
/** \return If the actor has arrived at his destination **/
|
||||
bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration);
|
||||
|
||||
PathFinder mPathFinder;
|
||||
|
||||
float mTimer;
|
||||
float mStuckTimer;
|
||||
float mTotalTime;
|
||||
|
||||
ESM::Position mStuckPos;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -21,75 +21,28 @@ MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const
|
|||
}
|
||||
bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
||||
const ESM::Cell *cell = actor.getCell()->getCell();
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
|
||||
|
||||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(target == MWWorld::Ptr())
|
||||
return true; //Target doesn't exist
|
||||
|
||||
// Big TODO: Sync this with current AiFollow. Move common code to a shared base class or helpers (applies to all AI packages, way too much duplicated code)
|
||||
//Set the target desition from the actor
|
||||
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||
|
||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
||||
ESM::Position targetPos = target.getRefData().getPosition();
|
||||
pathTo(actor, dest, duration); //Go to the destination
|
||||
|
||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
||||
if(!mPathFinder.isPathConstructed() || cellChange || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
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]) < 100*100)
|
||||
{
|
||||
movement.mPosition[1] = 0;
|
||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
||||
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;
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
||||
return true;
|
||||
}
|
||||
else
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
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;
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -9,18 +9,12 @@
|
|||
namespace MWMechanics
|
||||
{
|
||||
/// \brief Makes the actor very closely follow the actor
|
||||
/** Used for getting closer to fight, or to arrest (I think?) **/
|
||||
class AiPersue : public AiPackage
|
||||
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them. **/
|
||||
class AiPursue : public AiPackage
|
||||
{
|
||||
public:
|
||||
///Constructor
|
||||
/** \param objectId Actor to pursue **/
|
||||
AiPersue(const std::string &objectId);
|
||||
virtual AiPersue *clone() const;
|
||||
|
||||
class AiPursue : public AiPackage
|
||||
{
|
||||
public:
|
||||
AiPursue(const std::string &objectId);
|
||||
virtual AiPursue *clone() const;
|
||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||
|
@ -28,8 +22,6 @@ namespace MWMechanics
|
|||
|
||||
private:
|
||||
std::string mObjectId;
|
||||
|
||||
PathFinder mPathFinder;
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
|
|
|
@ -11,30 +11,6 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||
{
|
||||
x -= point.mX;
|
||||
y -= point.mY;
|
||||
z -= point.mZ;
|
||||
return sqrt(x * x + y * y + 0.1 * z * z);
|
||||
}
|
||||
|
||||
float distance(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||
{
|
||||
x -= point.mX;
|
||||
y -= point.mY;
|
||||
z -= point.mZ;
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b)
|
||||
{
|
||||
float x = a.mX - b.mX;
|
||||
float y = a.mY - b.mY;
|
||||
float z = a.mZ - b.mZ;
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
// Slightly cheaper version for comparisons.
|
||||
// Caller needs to be careful for very short distances (i.e. less than 1)
|
||||
// or when accumuating the results i.e. (a + b)^2 != a^2 + b^2
|
||||
|
@ -114,6 +90,30 @@ namespace
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||
{
|
||||
x -= point.mX;
|
||||
y -= point.mY;
|
||||
z -= point.mZ;
|
||||
return sqrt(x * x + y * y + 0.1 * z * z);
|
||||
}
|
||||
|
||||
float distance(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||
{
|
||||
x -= point.mX;
|
||||
y -= point.mY;
|
||||
z -= point.mZ;
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b)
|
||||
{
|
||||
float x = a.mX - b.mX;
|
||||
float y = a.mY - b.mY;
|
||||
float z = a.mZ - b.mZ;
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
PathFinder::PathFinder()
|
||||
: mIsPathConstructed(false),
|
||||
mPathgrid(NULL),
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace MWWorld
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
float distance(ESM::Pathgrid::Point point, float x, float y, float);
|
||||
float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b);
|
||||
class PathFinder
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -8,6 +8,20 @@ namespace ESM
|
|||
{
|
||||
unsigned int Pathgrid::sRecordId = REC_PGRD;
|
||||
|
||||
Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[]) {
|
||||
mX = rhs[0];
|
||||
mY = rhs[1];
|
||||
mZ = rhs[2];
|
||||
return *this;
|
||||
}
|
||||
Pathgrid::Point::Point(const float rhs[]) {
|
||||
mX = rhs[0];
|
||||
mY = rhs[1];
|
||||
mZ = rhs[2];
|
||||
}
|
||||
Pathgrid::Point::Point():mX(0),mY(0),mZ(0) {
|
||||
}
|
||||
|
||||
void Pathgrid::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHNT(mData, "DATA", 12);
|
||||
|
|
|
@ -31,6 +31,9 @@ struct Pathgrid
|
|||
unsigned char mAutogenerated; // autogenerated vs. user coloring flag?
|
||||
unsigned char mConnectionNum; // number of connections for this point
|
||||
short mUnknown;
|
||||
Point& operator=(const float[]);
|
||||
Point(const float[]);
|
||||
Point();
|
||||
}; // 16 bytes
|
||||
|
||||
struct Edge // path grid edge
|
||||
|
|
Loading…
Reference in a new issue