#include common_scripts\utility; #include maps\_utility; #include maps\_debug; #include maps\_vehicle; #include maps\_anim; ANG_LOOKAHEAD_DIST = 800; AHEAD_DISTANCE = 500; WHITE = ( 1, 1, 1 ); RED = ( 1, 0, 0 ); GREEN = ( 0, 1, 0 ); BLUE = ( 0, 0, 1 ); init_vehicle_splines() { create_dvar( "vehicle_spline_debug", 0 ); level.SPLINE_MIN_PROGRESS = -2000; level.enemy_snowmobiles_max = 6; level.player_ent = spawn( "script_origin", level.player.origin + ( 0, 0, 88 ) ); level.player_ent linkto( level.player ); level.snowmobile_path = make_road_path(); flag_init( "ai_snowmobiles_ram_player" ); flag_set( "ai_snowmobiles_ram_player" ); enable_spline_paths = getentarray( "enable_spline_path", "targetname" ); array_thread( enable_spline_paths, ::enable_spline_path_think ); } enable_spline_path_think() { for ( ;; ) { self waittill( "trigger", other ); other notify( "enable_spline_path" ); } } make_road_path() { level.drive_spline_path_fun = ::bike_drives_path; path = process_path(); flag_init( "race_complete" ); level.player_view_org = spawn( "script_model", ( 0, 0, 0 ) ); level.player_view_org setmodel( "tag_origin" ); level.enemy_snowmobiles = []; level.bike_score = 0; level.player thread bike_death_score(); return path; } bike_death_score() { self waittill( "death" ); } get_guy_from_spawner() { spawner = getent( "spawner", "targetname" ); spawner.count = 1; spawner.origin = self.origin; spawner.angles = ( 0, self.angles[ 1 ], 0 ); return spawner stalingradspawn(); } #using_animtree( "generic_human" ); orient_dir( yaw ) { for ( ;; ) { if ( !isdefined( self ) ) return; self OrientMode( "face angle", yaw ); wait( 0.05 ); } } process_path() { path = create_path(); level.snowmobile_path = path; //drop_path_to_ground( path ); add_collision_to_path( path ); /# if ( getdebugdvarint( "vehicle_spline_debug" ) ) thread draw_path( path ); #/ return path; } droppedLine( start, end, color, depth, cull, timer ) { start = drop_to_ground( start ); end = drop_to_ground( end ); thread linedraw( start, end, color, depth, cull, timer ); } droppedLineZ( z, start, end, color, depth, cull, timer ) { start = ( start[ 0 ], start[ 1 ], z ); start = drop_to_ground( start ); end = ( end[ 0 ], end[ 1 ], z ); end = drop_to_ground( end ); thread linedraw( start, end, color, depth, cull, timer ); } draw_path( path ) { old_left_node = undefined; old_right_node = undefined; for ( i = 0; i < path.size; i++ ) { node = path[ i ]; angles = vectortoangles( node.next_node.midpoint - node.midpoint ); forward = anglestoforward( angles ) * node.dist_to_next_targ; width = node.road_width * 0.5; start1 = get_position_from_spline( node, 0, width ); end1 = get_position_from_spline( node, node.dist_to_next_targ, width ); droppedLineZ( node.z, start1, end1, ( 0, 0.5, 1 ), 1, 1, 50000 ); start2 = get_position_from_spline( node, 0, width * -1 ); end2 = get_position_from_spline( node, node.dist_to_next_targ, width * -1 ); droppedLineZ( node.z, start2, end2, ( 0, 0.5, 1 ), 1, 1, 50000 ); droppedLineZ( node.z, start1, start2, ( 0, 0.5, 1 ), 1, 1, 50000 ); droppedLineZ( node.z, end1, end2, ( 0, 0.5, 1 ), 1, 1, 50000 ); /* start = node.origins[ "left" ]; end = start + forward; droppedLineZ( node.z, start, end, ( 1, 0.3, 0 ), 1, 1, 50000 ); start = node.origins[ "right" ]; end = start + forward; droppedLineZ( node.z, start, end, ( 1, 0.3, 0 ), 1, 1, 50000 ); droppedLineZ( node.z, node.origins[ "left" ] + (1,1,1), node.origins[ "right" ] + (1,1,1), ( 1, 0.3, 0 ), 1, 1, 50000 ); droppedLineZ( node.z, node.origins[ "left" ] + (1,1,1), node.origins[ "left" ] + (1,1,1) + forward, ( 1, 0.3, 0 ), 1, 1, 50000 ); droppedLineZ( node.z, node.origins[ "right" ] + (1,1,1), node.origins[ "right" ] + (1,1,1) + forward, ( 1, 0.3, 0 ), 1, 1, 50000 ); droppedLineZ( node.z, node.origins[ "left" ] + (1,1,1) + forward, node.origins[ "right" ] + (1,1,1) + forward, ( 1, 0.3, 0 ), 1, 1, 50000 ); */ /* midpoint1 = node.midpoint; midpoint2 = node.next_node.midpoint; angles = vectortoangles( midpoint1 - midpoint2 ); right = anglestoright( angles ); road_half_width = node.road_width * 0.5; left_node = node.midpoint + right * road_half_width; right_node = node.midpoint + right * road_half_width * -1; droppedLineZ( node.z, left_node, right_node, ( 1, 0.3, 0 ), 1, 0, 50000 ); if ( isdefined( old_left_node ) ) { droppedLineZ( node.z, left_node, old_left_node, ( 1, 0.3, 0 ), 1, 0, 50000 ); droppedLineZ( node.z, right_node, old_right_node, ( 1, 0.3, 0 ), 1, 0, 50000 ); } old_left_node = left_node; old_right_node = right_node; */ //Print3d( node.midpoint, "*", ( 0, 1, 1 ), 1, 3, 50000 ); foreach ( col_volume in node.col_volumes ) { node draw_col_vol( node.z, col_volume ); } foreach ( col_line in node.col_lines ) { //Line( col_line.origin, node.origin ); //Print3d( col_line.origin, col_line.progress, (0.5,1,1), 1, 2, 50000 ); start = col_line.origin; end = col_line.other_col_point.origin; droppedlineZ( node.z, start, end, ( 1, 0, 0 ), 1, 1, 50000 ); //print3d( col_line.origin + (0,0,-30 ), col_line.offset, ( 1,1,1), 1, 1, 50000 ); //print3d( col_line.other_col_point.origin + (0,0,-30 ), col_line.other_col_point.offset, ( 1,1,1), 1, 1, 50000 ); } } } draw_col_vol( z, vol ) { start = get_position_from_spline( self, vol[ "min" ], vol[ "left_offset" ] ); end = get_position_from_spline( self, vol[ "max" ], vol[ "left_offset" ] ); droppedLineZ( z, start, end, ( 0.5, 0, 1 ), 1, 1, 50000 ); start = get_position_from_spline( self, vol[ "min" ], vol[ "right_offset" ] ); end = get_position_from_spline( self, vol[ "max" ], vol[ "right_offset" ] ); droppedLineZ( z, start, end, ( 0.5, 0, 1 ), 1, 1, 50000 ); start = get_position_from_spline( self, vol[ "min" ], vol[ "right_offset" ] ); end = get_position_from_spline( self, vol[ "min" ], vol[ "left_offset" ] ); droppedLineZ( z, start, end, ( 0.5, 0, 1 ), 1, 1, 50000 ); start = get_position_from_spline( self, vol[ "max" ], vol[ "right_offset" ] ); end = get_position_from_spline( self, vol[ "max" ], vol[ "left_offset" ] ); droppedLineZ( z, start, end, ( 0.5, 0, 1 ), 1, 1, 50000 ); } draw_col_vol_offset( Z, vol, offset, forward, right ) { targ = self; start = get_position_from_spline( targ, vol[ "min" ], vol[ offset ] ); end = get_position_from_spline( targ, vol[ "max" ], vol[ offset ] ); droppedLineZ( z, start, end, ( 0.5, 0, 1 ), 1, 1, 50000 ); /* angles = vectortoangles( self.next_node.origin - self.origin ); forward = anglestoforward( angles ); right = anglestoright( angles ); start = self.midpoint - right * vol[ "right_offset" ] + forward * vol[ "min" ]; end = self.midpoint - right * vol[ "right_offset" ] + forward * vol[ "max" ]; start = drop_to_ground( start ); end = drop_to_ground( end ); Line( start, end, ( 1, 1, 1 ), 1, 0, 50000 ); start = self.midpoint - right * vol[ "left_offset" ] + forward * vol[ "min" ]; end = self.midpoint - right * vol[ "left_offset" ] + forward * vol[ "max" ]; start = drop_to_ground( start ); end = drop_to_ground( end ); Line( start, end, ( 1, 1, 1 ), 1, 0, 50000 ); */ } create_path() { targ = getstruct( "road_path_left", "targetname" ); assert( isdefined( targ ) ); path = []; /# targ.z = targ.origin[ 2 ]; #/ targ.origin = ( targ.origin[ 0 ], targ.origin[ 1 ], 0 ); count = 0; prev_targ = targ; for ( ;; ) { next_targ = targ; if ( isdefined( targ.target ) ) next_targ = getstruct( targ.target, "targetname" ); /# if ( !isdefined( next_targ.z ) ) next_targ.z = next_targ.origin[ 2 ]; #/ next_targ.origin = ( next_targ.origin[ 0 ], next_targ.origin[ 1 ], 0 ); path[ path.size ] = targ; targ.next_node = next_targ; targ.prev_node = prev_targ; next_targ.previous_node = targ; targ.col_lines = []; targ.col_volumes = []; targ.col_radiuses = []; targ.origins = []; targ.dist_to_next_targs = []; targ.origins[ "left" ] = targ.origin; targ.index = count; count++ ; if ( targ == next_targ ) break; prev_targ = targ; targ = next_targ; } targ = getstruct( "road_path_right", "targetname" ); /# targ.z = targ.origin[ 2 ]; #/ targ.origin = ( targ.origin[ 0 ], targ.origin[ 1 ], 0 ); new_count = 0; for ( ;; ) { next_targ = targ; if ( isdefined( targ.target ) ) next_targ = getstruct( targ.target, "targetname" ); /* vehicle_node = undefined; if ( isdefined( targ.script_linkto ) ) { vehicle_node = getVehicleNode( targ.script_linkto, "script_linkname" ); } */ /# if ( !isdefined( next_targ.z ) ) next_targ.z = next_targ.origin[ 2 ]; #/ next_targ.origin = ( next_targ.origin[ 0 ], next_targ.origin[ 1 ], 0 ); assertex( count >= new_count, "Had more right road nodes than left road nodes." ); parent = path[ new_count ]; assertex( isdefined( parent ), "Had more left road nodes than right road nodes." ); parent.origins[ "right" ] = targ.origin; parent.road_width = distance( parent.origins[ "right" ], parent.origins[ "left" ] ); /* if ( isdefined( vehicle_node ) ) { parent.vehicle_node = vehicle_node; } */ new_count++ ; if ( targ == next_targ ) break; targ = next_targ; } assertex( count == new_count, "Had more left road nodes than right road nodes." ); foreach ( node in path ) { node.midpoint = ( node.origins[ "left" ] + node.origins[ "right" ] ) * 0.5; } foreach ( node in path ) { // calc the new left/right based on road width midpoint1 = node.midpoint; midpoint2 = node.next_node.midpoint; angles = vectortoangles( midpoint1 - midpoint2 ); right = anglestoright( angles ); road_half_width = node.road_width * 0.5; node.origins[ "left" ] = node.midpoint + right * road_half_width; node.origins[ "right" ] = node.midpoint + right * road_half_width * - 1; } // this node doesn't get a mid point because it has no .target node = path[ path.size - 1 ].next_node; node.midpoint = ( node.origins[ "left" ] + node.origins[ "right" ] ) * 0.5; foreach ( node in path ) { node.dist_to_next_targ = distance( node.midpoint, node.next_node.midpoint ); node.dist_to_next_targs[ "left" ] = distance( node.origins[ "left" ], node.next_node.origins[ "left" ] ); node.dist_to_next_targs[ "right" ] = distance( node.origins[ "right" ], node.next_node.origins[ "right" ] ); } return path; } drop_path_to_ground( path ) { targ = self; foreach ( node in path ) { node.origin += ( 0, 0, 20 ); endpos = PhysicsTrace( node.origin, node.origin + ( 0, 0, -100 ) ); node.origin = endpos; } } add_collision_to_path( path ) { collision_lines = getstructarray( "moto_line", "targetname" ); foreach ( collision_line in collision_lines ) { collision_line.origin = ( collision_line.origin[ 0 ], collision_line.origin[ 1 ], 0 ); next_line = getstruct( collision_line.target, "targetname" ); // each collision line is made up of two points and each have a refence // to the other collision_line.other_col_point = next_line; next_line.other_col_point = collision_line; } foreach ( collision_line in collision_lines ) { //droppedLine( collision_line.origin, collision_line.other_col_point.origin, GREEN, 1, 0, 50000 ); } targ = self; foreach ( node in path ) { foreach ( collision_line in collision_lines ) { add_collision_to_path_ent( node, collision_line ); } } // add the hard collision radiuses to the nearest path points moto_collision = getentarray( "moto_collision", "targetname" ); foreach ( col_radius in moto_collision ) { closest_nodes = get_array_of_closest( col_radius.origin, path, undefined, 2 ); foreach ( node in closest_nodes ) { node.col_radiuses[ node.col_radiuses.size ] = col_radius; } } } get_offset_percent( targ, next_targ, progress, offset ) { // translates an offset distance to a percentage dist = distance( targ.midpoint, next_targ.midpoint ); //assertex( progress <= dist, "Too much progress" ); progress_percent = 1 - ( progress / dist ); offset_side = "left"; if ( offset > 0 ) { offset_side = "right"; } // bumper meaning the outer edge of the current targ area bumper_start = targ.origins[ offset_side ]; bumper_end = next_targ.origins[ offset_side ]; // the origin equivalent to our progress, on the bumper bumper_org = bumper_start * progress_percent + bumper_end * ( 1 - progress_percent ); center_start = targ.midpoint; center_end = next_targ.midpoint; // our progress on the center divider center_org = center_start * progress_percent + center_end * ( 1 - progress_percent ); // the track width at our current progress track_width = distance( center_org, bumper_org ); // our offset proportion based on that width return offset / track_width; } add_collision_to_path_ent( targ, col_org ) { if ( targ == targ.next_node ) return; max_dist = targ.road_width; if ( targ.dist_to_next_targ > max_dist ) max_dist = targ.dist_to_next_targ; if ( distance( col_org.origin, targ.next_node.midpoint ) > max_dist * 1.5 ) return; next_org = getstruct( col_org.target, "targetname" ); prog1 = get_progression_between_points( col_org.origin, targ.midpoint, targ.next_node.midpoint ); progress1 = prog1[ "progress" ]; prog2 = get_progression_between_points( next_org.origin, targ.midpoint, targ.next_node.midpoint ); progress2 = prog2[ "progress" ]; if ( progress1 < 0 || progress2 < 0 ) return; if ( progress1 > targ.dist_to_next_targ && progress2 > targ.dist_to_next_targ ) return; assertex( progress1 >= 0, "Negative progress" ); assertex( progress2 >= 0, "Negative progress" ); col_org.claimed = true; next_org.claimed = true; //start = get_position_from_spline( targ, prog1["progress"], prog1["offset"] ); //end = get_position_from_spline( targ, prog2["progress"], prog2["offset"] ); //droppedLineZ( targ.z, start, end, RED, 1, 0, 50000 ); col_org.progress = progress1; col_org.offset = prog1[ "offset" ]; col_org.offset_percent = get_offset_percent( targ, targ.next_node, progress1, prog1[ "offset" ] ); next_org.progress = progress2; next_org.offset = prog2[ "offset" ]; next_org.offset_percent = get_offset_percent( targ, targ.next_node, progress2, prog2[ "offset" ] ); col_org.origin = ( col_org.origin[ 0 ], col_org.origin[ 1 ], targ.midpoint[ 2 ] + 40 ); next_org.origin = ( next_org.origin[ 0 ], next_org.origin[ 1 ], targ.midpoint[ 2 ] + 40 ); // add the collision ents in order of earliest progress then later progress if ( progress1 < progress2 ) { add_collision_offsets_to_path_ent( targ, col_org, next_org ); targ.col_lines[ targ.col_lines.size ] = col_org; } else { add_collision_offsets_to_path_ent( targ, next_org, col_org ); targ.col_lines[ targ.col_lines.size ] = next_org; } } add_collision_offsets_to_path_ent( targ, close_org, far_org ) { // go through the path ents and apply the collision info to each node max_progress = far_org.progress + AHEAD_DISTANCE; min_progress = close_org.progress - level.DODGE_DISTANCE; right_offset = undefined; left_offset = undefined; right_offset_percent = undefined; left_offset_percent = undefined; if ( far_org.offset > close_org.offset ) { right_offset = far_org.offset; left_offset = close_org.offset; right_offset_percent = far_org.offset_percent; left_offset_percent = close_org.offset_percent; } else { right_offset = close_org.offset; left_offset = far_org.offset; right_offset_percent = close_org.offset_percent; left_offset_percent = far_org.offset_percent; } start_targ = targ; start_max_progress = max_progress; start_min_progress = min_progress; // travel down the path and set collision for ( ;; ) { add_vol_to_node( targ, max_progress, min_progress, right_offset, left_offset, right_offset_percent, left_offset_percent ); if ( !isdefined( targ.next_node ) ) break; if ( targ.dist_to_next_targ >= max_progress ) break; max_progress -= targ.dist_to_next_targ; targ = targ.next_node; min_progress = 0; } targ = start_targ; max_progress = start_max_progress; min_progress = start_min_progress; // travel up the path and set collision for ( ;; ) { if ( !isdefined( targ.previous_node ) ) break; if ( min_progress > 0 ) break; targ = targ.previous_node; max_progress = targ.dist_to_next_targ; min_progress = targ.dist_to_next_targ + min_progress; add_vol_to_node( targ, max_progress, min_progress, right_offset, left_offset, right_offset_percent, left_offset_percent ); } } add_vol_to_node( targ, max_col_progress, min_col_progress, right_offset, left_offset, right_offset_percent, left_offset_percent ) { colvol = []; colvol[ "max" ] = max_col_progress; if ( colvol[ "max" ] > targ.dist_to_next_targ ) colvol[ "max" ] = targ.dist_to_next_targ; colvol[ "min" ] = min_col_progress; if ( colvol[ "min" ] < 0 ) colvol[ "min" ] = 0; assert( colvol[ "min" ] < colvol[ "max" ] ); colvol[ "left_offset" ] = left_offset; colvol[ "right_offset" ] = right_offset; colvol[ "left_offset_percent" ] = left_offset_percent; colvol[ "right_offset_percent" ] = right_offset_percent; colvol[ "mid_offset" ] = ( right_offset + left_offset ) * 0.5; colvol[ "mid_offset_percent" ] = ( right_offset_percent + left_offset_percent ) * 0.5; targ.col_volumes[ targ.col_volumes.size ] = colvol; } /* ============= ///ScriptDocBegin "Name: get_progression_between_points( , , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_progression_between_points( start, first_point, second_point ) { first_point = ( first_point[ 0 ], first_point[ 1 ], 0 ); second_point = ( second_point[ 0 ], second_point[ 1 ], 0 ); start = ( start[ 0 ], start[ 1 ], 0 ); prog = []; angles = vectortoangles( second_point - first_point ); forward = anglestoforward( angles ); end = first_point; difference = vectornormalize( end - start ); dot = vectordot( forward, difference ); normal = vectorNormalize( second_point - first_point ); vec = start - first_point; progress = vectorDot( vec, normal ); offset_org = first_point + forward * progress; prog[ "progress" ] = progress; prog[ "offset" ] = distance( offset_org, start ); right = anglestoright( angles ); difference = vectornormalize( offset_org - start ); dot = vectordot( right, difference ); prog[ "dot" ] = dot; if ( dot > 0 ) prog[ "offset" ] *= -1; return prog; } wipe_out( bike ) { foreach ( col_radius in self.targ.col_radiuses ) { crashPoint = ( self.origin[ 0 ], self.origin[ 1 ], 0 ); if ( distance( ( col_radius.origin[ 0 ], col_radius.origin[ 1 ], 0 ), crashPoint ) < col_radius.radius ) return true; } if ( bike.health >= 100 )// 0 && bike.rider.health >= 100 ) return false; level.bike_score++ ; return true; } vehicle_line( bike ) { self endon( "death" ); bike endon( "death" ); for ( ;; ) { line( self.origin, bike.origin, ( 0.2, 0.8, 0.3 ), 1, 0 ); wait( 0.05 ); } } spawner_random_team() { waittillframeend; if ( !isdefined( self.riders ) ) return; team = "axis"; if ( cointoss() ) team = "allies"; foreach ( guy in self.riders ) { guy.team = team; } } get_spawn_position( player_targ, my_progress ) { // convert the progress/targ to the actual targ/progress ent = move_to_correct_segment( player_targ, my_progress ); progress = ent.progress; targ = ent.targ; // pick a random track offset then adjust it for obstacles half_road_width = targ.road_width * 0.5; offset = undefined; if ( isdefined( level.player.offset ) ) { random_offset = 500; if ( cointoss() ) random_offset *= -1; offset = level.player.offset + random_offset; } else { offset = randomfloatrange( half_road_width * -1, half_road_width ); } obstacle_array = get_obstacle_dodge_amount( targ, progress, offset ); if ( isdefined( obstacle_array["dodge"] ) ) offset = obstacle_array["dodge"]; // get the point on the spline spawn_pos = get_position_from_spline_unlimited( targ, progress, offset ); array = []; array["spawn_pos"] = spawn_pos; array["progress"] = progress; array["targ"] = targ; array["offset"] = offset; return array; } debug_enemy_vehicles() { /# if ( !getdebugdvarint( "vehicle_spline_debug" ) ) return; level notify( "stop_debugging_enemy_vehicles" ); array_thread( level.enemy_snowmobiles, ::debug_enemy_vehicles_line ); #/ } debug_enemy_vehicles_line() { self endon( "death" ); level endon( "stop_debugging_enemy_vehicles" ); for ( ;; ) { line( self.origin, level.player.origin, ( 1, 0.5, 0 ) ); wait( 0.05 ); } } spawn_enemy_bike() { assertex( isdefined( level.enemy_snowmobiles ), "Please add maps\_vehicle_spline::init_vehicle_splines(); to the beginning of your script" ); /# debug_enemy_vehicles(); #/ if ( level.enemy_snowmobiles.size >= level.enemy_snowmobiles_max ) return; player_targ = get_player_targ(); player_progress = get_player_progress(); my_direction = "forward"; spawn_array = get_spawn_position( player_targ, player_progress - 1000 - level.POS_LOOKAHEAD_DIST ); spawn_pos = spawn_array["spawn_pos"]; player_sees_me_spawn = within_fov( level.player.origin, level.player.angles, spawn_pos, 0 ); if ( player_sees_me_spawn ) { // player could see us so try spawning in front of the player and drive backwards spawn_array = get_spawn_position( player_targ, player_progress + 1000 ); spawn_pos = spawn_array["spawn_pos"]; my_direction = "backward"; player_sees_me_spawn = within_fov( level.player.origin, level.player.angles, spawn_pos, 0 ); if ( player_sees_me_spawn ) { return; } } // found a safe spawn pos spawn_pos = drop_to_ground( spawn_pos ); snowmobile_spawner = getent( "snowmobile_spawner", "targetname" ); assertEx( isdefined( snowmobile_spawner ), "Need a snowmobile spawner with targetname snowmobile_spawner in the level" ); targ = spawn_array["targ"]; snowmobile_spawner.origin = spawn_pos; //snowmobile_spawner.angles = vectortoangles( snowmobile_path_node.next_node.midpoint - snowmobile_path_node.midpoint ); snowmobile_spawner.angles = vectortoangles( targ.next_node.midpoint - targ.midpoint ); /* if ( isalive( level.player ) && isdefined( level.player.vehicle ) ) snowmobile_spawner.angles = level.player.vehicle.angles; */ ai_spawners = snowmobile_spawner get_vehicle_ai_spawners(); foreach ( spawner in ai_spawners ) { spawner.origin = snowmobile_spawner.origin; } bike = vehicle_spawn( snowmobile_spawner ); bike.offset_percent = spawn_array["offset"]; bike VehPhys_SetSpeed( 90 ); bike thread crash_detection(); bike.left_spline_path_time = gettime() - 3000; waittillframeend; // for bike.riders to get defined if ( !isalive( bike ) ) return; targ bike_drives_path( bike ); } crash_detection() { self waittill( "veh_collision", velocity, collisionNormal ); self wipeout( "collision!" ); } rider_death_detection( bike ) { self waittill( "death" ); if ( isdefined( bike ) ) { bike wipeout( "driver died!" ); } } wipeout( msg ) { /# if ( !self.wipeout ) { if ( getdebugdvarint( "vehicle_spline_debug" ) ) Print3d( self.origin, msg, (1,0.25,0), 1, 1.5, 400 ); } #/ self.wipeout = true; } update_bike_player_avoidance( my_bike ) { bikes = []; foreach ( bike in level.enemy_snowmobiles ) { if ( !isalive( bike ) ) continue; if ( bike.wipeout ) continue; bikes[ bikes.size ] = bike; } level.enemy_snowmobiles = bikes; if ( isalive( my_bike ) && !my_bike.wipeout ) { found_bike = false; foreach ( bike in level.enemy_snowmobiles ) { if ( bike == my_bike ) { found_bike = true; continue; } } if ( !found_bike ) { level.enemy_snowmobiles[ level.enemy_snowmobiles.size ] = my_bike; } } offset = 0; foreach ( bike in level.enemy_snowmobiles ) { bike.bike_avoidance_offset = offset; offset += 75; } } bike_drives_path( bike ) { if ( !isdefined( bike.left_spline_path_time ) ) bike.left_spline_path_time = gettime(); bike.wipeout = false; update_bike_player_avoidance( bike ); // speed = randomfloatrange( 50, 70 ); if ( !isdefined( bike.player_offset ) ) bike.player_offset = 250; bike.steering = 0; offset = randomfloatrange( 0, 1 ); if ( !isdefined( bike.offset_percent ) ) bike.offset_percent = offset * 2 - 1; targ = self; ent = spawnstruct(); ent.origin = self.midpoint; ent.progress = 0; ent.tilt_vel = 0; ent.speed = 100; ent ent_flag_init( "biker_reaches_path_end" ); // let other scripts know that track behavior has taken over bike notify( "enable_spline_path" ); /* foreach ( rider in bike.riders ) { if ( !isdefined( rider.magic_bullet_shield ) ) rider thread magic_bullet_shield(); } */ if ( !bike.riders.size ) { bike VehPhys_Crash(); return; } array_thread( bike.riders, ::rider_death_detection, bike ); ent.bike = bike; //bike EnableAimAssist(); //bike playloopsound( "veh_motorcycle_dist_loop" ); bike.health = 100; wipeout = false; ent thread bike_ent_wipe_out_check( bike ); // track the bike's progress along the path so we can do proper angles bike.progress_targ = targ; bike.offset_modifier = 0; bike.fails = 0; bike.direction = "forward"; bike.old_pos = bike.origin; for ( ;; ) { /# if ( getdebugdvarint( "vehicle_spline_debug" ) ) bike debug_bike_line(); #/ if ( !isalive( bike ) ) break; set_bike_position( ent ); if ( !isalive( bike ) ) break; if ( abs( bike.progress_dif ) > 6000 && gettime() > bike.left_spline_path_time + 4000 ) { bike wipeout( "left behind!" ); } waittillframeend;// for bike_ent wipeout to occur if ( bike.wipeout ) { if ( isdefined( bike.hero ) ) continue; bike VehPhys_Crash(); foreach ( rider in bike.riders ) { if ( isalive( rider ) ) { //rider stop_magic_bullet_shield(); rider kill(); } } wait( 5 ); if ( isdefined( bike ) ) { bike delete(); } update_bike_player_avoidance(); return; // bike thread bike_wipes_out( ent ); // bike hide(); } if ( ent ent_flag( "biker_reaches_path_end" ) || flag( "race_complete" ) ) break; } update_bike_player_avoidance(); ent notify( "stop_bike" ); level notify( "biker_dies" ); if ( bike.wipeout && !flag( "race_complete" ) ) wait( 5 ); ent ent_flag_clear( "biker_reaches_path_end" ); } get_obstacle_dodge_amount( targ, progress, offset ) { array[ "near_obstacle" ] = false; foreach ( vol in targ.col_volumes ) { if ( progress < vol[ "min" ] ) continue; if ( progress > vol[ "max" ] ) continue; array[ "near_obstacle" ] = true; if ( offset < vol[ "left_offset" ] ) continue; if ( offset > vol[ "right_offset" ] ) continue; org = ( targ.midpoint + targ.next_node.midpoint ) * 0.5; //droppedLineZ( targ.z, org, origin, RED, 1, 0, 1 ); if ( offset > vol[ "mid_offset" ] ) array[ "dodge" ] = vol[ "right_offset" ]; else array[ "dodge" ] = vol[ "left_offset" ]; break; } return array; } sweep_tells_vehicles_to_get_off_path() { for ( ;; ) { self waittill( "trigger", other ); if ( !isdefined( other.script_noteworthy ) ) continue; if ( other.script_noteworthy != "sweepable" ) continue; timer = randomfloatrange( 0, 1 ); other thread notify_delay( "enable_spline_path", timer ); } } drawmyoff() { for ( ;; ) { if ( isdefined( level.player.vehicle ) ) { my_speed = self vehicle_getSpeed(); p_speed = level.player.vehicle vehicle_getSpeed(); Print3d( self.origin + (0,0,64), my_speed - p_speed, (1,0,0.2), 1, 1.2 ); level.difference = my_speed - p_speed; Line( self.origin, level.player.origin, (1,0,0.2) ); } wait( 0.05 ); } } priceliner() { /# create_dvar( "price_line", 0 ); for ( ;; ) { if ( !isdefined( level.player.vehicle ) ) return; forward = anglestoforward( level.player.vehicle.angles ); forward *= -150; if ( getdebugdvarint( "price_line" ) ) Line( level.player.origin + forward, self.origin, (1,0,0) ); wait( 0.05 ); } #/ } modulate_speed_based_on_progress() { /* if ( flag( "price_leaves_player_throttling" ) ) return; level endon( "price_leaves_player_throttling" ); */ // thread drawmyoff(); thread priceliner(); self.targ = get_my_spline_node( self.origin ); self.min_speed = 1; self endon( "stop_modulating_speed" ); hud = undefined; /# hud = maps\_hud_util::createFontString( "default", 1.5 ); hud maps\_hud_util::setPoint( "MIDDLE", "MIDDLE", 0, 30 ); hud.color = ( 1, 1, 1 ); hud.alpha = 1; #/ for ( ;; ) { // wait( randomfloatrange( 0.4, 1.2 ) ); wait( 0.05 ); targ = self.targ; if ( targ == targ.next_node ) { // reached end return; } array = get_progression_between_points( self.origin, self.targ.midpoint, self.targ.next_node.midpoint ); progress = array["progress"]; progress += level.POS_LOOKAHEAD_DIST; ent = move_to_correct_segment( self.targ, progress ); progress = ent.progress; self.targ = ent.targ; self.progress = progress; player_targ = get_player_targ(); player_progress = get_player_progress(); dif = progress_dif( self.targ, self.progress, player_targ, player_progress ); level.progress_dif = dif; /* if ( dif < -1000 ) { // catch up if ( isdefined( player_targ.next_node ) && isdefined( player_targ.next_node.vehicle_node ) ) { path = player_targ.next_node.vehicle_node; endpos = self get_bike_pos_from_spline( player_targ, player_progress - 500, 0, path.origin[ 2 ] ); self Vehicle_Teleport( endpos, self.angles ); self startPath( path ); Line( level.player.origin, endpos, (1,0,1), 1, 0, 500 ); } } */ if ( !isdefined( level.player.vehicle ) ) { self Vehicle_SetSpeed( 65, 1, 1 ); continue; } if ( abs( dif > 3500 ) ) { speed = 65; // if we're between these two speeds, then //normal_max = 600; //normal_min = 300; //dif_min = 300; dif *= -1; dif += 750; // go this far ahead of the player speed = level.player.vehicle.veh_speed + dif * 0.05; max_speed = level.player.vehicle.veh_speed; if ( max_speed < 100 ) max_speed = 100; if ( speed > max_speed ) speed = max_speed; else if ( speed < self.min_speed ) speed = self.min_speed; level.desired_speed = speed; //my_speed = self vehicle_getSpeed(); //if ( abs( player_speed - my_speed ) > 50 ) // self Vehicle_SetSpeedImmediate( speed, 90, 20 ); //else self Vehicle_SetSpeed( speed, 90, 20 ); } else { price_match_player_speed( 10, 10 ); /# //hud setText( int( array["progress"] ) + " mult:" + multiplier + " dspeed:" + int( my_speed ) + " aspeed:" + int( self.veh_speed ) ); #/ } } } price_match_player_speed( maxaccell, maxdecel ) { angles = self.angles; angles = ( 0, angles[1], 0 ); forward = anglestoforward( angles ); array = get_progression_between_points( level.player.vehicle.origin, self.origin + forward * 1, self.origin - forward * 1 ); progress = array["progress"]; if ( progress > 4000 ) self Vehicle_SetSpeed( 0, 90, 20 ); else { dot = get_dot( self.origin, self.angles, level.player.origin ); multiplier = 1; if ( progress > 0 ) { // we're ahead of the player /* if ( progress > 3000 ) multiplier = 0.1; else if ( progress > 1000 ) multiplier = 0.2; else if ( progress > 500 ) multiplier = 0.6; else if ( progress > 300 ) multiplier = 0.9; else if ( progress > 150 ) multiplier = 0.98; else if ( progress > 100 ) multiplier = 0.99; else if ( progress > 50 ) multiplier = 1.0; multiplier += randomfloatrange( -0.5, 0.5 ); if ( multiplier < 1.2 && dot < -0.97 ) { // player is behind us so we need to stay in front of him multiplier = 1.2; } */ multiplier = 1; } else { if ( progress > -500 ) multiplier = 1.25; if ( multiplier > 0.95 && dot > 0.97 ) { // player is ahead of us, don't run him over multiplier = 0.95; } } my_speed = 70 * multiplier; if ( my_speed < self.min_speed ) my_speed = self.min_speed; if ( my_speed < 25 ) my_speed = 25; /* if ( my_speed + 8 < self.veh_speed ) { self Vehicle_SetSpeedImmediate( my_speed, 90, 90 ); } else { if ( my_speed > self.veh_speed + 50 ) self Vehicle_SetSpeedImmediate( my_speed, 90, 90 ); else self Vehicle_SetSpeed( my_speed, 90, 90 ); } */ level.price_desired_speed = my_speed; self Vehicle_SetSpeed( my_speed, maxaccell, maxdecel ); } } match_player_speed( maxaccell, maxdecel ) { angles = self.angles; angles = ( 0, angles[1], 0 ); forward = anglestoforward( angles ); array = get_progression_between_points( level.player.vehicle.origin, self.origin + forward * 1, self.origin - forward * 1 ); progress = array["progress"]; if ( progress > 4000 ) self Vehicle_SetSpeed( 0, 90, 20 ); else { if ( progress < level.SPLINE_MIN_PROGRESS && gettime() > self.left_spline_path_time + 4000 ) { self wipeout( "low progress!" ); } progress -= 750; progress += self.bike_avoidance_offset; multiplier = 1; if ( progress > 150 ) multiplier = 0.6; else if ( progress > 100 ) multiplier = 1.0; else if ( progress < -100 ) multiplier = 1.5; if ( isdefined( level.player.offset ) ) { if ( progress > 250 ) { // we're speeding up from behind so stay to the side // range = 200; // if ( array[ "offset" ] > level.player.offset + range ) // self.preferred_offset = level.player.offset + range; // else // if ( array[ "offset" ] < level.player.offset - range ) // self.preferred_offset = level.player.offset - range; //// self.preferred_offset = undefined; } /* else { self.preferred_offset = level.player.offset + randomfloatrange( -150, 150 ); } */ } my_speed = level.player.vehicle.veh_speed * multiplier; if ( my_speed < 25 ) my_speed = 25; /* if ( my_speed + 8 < self.veh_speed ) { self Vehicle_SetSpeedImmediate( my_speed, 90, 90 ); } else { if ( my_speed > self.veh_speed + 50 ) self Vehicle_SetSpeedImmediate( my_speed, 90, 90 ); else self Vehicle_SetSpeed( my_speed, 90, 90 ); } */ self Vehicle_SetSpeed( my_speed, maxaccell, maxdecel ); } } track_player_progress( org ) { self notify( "track_player_progress" ); self endon( "track_player_progress" ); self.targ = get_my_spline_node( org ); self.progress = 0; player_sweep_trigger = getent( "player_sweep_trigger", "targetname" ); sweep_trigger = isdefined( player_sweep_trigger ); if ( sweep_trigger ) player_sweep_trigger thread sweep_tells_vehicles_to_get_off_path(); for ( ;; ) { if ( self.targ == self.targ.next_node ) { // reached end return; } array = get_progression_between_points( self.origin, self.targ.midpoint, self.targ.next_node.midpoint ); progress = array["progress"]; progress += level.POS_LOOKAHEAD_DIST; ent = move_to_correct_segment( self.targ, progress ); progress = ent.progress; self.targ = ent.targ; self.progress = progress; self.offset = array[ "offset" ]; if ( sweep_trigger ) { trigger_pos = get_position_from_spline_unlimited( self.targ, progress + 2000, 0 ); trigger_pos = ( trigger_pos[ 0 ], trigger_pos[ 1 ], self.origin[ 2 ] - 500 ); player_sweep_trigger.origin = trigger_pos; lookahead_pos = get_position_from_spline_unlimited( self.targ, progress + 3000, 0 ); angles = vectortoangles( player_sweep_trigger.origin - lookahead_pos ); player_sweep_trigger.angles = ( 0, angles[ 1 ], 0 ); } if ( flag( "ai_snowmobiles_ram_player" ) ) { // now find which enemy is closest to the player level.closest_enemy_snowmobile_to_player = getClosest( self.origin, level.enemy_snowmobiles ); } else { // dont chase the player during crzy downhill part level.closest_enemy_snowmobile_to_player = undefined; } /* sweep_targ = self.targ; progress += 2000; for ( ;; ) { if ( progress > sweep_targ.dist_to_next_targ ) { progress -= sweep_targ.dist_to_next_targ; sweep_targ = sweep_targ.next_node; continue; } break; } player_sweep_trigger.origin = get_position_from_spline( sweep_targ, progress, 0 ); player_sweep_trigger.origin = ( player_sweep_trigger.origin[ 0 ], player_sweep_trigger.origin[ 1 ], self.origin[ 2 ] - 500 ); sweep_yaw = vectortoangles( sweep_targ.origin - sweep_targ.next_node.origin )[ 1 ]; sweep_yaw_next = vectortoangles( sweep_targ.next_node.origin - sweep_targ.next_node.next_node.origin )[ 1 ]; yaw = sweep_yaw * progress_percent + sweep_yaw_next * ( 1 - progress_percent ); player_sweep_trigger.angles = ( 0, yaw, 0 ); */ wait( 0.05 ); } } progress_dif( targ, progress, targ2, progress2 ) { while ( targ.index > targ2.index ) { targ = targ.prev_node; progress += targ.dist_to_next_targ; } while ( targ2.index > targ.index ) { targ2 = targ2.prev_node; progress2 += targ2.dist_to_next_targ; } return progress - progress2; } set_bike_position( ent ) { bike = ent.bike; timer = 0.1; // find the bike's progress and position on the path that runs down the middle of the road progress = 0; offset = 0; targ = bike.progress_targ; if ( targ == targ.next_node ) { bike delete(); return; } // don't consider targs we're a long way away from array = get_progression_between_points( bike.origin, targ.midpoint, targ.next_node.midpoint ); array_next = get_progression_between_points( bike.origin, targ.next_node.midpoint, targ.next_node.next_node.midpoint ); // if we could be in the next nodeset then put us there. if ( array_next["progress"] > 0 && array_next["progress"] < targ.next_node.dist_to_next_targ ) { array = array_next; targ = targ.next_node; } offset = array["offset"]; player_progress = 0; progress = array["progress"]; bike.progress = progress; obstacle_array = get_obstacle_dodge_amount( targ, progress, offset ); crashing = obstacle_array["near_obstacle"]; dif = progress_dif( targ, progress, get_player_targ(), get_player_progress() ); bike.progress_dif = dif; if ( bike.direction == "forward" ) { progress += level.POS_LOOKAHEAD_DIST; } else { progress -= level.POS_LOOKAHEAD_DIST; if ( dif < 500 ) { bike.direction = "forward"; } } min_speed = 60; // slowest to go when too fast ahead max_speed = 90; // max speed to catch up min_dist = 100; // distance at which to go max speed max_dist = 200; // distance at which you go slowest speed if ( dif > max_dist ) { speed = min_speed; } else if ( dif < min_dist ) { speed = max_speed; } else { dist_dif = max_dist - min_dist; speed_dif = max_speed - min_speed; speed = dif - min_dist; speed = dist_dif - speed; speed *= speed_dif / dist_dif; speed += min_speed; assert( speed >= min_speed && speed <= max_speed ); } if ( speed > 0 ) { if ( bike vehicle_getspeed() < 2 ) { bike.fails++ ; if ( bike.fails > 10 ) { bike wipeout( "move fail!" ); return; } } else bike.fails = 0; } else bike.fails = 0; offset_modifier = randomfloatrange( 0, 100 ); offset_modifier *= 0.001; chaseCam = false; /# if ( getdvarint( "chasecam" ) ) { chasecam = true; } #/ current_road_width = targ.road_width; ent = move_to_correct_segment( targ, progress ); progress = ent.progress; targ = ent.targ; org = ( targ.midpoint + targ.next_node.midpoint ) * 0.5; //droppedLineZ( targ.z, org, bike.origin, GREEN, 1, 0, timer ); // scale the offset by the ratio of the road width I'm going to offset = offset * targ.road_width / current_road_width; obstacle_array = get_obstacle_dodge_amount( targ, progress, offset ); if ( isdefined( obstacle_array["dodge"] ) ) { // is there an obstacle? dodge it offset = obstacle_array["dodge"]; } else { if ( isdefined( bike.preferred_offset ) ) { offset = bike.preferred_offset; } } // cap the offset to the legit road offset_limit = 0.95; road_half_width = targ.road_width * 0.5; road_half_width -= 50; // bring the edge in a little if ( offset > road_half_width ) offset = road_half_width; else if ( offset < - 1 * road_half_width ) offset = -1 * road_half_width; //speed = 70; if ( targ != targ.next_node ) { endpos = bike get_bike_pos_from_spline( targ, progress, offset, bike.origin[ 2 ] ); dot = get_dot( bike.origin, bike.angles, endpos ); //Print3d( bike.origin, dot, (0,0.3,1), 1, 1, int( timer * 20 ) ); if ( dot < 0.97 ) speed = 50; else if ( dot < 0.96 ) speed = 25; else if ( dot < 0.95 ) speed = 15; bike vehicleDriveTo( endpos, speed ); if ( !isdefined( level.player.vehicle ) ) { bike Vehicle_SetSpeed( 65, 1, 1 ); } else { bike.veh_topspeed = level.player.vehicle.veh_topspeed * 1.3; bike match_player_speed( 45, 30 ); } /# if ( getdebugdvarint( "vehicle_spline_debug" ) && isdefined( level.player.vehicle ) ) if ( bike.veh_speed > level.player.vehicle.veh_speed ) thread Linedraw( bike.origin, endpos, ( 0.9, 0.1, 0.3 ), 1, 0, timer ); else thread Linedraw( bike.origin, endpos, ( 0.3, 0.1, 0.9 ), 1, 0, timer ); #/ } bike.progress_targ = targ; bike.offset = offset; wait( timer ); } get_bike_pos_from_spline( targ, progress, offset, z ) { bike_lookahead_pos = get_position_from_spline( targ, progress, offset ); bike_lookahead_pos = set_z( bike_lookahead_pos, z ); return PhysicsTrace( bike_lookahead_pos + ( 0, 0, 200 ), bike_lookahead_pos + ( 0, 0, -200 ) ); } move_to_correct_segment( targ, progress ) { ent = spawnstruct(); // convert progress to proper progress and targ for ( ;; ) { if ( targ == targ.next_node ) { break; } if ( progress > targ.dist_to_next_targ ) { progress -= targ.dist_to_next_targ; targ = targ.next_node; continue; } if ( progress < 0 ) { progress += targ.dist_to_next_targ; targ = targ.prev_node; continue; } break; } ent.targ = targ; ent.progress = progress; return ent; } get_position_from_spline_unlimited( targ, progress, offset ) { // travels down the path first for ( ;; ) { if ( targ == targ.next_node ) { return targ.midpoint; } if ( progress > targ.dist_to_next_targ ) { progress -= targ.dist_to_next_targ; targ = targ.next_node; continue; } break; } return get_position_from_spline( targ, progress, offset ); } //get_position_from_spline( targ, progress, offset ) //{ /* angles = vectortoangles( targ.midpoint - targ.next_node.midpoint ); right = anglestoright( angles ); */ //pos = get_position_from_progress( targ, progress ); //pos = get_position_from_progress( targ, progress ); /* new_pos = get_position_from_offset( targ, targ.next_node, progress, offset ); ratio = 1 - ( progress / targ.dist_to_next_targ ); droppedLine( targ.midpoint, targ.next_node.midpoint, ( 0.5, 0.5, 0.5 ), 1, 0, 0.2 ); mid_origin = targ.midpoint * ratio + targ.next_node.midpoint * ( 1 - ratio ); droppedLine( mid_origin, new_pos, ( 0.4, 0.4, 0.6 ), 1, 0, 0.2 ); return new_pos; */ //} get_position_from_spline( targ, progress, offset ) { angles = vectortoangles( targ.next_node.midpoint - targ.midpoint ); forward = anglesToForward( angles ); right = anglesToRight( angles ); return targ.midpoint + forward * progress + right * offset; /* // assertex( progress >= 0, "Negative progress" ); // translates an offset distance to a percentage dist = distance( targ.midpoint, next_targ.midpoint ); assertex( progress <= dist, "Too much progress" ); progress_percent = 1 - ( progress / targ.dist_to_next_targ ); offset_side = "left"; if ( offset < 0 ) { offset_side = "right"; } // bumper meaning the outer edge of the current targ area bumper_start = targ.origins[ offset_side ]; bumper_end = next_targ.origins[ offset_side ]; // the origin equivalent to our progress, on the bumper bumper_org = bumper_start * progress_percent + bumper_end * ( 1 - progress_percent ); center_start = targ.midpoint; center_end = next_targ.midpoint; // our progress on the center divider center_org = center_start * progress_percent + center_end * ( 1 - progress_percent ); //droppedLine( center_org, bumper_org, GREEN, 1, 0, 5000 ); offset_percent = 1 - abs( offset_percent ); return center_org * offset_percent + bumper_org * ( 1 - offset_percent ); */ } get_position_from_progress( targ, progress ) { progress_percent = 1 - ( progress / targ.dist_to_next_targ ); return targ.midpoint * progress_percent + targ.next_node.midpoint * ( 1 - progress_percent ); } bike_ent_wipe_out_check( bike ) { self endon( "stop_bike" ); for ( ;; ) { //self.wipeout = wipe_out( bike ); self.wipeout = false;// need to find out from c0de if ( self.wipeout ) break; wait( 0.05 ); } } draw_bike_debug() { for ( ;; ) { waittillframeend; Print3d( self.origin, self.goal_dir, ( 1, 1, 1 ), 2 ); wait( 0.05 ); } } track_progress() { self endon( "stop_bike" ); for ( ;; ) { start = ( self.origin[ 0 ], self.origin[ 1 ], 0 ); end = ( self.targ.midpoint[ 0 ], self.targ.midpoint[ 1 ], 0 ); next_targ = ( self.next_targ.midpoint[ 0 ], self.next_targ.midpoint[ 1 ], 0 ); difference = vectornormalize( end - start ); forward = anglestoforward( self.angles ); dot = vectordot( forward, difference ); normal = vectorNormalize( next_targ - end ); vec = start - end; self.progress = vectorDot( vec, normal ); //Print3d( self.origin +(0,0,60), progress ); wait( 0.05 ); } } set_road_offset( targ ) { self.right_offset = targ.road_width * 0.5; self.safe_offset = self.right_offset - 100; } bike_avoids_obstacles( bike ) { self endon( "stop_bike" ); self endon( "end_path" ); self.goal_dir = 0; //thread bike_assigns_dodge_dir_from_obstacles( bike ); thread bike_randomly_changes_lanes(); bike_turns(); } bike_randomly_changes_lanes() { self endon( "stop_bike" ); self endon( "end_path" ); for ( ;; ) { if ( self.targ.col_volumes.size == 0 && self.dodge_dir == 0 ) { if ( cointoss() ) self.goal_dir++ ; else self.goal_dir -- ; if ( self.goal_dir > 1 ) self.goal_dir -= 3; else if ( self.goal_dir < - 1 ) self.goal_dir += 3; } wait( randomfloatrange( 1, 3 ) ); } } should_stabilize() { if ( self.goal_dir == 0 ) return true; if ( self.goal_dir == 1 && self.offset > self.safe_offset ) return true; if ( self.goal_dir == -1 && self.offset < self.safe_offset * - 1 ) return true; return false; } bike_turns() { self.tilt_vel = 0; tilt_vel_max = 12; tilt_rate = 3; max_turn_speed = 130; for ( ;; ) { if ( should_stabilize() ) { // stabilizing if ( self.tilt > 0 ) { self.tilt_vel -= tilt_rate; } else if ( self.tilt < 0 ) { self.tilt_vel += tilt_rate; } } else if ( self.goal_dir == 1 ) { self.tilt_vel += tilt_rate; } else if ( self.goal_dir == -1 ) { self.tilt_vel -= tilt_rate; } if ( self.tilt_vel > tilt_vel_max ) { self.tilt_vel = tilt_vel_max; } else if ( self.tilt_vel < - 1 * tilt_vel_max ) { self.tilt_vel = -1 * tilt_vel_max; } self.tilt += self.tilt_vel; if ( self.tilt > max_turn_speed ) { self.tilt = max_turn_speed; self.tilt_vel = 1;// keep some tilt so we don't change the turn logic } else if ( self.tilt < max_turn_speed * - 1 ) { self.tilt = max_turn_speed * - 1; self.tilt_vel = -1;// keep some tilt so we don't change the turn logic } wait( 0.05 ); } } stabalize( max_turn_speed, tilt_rate ) { if ( self.tilt > 0 ) { self.tilt -= tilt_rate; } else { self.tilt += tilt_rate; } if ( abs( self.tilt ) < tilt_rate ) self.tilt = tilt_rate; } tilt_right( max_turn_speed, tilt_rate ) { if ( self.offset >= self.safe_offset ) { self.goal_dir = 0; return; } self.tilt += tilt_rate; if ( self.tilt >= max_turn_speed ) self.tilt = max_turn_speed; } tilt_left( max_turn_speed, tilt_rate ) { if ( self.offset < self.safe_offset * - 1 ) { self.goal_dir = 0; return; } self.tilt -= tilt_rate; if ( self.tilt < max_turn_speed * - 1 ) self.tilt = max_turn_speed * - 1; } /* bike_ent_drives_path( ent, targ ) { bike = ent.bike; ent endon( "stop_bike" ); set_road_offset( targ ); ent.offset = randomfloatrange( ent.right_offset * - 1, ent.right_offset ); ent.progress_percent = 1; ent.offset_percent = 0.5; ent.tilt = 0; ent.targ = targ; next_targ = targ; thread bike_avoids_obstacles( bike ); next_turn = gettime() + randomfloatrange( 1000, 4000 ); count = 0; sides = []; sides[ sides.size ] = "left"; sides[ sides.size ] = "right"; frame_time = 0.05; for ( ;; ) { if ( ent.progress_percent >= 1.0 ) { ent.progress_percent -= 1.0; targ = next_targ; if ( !isdefined( targ.target ) ) break; next_targ = getent( targ.target, "targetname" ); ent.targ = targ; count++ ; ent.next_targ = next_targ; set_road_offset( targ ); } ent.offset += ent.tilt * 0.05; if ( ent.offset > ent.right_offset ) ent.offset = ent.right_offset; else if ( ent.offset < ent.right_offset * - 1 ) ent.offset = ent.right_offset * - 1; road_width = targ.road_width; column_position = []; foreach ( side in sides ) { column_position[ side ] = targ.origins[ side ] * ( 1 - ent.progress_percent ) + next_targ.origins[ side ] * ent.progress_percent; } current_column_position = column_position[ "left" ] * ent.offset_percent + column_position[ "right" ] * ( 1 - ent.offset_percent ); row_position = []; row_position[ "front" ] = targ.origins[ "left" ] * ent.offset_percent + targ.origins[ "right" ] * ( 1 - ent.offset_percent ); row_position[ "back" ] = next_targ.origins[ "left" ] * ent.offset_percent + next_targ.origins[ "right" ] * ( 1 - ent.offset_percent ); ent.origin = current_column_position; ent.angles = vectortoangles( row_position[ "front" ] - row_position[ "back" ] ); dist = distance( row_position[ "front" ], row_position[ "back" ] ); ent.progress = dist * ent.progress_percent; current_progress = ent.progress; next_progress = ent.progress + ent.speed * frame_time; ent.progress_percent = next_progress / dist; wait( frame_time ); } flag_set( "biker_reaches_path_end", ent ); ent notify( "end_path" ); } */ get_player_progress() { if ( isdefined( level.player.progress ) ) { return level.player.progress; } return 0; } get_player_targ() { if ( isdefined( level.player.targ ) ) return level.player.targ; return level.snowmobile_path[0]; } debug_bike_line() { color = ( 0.2, 0.2, 1.0 ); if ( isdefined( level.player.vehicle ) && self.veh_speed > level.player.vehicle.veh_speed ) color = ( 1.0, 0.2, 0.2 ); Line( self.old_pos, self.origin, color, 1, 0, 50000 ); self.old_pos = self.origin; }