Exemple #1
0
/*
============
idAASLocal::ShowFlyPath
============
*/
void idAASLocal::ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const {
	int i, areaNum, curAreaNum, travelTime;
	idReachability *reach;
	idVec3 org, areaCenter;
	aasPath_t path;
	if( !file ) {
		return;
	}
	org = origin;
	areaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AREA_REACHABLE_FLY );
	PushPointIntoAreaNum( areaNum, org );
	curAreaNum = areaNum;
	for( i = 0; i < 100; i++ ) {
		if( !RouteToGoalArea( curAreaNum, org, goalAreaNum, TFL_WALK | TFL_FLY | TFL_AIR, travelTime, &reach ) ) {
			break;
		}
		if( !reach ) {
			break;
		}
		gameRenderWorld->DebugArrow( colorPurple, org, reach->start, 2 );
		DrawReachability( reach );
		if( reach->toAreaNum == goalAreaNum ) {
			break;
		}
		curAreaNum = reach->toAreaNum;
		org = reach->end;
	}
	if( FlyPathToGoal( path, areaNum, origin, goalAreaNum, goalOrigin, TFL_WALK | TFL_FLY | TFL_AIR ) ) {
		gameRenderWorld->DebugArrow( colorBlue, origin, path.moveGoal, 2 );
	}
}
/*
============
idAASLocal::ShowArea
============
*/
void idAASLocal::ShowArea(const idVec3 &origin) const
{
	static int lastAreaNum;
	int areaNum;
	const aasArea_t *area;
	idVec3 org;

	areaNum = PointReachableAreaNum(origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY));
	org = origin;
	PushPointIntoAreaNum(areaNum, org);

	if (aas_goalArea.GetInteger()) {
		int travelTime;
		idReachability *reach;

		RouteToGoalArea(areaNum, org, aas_goalArea.GetInteger(), TFL_WALK|TFL_AIR, travelTime, &reach);
		gameLocal.Printf("\rtt = %4d", travelTime);

		if (reach) {
			gameLocal.Printf(" to area %4d", reach->toAreaNum);
			DrawArea(reach->toAreaNum);
		}
	}

	if (areaNum != lastAreaNum) {
		area = &file->GetArea(areaNum);
		gameLocal.Printf("area %d: ", areaNum);

		if (area->flags & AREA_LEDGE) {
			gameLocal.Printf("AREA_LEDGE ");
		}

		if (area->flags & AREA_REACHABLE_WALK) {
			gameLocal.Printf("AREA_REACHABLE_WALK ");
		}

		if (area->flags & AREA_REACHABLE_FLY) {
			gameLocal.Printf("AREA_REACHABLE_FLY ");
		}

		if (area->contents & AREACONTENTS_CLUSTERPORTAL) {
			gameLocal.Printf("AREACONTENTS_CLUSTERPORTAL ");
		}

		if (area->contents & AREACONTENTS_OBSTACLE) {
			gameLocal.Printf("AREACONTENTS_OBSTACLE ");
		}

		gameLocal.Printf("\n");
		lastAreaNum = areaNum;
	}

	if (org != origin) {
		idBounds bnds = file->GetSettings().boundingBoxes[ 0 ];
		bnds[ 1 ].z = bnds[ 0 ].z;
		gameRenderWorld->DebugBounds(colorYellow, bnds, org);
	}

	DrawArea(areaNum);
}
Exemple #3
0
/*
============
idAASLocal::ShowPushIntoArea
============
*/
void idAASLocal::ShowPushIntoArea( const idVec3 &origin ) const {
	int areaNum;
	idVec3 target;
	target = origin;
	areaNum = PointReachableAreaNum( target, DefaultSearchBounds(), ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) );
	PushPointIntoAreaNum( areaNum, target );
	gameRenderWorld->DebugArrow( colorGreen, origin, target, 1 );
}
Exemple #4
0
void idAASLocal::DrawEASRoute( const idVec3& playerOrigin, int goalArea )
{
	idVec3 origin = playerOrigin;
	int areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) );

	PushPointIntoAreaNum( areaNum, origin );

	elevatorSystem->DrawRoute(areaNum, goalArea);
}
Exemple #5
0
/*
============
idAASLocal::ShowPushIntoArea
============
*/
void idAASLocal::ShowPushIntoArea( const idVec3 &origin ) const {
	int areaNum;
	idVec3 target;

	target = origin;
	areaNum = PointReachableAreaNum( target, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
	PushPointIntoArea( areaNum, target );
	gameRenderWorld->DebugArrow( colorGreen, origin, target, 1, 0 );
}
Exemple #6
0
/*
============
idAASLocal::ShowNearestInsideArea
============
*/
void idAASLocal::ShowNearestInsideArea( const idVec3 &origin ) const {
	int areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );

	idAASCallback_FindFlaggedArea findInside( AAS_AREA_OUTSIDE, false );
	idAASGoal goal;
	if ( FindNearestGoal( goal, areaNum, origin, TravelFlagForTeam(), findInside ) ) {
		DrawArea( goal.areaNum );
		ShowWalkPath( areaNum, origin, goal.areaNum, goal.origin, TravelFlagForTeam(), TravelFlagWalkForTeam() );
		DrawCone( goal.origin, idVec3( 0, 0, 1 ), 16.0f, colorWhite );
	}
}
void hhCenturion::Event_MoveToObstruction() {
	idVec3 temp;
	if ( aas ) {
		int toAreaNum = PointReachableAreaNum( pillarEntity.GetEntity()->GetOrigin() );
		temp = pillarEntity.GetEntity()->GetOrigin();
		aas->PushPointIntoAreaNum( toAreaNum, temp );
		MoveToPosition( temp );
	} else {
		gameLocal.Warning( "Centurion has no aas for MoveToObstruction\n" );
	}
}
Exemple #8
0
/*
============
idAASLocal::ShowHopPath
============
*/
void idAASLocal::ShowHopPath( const idVec3 &startOrigin, int goalAreaNum, const idVec3 &goalOrigin ) const {

	if ( file == NULL ) {
		return;
	}

	idVec3 areaOrigin = startOrigin;
	int startAreaNum = PointReachableAreaNum( areaOrigin, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
	PushPointIntoArea( startAreaNum, areaOrigin );

	ShowHopPath( startAreaNum, areaOrigin, goalAreaNum, goalOrigin, TravelFlagForTeam(), TravelFlagWalkForTeam(), idAASHopPathParms() );
}
/*
============
idAASLocal::PullPlayer
============
*/
bool idAASLocal::PullPlayer( const idVec3& origin, int toAreaNum ) const
{
	int areaNum;
	idVec3 areaCenter, dir, vel;
	idAngles delta;
	aasPath_t path;
	idPlayer* player;
	
	player = gameLocal.GetLocalPlayer();
	if( !player )
	{
		return true;
	}
	
	idPhysics* physics = player->GetPhysics();
	if( !physics )
	{
		return true;
	}
	
	if( !toAreaNum )
	{
		return false;
	}
	
	areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) );
	areaCenter = AreaCenter( toAreaNum );
	if( player->GetPhysics()->GetAbsBounds().Expand( 8 ).ContainsPoint( areaCenter ) )
	{
		return false;
	}
	if( WalkPathToGoal( path, areaNum, origin, toAreaNum, areaCenter, TFL_WALK | TFL_AIR ) )
	{
		dir = path.moveGoal - origin;
		dir[2] *= 0.5f;
		dir.Normalize();
		delta = dir.ToAngles() - player->cmdAngles - player->GetDeltaViewAngles();
		delta.Normalize180();
		player->SetDeltaViewAngles( player->GetDeltaViewAngles() + delta * 0.1f );
		dir[2] = 0.0f;
		dir.Normalize();
		dir *= 100.0f;
		vel = physics->GetLinearVelocity();
		dir[2] = vel[2];
		physics->SetLinearVelocity( dir );
		return true;
	}
	else
	{
		return false;
	}
}
Exemple #10
0
/*
============
idAASLocal::ShowNearestCoverArea
============
*/
void idAASLocal::ShowNearestCoverArea( const idVec3 &origin, int targetAreaNum ) const {
	int areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
	idVec3 target = AreaCenter( targetAreaNum );

	DrawCone( target, idVec3(0,0,1), 16.0f, colorYellow );

	idAASCallback_FindCoverArea findCover( target );
	idAASGoal goal;
	if ( FindNearestGoal( goal, areaNum, origin, TravelFlagInvalidForTeam(), findCover ) ) {
		DrawArea( goal.areaNum );
		ShowWalkPath( areaNum, origin, goal.areaNum, goal.origin, TravelFlagForTeam(), TravelFlagWalkForTeam() );
		DrawCone( goal.origin, idVec3( 0, 0, 1 ), 16.0f, colorWhite );
	}
}
Exemple #11
0
/*
============
idAASLocal::ShowWallEdges
============
*/
void idAASLocal::ShowWallEdges( const idVec3 &origin ) const {
	int i, areaNum, numEdges, edges[1024];
	idVec3 start, end;
	idPlayer *player;
	player = gameLocal.GetLocalPlayer();
	if( !player ) {
		return;
	}
	areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) );
	numEdges = GetWallEdges( areaNum, idBounds( origin ).Expand( 256.0f ), TFL_WALK, edges, 1024 );
	for( i = 0; i < numEdges; i++ ) {
		GetEdge( edges[i], start, end );
		gameRenderWorld->DebugLine( colorRed, start, end );
		gameRenderWorld->DrawText( va( "%d", edges[i] ), ( start + end ) * 0.5f, 0.1f, colorWhite, player->viewAxis );
	}
}
Exemple #12
0
/*
============
idAASLocal::ShowHideArea
============
*/
void idAASLocal::ShowHideArea( const idVec3 &origin, int targetAreaNum ) const {
	int areaNum, numObstacles;
	idVec3 target;
	aasGoal_t goal;
	aasObstacle_t obstacles[10];
	areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), ( AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ) );
	target = AreaCenter( targetAreaNum );
	// consider the target an obstacle
	obstacles[0].absBounds = idBounds( target ).Expand( 16 );
	numObstacles = 1;
	DrawCone( target, idVec3( 0, 0, 1 ), 16.0f, colorYellow );
	idAASFindCover findCover( target );
	if( FindNearestGoal( goal, areaNum, origin, target, TFL_WALK | TFL_AIR, obstacles, numObstacles, findCover ) ) {
		DrawArea( goal.areaNum );
		ShowWalkPath( origin, goal.areaNum, goal.origin );
		DrawCone( goal.origin, idVec3( 0, 0, 1 ), 16.0f, colorWhite );
	}
}
Exemple #13
0
/*
============
idAASLocal::GetAreaNumAndLocation
============
*/
bool idAASLocal::GetAreaNumAndLocation( idCVar &cvar, const idVec3 &origin, int &areaNum, idVec3 &location ) const {

	areaNum = 0;
	location.Zero();

	if ( cvar.GetString()[0] == '\0' ) {
		return false;
	}

	if ( idStr::Icmp( cvar.GetString(), "memory" ) == 0 ) {
		cvar.SetString( aas_locationMemory.GetString() );
	}

	if ( idStr::Icmp( cvar.GetString(), "current" ) == 0 ) {
		cvar.SetString( origin.ToString() );
	}

	idLexer src( LEXFL_NOERRORS|LEXFL_NOWARNINGS );
	src.LoadMemory( cvar.GetString(), idStr::Length( cvar.GetString() ), "areaNum" );

	bool error = false;
	location.x = src.ParseFloat( &error );
	location.y = src.ParseFloat( &error );
	location.z = src.ParseFloat( &error );

	if ( !error ) {
		areaNum = PointReachableAreaNum( location, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
		PushPointIntoArea( areaNum, location );
		return true;
	}

	src.Reset();

	areaNum = src.ParseInt();

	if ( ( areaNum > 0 ) && ( areaNum < file->GetNumAreas() ) ) {
		location = AreaCenter( areaNum );
		return true;
	}

	return false;
}
Exemple #14
0
/*
============
idAASLocal::ShowFloorTrace
============
*/
void idAASLocal::ShowFloorTrace( const idVec3 &origin ) const {
	idPlayer *player;

	player = gameLocal.GetLocalPlayer();
	if ( !player ) {
		return;
	}
	idMat3 playerAxis = idAngles( 0.0f, player->GetViewAngles().yaw, 0.0f ).ToMat3();

	idVec3 org = origin;
	int areaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
	PushPointIntoArea( areaNum, org );

	aasTraceFloor_t trace;
	TraceFloor( trace, org, areaNum, origin + playerAxis[0] * 1024, TFL_WALK|TFL_AIR );

	gameRenderWorld->DebugArrow( colorCyan, org, trace.endpos, 1, 0 );
	idVec3 up = trace.endpos + playerAxis[2] * 64;
	const idVec4 &color = ( trace.fraction >= 1.0f ) ? colorGreen : colorRed;
	gameRenderWorld->DebugArrow( color, trace.endpos, up + playerAxis[1] * 32, 1, 0, true );
	gameRenderWorld->DebugArrow( color, trace.endpos, up - playerAxis[1] * 32, 1, 0, true );
}
bool rvMonsterStroggHover::MarkerPosValid ( void )
{
	//debouncer ftw
	if( markerCheckTime > gameLocal.GetTime() )	{
		return true;
	}

	markerCheckTime = gameLocal.GetTime() + 500 + (gameLocal.random.RandomFloat() * 500);

	trace_t trace;
	gameLocal.TracePoint( this, trace, marker.GetEntity()->GetPhysics()->GetOrigin(), marker.GetEntity()->GetPhysics()->GetOrigin(), GetPhysics()->GetClipMask(), NULL );
	if ( !(trace.c.contents&GetPhysics()->GetClipMask()) )
	{//not in solid
		gameLocal.TracePoint( this, trace, marker.GetEntity()->GetPhysics()->GetOrigin(), GetEnemy()->GetEyePosition(), MASK_SHOT_BOUNDINGBOX, GetEnemy() );
		idActor* enemyAct = NULL;
		rvVehicle* enemyVeh = NULL;
		if ( GetEnemy()->IsType( rvVehicle::GetClassType() ) ) {
			enemyVeh = static_cast<rvVehicle*>(GetEnemy());
		} else if ( GetEnemy()->IsType( idActor::GetClassType() ) ) {
			enemyAct = static_cast<idActor*>(GetEnemy());
		}
		idEntity* hitEnt = gameLocal.entities[trace.c.entityNum];
		idActor* hitAct = NULL;
		if ( hitEnt && hitEnt->IsType( idActor::GetClassType() ) ) {
			hitAct = static_cast<idActor*>(hitEnt);
		}
		if ( trace.fraction >= 1.0f 
			|| (enemyAct && enemyAct->IsInVehicle() && enemyAct->GetVehicleController().GetVehicle() == gameLocal.entities[trace.c.entityNum])
			|| (enemyVeh && hitAct && hitAct->IsInVehicle() && hitAct->GetVehicleController().GetVehicle() == enemyVeh) )
		{//have a clear LOS to enemy
			if ( PointReachableAreaNum( marker.GetEntity()->GetPhysics()->GetOrigin() ) )
			{//valid AAS there...
				return true;
			}
		}
	}
	return false;
}
Exemple #16
0
/*
============
idAASLocal::ShowArea
============
*/
void idAASLocal::ShowArea( const idVec3 &origin, int mode ) const {
	static int lastAreaNum;
	int areaNum;
	const aasArea_t *area;
	idVec3 org;

	org = origin;
	if ( mode == 1 ) {
		areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
		PushPointIntoArea( areaNum, org );
	} else {
		areaNum = PointAreaNum( origin );
	}

	if ( aas_showTravelTime.GetInteger() ) {
		int travelTime;
		const aasReachability_t *reach;
		
		RouteToGoalArea( areaNum, org, aas_showTravelTime.GetInteger(), TFL_WALK|TFL_AIR, travelTime, &reach );
		gameLocal.Printf( "\rtt = %4d", travelTime );
		if ( reach ) {
			gameLocal.Printf( " to area %4d", reach->toAreaNum );
			DrawArea( reach->toAreaNum );
		}
	}

	if ( areaNum != lastAreaNum ) {
		area = &file->GetArea( areaNum );
		gameLocal.Printf( "area %d:", areaNum );
		if ( area->flags & AAS_AREA_LEDGE ) {
			gameLocal.Printf( " ledge" );
		}
		if ( area->flags & AAS_AREA_CONTENTS_CLUSTERPORTAL ) {
			gameLocal.Printf( " clusterportal" );
		}
		if ( area->flags & AAS_AREA_CONTENTS_OBSTACLE ) {
			gameLocal.Printf( " obstacle" );
		}
		if ( area->flags & AAS_AREA_OUTSIDE ) {
			gameLocal.Printf( " outside" );
		}
		if ( area->flags & AAS_AREA_HIGH_CEILING ) {
			gameLocal.Printf( " highceiling" );
		}
		if ( area->travelFlags & ( TFL_INVALID | TFL_INVALID_GDF | TFL_INVALID_STROGG ) ) {
			gameLocal.Printf( " /" );
			if ( area->travelFlags & TFL_INVALID ) {
				gameLocal.Printf( " invalid" );
			}
			if ( area->travelFlags & TFL_INVALID_GDF ) {
				gameLocal.Printf( " invalidgdf" );
			}
			if ( area->travelFlags & TFL_INVALID_STROGG ) {
				gameLocal.Printf( " invalidstrogg" );
			}
		}
		gameLocal.Printf( "\n" );
		lastAreaNum = areaNum;
	}

	if ( org != origin ) {
		idBounds bnds = file->GetSettings().boundingBox;
		bnds[ 1 ].z = bnds[ 0 ].z;
		gameRenderWorld->DebugBounds( colorYellow, bnds, org );
		gameRenderWorld->DebugArrow( colorYellow, origin, org, 1 );
	}

	DrawArea( areaNum );
}
Exemple #17
0
/*
============
idAASLocal::ShowWallEdges
============
*/
void idAASLocal::ShowWallEdges( const idVec3 &origin, int mode, bool showNumbers ) const {
	const int MAX_WALL_EDGES = 1024;
	int edges[MAX_WALL_EDGES];
	float textSize;

	idPlayer *player = gameLocal.GetLocalPlayer();
	if ( player == NULL ) {
		return;
	}

	idMat3 viewAxis = player->GetViewAxis();
	idVec3 viewOrigin = player->GetViewPos();
	idMat3 playerAxis = idAngles( 0.0f, -player->GetViewAngles().yaw, 0.0f ).ToMat3();

	if ( mode == 3 ) {
		textSize = 0.2f;
	} else {
		textSize = 0.1f;
	}

	float radius = file->GetSettings().obstaclePVSRadius;

	int areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
	//int numEdges = GetWallEdges( areaNum, idBounds( origin ).Expand( radius ), TFL_WALK, 64.0f, edges, MAX_WALL_EDGES );
	int numEdges = GetObstaclePVSWallEdges( areaNum, edges, MAX_WALL_EDGES );

	// move the wall edges to the start of the list
	int numWallEdges = 0;
	for ( int i = 0; i < numEdges; i++ ) {
		if ( ( file->GetEdge( abs( edges[i] ) ).flags & AAS_EDGE_WALL ) != 0 ) {
			idSwap( edges[numWallEdges++], edges[i] );
		}
	}

	for ( int i = 0; i < numEdges; i++ ) {
		idVec3 start, end;

		GetEdge( edges[i], start, end );

		if ( mode == 2 ) {

			start.z = end.z = origin.z;

		} else if ( mode == 3 ) {

			ProjectTopDown( start, viewOrigin, viewAxis, playerAxis, radius * 2.0f );
			ProjectTopDown( end, viewOrigin, viewAxis, playerAxis, radius * 2.0f );
		}

		if ( ( file->GetEdge( abs( edges[i] ) ).flags & AAS_EDGE_WALL ) != 0 ) {
			gameRenderWorld->DebugLine( colorRed, start, end, 0 );
		} else {
			gameRenderWorld->DebugLine( colorGreen, start, end, 0 );
		}
		if ( showNumbers ) {
			gameRenderWorld->DrawText( va( "%d", edges[i] ), ( start + end ) * 0.5f, textSize, colorWhite, viewAxis, 1, 0 );
		}
	}

	if ( mode == 3 ) {
		idVec3 box[7] = { origin, origin, origin, origin, origin, origin, origin };

		box[0][0] += radius;
		box[0][1] += radius;

		box[1][0] += radius;
		box[1][1] -= radius;

		box[2][0] -= radius;
		box[2][1] -= radius;

		box[3][0] -= radius;
		box[3][1] += radius;

		box[4][1] += radius;

		box[5][0] += radius * 0.1f;
		box[5][1] += radius - radius * 0.1f;

		box[6][0] -= radius * 0.1f;
		box[6][1] += radius - radius * 0.1f;

		for ( int i = 0; i < 7; i++ ) {
			ProjectTopDown( box[i], viewOrigin, viewAxis, playerAxis, radius * 2.0f );
		}
		for ( int i = 0; i < 4; i++ ) {
			gameRenderWorld->DebugLine( colorCyan, box[i], box[(i+1)&3], 0 );
		}
		gameRenderWorld->DebugLine( colorCyan, box[4], box[5], 0 );
		gameRenderWorld->DebugLine( colorCyan, box[4], box[6], 0 );
	}
}
Exemple #18
0
/*
============
idAASLocal::PullPlayer
============
*/
bool idAASLocal::PullPlayer( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int &startAreaNum, int &travelTime ) const {

	startAreaNum = 0;
	travelTime = 0;

	idPlayer *player = gameLocal.GetLocalPlayer();
	if ( player == NULL ) {
		return true;
	}

	if ( goalAreaNum == 0 ) {
		return false;
	}

	if ( player->GetNoClip() ) {
		player->aasPullPlayer = false;
		return false;
	}

	idVec3 dir = goalOrigin - origin;
	float height = idMath::Fabs( dir.z );
	float dist = dir.ToVec2().Length();

	if ( dist < 32.0f && height < 128.0f ) {
		return false;
	}

	idVec3 org = origin;
	startAreaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AAS_AREA_REACHABLE_WALK, TravelFlagInvalidForTeam() );
	PushPointIntoArea( startAreaNum, org );

	const aasReachability_t *reach;
	RouteToGoalArea( startAreaNum, org, goalAreaNum, TravelFlagForTeam(), travelTime, &reach );

	ShowWalkPath( startAreaNum, org, goalAreaNum, goalOrigin, TravelFlagForTeam(), TravelFlagWalkForTeam() );

	idAASPath path;
	if ( !WalkPathToGoal( path, startAreaNum, org, goalAreaNum, goalOrigin, TravelFlagForTeam(), TravelFlagWalkForTeam() ) ) {
		return false;
	}

	idObstacleAvoidance::obstaclePath_t obstaclePath;
	idObstacleAvoidance obstacleAvoidance;
	botThreadData.BuildObstacleList( obstacleAvoidance, org, startAreaNum, false );
	obstacleAvoidance.FindPathAroundObstacles( file->GetSettings().boundingBox, file->GetSettings().obstaclePVSRadius, this, org, path.moveGoal, obstaclePath );
	path.moveGoal = obstaclePath.seekPos;

	player->aasPullPlayer = true;

	usercmd_t usercmd;
	memset( &usercmd, 0, sizeof( usercmd ) );

	usercmd.forwardmove = 127;
	usercmd.buttons.btn.run = true;
	usercmd.buttons.btn.sprint = false;

	idVec3 moveDir = path.moveGoal - org;
	idVec3 horizontalDir( moveDir.x, moveDir.y, 0.0f );
	float horizontalDist = horizontalDir.Normalize();
	moveDir.Normalize();

	switch( path.type ) {
		case PATHTYPE_WALKOFFLEDGE:
		case PATHTYPE_WALKOFFBARRIER: {
			if ( horizontalDist < 80.0f ) {
				usercmd.buttons.btn.run = false;
				usercmd.forwardmove = 16 + horizontalDist;
			}
			break;
		}
		case PATHTYPE_BARRIERJUMP:
		case PATHTYPE_JUMP: {
			if ( horizontalDist < 24.0f ) {
				pullPlayerState.jumpNow = !pullPlayerState.jumpNow;
				if ( pullPlayerState.jumpNow ) {
					usercmd.upmove = 127;
				}
			}
			if ( player->GetPlayerPhysics().IsGrounded() ) {
				if ( horizontalDist < 100.0f ) {
					usercmd.buttons.btn.run = false;
					usercmd.forwardmove = 8 + horizontalDist;
				}
			} else {
				moveDir = path.reachability->GetEnd() - org;
				moveDir.Normalize();
			}
			break;
		}
		case PATHTYPE_LADDER: {
			pullPlayerState.ladderDir = moveDir;
			pullPlayerState.ladderTime = gameLocal.time;
#if 0
			// test ladder physics code
			if ( !player->GetPlayerPhysics().IsGrounded() ) {
				trace_t trace;
				bool onLadder = false;
				if ( gameLocal.clip.Translation( CLIP_DEBUG_PARMS_CLIENTINFO( self ) trace, org, org + horizontalDir * 32.0f, NULL, mat3_identity, MASK_PLAYERSOLID, player ) ) {
					onLadder = ( gameLocal.entities[ trace.c.entityNum ]->Cast< sdLadderEntity >() != NULL );
				}
				if ( onLadder && !player->GetPlayerPhysics().OnLadder() ) {
					usercmd.forwardmove = 0;
				}
			}
#endif
			break;
		}
	}

	if ( player->GetPlayerPhysics().OnLadder() || pullPlayerState.ladderTime > gameLocal.time - 500 ) {
		moveDir = pullPlayerState.ladderDir;
	}

	idAngles viewAngles = moveDir.ToAngles();

	player->Move( usercmd, viewAngles );

	return true;
}