IW4-Dump-Files/maps/_vehicle_spline.gsc

2107 lines
50 KiB
Plaintext

#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( <start> , <first_point> , <second_point> )"
"Summary: "
"Module: Entity"
"CallOn: An entity"
"MandatoryArg: <param1>: "
"OptionalArg: <param2>: "
"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;
}