/* ============ 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); }
/* ============ 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 ); }
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); }
/* ============ 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 ); }
/* ============ 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" ); } }
/* ============ 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; } }
/* ============ 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 ); } }
/* ============ 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 ); } }
/* ============ 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 ); } }
/* ============ 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; }
/* ============ 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; }
/* ============ 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 ); }
/* ============ 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 ); } }
/* ============ 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; }