+ v3f bound[2];
+
+ for( int j=0; j<2; j++ ){
+ v3_muls( launch_v_bounds[j], t, bound[j] );
+ v3_muladds( bound[j], basis[1], -0.5f*gravity*t*t, bound[j] );
+ v3_add( launch_co, bound[j], bound[j] );
+ }
+
+ float limh = vg_minf( 2.0f, t ),
+ minh = vg_minf( bound[0][1], bound[1][1] )-limh,
+ maxh = vg_maxf( bound[0][1], bound[1][1] )+limh;
+
+ if( (closest[1] < minh) || (closest[1] > maxh) ){
+ search_for_grind = 0;
+ }
+ }
+ else
+ search_for_grind = 0;
+ }
+
+ if( search_for_grind ){
+ v3f ve;
+ v3_copy( launch_v, ve );
+ v3_muladds( ve, basis[1], -gravity * t, ve );
+
+ if( skate_grind_scansq( player, closest, ve, 0.5f, &grind ) ){
+ /* check alignment */
+ v2f v0 = { v3_dot( ve, basis[0] ),
+ v3_dot( ve, basis[2] ) },
+ v1 = { v3_dot( grind.dir, basis[0] ),
+ v3_dot( grind.dir, basis[2] ) };
+
+ v2_normalize( v0 );
+ v2_normalize( v1 );
+
+ float a = v2_dot( v0, v1 );
+
+ float a_min = cosf( VG_PIf * 0.185f );
+ if( s->grind_cooldown )
+ a_min = cosf( VG_PIf * 0.05f );
+
+ /* check speed */
+ if( (fabsf(v3_dot( ve, grind.dir ))>=k_grind_axel_min_vel) &&
+ (a >= a_min) &&
+ (fabsf(grind.dir[1]) < 0.70710678118654752f))
+ {
+ grind_located = 1;
+ grind_located_gravity = inf->gravity;
+ }
+ }
+ }
+
+ if( trace_world->rendering_gate ){
+ ent_gate *gate = trace_world->rendering_gate;
+ if( gate_intersect( gate, co1, co0 ) ){
+ m4x3_mulv( gate->transport, co0, co0 );
+ m4x3_mulv( gate->transport, co1, co1 );
+ m3x3_mulv( gate->transport, launch_v, launch_v);
+ m4x3_mulv( gate->transport, launch_co, launch_co );
+ m3x3_mul( gate->transport, basis, basis );
+
+ if( gate->type == k_gate_type_nonlocel ){
+ trace_world = &world_global.worlds[ gate->target ];