2012-11-14 17:42:04 +00:00
# include "aitravel.hpp"
2014-06-12 21:27:04 +00:00
# include <components/esm/aisequence.hpp>
2015-07-25 02:14:22 +00:00
# include <components/esm/loadcell.hpp>
2014-06-12 21:27:04 +00:00
2013-03-06 20:31:47 +00:00
# include "../mwbase/world.hpp"
# include "../mwbase/environment.hpp"
2014-02-23 19:11:05 +00:00
2013-06-01 00:49:52 +00:00
# include "../mwworld/class.hpp"
2014-02-23 19:11:05 +00:00
# include "../mwworld/cellstore.hpp"
2013-03-06 20:31:47 +00:00
2014-01-29 19:29:07 +00:00
# include "steering.hpp"
# include "movement.hpp"
2014-04-24 03:17:01 +00:00
# include "creaturestats.hpp"
2014-01-29 19:29:07 +00:00
2016-01-19 13:51:37 +00:00
namespace
{
bool isWithinMaxRange ( const osg : : Vec3f & pos1 , const osg : : Vec3f & pos2 )
{
// Maximum travel distance for vanilla compatibility.
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
return ( pos1 - pos2 ) . length2 ( ) < = 7168 * 7168 ;
}
}
2014-12-31 17:55:07 +00:00
2013-06-01 00:49:52 +00:00
namespace MWMechanics
2013-05-25 01:16:35 +00:00
{
2013-06-01 00:49:52 +00:00
AiTravel : : AiTravel ( float x , float y , float z )
2014-10-08 21:09:50 +00:00
: mX ( x ) , mY ( y ) , mZ ( z )
2014-02-05 15:12:50 +00:00
, mCellX ( std : : numeric_limits < int > : : max ( ) )
, mCellY ( std : : numeric_limits < int > : : max ( ) )
2013-06-01 00:49:52 +00:00
{
}
2013-03-31 17:30:03 +00:00
2014-06-12 21:27:04 +00:00
AiTravel : : AiTravel ( const ESM : : AiSequence : : AiTravel * travel )
: mX ( travel - > mData . mX ) , mY ( travel - > mData . mY ) , mZ ( travel - > mData . mZ )
, mCellX ( std : : numeric_limits < int > : : max ( ) )
, mCellY ( std : : numeric_limits < int > : : max ( ) )
{
}
2013-06-01 00:49:52 +00:00
AiTravel * MWMechanics : : AiTravel : : clone ( ) const
{
return new AiTravel ( * this ) ;
}
2013-04-01 15:44:08 +00:00
2015-06-26 15:47:04 +00:00
bool AiTravel : : execute ( const MWWorld : : Ptr & actor , CharacterController & characterController , AiState & state , float duration )
2013-06-01 00:49:52 +00:00
{
ESM : : Position pos = actor . getRefData ( ) . getPosition ( ) ;
2013-04-01 15:44:08 +00:00
2014-04-24 03:17:01 +00:00
actor . getClass ( ) . getCreatureStats ( actor ) . setMovementFlag ( CreatureStats : : Flag_Run , false ) ;
2014-07-28 15:28:00 +00:00
actor . getClass ( ) . getCreatureStats ( actor ) . setDrawState ( DrawState_Nothing ) ;
2015-06-03 17:41:19 +00:00
if ( ! isWithinMaxRange ( osg : : Vec3f ( mX , mY , mZ ) , pos . asVec3 ( ) ) )
2014-09-17 10:39:10 +00:00
return false ;
2015-06-11 06:28:31 +00:00
if ( pathTo ( actor , ESM : : Pathgrid : : Point ( static_cast < int > ( mX ) , static_cast < int > ( mY ) , static_cast < int > ( mZ ) ) , duration ) )
2013-03-10 15:07:22 +00:00
{
2015-06-11 06:28:31 +00:00
actor . getClass ( ) . getMovementSettings ( actor ) . mPosition [ 1 ] = 0 ;
return true ;
2013-03-10 15:07:22 +00:00
}
2015-06-11 06:28:31 +00:00
return false ;
}
2013-03-06 20:31:47 +00:00
2015-06-11 06:28:31 +00:00
bool AiTravel : : doesPathNeedRecalc ( ESM : : Pathgrid : : Point dest , const ESM : : Cell * cell )
{
bool cellChange = cell - > mData . mX ! = mCellX | | cell - > mData . mY ! = mCellY ;
if ( ! mPathFinder . isPathConstructed ( ) | | cellChange )
2013-06-01 00:49:52 +00:00
{
2015-06-11 06:28:31 +00:00
mCellX = cell - > mData . mX ;
mCellY = cell - > mData . mY ;
2013-06-01 00:49:52 +00:00
return true ;
}
return false ;
2013-03-06 20:31:47 +00:00
}
2013-04-01 15:44:08 +00:00
2013-06-01 00:49:52 +00:00
int AiTravel : : getTypeId ( ) const
2013-03-06 20:31:47 +00:00
{
2014-01-07 00:12:37 +00:00
return TypeIdTravel ;
2013-03-06 20:31:47 +00:00
}
2014-06-12 21:27:04 +00:00
2014-12-31 17:41:57 +00:00
void AiTravel : : fastForward ( const MWWorld : : Ptr & actor , AiState & state )
{
2015-06-03 17:41:19 +00:00
if ( ! isWithinMaxRange ( osg : : Vec3f ( mX , mY , mZ ) , actor . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) )
2014-12-31 17:55:07 +00:00
return ;
// does not do any validation on the travel target (whether it's in air, inside collision geometry, etc),
// that is the user's responsibility
MWBase : : Environment : : get ( ) . getWorld ( ) - > moveObject ( actor , mX , mY , mZ ) ;
actor . getClass ( ) . adjustPosition ( actor , false ) ;
2014-12-31 17:41:57 +00:00
}
2014-06-12 21:27:04 +00:00
void AiTravel : : writeState ( ESM : : AiSequence : : AiSequence & sequence ) const
{
std : : auto_ptr < ESM : : AiSequence : : AiTravel > travel ( new ESM : : AiSequence : : AiTravel ( ) ) ;
travel - > mData . mX = mX ;
travel - > mData . mY = mY ;
travel - > mData . mZ = mZ ;
ESM : : AiSequence : : AiPackageContainer package ;
package . mType = ESM : : AiSequence : : Ai_Travel ;
package . mPackage = travel . release ( ) ;
sequence . mPackages . push_back ( package ) ;
}
2013-05-25 01:16:35 +00:00
}