2856 lines
68 KiB
Plaintext
2856 lines
68 KiB
Plaintext
|
#include maps\_utility;
|
||
|
#include common_scripts\utility;
|
||
|
#include maps\_anim;
|
||
|
#include animscripts\utility;
|
||
|
#include maps\_vehicle_spline_zodiac;
|
||
|
#include maps\_vehicle;
|
||
|
|
||
|
trigger_multiple_speed_think()
|
||
|
{
|
||
|
speed = self.script_speed;
|
||
|
AssertEx( IsDefined( speed ), "Trigger at " + self.origin + " has no script_speed" );
|
||
|
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self waittill( "trigger", other );
|
||
|
if ( !isdefined( other.vehicle ) )
|
||
|
continue;
|
||
|
other.vehicle.veh_topspeed = speed;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//hmmmmmmmm
|
||
|
|
||
|
/*QUAKED trigger_multiple_speed (0.12 0.23 1.0) ? AI_AXIS AI_ALLIES AI_NEUTRAL NOTPLAYER VEHICLE TRIGGER_SPAWN TOUCH_ONCE
|
||
|
defaulttexture="trigger"
|
||
|
Set the player vehicle maxspeed with script_speed.*/
|
||
|
|
||
|
ZODIAC_TREADFX_MOVETIME = .2;
|
||
|
ZODIAC_TREADFX_MOVETIMEFRACTION = 1 / ( ZODIAC_TREADFX_MOVETIME + .05 );
|
||
|
ZODIAC_TREADFX_HEIGHTOFFSET = ( 0, 0, 16 );
|
||
|
|
||
|
zodiac_treadfx_chaser( chaseobj )
|
||
|
{
|
||
|
// self here is the invisible boat for playing leveled wake fx.
|
||
|
PlayFXOnTag( getfx( "zodiac_wake_geotrail" ), self, "tag_origin" );
|
||
|
self NotSolid();
|
||
|
self Hide();
|
||
|
self endon( "death" );
|
||
|
chaseobj endon( "death" );
|
||
|
|
||
|
// needs to be it's own thread so can cleanup after the thing dies.
|
||
|
thread zodiac_treadfx_chaser_death( chaseobj );
|
||
|
|
||
|
chaseobj ent_flag_init( "in_air" );
|
||
|
|
||
|
childthread zodiac_treadfx_stop_notify( chaseobj );
|
||
|
childthread zodiac_treadfx_toggle( chaseobj );
|
||
|
|
||
|
while ( IsAlive( chaseobj ) )
|
||
|
{
|
||
|
// self DontInterpolate();
|
||
|
self MoveTo( chaseobj GetTagOrigin( "tag_origin" ) + ZODIAC_TREADFX_HEIGHTOFFSET + ( chaseobj Vehicle_GetVelocity() / ZODIAC_TREADFX_MOVETIMEFRACTION ), ZODIAC_TREADFX_MOVETIME );
|
||
|
self RotateTo( ( 0, chaseobj.angles[ 1 ], 0 ), ZODIAC_TREADFX_MOVETIME ) ;
|
||
|
wait ZODIAC_TREADFX_MOVETIME + .05;// + .05 to get rid of silly jiggle at the end when issueing back to back moveto's. Code bug I believe.
|
||
|
waittillframeend;
|
||
|
}
|
||
|
self Delete();
|
||
|
}
|
||
|
|
||
|
zodiac_treadfx_toggle( chaseobj )
|
||
|
{
|
||
|
while ( 1 )
|
||
|
{
|
||
|
msg = chaseobj waittill_any_return( "zodiac_treadfx_stop", "veh_leftground" );
|
||
|
if ( msg == "veh_leftground" )
|
||
|
chaseobj ent_flag_set( "in_air" );
|
||
|
|
||
|
StopFXOnTag( getfx( "zodiac_wake_geotrail" ), self, "tag_origin" );
|
||
|
|
||
|
msg = chaseobj waittill_any_return( "zodiac_treadfx_go", "veh_landed" );
|
||
|
if ( msg == "veh_landed" )
|
||
|
chaseobj ent_flag_clear( "in_air" );
|
||
|
|
||
|
PlayFXOnTag( getfx( "zodiac_wake_geotrail" ), self, "tag_origin" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
zodiac_treadfx_stop_notify( chaseobj )
|
||
|
{
|
||
|
while ( 1 )
|
||
|
{
|
||
|
if ( chaseobj Vehicle_GetSpeed() < 4 )
|
||
|
chaseobj notify( "zodiac_treadfx_stop" );
|
||
|
else if ( ! chaseobj ent_flag( "in_air" ) )
|
||
|
chaseobj notify( "zodiac_treadfx_go" );
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
zodiac_treadfx_chaser_death( chaseobj )
|
||
|
{
|
||
|
chaseobj waittill_any( "stop_bike", "death", "kill_treadfx" );
|
||
|
self Delete();
|
||
|
}
|
||
|
|
||
|
zodiac_treadfx()
|
||
|
{
|
||
|
chaser = Spawn( "script_model", self.origin );
|
||
|
chaser SetModel( self.model );
|
||
|
chaser.angles = ( 0, self.angles[ 1 ], 0 );
|
||
|
chaser thread zodiac_treadfx_chaser( self );
|
||
|
}
|
||
|
|
||
|
enemy_chase_boat_breadcrumb()
|
||
|
{
|
||
|
struct = SpawnStruct();
|
||
|
struct.origin = self.origin;
|
||
|
struct.angles = flat_angle( self.angles );
|
||
|
struct.spawn_time = GetTime();
|
||
|
level.breadcrumb[ level.breadcrumb.size ] = struct;
|
||
|
}
|
||
|
|
||
|
vehicle_dump()
|
||
|
{
|
||
|
predumpvehicles = GetEntArray( "script_vehicle", "code_classname" );
|
||
|
vehicles = [];
|
||
|
|
||
|
// dumping can jump a frame in which the information could be altered, this stores the necessary info real quick
|
||
|
foreach ( vehicle in predumpvehicles )
|
||
|
{
|
||
|
if ( IsSpawner( vehicle ) )
|
||
|
continue;
|
||
|
struct = SpawnStruct();
|
||
|
struct.classname = vehicle.classname;
|
||
|
struct.origin = vehicle.origin;
|
||
|
struct.angles = vehicle.angles;
|
||
|
// struct.spawner_id = vehicle.spawner_id;
|
||
|
struct.speedbeforepause = vehicle Vehicle_GetSpeed();
|
||
|
struct.script_VehicleSpawngroup = vehicle.script_vehiclespawngroup;
|
||
|
struct.script_VehicleStartMove = vehicle.script_vehiclestartmove;
|
||
|
struct.model = vehicle.model;
|
||
|
struct.angles = vehicle.angles;
|
||
|
if ( IsDefined( level.playersride ) && vehicle == level.playersride )
|
||
|
struct.playersride = true;
|
||
|
vehicles[ vehicles.size ] = struct;
|
||
|
}
|
||
|
|
||
|
fileprint_launcher_start_file();
|
||
|
fileprint_map_start();
|
||
|
|
||
|
foreach ( i, vehicle in vehicles )
|
||
|
{
|
||
|
origin = fileprint_radiant_vec( vehicle.origin );// convert these vectors to mapfile keypair format
|
||
|
angles = fileprint_radiant_vec( vehicle.angles );
|
||
|
|
||
|
fileprint_map_entity_start();
|
||
|
fileprint_map_keypairprint( "classname", "script_struct" );
|
||
|
fileprint_map_keypairprint( "model", vehicle.model );
|
||
|
fileprint_map_keypairprint( "origin", origin );
|
||
|
fileprint_map_keypairprint( "angles", angles );
|
||
|
if ( IsDefined( vehicle.speedbeforepause ) )
|
||
|
fileprint_map_keypairprint( "current_speed", vehicle.speedbeforepause );
|
||
|
if ( IsDefined( vehicle.script_VehicleSpawngroup ) )
|
||
|
fileprint_map_keypairprint( "script_vehiclespawngroup", vehicle.script_VehicleSpawngroup );
|
||
|
if ( IsDefined( vehicle.script_VehicleStartMove ) )
|
||
|
fileprint_map_keypairprint( "script_vehiclestartmove", vehicle.script_VehicleStartMove );
|
||
|
fileprint_map_entity_end();
|
||
|
}
|
||
|
map_name = level.script + "_veh_ref.map";
|
||
|
fileprint_launcher_end_file( "/map_source/" + map_name );
|
||
|
launcher_write_clipboard( map_name );
|
||
|
}
|
||
|
|
||
|
draw_crumb( crumb, lastcrumb, fraction )
|
||
|
{
|
||
|
if ( !flag( "debug_crumbs" ) )
|
||
|
return;
|
||
|
left_spot = crumb.origin + AnglesToRight( crumb.angles ) * -1000 ;
|
||
|
right_spot = crumb.origin + AnglesToRight( crumb.angles ) * 1000 ;
|
||
|
color = ( fraction, 1 - fraction, 0 );
|
||
|
|
||
|
Line( left_spot, right_spot, color );
|
||
|
|
||
|
if ( !isdefined( lastcrumb ) )
|
||
|
return;
|
||
|
|
||
|
left_spot_last = lastcrumb.origin + AnglesToRight( lastcrumb.angles ) * -1000 ;
|
||
|
right_spot_last = lastcrumb.origin + AnglesToRight( lastcrumb.angles ) * 1000 ;
|
||
|
Line( left_spot, left_spot_last, color );
|
||
|
Line( right_spot, right_spot_last, color );
|
||
|
}
|
||
|
|
||
|
zodiac_physics()
|
||
|
{
|
||
|
self.bigjump_timedelta = 500;
|
||
|
self.event_time = -1;
|
||
|
self.event = [];
|
||
|
self.event[ "jump" ] = [];
|
||
|
self.event[ "jump" ][ "driver" ] = false;
|
||
|
self.event[ "jump" ][ "passenger" ] = false;
|
||
|
self.event[ "bump" ] = [];
|
||
|
self.event[ "bump" ][ "driver" ] = false;
|
||
|
self.event[ "bump" ][ "passenger" ] = false;
|
||
|
self.event[ "bump_big" ] = [];
|
||
|
self.event[ "bump_big" ][ "driver" ] = false;
|
||
|
self.event[ "bump_big" ][ "passenger" ] = false;
|
||
|
self.event[ "sway_left" ] = [];
|
||
|
self.event[ "sway_left" ][ "driver" ] = false;
|
||
|
self.event[ "sway_left" ][ "passenger" ] = false;
|
||
|
self.event[ "sway_right" ] = [];
|
||
|
self.event[ "sway_right" ][ "driver" ] = false;
|
||
|
self.event[ "sway_right" ][ "passenger" ] = false;
|
||
|
self childthread watchVelocity();
|
||
|
self childthread listen_leftground();
|
||
|
self childthread listen_landed();
|
||
|
self childthread listen_jolt();
|
||
|
self childthread listen_bounce();
|
||
|
self childthread listen_turn_spray();
|
||
|
// self thread listen_collision();
|
||
|
}
|
||
|
|
||
|
zodiac_fx( fxName )
|
||
|
{
|
||
|
tag = "tag_origin";
|
||
|
|
||
|
if ( IsDefined( level._effect_tag[ fxName ] ) )
|
||
|
tag = level._effect_tag[ fxName ];
|
||
|
|
||
|
if ( IsDefined( level._effect[ fxName ] ) )
|
||
|
PlayFXOnTag( level._effect[ fxName ], self, tag );
|
||
|
//iprintlnbold( fxName );
|
||
|
if ( IsDefined( level.zodiac_fx_sound[ fxname ] ) )
|
||
|
thread play_sound_on_entity( level.zodiac_fx_sound[ fxname ] );
|
||
|
//println( fxName );
|
||
|
}
|
||
|
|
||
|
listen_leftground()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
flag_wait( "player_on_boat" );
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self waittill( "veh_leftground" );
|
||
|
self.event_time = GetTime();
|
||
|
self.event[ "jump" ][ "driver" ] = true;
|
||
|
self.event[ "jump" ][ "passenger" ] = true;
|
||
|
|
||
|
zodiac_fx( "zodiac_leftground" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
listen_landed()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
wait 2; // no ignore the land that happens when they spawn above the water.
|
||
|
flag_wait( "player_on_boat" );
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self waittill( "veh_landed" );
|
||
|
if ( self.event_time + self.bigjump_timedelta < GetTime() )
|
||
|
{
|
||
|
self.event[ "bump_big" ][ "driver" ] = true;
|
||
|
self.event[ "bump_big" ][ "passenger" ] = true;
|
||
|
if ( ! flag( "player_in_sight_of_boarding" ) )
|
||
|
thread water_bump( "bump_big" );
|
||
|
if ( self == level.players_boat )
|
||
|
zodiac_fx( "player_zodiac_bumpbig" );
|
||
|
else
|
||
|
zodiac_fx( "zodiac_bumpbig" );
|
||
|
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self.event[ "bump" ][ "driver" ] = true;
|
||
|
self.event[ "bump" ][ "passenger" ] = true;
|
||
|
if ( ! flag( "player_in_sight_of_boarding" ) )
|
||
|
thread water_bump( "bump" );
|
||
|
if ( self == level.players_boat )
|
||
|
zodiac_fx( "player_zodiac_bump" );
|
||
|
else
|
||
|
zodiac_fx( "zodiac_bump" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
trigger_set_water_sheating_time( bump_small, bump_big )
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
set_water_sheating_time( bump_small, bump_big );
|
||
|
}
|
||
|
|
||
|
set_water_sheating_time( bump_small, bump_big )
|
||
|
{
|
||
|
// duplicated in af_chase_knife_fight_code
|
||
|
level.water_sheating_time[ "bump" ] = level.water_sheating_time[ bump_small ];
|
||
|
level.water_sheating_time[ "bump_big" ] = level.water_sheating_time[ bump_big ];
|
||
|
}
|
||
|
|
||
|
water_bump( bumptype )
|
||
|
{
|
||
|
if ( !isdefined( level.players_boat ) || self != level.players_boat )
|
||
|
return;
|
||
|
level endon( "missionfailed" );
|
||
|
if ( flag( "missionfailed" ) )
|
||
|
return;
|
||
|
|
||
|
if ( bumptype == "bump_big" )
|
||
|
level.player PlayRumbleOnEntity( "damage_heavy" );
|
||
|
else
|
||
|
level.player PlayRumbleOnEntity( "damage_light" );
|
||
|
|
||
|
if ( !flag( "no_more_physics_effects" ) )
|
||
|
level.player SetWaterSheeting( 1, level.water_sheating_time[ bumptype ] );
|
||
|
}
|
||
|
|
||
|
listen_jolt()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
flag_wait( "player_on_boat" );
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self waittill( "veh_jolt", jolt );
|
||
|
if ( jolt[ 1 ] >= 0 )
|
||
|
{
|
||
|
self.event[ "sway_left" ][ "driver" ] = true;
|
||
|
self.event[ "sway_left" ][ "passenger" ] = true;
|
||
|
|
||
|
zodiac_fx( "zodiac_sway_left" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self.event[ "sway_right" ][ "driver" ] = true;
|
||
|
self.event[ "sway_right" ][ "passenger" ] = true;
|
||
|
|
||
|
zodiac_fx( "zodiac_sway_right" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
listen_bounce()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
flag_wait( "player_on_boat" );
|
||
|
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self waittill( "veh_boatbounce", force );
|
||
|
|
||
|
// if ( self == level.players_boat )
|
||
|
// IPrintLnBold( force );
|
||
|
|
||
|
if ( force < 50.0 )
|
||
|
{
|
||
|
//PlayFXOnTag( getfx( "zodiac_bounce_small_left" ), self, "TAG_FX_LF" );
|
||
|
//PlayFXOnTag( getfx( "zodiac_bounce_small_left" ), self, "TAG_FX_RF" );
|
||
|
zodiac_fx( "zodiac_bounce_small_left" );
|
||
|
zodiac_fx( "zodiac_bounce_small_right" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//PlayFXOnTag( getfx( "zodiac_bounce_large_left" ), self, "TAG_FX_LF" );
|
||
|
//PlayFXOnTag( getfx( "zodiac_bounce_large_left" ), self, "TAG_FX_RF" );
|
||
|
zodiac_fx( "zodiac_bounce_large_left" );
|
||
|
zodiac_fx( "zodiac_bounce_large_right" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
listen_turn_spray()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
velocity = self Vehicle_GetBodyVelocity();
|
||
|
|
||
|
if ( self Vehicle_GetSpeed() > 40 )
|
||
|
{
|
||
|
if ( velocity[ 1 ] < -150.0 )
|
||
|
zodiac_fx( "zodiac_sway_right" );
|
||
|
else if ( velocity[ 1 ] > 150.0 )
|
||
|
zodiac_fx( "zodiac_sway_left" );
|
||
|
}
|
||
|
else if ( self Vehicle_GetSpeed() > 10 )
|
||
|
{
|
||
|
if ( velocity[ 1 ] < -30.0 )
|
||
|
zodiac_fx( "zodiac_sway_right_light" );
|
||
|
else if ( velocity[ 1 ] > 30.0 )
|
||
|
zodiac_fx( "zodiac_sway_left_light" );
|
||
|
}
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
listen_collision()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self waittill( "veh_collision", collision, start_vel );
|
||
|
|
||
|
foreach ( rider in self.riders )
|
||
|
{
|
||
|
if ( IsAlive( rider ) && !isdefined( rider.magic_bullet_shield ) )
|
||
|
{
|
||
|
// rider.specialDeathFunc = animscripts\snowmobile::snowmobile_collide_death;
|
||
|
rider Kill();
|
||
|
}
|
||
|
}
|
||
|
zodiac_fx( "zodiac_collision" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
watchVelocity()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
vel = self Vehicle_GetVelocity();
|
||
|
for ( ;; )
|
||
|
{
|
||
|
self.prevFrameVelocity = vel;
|
||
|
vel = self Vehicle_GetVelocity();
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
autosave_boat_chase()
|
||
|
{
|
||
|
// I should just replace these with real autosave triggers.
|
||
|
self waittill( "trigger" );
|
||
|
|
||
|
if ( IsDefined( self.targetname ) )
|
||
|
autosave_by_name( self.targetname );
|
||
|
else
|
||
|
autosave_by_name( "boat_chase" );
|
||
|
}
|
||
|
|
||
|
autosave_boat_check_trailing()
|
||
|
{
|
||
|
return bread_crumb_get_player_trailing_fraction() < .5;
|
||
|
}
|
||
|
|
||
|
autosave_boat_check_player_speeding_along()
|
||
|
{
|
||
|
return level.players_boat Vehicle_GetSpeed() > 20;
|
||
|
}
|
||
|
|
||
|
bread_crumb_get_player_trailing_fraction()
|
||
|
{
|
||
|
if ( ! level.breadcrumb.size )
|
||
|
return 0;
|
||
|
crumb = level.breadcrumb[ 0 ];
|
||
|
time = ( GetTime() - crumb.spawn_time ) / 1000;
|
||
|
return time / level.breadcrumb_settings.fail_time;
|
||
|
}
|
||
|
|
||
|
bread_crumb_chase()
|
||
|
{
|
||
|
/#
|
||
|
SetDvarIfUninitialized( "scr_debug_breadcrumbs", 1 );
|
||
|
#/
|
||
|
|
||
|
/#
|
||
|
if ( GetDvarInt( "scr_zodiac_test" ) )
|
||
|
return;
|
||
|
#/
|
||
|
|
||
|
currenttime = GetTime();
|
||
|
lastcrumb = undefined;
|
||
|
test_array = [];
|
||
|
count = 0;
|
||
|
|
||
|
foreach ( crumb in level.breadcrumb )
|
||
|
{
|
||
|
time = ( currenttime - crumb.spawn_time ) / 1000;
|
||
|
trailing_fraction = time / level.breadcrumb_settings.fail_time;
|
||
|
|
||
|
if ( trailing_fraction > 1 )
|
||
|
bread_crumb_fail();
|
||
|
|
||
|
if ( ! count )
|
||
|
breadcrumb_docatchup( trailing_fraction );
|
||
|
|
||
|
if ( count < level.breadcrumb_settings.checkdepth )
|
||
|
test_array[ count ] = crumb;
|
||
|
|
||
|
if ( is_breadcrumb_debug() )
|
||
|
draw_crumb( crumb, lastcrumb, trailing_fraction );
|
||
|
|
||
|
lastcrumb = crumb;
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
// skipped = false;
|
||
|
foreach ( crumb in test_array )
|
||
|
{
|
||
|
vec = AnglesToForward( crumb.angles );
|
||
|
vec2 = VectorNormalize( ( level.player.origin - crumb.origin ) );
|
||
|
vecdot = VectorDot( vec, vec2 );
|
||
|
if ( vecdot > 0 )
|
||
|
level.breadcrumb = array_remove( level.breadcrumb, crumb );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
breadcrumb_docatchup( trailing_fraction )
|
||
|
{
|
||
|
if ( trailing_fraction < .25 )
|
||
|
flag_set( "zodiac_catchup" );
|
||
|
else
|
||
|
flag_clear( "zodiac_catchup" );
|
||
|
}
|
||
|
|
||
|
bread_crumb_fail()
|
||
|
{
|
||
|
if ( !isalive( level.player ) )
|
||
|
return;
|
||
|
|
||
|
/#
|
||
|
if ( GetDvarInt( "scr_zodiac_test" ) )
|
||
|
return;
|
||
|
#/
|
||
|
|
||
|
// Shepherd got away.
|
||
|
level notify ( "stop_deadquote_for_gettingout_of_bounds" );
|
||
|
SetDvar( "ui_deadquote", &"AF_CHASE_MISSION_FAILED_KEEP_UP" );
|
||
|
if ( level.start_point != "test_boat_current" )
|
||
|
missionFailedWrapper();
|
||
|
}
|
||
|
|
||
|
is_breadcrumb_debug()
|
||
|
{
|
||
|
return GetDvarInt( "scr_debug_breadcrumbs" );
|
||
|
}
|
||
|
|
||
|
zodiac_monitor_player_trailing_time()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
flag_wait( "player_on_boat" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
level waittill( "zodiac_catchup" );
|
||
|
|
||
|
if ( flag( "zodiac_boarding" ) )
|
||
|
return;
|
||
|
|
||
|
if ( flag( "zodiac_catchup" ) )
|
||
|
{
|
||
|
player_boat_speed_plus = level.players_boat Vehicle_GetSpeed() + 5;
|
||
|
if ( self Vehicle_GetSpeed() < player_boat_speed_plus )
|
||
|
self Vehicle_SetSpeed( player_boat_speed_plus, 15, 15 );
|
||
|
player_boat_speed_plus = undefined;
|
||
|
}
|
||
|
else
|
||
|
self ResumeSpeed( 15 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
zodiac_catchup()
|
||
|
{
|
||
|
player_speed_plus = level.players_boat Vehicle_GetSpeed() + 5;
|
||
|
if ( self Vehicle_GetSpeed() < player_speed_plus )
|
||
|
self Vehicle_SetSpeed( player_speed_plus, 15, 15 );
|
||
|
}
|
||
|
|
||
|
is_main_enemy_boat()
|
||
|
{
|
||
|
if ( !isdefined( self.targetname ) )
|
||
|
return false;
|
||
|
return self.targetname == "enemy_chase_boat";
|
||
|
}
|
||
|
|
||
|
zodiac_boat_ai( boat )
|
||
|
{
|
||
|
// kill _vehicle_anim stuff. not completely just gets them out of idle loop
|
||
|
if ( !isai( self ) )
|
||
|
return;
|
||
|
self notify( "newanim" );
|
||
|
|
||
|
//make them crouch
|
||
|
self.desired_anim_pose = "crouch";
|
||
|
self AllowedStances( "crouch" );
|
||
|
self thread animscripts\utility::UpdateAnimPose();
|
||
|
self AllowedStances( "crouch" );
|
||
|
|
||
|
self.baseaccuracy = 0;// don't get accurate untill they are in range.
|
||
|
self.accuracystationarymod = .5;
|
||
|
}
|
||
|
|
||
|
heli_attack_player_idle()
|
||
|
{
|
||
|
self waittill( "trigger", heli );
|
||
|
|
||
|
level.players_boat endon( "death" );
|
||
|
heli thread mgoff();
|
||
|
|
||
|
heli endon( "death" );
|
||
|
|
||
|
heli thread handle_fire_missiles();
|
||
|
|
||
|
while ( Distance( level.player.origin, self.origin ) > 8500 )
|
||
|
wait .05;
|
||
|
|
||
|
heli thread mgon();
|
||
|
foreach ( turret in heli.mgturret )
|
||
|
{
|
||
|
turret SetAISpread( 2 );
|
||
|
turret SetConvergenceTime( 5 );
|
||
|
turret.accuracy = .5;
|
||
|
}
|
||
|
|
||
|
if ( ! flag( "rapids_trigger" ) )// don't care about this particular dialog after the rapids.
|
||
|
level notify( "dialog_helicopter_ahead" );
|
||
|
|
||
|
heli SetLookAtEnt( level.player );
|
||
|
|
||
|
|
||
|
while ( in_front( level.players_boat, heli ) )
|
||
|
wait .05;
|
||
|
|
||
|
if ( ! flag( "rapids_trigger" ) )// don't care about this particular dialog after the rapids.
|
||
|
level notify( "dialog_helicopter_six" );
|
||
|
|
||
|
|
||
|
foreach ( turret in heli.mgturret )
|
||
|
{
|
||
|
turret SetAISpread( 20 );
|
||
|
turret SetConvergenceTime( 7 );
|
||
|
turret.accuracy = 0;
|
||
|
}
|
||
|
|
||
|
wait 3;// let it try to converge then turn it off.
|
||
|
|
||
|
heli thread mgoff();
|
||
|
|
||
|
}
|
||
|
|
||
|
rumble_with_throttle()
|
||
|
{
|
||
|
rumble_ent = get_rumble_ent();
|
||
|
|
||
|
throttle_leveling_time = 3.4;
|
||
|
|
||
|
level_throttle = .01;
|
||
|
|
||
|
full_throttled_time = 0;
|
||
|
|
||
|
rumble_fraction = .13;
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
throttle = self Vehicle_GetThrottle();
|
||
|
|
||
|
full_throttled_time += .05;
|
||
|
|
||
|
if ( throttle < .5 )
|
||
|
{
|
||
|
full_throttled_time = 0;
|
||
|
throttle_level_fraction = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
throttle_level_fraction = 1 - ( full_throttled_time / throttle_leveling_time );
|
||
|
}
|
||
|
|
||
|
rumble_ent.intensity = ( throttle * rumble_fraction * throttle_level_fraction );
|
||
|
|
||
|
if ( full_throttled_time > throttle_leveling_time || self Vehicle_GetSpeed() > 43 )
|
||
|
{
|
||
|
full_throttled_time = throttle_leveling_time;// probably not necessary. just keeping the number from going really high.
|
||
|
rumble_ent.intensity = 0;
|
||
|
}
|
||
|
|
||
|
wait .05;
|
||
|
if ( flag( "player_in_sight_of_boarding" ) )
|
||
|
break;
|
||
|
}
|
||
|
rumble_ent Delete();
|
||
|
}
|
||
|
|
||
|
kill_ai_in_volume()
|
||
|
{
|
||
|
volume = GetEnt( self.target, "targetname" );
|
||
|
Assert( IsDefined( volume ) );
|
||
|
|
||
|
self waittill( "trigger" );
|
||
|
ai = GetAIArray();
|
||
|
|
||
|
foreach ( guy in ai )
|
||
|
if ( guy IsTouching( volume ) && !guy is_hero() )
|
||
|
guy Delete();
|
||
|
|
||
|
//hack.. shortcutting adding another volume. want to delete these fx forever.
|
||
|
tester = Spawn( "script_origin", ( 0, 0, 0 ) );
|
||
|
|
||
|
inc = 0;
|
||
|
foreach ( createfxent in level.createfxent )
|
||
|
{
|
||
|
inc++;
|
||
|
if ( IsDefined( createfxent.looper ) )
|
||
|
{
|
||
|
level.createfxent = array_remove( level.createfxent, createfxent );
|
||
|
tester.origin = createfxent.v[ "origin" ];
|
||
|
if ( tester IsTouching( volume ) )
|
||
|
createfxent.looper Delete();
|
||
|
}
|
||
|
if ( inc > 3 )
|
||
|
{
|
||
|
inc = 0;
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
tester Delete();
|
||
|
}
|
||
|
|
||
|
kill_all_the_ai_and_fx_from_boatride()
|
||
|
{
|
||
|
kill_ai_in_volume = GetEntArray( "kill_ai_in_volume", "targetname" );
|
||
|
foreach ( trigger in kill_ai_in_volume )
|
||
|
{
|
||
|
wait( 0.1 );
|
||
|
trigger notify( "trigger", level.player );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
kill_destructibles_and_barrels_in_volume()
|
||
|
{
|
||
|
volume = GetEnt( self.target, "targetname" );
|
||
|
Assert( IsDefined( volume ) );
|
||
|
|
||
|
self waittill( "trigger" );
|
||
|
|
||
|
shootable_stuff = GetEntArray( "destructible_toy", "targetname" );
|
||
|
|
||
|
inc = 0;
|
||
|
foreach ( thing in shootable_stuff )
|
||
|
{
|
||
|
thing delete_shootable_stuff_in_volume( volume );
|
||
|
inc++;
|
||
|
if ( inc > 3 )
|
||
|
{
|
||
|
inc = 0;
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//dupping script for speed.
|
||
|
shootable_stuff = GetEntArray( "explodable_barrel", "targetname" );
|
||
|
foreach ( thing in shootable_stuff )
|
||
|
{
|
||
|
thing delete_shootable_stuff_in_volume( volume );
|
||
|
inc++;
|
||
|
if ( inc > 3 )
|
||
|
{
|
||
|
inc = 0;
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
delete_shootable_stuff_in_volume( volume )
|
||
|
{
|
||
|
if ( ! self IsTouching( volume ) )
|
||
|
return;
|
||
|
|
||
|
self notify( "delete_destructible" );// kill the effects looping first.
|
||
|
self Delete();
|
||
|
}
|
||
|
|
||
|
disable_origin_offset()
|
||
|
{
|
||
|
// I need this for more precise hovering with the ramp in the water.
|
||
|
self.originheightoffset = undefined;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
destructible_fake()
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
destructible_org = GetEnt( self.target, "targetname" );
|
||
|
|
||
|
radius = 600;
|
||
|
if ( IsDefined( destructible_org.radius ) )
|
||
|
radius = destructible_org.radius;
|
||
|
|
||
|
count = 3;
|
||
|
|
||
|
destructible_damage_count_in_radius( count, radius, destructible_org.origin );
|
||
|
|
||
|
}
|
||
|
|
||
|
destructible_damage_count_in_radius( count, radius, origin )
|
||
|
{
|
||
|
destructible_toys = get_array_of_closest( origin, GetEntArray( "destructible_toy", "targetname" ), undefined, count, radius, 0 ) ;
|
||
|
foreach ( toy in destructible_toys )
|
||
|
{
|
||
|
wait RandomFloatRange( .1, .4 );
|
||
|
// toy thread common_scripts\_destructible::force_explosion();
|
||
|
thread destroy_fast( toy );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
destroy_fast( toy )
|
||
|
{
|
||
|
for ( i = 0; i < 5; i++ )
|
||
|
{
|
||
|
toy notify( "damage", 160, level.player, self.origin, toy.origin, "MOD_PISTOL_BULLET", "", "" );
|
||
|
wait RandomFloatRange( .1, .2 );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
raise_attacker_accuracy_on_nearby_boats()
|
||
|
{
|
||
|
flag_wait( "player_on_boat" );
|
||
|
|
||
|
level.players_boat endon( "death" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
attack_boats_in_range_in_front();
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SQRT_BOATS_IN_RANGE = 1400 * 1400;
|
||
|
SQRT_BOATS_IN_RANGE_BEHIND = 50 * 50;
|
||
|
|
||
|
attack_boats_in_range_in_front( range, backrange )
|
||
|
{
|
||
|
boats = GetEntArray( "script_vehicle_zodiac_physics", "classname" );
|
||
|
|
||
|
return_boats = [];
|
||
|
foreach ( boat in boats )
|
||
|
{
|
||
|
if ( boat == level.players_boat )
|
||
|
continue;
|
||
|
if ( IsSpawner( boat ) )
|
||
|
continue;
|
||
|
if ( ! boat_in_range_in_front( boat ) )
|
||
|
continue;
|
||
|
|
||
|
boat thread raise_attacker_accuracy_while_in_range();
|
||
|
}
|
||
|
return return_boats;
|
||
|
}
|
||
|
|
||
|
raise_attacker_accuracy_while_in_range()
|
||
|
{
|
||
|
self notify( "raise_attacker_accuracy_while_in_range" );
|
||
|
self endon( "raise_attacker_accuracy_while_in_range" );
|
||
|
self endon( "death" );
|
||
|
|
||
|
foreach ( rider in self.riders )
|
||
|
{
|
||
|
rider.baseaccuracy = 6;
|
||
|
// rider.baseaccuracy = 10;
|
||
|
rider.suppressionwait = 1000;
|
||
|
}
|
||
|
|
||
|
while ( boat_in_range_in_front( self ) )
|
||
|
wait .05;
|
||
|
|
||
|
foreach ( rider in self.riders )
|
||
|
{
|
||
|
rider.baseaccuracy = 0;
|
||
|
// rider.ignoreSuppression = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
boat_in_range_in_front( boat )
|
||
|
{
|
||
|
if ( flag( "player_in_open" ) )
|
||
|
return true;
|
||
|
if ( DistanceSquared( boat.origin, level.players_boat.origin ) > SQRT_BOATS_IN_RANGE )
|
||
|
return false;
|
||
|
dot = get_dot( level.players_boat.origin, level.players_boat.angles, boat.origin );
|
||
|
// if ( dot < 0 && DistanceSquared( boat.origin, level.players_boat.origin ) > SQRT_BOATS_IN_RANGE_BEHIND )
|
||
|
if ( dot < 0.642787 )// ~50
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
conveyerbelt_speed( yaw, speed, rate )
|
||
|
{
|
||
|
level.VehPhys_SetConveyorBelt_yaw = yaw;
|
||
|
|
||
|
speeddiff = speed - level.VehPhys_SetConveyorBelt_speed;
|
||
|
|
||
|
if ( speeddiff == 0 )
|
||
|
return;
|
||
|
|
||
|
time = abs( speeddiff / rate );
|
||
|
|
||
|
level notify( "conveyerbelt_speed" );
|
||
|
level endon( "conveyerbelt_speed" );
|
||
|
|
||
|
iterations = Int( time / .05 ) ;
|
||
|
|
||
|
speedinc = 0;
|
||
|
if ( iterations != 0 )
|
||
|
speedinc = speeddiff / iterations;
|
||
|
else
|
||
|
return;
|
||
|
|
||
|
for ( i = 0; i < iterations; i++ )
|
||
|
{
|
||
|
wait .05;
|
||
|
level.VehPhys_SetConveyorBelt_speed += speedinc;
|
||
|
}
|
||
|
|
||
|
level.VehPhys_SetConveyorBelt_speed = speed;
|
||
|
|
||
|
}
|
||
|
|
||
|
CONVEYERBELT_PLAYER_MAX_SPEED = 40;
|
||
|
CONVEYERBELT_PLAYER_MIN_SPEED = 20;
|
||
|
|
||
|
conveyerbelt_player_speed_mod()
|
||
|
{
|
||
|
mod = 1;
|
||
|
dif = CONVEYERBELT_PLAYER_MAX_SPEED - CONVEYERBELT_PLAYER_MIN_SPEED;
|
||
|
|
||
|
velocity = level.players_boat Vehicle_GetVelocity();
|
||
|
speed = Distance( velocity, ( 0, 0, 0 ) ) / 17.6;
|
||
|
|
||
|
velocity = flat_origin( velocity );
|
||
|
|
||
|
normal = VectorNormalize( velocity );
|
||
|
forward = AnglesToForward( ( 0, level.VehPhys_SetConveyorBelt_yaw, 0 ) );
|
||
|
dot = VectorDot( forward, normal );
|
||
|
|
||
|
// speed = level.players_boat Vehicle_GetSpeed();
|
||
|
|
||
|
if ( flag( "enemy_heli_takes_off" ) )
|
||
|
mod = 1;
|
||
|
if ( speed > CONVEYERBELT_PLAYER_MAX_SPEED )
|
||
|
mod = 0;
|
||
|
else if ( speed < CONVEYERBELT_PLAYER_MIN_SPEED )
|
||
|
mod = 1;
|
||
|
else
|
||
|
{
|
||
|
players_dif = speed - CONVEYERBELT_PLAYER_MIN_SPEED;
|
||
|
mod = 1 - ( players_dif / dif );
|
||
|
}
|
||
|
level.conveyerbelt_player_speed_mod = level.VehPhys_SetConveyorBelt_speed * mod;// for debugging
|
||
|
|
||
|
level.conveyerbelt_player_speed_mod *= level.VehPhys_SetConveyorBelt_speed_fraction;
|
||
|
|
||
|
self VehPhys_SetConveyorBelt( level.VehPhys_SetConveyorBelt_yaw, level.conveyerbelt_player_speed_mod );
|
||
|
}
|
||
|
|
||
|
conveyerbelt_set_speed_fraction( dest_fraction, time )
|
||
|
{
|
||
|
level notify( "conveyerbelt_set_speed_fraction" );
|
||
|
level endon( "conveyerbelt_set_speed_fraction" );
|
||
|
|
||
|
if ( time == 0 )
|
||
|
{
|
||
|
level.VehPhys_SetConveyorBelt_speed_fraction = dest_fraction;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
current_fraction = level.VehPhys_SetConveyorBelt_speed_fraction;
|
||
|
incs = Int( time * 20 );
|
||
|
fraction_increment = ( dest_fraction - current_fraction ) / incs;
|
||
|
|
||
|
for ( i = 0; i < incs; i++ )
|
||
|
{
|
||
|
level.VehPhys_SetConveyorBelt_speed_fraction += fraction_increment;
|
||
|
wait .05;
|
||
|
}
|
||
|
|
||
|
level.VehPhys_SetConveyorBelt_speed_fraction = dest_fraction;
|
||
|
}
|
||
|
|
||
|
conveyerbelt_clear_speed_fraction()
|
||
|
{
|
||
|
conveyerbelt_set_speed_fraction( 1 );
|
||
|
}
|
||
|
|
||
|
set_fixed_node_after_seeing_player_spawn_func()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
|
||
|
if ( IsSubStr( self.classname, "shepherd" ) )
|
||
|
return;
|
||
|
|
||
|
while ( !self CanSee( level.player ) && Distance( self.origin, level.player.origin ) > 3500 )
|
||
|
wait .1;
|
||
|
self.fixednode = true;
|
||
|
|
||
|
self.pathenemyfightdist = 0;
|
||
|
self.pathenemylookahead = 0;
|
||
|
}
|
||
|
|
||
|
CONVEYER_RATE = 4;
|
||
|
river_current( noteworthy )
|
||
|
{
|
||
|
level notify( "new_river_current" );
|
||
|
level endon( "new_river_current" );
|
||
|
|
||
|
/#
|
||
|
if ( GetDvarInt( "scr_zodiac_test" ) )
|
||
|
return;
|
||
|
#/
|
||
|
|
||
|
current_node = getstruct( noteworthy, "script_noteworthy" );
|
||
|
next_node = getstruct( current_node.target, "targetname" );
|
||
|
|
||
|
maxdropspeed_cos = Cos( 35 );
|
||
|
maxdropspeed = 45;
|
||
|
maxdropspeed_lower_cap = maxdropspeed;
|
||
|
mindropspeed_cos = Cos( 3 );
|
||
|
mindropspeed = 10;
|
||
|
|
||
|
if ( IsDefined( current_node.script_speed ) )
|
||
|
mindropspeed = current_node.script_speed;
|
||
|
|
||
|
next_angle = get_next_angle( next_node );
|
||
|
|
||
|
level.VehPhys_SetConveyorBelt_speed = 4;
|
||
|
|
||
|
flag_wait( "player_on_boat" );
|
||
|
|
||
|
level.players_boat endon( "death" );
|
||
|
|
||
|
level endon( "player_over_the_waterfall" );
|
||
|
level endon( "water_cliff_jump_splash_sequence" );
|
||
|
|
||
|
childthread river_current_apply();
|
||
|
|
||
|
flat_angle = ( 0, 0, 0 );
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
dot = get_dot( next_node.origin, next_angle, level.players_boat.origin );
|
||
|
if ( dot < 0 )
|
||
|
{
|
||
|
// draw_arrow( current_node.origin , next_node.origin, (0,1,0) );
|
||
|
|
||
|
dot = get_dot( current_node.origin, flat_angle( VectorToAngles( next_node.origin - current_node.origin ) ), level.players_boat.origin );
|
||
|
if ( dot > 0 )
|
||
|
{
|
||
|
wait .05;
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
current_node = getstruct( current_node.targetname, "target" );
|
||
|
if ( !isdefined( current_node ) )
|
||
|
{
|
||
|
current_node = getstruct( next_node.targetname, "target" );// reset to the first node..
|
||
|
level.players_boat thread conveyerbelt_speed( flat_angle[ 1 ], 0, CONVEYER_RATE );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
current_node = next_node;
|
||
|
}
|
||
|
|
||
|
if ( IsDefined( current_node.script_speed ) )
|
||
|
mindropspeed = current_node.script_speed;
|
||
|
if ( !isdefined( current_node.target ) )
|
||
|
break;
|
||
|
|
||
|
if ( mindropspeed > maxdropspeed_lower_cap )
|
||
|
maxdropspeed = mindropspeed + 20;
|
||
|
else
|
||
|
maxdropspeed = maxdropspeed_lower_cap;
|
||
|
next_node = getstruct( current_node.target, "targetname" );
|
||
|
if ( !isdefined( next_node ) )
|
||
|
{
|
||
|
next_node = current_node;
|
||
|
current_node = getstruct( next_node.targetname, "target" );// keep cycling the last section in this case.
|
||
|
wait .05;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( IsDefined( next_node.target ) )
|
||
|
next_angle = get_next_angle( next_node );
|
||
|
|
||
|
speed = mindropspeed;
|
||
|
flat_angle = flat_angle( VectorToAngles( next_node.origin - current_node.origin ) );
|
||
|
|
||
|
dot = get_dot( current_node.origin, flat_angle, next_node.origin );
|
||
|
dot = abs( dot );
|
||
|
|
||
|
if ( dot > mindropspeed_cos )
|
||
|
speed = mindropspeed;
|
||
|
else if ( dot < maxdropspeed_cos )
|
||
|
speed = maxdropspeed;
|
||
|
else
|
||
|
speed = maxdropspeed_cos / dot * maxdropspeed;
|
||
|
|
||
|
level.boatdropspeed = speed;
|
||
|
level.players_boat childthread conveyerbelt_speed( flat_angle[ 1 ], speed, CONVEYER_RATE );
|
||
|
|
||
|
wait .05;
|
||
|
}
|
||
|
level.players_boat childthread conveyerbelt_speed( 0, 0, CONVEYER_RATE );
|
||
|
}
|
||
|
|
||
|
river_current_apply()
|
||
|
{
|
||
|
|
||
|
if ( !isdefined( level.VehPhys_SetConveyorBelt_speed_fraction ) )
|
||
|
level.VehPhys_SetConveyorBelt_speed_fraction = 1;
|
||
|
|
||
|
while ( !isdefined( level.vehphys_setconveyorbelt_yaw ) )
|
||
|
wait .05;
|
||
|
|
||
|
level.players_boat endon( "death" );
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
level.players_boat conveyerbelt_player_speed_mod();
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
get_next_angle( current_node, currentangles )
|
||
|
{
|
||
|
next_node = getstruct( current_node.target, "targetname" );
|
||
|
Assert( IsDefined( next_node ) );
|
||
|
return VectorToAngles( next_node.origin - current_node.origin );
|
||
|
}
|
||
|
|
||
|
enable_bread_crumb_chase()
|
||
|
{
|
||
|
s = SpawnStruct();
|
||
|
s.checkdepth = 3;// how far up the chain do I crawl to see if we're caught up.
|
||
|
s.fail_time = 10;// how far behind the player is allowed to trail..
|
||
|
|
||
|
level endon( "quit_bread_crumb" );
|
||
|
|
||
|
level.breadcrumb_settings = s;
|
||
|
|
||
|
level.breadcrumb = [];
|
||
|
|
||
|
// thread bread_crumb_button();
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
bread_crumb_chase();
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set_breadcrumb_fail_time( fail_time, transition_time )
|
||
|
{
|
||
|
if ( !isdefined( transition_time ) )
|
||
|
{
|
||
|
level.breadcrumb_settings.fail_time = fail_time;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
level notify( "set_breadcrumb_fail_time" );
|
||
|
level endon( "set_breadcrumb_fail_time" );
|
||
|
|
||
|
last_time = level.breadcrumb_settings.fail_time;
|
||
|
increase_time_by = fail_time - last_time;
|
||
|
increments = transition_time * 20;
|
||
|
inc_step = increase_time_by / increments;
|
||
|
|
||
|
for ( i = 0; i < increments; i++ )
|
||
|
{
|
||
|
level.breadcrumb_settings.fail_time += inc_step;
|
||
|
wait .05;
|
||
|
}
|
||
|
|
||
|
level.breadcrumb_settings.fail_time = fail_time;
|
||
|
|
||
|
}
|
||
|
|
||
|
bread_crumb_button()
|
||
|
{
|
||
|
while ( 1 )
|
||
|
{
|
||
|
while ( !level.player ButtonPressed( "BUTTON_Y" ) )
|
||
|
wait .05;
|
||
|
if ( flag( "debug_crumbs" ) )
|
||
|
flag_clear( "debug_crumbs" );
|
||
|
else
|
||
|
flag_set( "debug_crumbs" );
|
||
|
while ( level.player ButtonPressed( "BUTTON_Y" ) )
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
test_m203()
|
||
|
{
|
||
|
level.price endon( "death" );
|
||
|
effect = LoadFX( "muzzleflashes/m203_flshview" );
|
||
|
while ( ! flag( "exit_caves" ) )
|
||
|
{
|
||
|
start = level.price GetTagOrigin( "tag_flash" );
|
||
|
angles = level.price GetTagAngles( "tag_flash" );
|
||
|
if ( level.price has_good_enemy_for_grenade_launcher( start, angles ) )
|
||
|
{
|
||
|
PlayFXOnTag( effect, level.price, "tag_flash" );
|
||
|
shootpos = level.price.enemy GetShootAtPos() + ( 0, 0, 150 );
|
||
|
if ( Distance( level.price.origin, level.price.enemy.origin ) > 1700 )
|
||
|
shootpos += ( 0, 0, 150 );// I'm just guessing here. magical numbers make grenads go farther..
|
||
|
MagicBullet( "m203", start, shootpos );
|
||
|
wait 2.5;
|
||
|
}
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
test_m203_again()
|
||
|
{
|
||
|
level.price endon( "death" );
|
||
|
effect = LoadFX( "muzzleflashes/m203_flshview" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
start = level.price GetTagOrigin( "tag_flash" );
|
||
|
angles = level.price GetTagAngles( "tag_flash" );
|
||
|
if ( level.price has_good_enemy_for_grenade_launcher( start, angles ) )
|
||
|
{
|
||
|
PlayFXOnTag( effect, level.price, "tag_flash" );
|
||
|
shootpos = level.price.enemy GetShootAtPos() + ( 0, 0, 190 );
|
||
|
if ( Distance( level.price.origin, level.price.enemy.origin ) > 1700 )
|
||
|
shootpos += ( 0, 0, 120 );// I'm just guessing here. magical numbers make grenads go farther..
|
||
|
MagicBullet( "m203", start, shootpos );
|
||
|
wait 2.5;
|
||
|
}
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FOV_M203 = 0.965925;// Cos( 15 )
|
||
|
DIST_M203_SQRD = 650 * 650;
|
||
|
|
||
|
//good_spot_for_grenade_launcher
|
||
|
|
||
|
has_good_enemy_for_grenade_launcher( start, angles )
|
||
|
{
|
||
|
if ( !isdefined( self.enemy ) )
|
||
|
return false;
|
||
|
if ( ! DistanceSquared( start, self.enemy.origin ) > DIST_M203_SQRD )
|
||
|
return false;
|
||
|
if ( ! within_fov( start, angles, self.enemy GetShootAtPos(), FOV_M203 ) )
|
||
|
return false;
|
||
|
|
||
|
good_spot_for_grenade_launcher = getstructarray( "good_spot_for_grenade_launcher", "targetname" );
|
||
|
foreach ( spot in good_spot_for_grenade_launcher )
|
||
|
{
|
||
|
Assert( IsDefined( spot.radius ) );
|
||
|
if ( Distance( spot.origin, self.enemy.origin ) < spot.radius )
|
||
|
if ( ! burning_barrel_in_spots_radius( spot ) )
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
burning_barrel_in_spots_radius( spot )
|
||
|
{
|
||
|
barrels = GetEntArray( "explodable_barrel", "targetname" );
|
||
|
squaredist = spot.radius * spot.radius;
|
||
|
foreach ( barrel in barrels )
|
||
|
{
|
||
|
if ( DistanceSquared( spot.origin, barrel.origin ) > squaredist )
|
||
|
continue;
|
||
|
if ( barrel.damagetaken )
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
price_position_switch()
|
||
|
{
|
||
|
Assert( IsDefined( self.script_noteworthy ) );
|
||
|
|
||
|
self waittill( "trigger" );
|
||
|
|
||
|
level.price.scripted_boat_pose = self.script_noteworthy;
|
||
|
}
|
||
|
|
||
|
bobbing_boat_spawn()
|
||
|
{
|
||
|
self VehPhys_Crash();
|
||
|
}
|
||
|
|
||
|
in_front( ent1, ent2 )
|
||
|
{
|
||
|
return get_dot( ent1.origin, ent1.angles, ent2.origin ) > 0 ;
|
||
|
}
|
||
|
|
||
|
in_front_by_velocity( ent1, ent2 )
|
||
|
{
|
||
|
return get_dot( ent1.origin, VectorToAngles( ent1 Vehicle_GetVelocity() ), ent2.origin ) > 0 ;
|
||
|
}
|
||
|
|
||
|
delete_when_not_in_view()
|
||
|
{
|
||
|
cosa = Cos( 55 );
|
||
|
while ( within_fov_of_players( self.origin, cosa ) )
|
||
|
wait .05;
|
||
|
self Delete();
|
||
|
}
|
||
|
|
||
|
//movewithrate( dest, destang, moverate, endrate, gravity, accelfraction, decelfraction )
|
||
|
movewithrate( dest, moverate, accelfraction, decelfraction )
|
||
|
{
|
||
|
self notify( "newmove" );
|
||
|
self endon( "newmove" );
|
||
|
|
||
|
if ( !isdefined( accelfraction ) )
|
||
|
accelfraction = 0;
|
||
|
if ( !isdefined( decelfraction ) )
|
||
|
decelfraction = 0;
|
||
|
self.movefinished = false;
|
||
|
// moverate = units / persecond
|
||
|
if ( !isdefined( moverate ) )
|
||
|
moverate = 200;
|
||
|
|
||
|
dist = Distance( self.origin, dest );
|
||
|
movetime = dist / moverate;
|
||
|
movevec = VectorNormalize( dest - self.origin );
|
||
|
|
||
|
accel = 0;
|
||
|
decel = 0;
|
||
|
|
||
|
if ( accelfraction > 0 )
|
||
|
accel = movetime * accelfraction;
|
||
|
if ( decelfraction > 0 )
|
||
|
decel = movetime * decelfraction;
|
||
|
|
||
|
self MoveTo( dest, movetime, accel, decel );
|
||
|
// self RotateTo( destang, movetime, accel, decel );
|
||
|
wait movetime;
|
||
|
|
||
|
if ( !isdefined( self ) )
|
||
|
return;
|
||
|
self.velocity = movevec * ( dist / movetime );
|
||
|
self.movefinished = true;
|
||
|
}
|
||
|
|
||
|
price_anim_single_on_boat( anim_scene, relink )
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
if ( !isdefined( relink ) )
|
||
|
relink = true;
|
||
|
|
||
|
level.price notify( "new_price_anim_single_on_boat" );
|
||
|
level.price endon( "new_price_anim_single_on_boat" );
|
||
|
|
||
|
flag_set( "price_anim_on_boat" );
|
||
|
|
||
|
level.price radio_dialogue_stop();
|
||
|
level.price LinkTo( level.players_boat, "tag_guy2" );
|
||
|
level.players_boat anim_generic_queue( level.price, anim_scene, "tag_guy2" );
|
||
|
|
||
|
if ( ! relink )
|
||
|
return;// assuming a looped anim call follows
|
||
|
|
||
|
price_link_and_think();
|
||
|
|
||
|
flag_clear( "price_anim_on_boat" );
|
||
|
}
|
||
|
|
||
|
price_anim_loop_on_boat( anim_scene, notify_str, relink )
|
||
|
{
|
||
|
if ( !isdefined( relink ) )
|
||
|
relink = true;
|
||
|
|
||
|
level.price notify( "new_price_anim_single_on_boat" );
|
||
|
level.price endon( "new_price_anim_single_on_boat" );
|
||
|
|
||
|
level.players_boat thread anim_generic_loop( level.price, anim_scene, notify_str, "tag_guy2" );
|
||
|
|
||
|
level.players_boat waittill( notify_str );
|
||
|
|
||
|
if ( relink )
|
||
|
price_link_and_think();
|
||
|
|
||
|
flag_clear( "price_anim_on_boat" );
|
||
|
}
|
||
|
|
||
|
|
||
|
boatrider_link( vehicle )
|
||
|
{
|
||
|
self LinkToBlendToTag( vehicle, "tag_guy2", false );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
boatrider_think( vehicle )
|
||
|
{
|
||
|
boatrider_link( vehicle );
|
||
|
|
||
|
self AllowedStances( "crouch" );
|
||
|
self.vehicle = vehicle;
|
||
|
self.force_canAttackEnemyNode = true;
|
||
|
|
||
|
self thread boatrider_targets();
|
||
|
self.fullAutoRangeSq = 2000 * 2000;
|
||
|
|
||
|
// make Price know about all enemies (helps enemy selection when moving fast)
|
||
|
self.highlyAwareRadius = 2048;
|
||
|
|
||
|
self AnimCustom( maps\_zodiac_ai::think );
|
||
|
}
|
||
|
|
||
|
|
||
|
boatrider_targets()
|
||
|
{
|
||
|
level.price endon( "stop_boatrider_targets" );
|
||
|
level.price endon( "death" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
wait .05;
|
||
|
end = level.price maps\_zodiac_drive::drive_magic_bullet_get_end( level.players_boat, level.player GetEye(), true );// piggyback this functionality. Price finds the same targets interesting.
|
||
|
|
||
|
if ( !isdefined( end.obj ) )
|
||
|
{
|
||
|
level.price ClearEntityTarget();
|
||
|
continue;
|
||
|
}
|
||
|
if ( !isai( end.obj ) )
|
||
|
{
|
||
|
level.price SetEntityTarget( end.obj );
|
||
|
level.price.favoriteenemy = undefined;
|
||
|
if ( IsDefined( end.shootable_driver ) )
|
||
|
end.obj thread enable_shoot_driver();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
level.price ClearEntityTarget();
|
||
|
level.price.favoriteenemy = end.obj;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
enable_shoot_driver()
|
||
|
{
|
||
|
self notify( "enable_shoot_driver" );
|
||
|
self endon( "enable_shoot_driver" );
|
||
|
|
||
|
self.allowdeath = 1;
|
||
|
self SetCanDamage( true );
|
||
|
|
||
|
self waittill( "damage" );
|
||
|
maps\_zodiac_drive::driver_death( self );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
price_link_and_think()
|
||
|
{
|
||
|
level.price boatrider_link( level.players_boat );
|
||
|
level.price AnimCustom( maps\_zodiac_ai::think );
|
||
|
}
|
||
|
|
||
|
player_lerplink_fov( opts )
|
||
|
{
|
||
|
time = opts.time;
|
||
|
ent = opts.ent;
|
||
|
tag = opts.tag;
|
||
|
base_fov = opts.base_fov;
|
||
|
dest_fov = opts.dest_fov;
|
||
|
|
||
|
level.player FreezeControls( true );
|
||
|
// this is ghetto hack..
|
||
|
Assert( time > 0.0 );
|
||
|
timeincs = time * 20;
|
||
|
current_fov = base_fov;
|
||
|
fov_dif = dest_fov - base_fov;
|
||
|
fov_inc = fov_dif / timeincs;
|
||
|
timeincs = Int( timeincs );
|
||
|
|
||
|
for ( i = 0; i < timeincs; i++ )
|
||
|
{
|
||
|
current_fov += fov_inc;
|
||
|
level.player PlayerLinkToDelta( ent, tag, 1, current_fov, current_fov, current_fov, current_fov );
|
||
|
wait .05;
|
||
|
}
|
||
|
level.player FreezeControls( false );
|
||
|
}
|
||
|
|
||
|
trigger_thread_the_needle()
|
||
|
{
|
||
|
targetent = getstruct( self.target, "targetname" );
|
||
|
Assert( IsDefined( targetent ) );
|
||
|
|
||
|
self waittill( "trigger" );
|
||
|
|
||
|
normal = VectorNormalize( self.origin - targetent.origin );
|
||
|
forward = VectorNormalize( level.players_boat Vehicle_GetVelocity() );
|
||
|
dot = VectorDot( forward, normal );
|
||
|
|
||
|
if ( dot > 0.984807 )// cos 10
|
||
|
level.price radio_dialogue( "afchase_pri_threadtheneedle", 1 );
|
||
|
}
|
||
|
|
||
|
_objective_onentity( id, ent )
|
||
|
{
|
||
|
Objective_OnEntity( id, ent, ( 0, 0, 80 ) );
|
||
|
ent waittill( "death" );
|
||
|
Objective_Position( id, ( 0, 0, 0 ) );
|
||
|
|
||
|
/*
|
||
|
ent endon( "death" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
eye_pos = level.player GetEye();
|
||
|
Objective_Position( id, (ent.origin[0],ent.origin[1],eye_pos[2]) );
|
||
|
wait .05;
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
crashable_whizby_boats()
|
||
|
{
|
||
|
self.veh_pathtype = "follow";
|
||
|
self VehPhys_EnableCrashing();
|
||
|
while ( 1 )
|
||
|
{
|
||
|
self waittill( "veh_jolt" );// veh_collision wasn't working, just make it crash when it jolts around the player that should do.
|
||
|
if ( Distance( self.origin, level.player.origin ) < 512 )
|
||
|
break;
|
||
|
}
|
||
|
self VehPhys_Crash();
|
||
|
}
|
||
|
|
||
|
get_farthest_struct( org, array )
|
||
|
{
|
||
|
if ( array.size < 1 )
|
||
|
return;
|
||
|
|
||
|
dist = DistanceSquared( array[ 0 ].origin, org );
|
||
|
ent = array[ 0 ];
|
||
|
for ( i = 0; i < array.size; i++ )
|
||
|
{
|
||
|
newdist = DistanceSquared( array[ i ].origin, org );
|
||
|
if ( newdist < dist )
|
||
|
continue;
|
||
|
dist = newdist;
|
||
|
ent = array[ i ];
|
||
|
}
|
||
|
return ent;
|
||
|
}
|
||
|
|
||
|
ignoreall_till_not_touch( guy )
|
||
|
{
|
||
|
prevteam = guy.team;
|
||
|
guy endon( "death" );
|
||
|
guy.ignoreall = true;
|
||
|
while ( guy IsTouching( self ) )// teehee
|
||
|
wait .05;
|
||
|
guy.ignoreall = false;
|
||
|
}
|
||
|
|
||
|
dump_on_command()
|
||
|
{
|
||
|
while ( 1 )
|
||
|
{
|
||
|
while ( ! level.player ButtonPressed( "BUTTON_B" ) )
|
||
|
wait .05;
|
||
|
vehicle_dump();
|
||
|
while ( level.player ButtonPressed( "BUTTON_B" ) )
|
||
|
wait .05;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set_lerp_opts( time, ent, tag, base_fov, dest_fov )
|
||
|
{
|
||
|
opts = SpawnStruct();
|
||
|
opts.time = time;
|
||
|
opts.ent = ent;
|
||
|
opts.tag = tag;
|
||
|
opts.base_fov = base_fov;
|
||
|
opts.dest_fov = dest_fov;
|
||
|
return opts;
|
||
|
}
|
||
|
|
||
|
player_full_heath()
|
||
|
{
|
||
|
return level.player.health / level.player.maxhealth == 1;
|
||
|
}
|
||
|
|
||
|
trigger_neutral_enemies()
|
||
|
{
|
||
|
while ( 1 )
|
||
|
{
|
||
|
self waittill( "trigger", other );
|
||
|
if ( !isalive( other ) )
|
||
|
continue;
|
||
|
|
||
|
if ( !first_touch( other ) )
|
||
|
continue;
|
||
|
|
||
|
thread ignoreall_till_not_touch( other );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
draw_arrow_forward()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
draw_arrow( self.origin, self.origin + AnglesToForward( self.angles ) * 200, ( 0, 0, 1 ) );
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dvar_warn()
|
||
|
{
|
||
|
if ( ! GetDvarInt( "scr_zodiac_test" ) )
|
||
|
return;
|
||
|
wait 3;
|
||
|
IPrintLnBold( "you will need to reset scr_zodiac_test to play the level normally again ( restart the game )" );
|
||
|
}
|
||
|
|
||
|
get_boat_rider( num )
|
||
|
{
|
||
|
if ( !isdefined( level.boatrider ) )
|
||
|
level.boatrider = [];
|
||
|
else
|
||
|
if ( IsDefined( level.boatrider[ num ] ) )
|
||
|
return level.boatrider[ num ];
|
||
|
|
||
|
level.boatrider[ num ] = spawn_targetname( num, true );
|
||
|
level.boatrider[ num ] magic_bullet_shield();
|
||
|
level.boatrider[ num ] disable_pain();
|
||
|
level.boatrider[ num ].ignoreSuppression = true;
|
||
|
level.boatrider[ num ] set_battlechatter( false ); // got enough chatter on the boat.
|
||
|
return level.boatrider[ num ];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
set_price_auto_switch_pose()
|
||
|
{
|
||
|
level.price.scripted_boat_pose = undefined;
|
||
|
level.price.use_auto_pose = true;
|
||
|
}
|
||
|
|
||
|
ZODIAC_DIALOGUE_RANGE = 3000 * 3000;
|
||
|
zodiac_enemy_setup()
|
||
|
{
|
||
|
self.dontunloadonend = true;
|
||
|
// self thread zodiac_monitor_player_trailing_time();
|
||
|
foreach ( rider in self.riders )
|
||
|
{
|
||
|
rider thread zodiac_boat_ai( self );
|
||
|
}
|
||
|
flag_wait( "player_on_boat" );
|
||
|
|
||
|
self endon( "death" );
|
||
|
level.players_boat endon( "death" );
|
||
|
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
start_origin = level.players_boat.origin;
|
||
|
end_origin = self.origin;
|
||
|
// normal = VectorNormalize( end_origin - start_origin );
|
||
|
// forward = AnglesToRight( level.players_boat.angles );
|
||
|
// dot = VectorDot( forward, normal );
|
||
|
|
||
|
if ( DistanceSquared( self.origin, level.players_boat.origin ) > ZODIAC_DIALOGUE_RANGE )
|
||
|
{
|
||
|
wait .05;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
level.dialog_dir = animscripts\battlechatter::getDirectionFacingClock( level.players_boat.angles, start_origin, end_origin );
|
||
|
level notify( "dialog_direction" );
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exp_fade_overlay( target_alpha, fade_time )
|
||
|
{
|
||
|
self notify( "exp_fade_overlay" );
|
||
|
self endon( "exp_fade_overlay" );
|
||
|
|
||
|
fade_steps = 4;
|
||
|
step_angle = 90 / fade_steps;
|
||
|
current_angle = 0;
|
||
|
step_time = fade_time / fade_steps;
|
||
|
|
||
|
current_alpha = self.alpha;
|
||
|
alpha_dif = current_alpha - target_alpha;
|
||
|
|
||
|
for ( i = 0; i < fade_steps; i++ )
|
||
|
{
|
||
|
current_angle += step_angle;
|
||
|
|
||
|
self FadeOverTime( step_time );
|
||
|
if ( target_alpha > current_alpha )
|
||
|
{
|
||
|
fraction = 1 - Cos( current_angle );
|
||
|
self.alpha = current_alpha - alpha_dif * fraction;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fraction = Sin( current_angle );
|
||
|
self.alpha = current_alpha - alpha_dif * fraction;
|
||
|
}
|
||
|
|
||
|
wait step_time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
handle_fire_missiles()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
level.players_boat endon( "death" );
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
dofire = true;
|
||
|
predictorg = fire_volley_of_missiles_predict( level.players_boat Vehicle_GetVelocity() );
|
||
|
// draw_arrow( self.origin, predictorg, (1,0,0) );
|
||
|
if ( !within_fov_2d( self.origin, self.angles, predictorg, 0.984807753 ) )
|
||
|
dofire = false;
|
||
|
if ( Distance( self.origin, predictorg ) < 2000 )
|
||
|
dofire = false;
|
||
|
if ( Distance( self.origin, predictorg ) > 5000 )
|
||
|
dofire = false;
|
||
|
if ( ! player_full_heath() )
|
||
|
dofire = false;
|
||
|
|
||
|
if ( dofire )
|
||
|
{
|
||
|
thread fire_volley_of_missiles_at_player();
|
||
|
flag_waitopen( "heli_firing" );
|
||
|
wait RandomFloatRange( 1.2, 2.4 );
|
||
|
}
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fire_volley_of_missiles_predict( velocity )
|
||
|
{
|
||
|
return level.players_boat.origin + ( velocity * 1.50 );// guessing
|
||
|
}
|
||
|
|
||
|
dialog_fire_volley_of_missiles_at_player( base_origin )
|
||
|
{
|
||
|
if ( flag( "rapids_trigger" ) )
|
||
|
return;
|
||
|
normal = VectorNormalize( base_origin - level.players_boat.origin );
|
||
|
forward = AnglesToRight( level.players_boat.angles );
|
||
|
dot = VectorDot( forward, normal );
|
||
|
if ( dot < 0 )
|
||
|
{
|
||
|
if ( cointoss() )
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_rightright", .5 );
|
||
|
else
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_right", .5 );
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( cointoss() )
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_leftleft", .5 );
|
||
|
else
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_left", .5 );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
fire_volley_of_missiles_at_player()
|
||
|
{
|
||
|
if ( !isalive( self ) )
|
||
|
return;
|
||
|
|
||
|
if ( flag( "heli_firing" ) )
|
||
|
return;
|
||
|
flag_set( "heli_firing" );
|
||
|
|
||
|
timer = GetTime() + 3000;
|
||
|
|
||
|
if ( !isalive( self ) )
|
||
|
{
|
||
|
flag_clear( "heli_firing" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
number_of_shots = RandomIntRange( 4, 5 );
|
||
|
velocity = level.players_boat Vehicle_GetVelocity();
|
||
|
base_origin = fire_volley_of_missiles_predict( velocity );
|
||
|
base_origin += flat_origin( randomvectorrange( -120, 120 ) );
|
||
|
|
||
|
dialog_fire_volley_of_missiles_at_player( base_origin );
|
||
|
|
||
|
|
||
|
// base_origin += ( 0, 0, 24 );
|
||
|
shot_origin = base_origin;
|
||
|
|
||
|
shotorgs = [];
|
||
|
|
||
|
linkorg = Spawn( "script_origin", level.players_boat.origin );
|
||
|
linkorg thread linkorg( level.players_boat );
|
||
|
|
||
|
// if( IsDefined( level.players_boat ) )
|
||
|
// thread draw_line_from_ent_to_ent_until_notify( linkorg , level.players_boat , 0 , 1 , 0 , linkorg , "balls" );
|
||
|
|
||
|
for ( i = 0; i < number_of_shots; i++ )
|
||
|
{
|
||
|
shotorgs[ i ] = Spawn( "script_origin", shot_origin );
|
||
|
shotorgs[ i ] LinkTo( linkorg );
|
||
|
shot_origin += velocity * .1;
|
||
|
// thread draw_line_from_ent_to_ent_until_notify( linkorg , shotorgs[i] , 1 , 0 , 1 , linkorg , "balls" );
|
||
|
}
|
||
|
|
||
|
tags = [];
|
||
|
tags[ 0 ] = "tag_missile_right";
|
||
|
tags[ 1 ] = "tag_missile_left";
|
||
|
ents = [];
|
||
|
|
||
|
|
||
|
for ( i = 0; i < number_of_shots; i++ )
|
||
|
{
|
||
|
if ( !isalive( self ) )
|
||
|
break;
|
||
|
self SetVehWeapon( "littlebird_FFAR" );
|
||
|
self SetTurretTargetEnt( shotorgs[ i ] );
|
||
|
missile = self FireWeapon( tags[ i % tags.size ], shotorgs[ i ], ( 0, 0, 0 ) );
|
||
|
missile Missile_SetFlightmodeDirect();
|
||
|
missile Missile_SetTargetEnt( shotorgs[ i ] );
|
||
|
missile thread kill_rpg_shot_behind_player();
|
||
|
// missile delayCall( 2.51, ::Missile_ClearTarget );
|
||
|
wait RandomFloatRange( 0.2, 0.3 );
|
||
|
}
|
||
|
linkorg notify( "balls" );
|
||
|
flag_clear( "heli_firing" );
|
||
|
wait 15;
|
||
|
foreach ( ent in shotorgs )
|
||
|
ent Delete();
|
||
|
linkorg Delete();
|
||
|
}
|
||
|
|
||
|
linkorg( linkent )
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
linkent endon( "death" );
|
||
|
offset = self.origin - linkent.origin;
|
||
|
while ( 1 )
|
||
|
{
|
||
|
self MoveTo( linkent.origin + offset, .05, 0, 0 );
|
||
|
// self.origin = linkent.origin + offset;
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
get_generic_anim( anime )
|
||
|
{
|
||
|
return level.scr_anim[ "generic" ][ anime ];
|
||
|
}
|
||
|
|
||
|
cleanup_stuff_on_players_boat()
|
||
|
{
|
||
|
level.players_boat notify( "cleanup" );
|
||
|
if ( IsDefined( level.players_boat.gun_attached ) )
|
||
|
{
|
||
|
level.players_boat Detach( level.zodiac_gunModel, "tag_weapon_left" );
|
||
|
level.players_boat.gun_attached = undefined;
|
||
|
}
|
||
|
level.players_boat Detach( level.zodiac_playerHandModel, "tag_player" );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
TEST_FLIP = false;
|
||
|
|
||
|
flip_when_player_dies()
|
||
|
{
|
||
|
level endon( "water_cliff_jump_splash_sequence" );
|
||
|
|
||
|
if ( !TEST_FLIP )
|
||
|
level.player waittill( "death" );
|
||
|
|
||
|
if ( TEST_FLIP )
|
||
|
{
|
||
|
while ( ! level.player ButtonPressed( "BUTTON_B" ) )
|
||
|
wait .05;
|
||
|
}
|
||
|
|
||
|
thread radio_dialogue_stop();
|
||
|
|
||
|
set_water_sheating_time( "bump_small_player_dies", "bump_big_player_dies" );
|
||
|
|
||
|
cleanup_stuff_on_players_boat();
|
||
|
|
||
|
|
||
|
linkobj = Spawn( "script_model", level.player.origin );
|
||
|
linkobj.angles = level.player.angles;
|
||
|
linkobj Hide();
|
||
|
linkobj SetModel( "zodiac_head_roller" );
|
||
|
linkobj LinkTo( self, "tag_player", ( 0, 0, 60 ), ( 0, 0, 0 ) );
|
||
|
|
||
|
offset_obj = Spawn( "script_model", level.player.origin );
|
||
|
offset_obj SetModel( "zodiac_head_roller" );
|
||
|
offset_obj LinkTo( linkobj, "tag_player", ( 0, 0, -60 ), ( 0, 0, 0 ) );
|
||
|
offset_obj.angles = level.player.angles;
|
||
|
offset_obj Hide();
|
||
|
|
||
|
|
||
|
blend_time = 1;
|
||
|
|
||
|
if ( TEST_FLIP )
|
||
|
{
|
||
|
level.player DismountVehicle();
|
||
|
level.player.drivingVehicle = level.players_boat;
|
||
|
|
||
|
}
|
||
|
|
||
|
wait .1;
|
||
|
|
||
|
// level.player PlayerLinkWeaponViewToDelta( linkobj, "tag_player", 1.0 );
|
||
|
level.player PlayerLinkToDelta( offset_obj, "tag_player", 1.0, 0, 0, 0, 0 );
|
||
|
level.player PlayerSetGroundReferenceEnt( offset_obj );
|
||
|
|
||
|
|
||
|
boatvelocity = self Vehicle_GetVelocity();
|
||
|
|
||
|
foreach ( rider in level.boatrider )
|
||
|
{
|
||
|
rider stop_magic_bullet_shield();
|
||
|
rider Unlink();
|
||
|
|
||
|
if ( IsDefined( rider.function_stack ) )
|
||
|
rider function_stack_clear();
|
||
|
rider Kill();
|
||
|
}
|
||
|
|
||
|
// if ( self Vehicle_GetSpeed() > 50 )
|
||
|
// self VehPhys_Crash( true );
|
||
|
// else if ( self Vehicle_GetSpeed() > 30 )
|
||
|
self delayCall( .75, ::VehPhys_Crash );
|
||
|
|
||
|
// wait 0.75;
|
||
|
|
||
|
oldorg = self.origin;
|
||
|
wait .1;
|
||
|
linkobj Unlink();
|
||
|
|
||
|
offset_vec = oldorg - self.origin;
|
||
|
offset_launchpoint = ( 0, 0, 0 );
|
||
|
//for spin
|
||
|
offset_launchpoint = ( offset_vec[ 0 ] * 100, offset_vec[ 1 ] * 100, 0 );
|
||
|
|
||
|
linkobj PhysicsLaunchServer( linkobj.origin + offset_launchpoint, 8 * boatvelocity + ( 0, 0, 500 ) );
|
||
|
|
||
|
lastorg = ( 0, 0, 0 );
|
||
|
|
||
|
while ( lastorg != linkobj.origin )
|
||
|
{
|
||
|
lastorg = linkobj.origin;
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
node_can_reach_spot_infront_of_player( basenode )
|
||
|
{
|
||
|
//might check basenode moveability
|
||
|
nodearray = GetNodesInRadius( level.player.origin, 800, 500, 1000, "path" );
|
||
|
forward = AnglesToForward( level.player.angles );
|
||
|
foreach ( node in nodearray )
|
||
|
{
|
||
|
normal = VectorNormalize( node.origin - level.player.origin );
|
||
|
dot = VectorDot( forward, normal );
|
||
|
if ( dot > Cos( 15 ) )
|
||
|
{
|
||
|
level.node_to_reach = node;// in a spawn function
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
find_good_node_for_price_to_spawn_at()
|
||
|
{
|
||
|
nodearray = GetNodesInRadius( level.player.origin, 230, 100, 1000, "path" );
|
||
|
forward = AnglesToForward( level.player.angles );
|
||
|
foreach ( node in nodearray )
|
||
|
{
|
||
|
normal = VectorNormalize( node.origin - level.player.origin );
|
||
|
dot = VectorDot( forward, normal );
|
||
|
//should spawn on the periphery
|
||
|
if ( dot < Cos( 45 ) && dot > 0 && node_can_reach_spot_infront_of_player( node ) )
|
||
|
return node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lower_accuracy_behind_player()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
originalbaseaccuracy = self.baseaccuracy;
|
||
|
wait .1;// just in case I'm first.
|
||
|
if ( !isdefined( level.players_boat ) )
|
||
|
return;// craziness keeps goiing.
|
||
|
level.players_boat endon( "death" );
|
||
|
|
||
|
if ( IsDefined( self.ridingVehicle ) && IsSubStr( self.ridingvehicle.classname, "zodiac" ) )
|
||
|
return;
|
||
|
if ( IsSubStr( self.classname, "shepherd" ) )
|
||
|
return;
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
while ( boat_in_range_in_front( self ) )
|
||
|
wait .05;
|
||
|
self.baseaccuracy = 0;
|
||
|
self.ignoreSuppression = false;
|
||
|
while ( ! boat_in_range_in_front( self ) )
|
||
|
wait .05;
|
||
|
self.baseaccuracy = originalbaseaccuracy;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
point_end( shepherd )
|
||
|
{
|
||
|
Shepherd notify( "point_end" );
|
||
|
controller = Shepherd getanim( "ending_additive_controller" );
|
||
|
Shepherd ClearAnim( controller, 0.2 );
|
||
|
shepherd SetLookAtEntity( level.player );
|
||
|
//( position, turn acceleration );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
setup_boat_for_drive()
|
||
|
{
|
||
|
self Vehicle_TurnEngineOff();
|
||
|
self maps\_vehicle::godon();
|
||
|
self MakeUnusable();
|
||
|
level.players_boat = self;
|
||
|
|
||
|
level.players_boat StartUsingHeroOnlyLighting();
|
||
|
|
||
|
self SetModel( "vehicle_zodiac" );
|
||
|
|
||
|
self waittill( "vehicle_mount", player );
|
||
|
|
||
|
|
||
|
level.dofDefault[ "nearStart" ] = 10;
|
||
|
level.dofDefault[ "nearEnd" ] = 20;
|
||
|
|
||
|
// thread missile_repulser();
|
||
|
|
||
|
level.price.orgmodel = level.price.model;
|
||
|
|
||
|
|
||
|
level.price SetModel( "body_desert_tf141_zodiac" );
|
||
|
hideTagList = GetWeaponHideTags( level.price.weapon );
|
||
|
for ( i = 0; i < hideTagList.size; i++ )
|
||
|
level.price HidePart( hideTagList[ i ], "weapon_m4" );
|
||
|
|
||
|
self SetModel( "vehicle_zodiac_viewmodel" );
|
||
|
|
||
|
self Vehicle_TurnEngineOn();
|
||
|
|
||
|
flag_set( "player_on_boat" );
|
||
|
|
||
|
thread autosave_by_name_silent( "mount_boat" );
|
||
|
|
||
|
delayThread( 4, ::add_extra_autosave_check, "boat_check_player_speeding_along", ::autosave_boat_check_player_speeding_along, "players boat not moving fast enough!" );
|
||
|
|
||
|
|
||
|
level.player ent_flag_clear( "near_death_vision_enabled" );
|
||
|
|
||
|
thread dialog_boat_nag();
|
||
|
|
||
|
thread dialog_boat_direction_nag();
|
||
|
|
||
|
thread raise_attacker_accuracy_on_nearby_boats();
|
||
|
|
||
|
thread rumble_with_throttle();
|
||
|
|
||
|
thread flip_when_player_dies();
|
||
|
|
||
|
thread zodiac_treadfx();
|
||
|
|
||
|
boatrider = get_boat_rider( "boatrider0" );
|
||
|
|
||
|
if ( ! boatrider ent_flag_exist( "price_animated_into_boat" ) )
|
||
|
boatrider thread boatrider_think( self );
|
||
|
else
|
||
|
{
|
||
|
boatrider ent_flag_wait( "price_animated_into_boat" );
|
||
|
level notify( "stop_animate_price_into_boat" );
|
||
|
level.price StopAnimScripted();
|
||
|
level.price thread boatrider_think( level.players_boat );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
price_ai_mods( price )
|
||
|
{
|
||
|
price.attackeraccuracy = 0;
|
||
|
price.baseaccuracy = .1;
|
||
|
price.ignoreSuppression = true;
|
||
|
price.dontavoidplayer = true;
|
||
|
price.takedamage = false;
|
||
|
price.suppressionwait = 0;
|
||
|
price.pathrandompercent = 0;
|
||
|
price.ignoreExplosionEvents = true;
|
||
|
price disable_surprise();
|
||
|
price.grenadeawareness = 0;
|
||
|
price.ignoreme = true;
|
||
|
price.IgnoreRandomBulletDamage = true;
|
||
|
price.disableBulletWhizbyReaction = true;
|
||
|
flag_wait( "player_on_boat" );
|
||
|
price.baseaccuracy = 25;
|
||
|
}
|
||
|
|
||
|
players_boat()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
change_target_on_vehicle_spawner( boat_targetname, boat_destination_node )
|
||
|
{
|
||
|
boat = GetEnt( boat_targetname, "targetname" );
|
||
|
destnode = GetVehicleNode( boat_destination_node, "targetname" );
|
||
|
boat.target = destnode.targetname;
|
||
|
}
|
||
|
|
||
|
change_target_ent_on_vehicle_spawner( heli_targetname, boat_destination_node )
|
||
|
{
|
||
|
boat = GetEnt( heli_targetname, "targetname" );
|
||
|
destnode = GetEnt( boat_destination_node, "targetname" );
|
||
|
boat.target = destnode.targetname;
|
||
|
|
||
|
//this stuff should probably be in another function
|
||
|
boat.origin = destnode.origin;
|
||
|
boat.angles = destnode.angles;
|
||
|
boat.speed = destnode.speed;
|
||
|
}
|
||
|
|
||
|
enemy_chase_boat()
|
||
|
{
|
||
|
level.breadcrumb = [];
|
||
|
level.enemy_boat = self;
|
||
|
self endon( "death" );
|
||
|
self VehPhys_DisableCrashing();
|
||
|
self.veh_pathtype = "constrained";
|
||
|
self thread zodiac_monitor_player_trailing_time();
|
||
|
|
||
|
foreach ( rider in self.riders )
|
||
|
{
|
||
|
if ( IsDefined( rider.magic_bullet_shield ) && rider.magic_bullet_shield )
|
||
|
continue;
|
||
|
rider thread magic_bullet_shield();
|
||
|
}
|
||
|
|
||
|
// self.veh_pathtype = "follow";
|
||
|
while ( 1 )
|
||
|
{
|
||
|
wait .25;
|
||
|
enemy_chase_boat_breadcrumb();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
boat_common()
|
||
|
{
|
||
|
if( ! is_default_start() )
|
||
|
maps\_friendlyfire::TurnOff();
|
||
|
boatrider = get_boat_rider( "boatrider0" );
|
||
|
level.price = boatrider;
|
||
|
thread price_ai_mods( boatrider );
|
||
|
thread test_m203();
|
||
|
|
||
|
kill_ai_in_volume = GetEntArray( "kill_ai_in_volume", "targetname" );
|
||
|
array_thread( kill_ai_in_volume, ::kill_ai_in_volume );
|
||
|
}
|
||
|
|
||
|
rpg_bridge_guy()
|
||
|
{
|
||
|
trigger = Spawn( "trigger_radius", self.origin + ( 0, 0, -2000 ), 0, 4500, 2000 );
|
||
|
trigger waittill( "trigger" );
|
||
|
level notify( "dialog_rpg_bridge_guy" );
|
||
|
}
|
||
|
|
||
|
rpg_bridge_guy_target()
|
||
|
{
|
||
|
target_ent = Spawn( "script_origin", level.players_boat.origin );
|
||
|
self ent_flag_init( "first_player_sighting" );
|
||
|
self disable_long_death();
|
||
|
self SetEntityTarget( target_ent );
|
||
|
self.favoriteenemy = target_ent;
|
||
|
self.ignoreall = true;
|
||
|
self.rpg_setup_time = GetTime() + RandomIntRange( 1000, 2000 );// "reaction time so they don't instantly shoot when you round a corner.
|
||
|
|
||
|
random_vec = flat_origin( randomvectorrange( -64, 64 ) );
|
||
|
firing_range = 3000;
|
||
|
while ( IsAlive( self ) )
|
||
|
{
|
||
|
velocity_offset = level.players_boat Vehicle_GetVelocity() * 1.4 ;
|
||
|
|
||
|
// target_ent.origin = level.players_boat.origin +( level.players_boat Vehicle_GetVelocity() * 1.89 );
|
||
|
|
||
|
forward_origin = level.players_boat.origin + velocity_offset;
|
||
|
forward_origin = set_z( forward_origin, level.players_boat.origin[ 2 ] + 24 );
|
||
|
|
||
|
// Line( forward_origin, level.players_boat.origin, (0,1,0) );
|
||
|
|
||
|
|
||
|
//when the player is headed towards something use the spline direction to influence the shot. otherwise fire away in the direct forward path.
|
||
|
if ( ! BulletTracePassed( level.player GetEye() + ( 0, 0, 16 ), forward_origin, false, self ) )
|
||
|
{
|
||
|
offset = Distance( ( 0, 0, 0 ), velocity_offset );
|
||
|
target_ent.origin = get_position_from_spline_unlimited( level.player.targ, level.player.progress + offset - level.POS_LOOKAHEAD_DIST, level.player.offset );
|
||
|
target_ent.origin = set_z( target_ent.origin, level.players_boat.origin[ 2 ] + 24 );
|
||
|
// Line( target_ent.origin, level.players_boat.origin, (0,0,1) );
|
||
|
target_ent.origin = ( target_ent.origin + forward_origin ) / 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
target_ent.origin = forward_origin;
|
||
|
}
|
||
|
|
||
|
// Line( target_ent.origin, level.players_boat.origin, (1,0,0) );
|
||
|
self OrientMode( "face point", target_ent.origin ) ;
|
||
|
|
||
|
bullettraced_to_player = false;
|
||
|
if ( BulletTracePassed( self GetTagOrigin( "tag_flash" ), level.player GetEye(), false, self ) )
|
||
|
{
|
||
|
bullettraced_to_player = true;
|
||
|
if ( ! ent_flag( "first_player_sighting" ) )
|
||
|
ent_flag_set( "first_player_sighting" );
|
||
|
}
|
||
|
|
||
|
if ( ! ent_flag( "first_player_sighting" ) )
|
||
|
self.rpg_setup_time = GetTime() + RandomIntRange( 1000, 2000 );// "reaction time so they don't instantly shoot when you round a corner.
|
||
|
|
||
|
if ( GetTime() > self.rpg_setup_time )
|
||
|
if ( bullettraced_to_player )
|
||
|
if ( BulletTracePassed( self GetTagOrigin( "tag_flash" ), target_ent.origin + random_vec, false, self ) )
|
||
|
if ( Distance( self.origin, level.player.origin ) < firing_range )
|
||
|
if ( GetTime() > level.next_rpg_firetime )
|
||
|
break;
|
||
|
|
||
|
wait .05;
|
||
|
}
|
||
|
|
||
|
ammo = "rpg_straight_af_chase";
|
||
|
// if( cointoss() )
|
||
|
// ammo = "rpg";
|
||
|
|
||
|
if ( IsDefined( self ) && IsDefined( self GetTagOrigin( "tag_flash" ) ) )// Tried isalive . debugger is broken today = ( .
|
||
|
{
|
||
|
rpg_shot = MagicBullet( ammo, self GetTagOrigin( "tag_flash" ), target_ent.origin + random_vec );
|
||
|
rpg_shot thread kill_rpg_shot_behind_player();
|
||
|
}
|
||
|
level.next_rpg_firetime = GetTime() + RandomIntRange( 300, 500 );// stagger time between multiple guys
|
||
|
target_ent Delete();
|
||
|
}
|
||
|
|
||
|
kill_rpg_shot_behind_player()
|
||
|
{
|
||
|
level.players_boat endon( "death" );
|
||
|
self endon( "death" );
|
||
|
while ( in_front( level.player, self ) )
|
||
|
wait .05;
|
||
|
thread play_sound_in_space( "rocket_explode_water" );
|
||
|
self Delete();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
set_price_autoswitch_after_caves()
|
||
|
{
|
||
|
flag_wait( "exit_caves" );
|
||
|
set_price_auto_switch_pose();
|
||
|
}
|
||
|
|
||
|
|
||
|
teleport_price_on_mount( node )
|
||
|
{
|
||
|
level endon( "end_teleport_price_on_mount" );
|
||
|
level.players_boat waittill( "vehicle_mount" );
|
||
|
level.price teleport_ai_here( node );
|
||
|
}
|
||
|
|
||
|
teleport_ai_here( eNode )
|
||
|
{
|
||
|
AssertEx( IsAI( self ), "Function teleport_ai can only be called on an AI entity" );
|
||
|
AssertEx( IsDefined( eNode ), "Need to pass a node entity to function teleport_ai" );
|
||
|
self ForceTeleport( eNode.origin, eNode.angles );
|
||
|
self SetGoalPos( self.origin );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
dialog_boat_battlechatter()
|
||
|
{
|
||
|
|
||
|
dialog_direction = [];
|
||
|
dialog_direction = array_add( dialog_direction, "TF_pri_callout_targetclock_" );
|
||
|
|
||
|
dialog_helicopter_six = [];
|
||
|
dialog_helicopter_six = array_add( dialog_helicopter_six, "afchase_pri_evasive" );
|
||
|
dialog_helicopter_six = array_add( dialog_helicopter_six, "afchase_pri_shakeemoff" );
|
||
|
dialog_helicopter_six = array_add( dialog_helicopter_six, "afchase_pri_miniguns" );
|
||
|
|
||
|
dialog_helicopter_ahead = [];
|
||
|
dialog_helicopter_ahead = array_add( dialog_helicopter_ahead, "afchase_pri_dodgeheli" );
|
||
|
dialog_helicopter_ahead = array_add( dialog_helicopter_ahead, "afchase_pri_gunsspinup" );
|
||
|
dialog_helicopter_ahead = array_add( dialog_helicopter_ahead, "afchase_pri_steerclear" );
|
||
|
|
||
|
dialog_rpg_bridge_guy = [];
|
||
|
dialog_rpg_bridge_guy = array_add( dialog_rpg_bridge_guy, "afchase_pri_rpgsonbridge" );
|
||
|
|
||
|
dialog = [];
|
||
|
dialog[ "dialog_direction" ] = dialog_direction;
|
||
|
dialog[ "dialog_helicopter_six" ] = dialog_helicopter_six;
|
||
|
dialog[ "dialog_helicopter_ahead" ] = dialog_helicopter_ahead;
|
||
|
dialog[ "dialog_rpg_bridge_guy" ] = dialog_rpg_bridge_guy;
|
||
|
|
||
|
timeout[ "dialog_direction" ] = .5;
|
||
|
timeout[ "dialog_helicopter_six" ] = 1;
|
||
|
timeout[ "dialog_helicopter_ahead" ] = 1;
|
||
|
timeout[ "dialog_rpg_bridge_guy" ] = .7;
|
||
|
|
||
|
nagtime[ "dialog_direction" ] = 5500;
|
||
|
nagtime[ "dialog_helicopter_six" ] = 9300;
|
||
|
nagtime[ "dialog_helicopter_ahead" ] = 2000;
|
||
|
nagtime[ "dialog_rpg_bridge_guy" ] = 10000;
|
||
|
|
||
|
last_nagtime[ "dialog_direction" ] = GetTime();
|
||
|
last_nagtime[ "dialog_helicopter_six" ] = GetTime();
|
||
|
last_nagtime[ "dialog_helicopter_ahead" ] = GetTime();
|
||
|
last_nagtime[ "dialog_rpg_bridge_guy" ] = GetTime();
|
||
|
|
||
|
unused_dialog = dialog;
|
||
|
|
||
|
picked = undefined;
|
||
|
|
||
|
wait 1;// let enemy boat get defined..
|
||
|
|
||
|
/#
|
||
|
if ( GetDvarInt( "scr_zodiac_test" ) )
|
||
|
return;
|
||
|
#/
|
||
|
|
||
|
level endon( "price_stops_talking_about_helicopters" );
|
||
|
|
||
|
level.player endon( "death" );
|
||
|
self endon( "death" );
|
||
|
flag_wait( "exit_caves" );
|
||
|
while ( 1 )
|
||
|
{
|
||
|
type = level waittill_any_return( "dialog_direction", "dialog_helicopter_six", "dialog_helicopter_ahead", "dialog_rpg_bridge_guy" );
|
||
|
if ( flag( "price_anim_on_boat" ) )
|
||
|
continue;
|
||
|
if ( flag( "rapids_head_bobbing" ) )
|
||
|
continue;
|
||
|
picked = random( unused_dialog[ type ] );
|
||
|
|
||
|
if ( GetTime() - last_nagtime[ type ] < nagtime[ type ] )
|
||
|
continue;
|
||
|
|
||
|
last_nagtime[ type ] = GetTime();
|
||
|
|
||
|
if ( type == "dialog_direction" )
|
||
|
level.price thread generic_dialogue_queue( picked + level.dialog_dir, timeout[ type ] );
|
||
|
else
|
||
|
level.price thread generic_dialogue_queue( picked, timeout[ type ] );
|
||
|
|
||
|
|
||
|
unused_dialog[ type ] = array_remove( unused_dialog[ type ], picked );
|
||
|
if ( !unused_dialog[ type ].size )
|
||
|
unused_dialog[ type ] = dialog[ type ];
|
||
|
wait .05;
|
||
|
if ( flag( "player_in_sight_of_boarding" ) )
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dialog_boat_nag()
|
||
|
{
|
||
|
nagtime = 8000;
|
||
|
next_nag = GetTime() + nagtime;
|
||
|
|
||
|
dialog = [];
|
||
|
dialog = array_add( dialog, "afchase_pri_gettingaway" );
|
||
|
dialog = array_add( dialog, "afchase_pri_gogogo" );
|
||
|
dialog = array_add( dialog, "afchase_pri_cantlet" );
|
||
|
dialog = array_add( dialog, "afchase_pri_losinghim" );
|
||
|
dialog = array_add( dialog, "afchase_pri_drivingtheboat" );
|
||
|
dialog = array_add( dialog, "afchase_pri_fullpower" );
|
||
|
|
||
|
unused_dialog = dialog;
|
||
|
|
||
|
picked = undefined;
|
||
|
|
||
|
self endon( "death" );
|
||
|
level.price endon( "death" );
|
||
|
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
if ( bread_crumb_get_player_trailing_fraction() > .5 && next_nag < GetTime() && ! level.price ent_flag( "transitioning_positions" ) )
|
||
|
{
|
||
|
picked = random( unused_dialog );
|
||
|
// level.price thread radio_dialogue( picked );
|
||
|
side = level.price.a.boat_pose;
|
||
|
Assert( IsDefined( side ) && ( side == "left" || side == "right" ) );
|
||
|
|
||
|
doradio = false;
|
||
|
|
||
|
if ( level.price.a.lastShootTime > GetTime() - 2000 && ! player_full_heath() )
|
||
|
doradio = true;
|
||
|
if ( flag( "rapids_head_bobbing" ) )
|
||
|
{
|
||
|
wait .05;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( doradio )
|
||
|
level.price thread generic_dialogue_queue( picked, 1 );
|
||
|
else
|
||
|
level.price thread price_anim_single_on_boat( side + "_" + picked );
|
||
|
|
||
|
unused_dialog = array_remove( unused_dialog, picked );
|
||
|
next_nag = GetTime() + nagtime;
|
||
|
if ( !unused_dialog.size )
|
||
|
unused_dialog = dialog;
|
||
|
}
|
||
|
wait .05;
|
||
|
if ( flag( "stop_boat_dialogue" ) )
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
dialog_cave()
|
||
|
{
|
||
|
level.player endon( "death" );
|
||
|
self waittill( "trigger" );
|
||
|
level.price generic_dialogue_queue( "afchase_pri_thrucave" );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
dialog_start()
|
||
|
{
|
||
|
// thread add_dialogue_line( "Price", "They're just around the corner, come on." );
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_aroundcorner" );
|
||
|
wait 4;
|
||
|
// thread add_dialogue_line( "Price", "We need to get on that boat. " );
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_getonboat" );
|
||
|
|
||
|
wait 2;
|
||
|
}
|
||
|
|
||
|
dialog_boat_direction_nag()
|
||
|
{
|
||
|
nagtime = 4000;
|
||
|
next_nag = GetTime() + nagtime;
|
||
|
wrong_way_time = 2;
|
||
|
wrong_way_time_count = 0;
|
||
|
|
||
|
dialog = [];
|
||
|
dialog = array_add( dialog, "afchase_pri_wrongway" );
|
||
|
dialog = array_add( dialog, "afchase_pri_turntoobjective" );
|
||
|
dialog = array_add( dialog, "afchase_pri_wheregoing" );
|
||
|
|
||
|
unused_dialog = dialog;
|
||
|
|
||
|
picked = undefined;
|
||
|
|
||
|
wait 1;// let enemy boat get defined..
|
||
|
|
||
|
/#
|
||
|
if ( GetDvarInt( "scr_zodiac_test" ) )
|
||
|
return;
|
||
|
#/
|
||
|
|
||
|
self endon( "death" );
|
||
|
level.enemy_boat endon( "death" );
|
||
|
level.player endon( "death" );
|
||
|
|
||
|
while ( 1 )
|
||
|
{
|
||
|
if ( !in_front_by_velocity( level.players_boat, level.enemy_boat ) && next_nag < GetTime() )
|
||
|
wrong_way_time_count += .05;
|
||
|
else
|
||
|
wrong_way_time_count = 0;
|
||
|
|
||
|
if ( flag( "price_anim_on_boat" ) )
|
||
|
{
|
||
|
wait .05;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( wrong_way_time_count > wrong_way_time )
|
||
|
{
|
||
|
picked = random( unused_dialog );
|
||
|
level.price thread generic_dialogue_queue( picked );
|
||
|
unused_dialog = array_remove( unused_dialog, picked );
|
||
|
next_nag = GetTime() + nagtime;
|
||
|
if ( !unused_dialog.size )
|
||
|
unused_dialog = dialog;
|
||
|
}
|
||
|
|
||
|
wait .05;
|
||
|
if ( flag( "stop_boat_dialogue" ) )
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
animate_price_into_boat()
|
||
|
{
|
||
|
level endon( "stop_animate_price_into_boat" );
|
||
|
waittillframeend;// let players boat get spawned and defined
|
||
|
pathnode = GetNode( self.target, "targetname" );
|
||
|
node = Spawn( "script_origin", pathnode.origin );
|
||
|
node.angles = pathnode.angles + ( 0, -90, 0 );
|
||
|
level.price ent_flag_init( "price_animated_into_boat" );
|
||
|
|
||
|
//make the scene stick to boat should player start to drive
|
||
|
node delayCall( 2, ::linkto, level.players_boat );// give it time to settle before linking
|
||
|
|
||
|
thread teleport_price_on_mount( node );
|
||
|
node anim_generic_reach( level.price, "price_into_boat" );
|
||
|
level notify( "end_teleport_price_on_mount" );
|
||
|
level.price LinkTo( node );
|
||
|
|
||
|
level.price delayThread( 1.5, ::ent_flag_set, "price_animated_into_boat" );// I timed this as a good cutoff point for when the player jumps in first.
|
||
|
level.players_boat delayCall( 1, ::JoltBody, level.price.origin, .15 );
|
||
|
level.players_boat delayThread( 1, ::play_sound_in_space, "water_boat_splash_small", level.players_boat.origin );
|
||
|
|
||
|
node anim_generic( level.price, "price_into_boat" );
|
||
|
level.price thread boatrider_think( level.players_boat );
|
||
|
}
|
||
|
|
||
|
search_the_scrash_site()
|
||
|
{
|
||
|
GetEnt( "damaged_pavelow", "targetname" ) Hide();
|
||
|
|
||
|
flag_wait( "end_heli_crashed" );
|
||
|
exploder( "heli_fire" );
|
||
|
damaged_heli = GetEnt( "damaged_pavelow", "targetname" );
|
||
|
wait .5;
|
||
|
damaged_heli Show();
|
||
|
trigger = Spawn( "trigger_radius", damaged_heli.origin + ( 0, 0, -100 ), 0, 670, 600 );
|
||
|
trigger waittill( "trigger" );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
trigger_out_of_caves()
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_openareas" );
|
||
|
}
|
||
|
|
||
|
trigger_boat_mount()
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
|
||
|
if ( flag( "player_on_boat" ) )
|
||
|
return;
|
||
|
|
||
|
origin = level.players_boat GetTagOrigin( "tag_player" );
|
||
|
angles = level.players_boat GetTagAngles( "tag_player" );
|
||
|
level.player SwitchToWeapon( "uzi" );
|
||
|
level.player FreezeControls( true );
|
||
|
level.player PlayerLinkToBlend( level.players_boat, "tag_player", .35, .2, .1 );
|
||
|
wait .35;
|
||
|
level.player FreezeControls( false );
|
||
|
// level.price ent_flag_wait( "price_animated_into_boat" );
|
||
|
level.players_boat MakeUsable();
|
||
|
level.players_boat UseBy( level.player );
|
||
|
level.player.drivingVehicle = level.players_boat;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
trigger_price_tells_player_go_right()
|
||
|
{
|
||
|
self.origin += ( 0, 0, -50 );
|
||
|
self waittill( "trigger" );
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_right" );
|
||
|
|
||
|
}
|
||
|
|
||
|
hint_test()
|
||
|
{
|
||
|
return player_steadies_boat();
|
||
|
}
|
||
|
|
||
|
|
||
|
trigger_end_caves()
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
flag_set( "exit_caves" );
|
||
|
wait 1.1;
|
||
|
|
||
|
thread maps\_utility::set_ambient( "af_chase_exit" );
|
||
|
wait 3;
|
||
|
SetSavedDvar( "sm_sunSampleSizeNear", "2" );
|
||
|
if ( IsDefined( level.price ) )
|
||
|
level.price DontCastShadows();
|
||
|
|
||
|
}
|
||
|
|
||
|
rope_splashers()
|
||
|
{
|
||
|
self endon( "death" );
|
||
|
wait .5;
|
||
|
org_z = self.origin[ 2 ];
|
||
|
|
||
|
while ( self.origin[ 2 ] == org_z )
|
||
|
wait .1;
|
||
|
|
||
|
self Kill();
|
||
|
|
||
|
//this might be cool if I could do client ragdoll..
|
||
|
|
||
|
//self waittill ( "death" );
|
||
|
//self endon ("death");
|
||
|
//
|
||
|
//ent = SpawnStruct();
|
||
|
//ent endon( "complete" );
|
||
|
//ent delayThread( 5, ::send_notify, "complete" );
|
||
|
|
||
|
// while( self.origin[2] > 48 )
|
||
|
// wait .05;
|
||
|
//
|
||
|
// PlayFX( getfx("body_falls_from_ropes_splash") , set_z( self.origin,48 ) );
|
||
|
// StartRagdoll();
|
||
|
}
|
||
|
|
||
|
|
||
|
trigger_set_max_zodiacs( value )
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
level.enemy_snowmobiles_max = value;
|
||
|
}
|
||
|
|
||
|
trigger_rapids()
|
||
|
{
|
||
|
level.player endon( "death" );
|
||
|
self waittill( "trigger" );
|
||
|
flag_set( "rapids_trigger" );
|
||
|
thread maps\_utility::set_ambient( "af_chase_rapids" );
|
||
|
level.player.nooffset = true;// makes enemy boats spawn exactly behind the player.
|
||
|
|
||
|
level.enemy_snowmobiles_max = 1;
|
||
|
|
||
|
flag_set( "rapids_head_bobbing" );
|
||
|
// price_anim_single_on_boat( "rapids_in", false );
|
||
|
level.price generic_dialogue_queue( "afchase_pri_rapidsahead" );
|
||
|
thread price_anim_loop_on_boat( "rapids_loop", "end_the_rapids_loop" );
|
||
|
|
||
|
end_price_crazy = GetEnt( "end_price_crazy", "targetname" );
|
||
|
end_price_crazy waittill( "trigger" );
|
||
|
flag_clear( "rapids_head_bobbing" );
|
||
|
|
||
|
level.players_boat notify( "end_the_rapids_loop" );
|
||
|
level.enemy_snowmobiles_max = 2;
|
||
|
|
||
|
wait 1;
|
||
|
set_price_auto_switch_pose();
|
||
|
|
||
|
// they get really bogged in so reduce them after a bit.
|
||
|
wait 9;
|
||
|
level.enemy_snowmobiles_max = 1;
|
||
|
}
|
||
|
|
||
|
trigger_on_river()
|
||
|
{
|
||
|
self waittill( "trigger" );
|
||
|
thread maps\_utility::set_ambient( "af_chase_river" );
|
||
|
flag_set( "on_river" );
|
||
|
}
|
||
|
|
||
|
|
||
|
trigger_open_area()
|
||
|
{
|
||
|
flag_wait( "exit_caves" );
|
||
|
level endon ( "stop_deadquote_for_gettingout_of_bounds" );
|
||
|
level.player endon( "death" );
|
||
|
nagtime = GetTime() + 30000;
|
||
|
while ( 1 )
|
||
|
{
|
||
|
SetDvar( "ui_deadquote", "" );
|
||
|
level thread maps\_quotes::setDeadQuote();
|
||
|
|
||
|
flag_clear( "player_in_open" );
|
||
|
self waittill( "trigger" );
|
||
|
while ( level.player IsTouching( self ) )
|
||
|
{
|
||
|
if ( GetTime() > nagtime )
|
||
|
{
|
||
|
nagtime = GetTime() + RandomFloatRange( 20000, 22000 );
|
||
|
|
||
|
//Price: Stay clear of open areas as much as possible!
|
||
|
level.price thread generic_dialogue_queue( "afchase_pri_openareas" );
|
||
|
}
|
||
|
flag_set( "player_in_open" );// done every frame to support overlap.
|
||
|
level notify( "new_quote_string" );
|
||
|
// Stay clear of open areas as much as possible!
|
||
|
SetDvar( "ui_deadquote", &"AF_CHASE_MISSION_FAILED_IN_THE_OPEN" );
|
||
|
wait .05;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
setDeadQuote()
|
||
|
{
|
||
|
level endon( "mine death" );
|
||
|
|
||
|
// kill any deadquotes already running
|
||
|
level notify( "new_quote_string" );
|
||
|
level endon( "new_quote_string" );
|
||
|
|
||
|
*/
|
||
|
|
||
|
sentry_technical_think()
|
||
|
{
|
||
|
wait .5;
|
||
|
turret = self.mgturret[ 0 ];
|
||
|
turret SetMode( "manual_ai" );
|
||
|
turret SetTargetEntity( level.player );
|
||
|
|
||
|
foreach ( rider in self.riders )
|
||
|
{
|
||
|
rider.favoriteenemy = level.player;
|
||
|
rider.maxsightdistsqrd = 20000 * 20000;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sunsample_after_caves()
|
||
|
{
|
||
|
flag_wait( "exit_caves" );
|
||
|
SetSavedDvar( "sm_sunSampleSizeNear", "2" );
|
||
|
}
|
||
|
|
||
|
|
||
|
boatsquish()
|
||
|
{
|
||
|
if ( IsDefined( level.noTankSquish ) )
|
||
|
{
|
||
|
AssertEx( level.noTankSquish, "level.noTankSquish must be true or undefined" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( IsDefined( level.levelHasVehicles ) && !level.levelHasVehicles )
|
||
|
return;
|
||
|
self add_damage_function( ::boatsquish_damage_check );
|
||
|
self remove_damage_function( maps\_spawner::tanksquish_damage_check );
|
||
|
}
|
||
|
|
||
|
boatsquish_damage_check( amt, who, force, b, c, d, e )
|
||
|
{
|
||
|
if ( !isdefined( self ) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if ( IsAlive( self ) )
|
||
|
return;
|
||
|
|
||
|
if ( !isalive( who ) )
|
||
|
return;
|
||
|
if ( !isdefined( who.vehicletype ) )
|
||
|
return;
|
||
|
|
||
|
if ( who maps\_vehicle::ishelicopter() )
|
||
|
return;
|
||
|
|
||
|
if ( abs( self.origin[ 2 ] - level.players_boat.origin[ 2 ] ) > 64 )
|
||
|
{
|
||
|
self Delete();// these guys are getting hit by the players tall boat collision.. just delete them so they don't fly over.
|
||
|
}
|
||
|
|
||
|
self thread boat_squish_ragdoll_or_bust();
|
||
|
|
||
|
if ( !isdefined( self ) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
self remove_damage_function( ::boatsquish_damage_check );
|
||
|
|
||
|
// self PlaySound( "human_crunch" );
|
||
|
}
|
||
|
|
||
|
boat_squish_ragdoll_or_bust()
|
||
|
{
|
||
|
make_room_for_priority_squished_guy_corpse();
|
||
|
timer = GetTime() + 500;
|
||
|
while ( GetTime() < timer )
|
||
|
{
|
||
|
if ( !isdefined( self ) )
|
||
|
return;
|
||
|
if ( self IsRagdoll() )
|
||
|
return;
|
||
|
self StartRagdoll();
|
||
|
wait .05;
|
||
|
}
|
||
|
self Delete();
|
||
|
}
|
||
|
|
||
|
make_room_for_priority_squished_guy_corpse()
|
||
|
{
|
||
|
corpses = GetCorpseArray();
|
||
|
foreach ( corpse in corpses )
|
||
|
if ( Distance( corpse.origin, level.player GetEye() ) > 600 )
|
||
|
corpse Delete();
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
explode_barrels_in_radius_think()
|
||
|
{
|
||
|
assert( isdefined( self.radius ) );
|
||
|
|
||
|
shootable_stuff = GetEntArray( "explodable_barrel", "targetname" );
|
||
|
flat_org = flat_origin ( self.origin );
|
||
|
|
||
|
my_barrels = [];
|
||
|
foreach ( thing in shootable_stuff )
|
||
|
{
|
||
|
if( distance( flat_org, flat_origin( thing.origin) ) < self.radius )
|
||
|
my_barrels[ my_barrels.size ] = thing;
|
||
|
}
|
||
|
|
||
|
self waittill ( "trigger" );
|
||
|
|
||
|
for ( i = 0; i < 10; i++ )
|
||
|
{
|
||
|
foreach( barrel in my_barrels )
|
||
|
barrel notify( "damage", 50, level.player, (0,0,0), barrel.origin, "MOD_EXPLOSIVE" );
|
||
|
wait .05;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
player_steadies_boat()
|
||
|
{
|
||
|
return level.player ButtonPressed( "BUTTON_B" ) || 1;
|
||
|
}
|
||
|
|
||
|
remove_global_spawn_funcs()
|
||
|
{
|
||
|
flag_wait( "water_cliff_jump_splash_sequence" );
|
||
|
|
||
|
remove_global_spawn_function( "axis", ::lower_accuracy_behind_player );
|
||
|
remove_global_spawn_function( "axis", ::set_fixed_node_after_seeing_player_spawn_func );
|
||
|
}
|