619 lines
16 KiB
Plaintext
619 lines
16 KiB
Plaintext
#using scripts\mp\_events;
|
|
#using scripts\mp\_util;
|
|
#using scripts\mp\gametypes\ctf;
|
|
#using scripts\mp\killstreaks\_supplydrop;
|
|
#using scripts\codescripts\struct;
|
|
#using scripts\shared\clientfield_shared;
|
|
#using scripts\shared\exploder_shared;
|
|
#using scripts\shared\gameobjects_shared;
|
|
#using scripts\shared\util_shared;
|
|
#using scripts\shared\weapons\_weaponobjects;
|
|
|
|
|
|
#precache( "fx", "light/fx_light_red_train_track_warning" );
|
|
#precache( "fx", "water/fx_water_train_mist_kick_up_metro" );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function init()
|
|
{
|
|
level.train_positions = [];
|
|
level.train_angles = [];
|
|
|
|
start1 = GetVehicleNode( "train_start_1", "targetname" );
|
|
start2 = GetVehicleNode( "train_start_2", "targetname" );
|
|
|
|
cars1 = [];
|
|
cars2 = [];
|
|
|
|
dividers1 = [];
|
|
dividers2 = [];
|
|
|
|
spawn_start_train( cars1, dividers1, start1, "train1" );
|
|
spawn_start_train( cars2, dividers2, start2, "train2" );
|
|
|
|
gate_inner_left = getentarray("metro_doors_inside_left", "targetname");
|
|
gate_outer_left = getentarray("metro_doors_outside_left", "targetname");
|
|
gate_end_left = getentarray("metro_doors_end_left", "targetname");
|
|
gate_speakers_left = struct::get_array( "metro_train_track_vox_left" );
|
|
gate_inner_right = getentarray("metro_doors_inside_right", "targetname");
|
|
gate_outer_right = getentarray("metro_doors_outside_right", "targetname");
|
|
gate_end_right = getentarray("metro_doors_end_right", "targetname");
|
|
gate_speakers_right = struct::get_array( "metro_train_track_vox_right" );
|
|
|
|
gate_kill_left = getent("train_killtrigger_left", "targetname");
|
|
gate_kill_right = getent("train_killtrigger_right", "targetname");
|
|
|
|
gate_end_kill_left = getent("train_killtrigger_left_end", "targetname");
|
|
gate_end_kill_right = getent("train_killtrigger_right_end", "targetname");
|
|
|
|
security_barriers_1 = getEntArray( "mp_metro_platform_edge_left", "targetname" );
|
|
security_barriers_2 = getEntArray( "mp_metro_platform_edge_right", "targetname" );
|
|
|
|
level._effect[ "fx_light_red_train_track_warning" ] = "light/fx_light_red_train_track_warning";
|
|
level._effect[ "fx_water_train_mist_kick_up_metro" ] = "water/fx_water_train_mist_kick_up_metro";
|
|
|
|
waittillframeend;
|
|
|
|
if ( level.timelimit )
|
|
{
|
|
seconds = level.timelimit * 60;
|
|
events::add_timed_event( Int( seconds * 0.25 ), "train_start_1" );
|
|
events::add_timed_event( Int( seconds * 0.75 ), "train_start_2" );
|
|
|
|
}
|
|
else if ( level.scorelimit )
|
|
{
|
|
events::add_score_event( Int( level.scorelimit * 0.25 ), "train_start_1" );
|
|
events::add_score_event( Int( level.scorelimit * 0.75 ), "train_start_2" );
|
|
}
|
|
else if( level.roundScoreLimit )
|
|
{
|
|
events::add_round_score_event( Int( level.roundScoreLimit * 0.25 ), "train_start_1" );
|
|
events::add_round_score_event( Int( level.roundScoreLimit * 0.75 ), "train_start_2" );
|
|
}
|
|
|
|
wait ( 1 );
|
|
if ( level.gameType == "escort" )
|
|
{
|
|
return;
|
|
}
|
|
level thread train_think( cars1, dividers1, "train_start_1", start1, gate_inner_left, gate_outer_left, gate_end_left, security_barriers_1, gate_kill_right, gate_end_kill_right, gate_speakers_right, "right" );
|
|
level thread train_think( cars2, dividers2, "train_start_2", start2, gate_inner_right, gate_outer_right, gate_end_right, security_barriers_2, gate_kill_left, gate_end_kill_left, gate_speakers_left, "left" );
|
|
}
|
|
|
|
function setup_gate( gate, gate_kill )
|
|
{
|
|
gate SetMovingPlatformEnabled(true);
|
|
gate.gate_kill = gate_kill;
|
|
gate.gate_kill EnableLinkTo();
|
|
gate.gate_kill LinkTo( gate );
|
|
}
|
|
|
|
function spawn_start_train( &cars, ÷rs, start, name )
|
|
{
|
|
cars[0] = SpawnVehicle( "train_test_mp", (0,-2000,-200), (0, 0, 0), name );
|
|
cars[0] setteam( "neutral" );
|
|
cars[0] Ghost();
|
|
cars[0].isMagicBullet = true;
|
|
max_cars = getdvarint( "train_length", 10 );
|
|
for( i = 1; i < max_cars; i++ )
|
|
{
|
|
if( i == max_cars - 1 )
|
|
{
|
|
cars[i] = Spawn( "script_model", (0,-2000,-200) );
|
|
cars[i] SetModel( "p7_zur_metro_train_cab_module" );
|
|
cars[i].rotate180 = true;
|
|
}
|
|
else
|
|
{
|
|
cars[i] = Spawn( "script_model", (0,-2000,-200) );
|
|
cars[i] SetModel( "p7_zur_metro_train_car_module" );
|
|
}
|
|
cars[i] Ghost();
|
|
dividers[i] = Spawn( "script_model", (0,-2000,-200) );
|
|
dividers[i] SetModel( "p7_zur_metro_train_divider" );
|
|
dividers[i] Ghost();
|
|
}
|
|
}
|
|
|
|
function showAfterTime( time )
|
|
{
|
|
wait ( time ) ;
|
|
self Show();
|
|
}
|
|
|
|
|
|
function rotatePieces( gatePieceArray, waitTime, rotateTime, rotateAngles, startFromTop )
|
|
{
|
|
skip = startFromTop;
|
|
foreach( gatePiece in gatePieceArray )
|
|
{
|
|
if ( !skip )
|
|
{
|
|
gatePiece rotateTo( gatePiece.originalAngles + rotateAngles, rotateTime );
|
|
wait ( waitTime );
|
|
}
|
|
skip = !skip;
|
|
}
|
|
|
|
foreach( gatePiece in gatePieceArray )
|
|
{
|
|
if ( !skip )
|
|
{
|
|
gatePiece rotateTo( gatePiece.originalAngles + rotateAngles, rotateTime );
|
|
wait ( waitTime );
|
|
}
|
|
skip = !skip;
|
|
}
|
|
}
|
|
|
|
|
|
function train_think( cars, dividers, notifier, start, gate_a, gate_b, gate_end, security_barriers, gate_kill_trigger, gate_end_kill_trigger, train_speakers, trackside )
|
|
{
|
|
level endon ( "game_ended" );
|
|
|
|
foreach( gate in gate_a )
|
|
{
|
|
gate.originalAngles = gate.angles;
|
|
}
|
|
foreach( gate in gate_b )
|
|
{
|
|
gate.originalAngles = gate.angles;
|
|
}
|
|
foreach( gate in gate_end )
|
|
{
|
|
gate.originalAngles = gate.angles;
|
|
}
|
|
|
|
foreach( barrier in security_barriers )
|
|
{
|
|
barrier.originalOrigin = barrier.origin;
|
|
}
|
|
|
|
rotateDirection = ( 0, 90, 0 );
|
|
if ( trackside == "left" )
|
|
{
|
|
rotateDirection *= -1;
|
|
}
|
|
for ( ;; )
|
|
{
|
|
level waittill( notifier );
|
|
|
|
foreach( speaker in train_speakers )
|
|
{
|
|
PlaySoundAtPosition( "vox_metr_metro_approaching", speaker.origin );
|
|
}
|
|
|
|
metro_vox_wait_time = getdvarfloat( "metro_vox_wait_time", 4.0 );
|
|
wait( metro_vox_wait_time );
|
|
|
|
gate_move_time = getdvarfloat( "gate_move_time", 2.0 );
|
|
gate_end_move_time = getdvarfloat( "gate_end_move_time", 1.0 );
|
|
gate_piece_wait_time = getdvarfloat( "gate_wait_time", 0.3 );
|
|
|
|
gate_a[0] PlayLoopSound ( "amb_train_alarm" );
|
|
gate_b[0] PlayLoopSound ( "amb_train_alarm" );
|
|
|
|
barrier_move_time = getdvarfloat( "barrier_move_time", 2.0 );
|
|
barrier_move_height = getdvarfloat( "barrier_move_height", 30.0 );
|
|
foreach( barrier in security_barriers )
|
|
{
|
|
barrier moveto( barrier.origin + ( 0, 0 , barrier_move_height ), barrier_move_time );
|
|
barrier playsound ("evt_wall_up");
|
|
}
|
|
|
|
gate_wait_train_time = getdvarfloat( "gate_wait_train_time", 5.0 );
|
|
wait( gate_wait_train_time );
|
|
cars[0] AttachPath( start );
|
|
cars[0] StartPath();
|
|
cars[0] showAfterTime( 0.1 );
|
|
cars[0] thread record_positions(trackside);
|
|
cars[0] PlayLoopSound ( "amb_train_by" );
|
|
|
|
max_cars = getdvarint( "train_length", 10 );
|
|
for( i = 1; i < max_cars; i++ )
|
|
{
|
|
wait( .30 );
|
|
dividers[i] thread car_move(trackside);
|
|
dividers[i] thread watch_player_touch();
|
|
wait( .30 );
|
|
cars[i] thread car_move(trackside);
|
|
cars[i] thread watch_player_touch();
|
|
cars[i] PlayLoopSound ( "amb_train_by" );
|
|
}
|
|
foreach( speaker in train_speakers )
|
|
{
|
|
PlaySoundAtPosition( "vox_metr_metro_gap", speaker.origin );
|
|
}
|
|
level thread rotatePieces( gate_end, 1, gate_end_move_time, -rotateDirection, 0 );
|
|
gate_end[0] playsound ("evt_gate_open");
|
|
gate_end_kill_trigger security_door_close_think( false, 0, gate_end_move_time );
|
|
|
|
level thread rotatePieces( gate_a, gate_piece_wait_time, gate_move_time, rotateDirection, 0 );
|
|
gate_a[0] playsound ("evt_gate_open");
|
|
level thread rotatePieces( gate_b, gate_piece_wait_time, gate_move_time, rotateDirection, 1 );
|
|
gate_b[0] playsound ("evt_gate_open");
|
|
gate_kill_trigger security_door_close_think( true, 0, gate_move_time );
|
|
|
|
wait ( getdvarfloat( "gate_wait_close_door_end", 8.0 ) );
|
|
|
|
level thread rotatePieces( gate_end, 1, gate_move_time, (0,0,0), 0 );
|
|
gate_end[0] playsound ("evt_gate_close");
|
|
gate_end_kill_trigger security_door_close_think( false, 0, gate_move_time );
|
|
wait ( getdvarfloat( "gate_wait_close_doors", 4.0 ) );
|
|
|
|
level thread rotatePieces( gate_a, gate_piece_wait_time, gate_move_time, (0,0,0), 0 );
|
|
gate_a[0] playsound ("evt_gate_close");
|
|
level thread rotatePieces( gate_b, gate_piece_wait_time, gate_move_time, (0,0,0), 1 );
|
|
gate_b[0] playsound ("evt_gate_close");
|
|
|
|
gate_kill_trigger security_door_close_think( false, 0, gate_move_time );
|
|
gate_kill_trigger security_door_close_think( true, gate_move_time, 0.25 );
|
|
|
|
foreach( barrier in security_barriers )
|
|
{
|
|
barrier moveto(barrier.originalOrigin, barrier_move_time );
|
|
barrier playsound ("evt_wall_down");
|
|
}
|
|
|
|
gate_a[0] StopLoopSound ( 2 );
|
|
gate_b[0] StopLoopSound ( 2 );
|
|
|
|
cars[0] waittill( "reached_end_node" );
|
|
cars[0] StopLoopSound ( 2 );
|
|
for( i = 1; i < max_cars; i++ )
|
|
{
|
|
cars[i] ghost();
|
|
cars[i] notify( "stop_kill" );
|
|
dividers[i] ghost();
|
|
dividers[i] notify( "stop_kill" );
|
|
cars[i] StopLoopSound ( 2 );
|
|
}
|
|
cars[0] notify( "stop_kill" );
|
|
cars[0] ghost();
|
|
}
|
|
}
|
|
|
|
function record_positions( tracknum )
|
|
{
|
|
self endon( "reached_end_node" );
|
|
|
|
level.train_positions[tracknum] = [];
|
|
level.train_angles[tracknum] = [];
|
|
|
|
|
|
if ( tracknum == "left" )
|
|
{
|
|
train_position_start_water = getdvarint( "train_position_start_water_left", 205 );
|
|
train_dust_kickup_1 = getdvarint( "train_dust_kickup_1_left", 150 );
|
|
train_dust_kickup_2 = getdvarint( "train_dust_kickup_2_left", 174 );
|
|
train_dust_kickup_3 = getdvarint( "train_dust_kickup_3_left", 200 );
|
|
}
|
|
else
|
|
{
|
|
train_position_start_water = getdvarint( "train_position_start_water_right", 205 );
|
|
train_dust_kickup_1 = getdvarint( "train_dust_kickup_1_right", 150 );
|
|
train_dust_kickup_2 = getdvarint( "train_dust_kickup_1_right", 174 );
|
|
train_dust_kickup_3 = getdvarint( "train_dust_kickup_1_right", 200 );
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
if ( !isdefined( self ) )
|
|
return;
|
|
|
|
level.train_positions[tracknum][ level.train_positions[tracknum].size ] = self.origin;
|
|
level.train_angles[tracknum][ level.train_angles[tracknum].size ] = self.angles;
|
|
if ( level.train_angles[tracknum].size == train_position_start_water )
|
|
{
|
|
playfxontag( level._effect[ "fx_water_train_mist_kick_up_metro" ], self, "tag_origin" );
|
|
}
|
|
else if ( level.train_angles[tracknum].size == train_dust_kickup_1 )
|
|
{
|
|
level thread dust_kickup( 1, tracknum );
|
|
}
|
|
else if ( level.train_angles[tracknum].size == train_dust_kickup_2 )
|
|
{
|
|
level thread dust_kickup( 2, tracknum );
|
|
}
|
|
else if ( level.train_angles[tracknum].size == train_dust_kickup_3 )
|
|
{
|
|
level thread dust_kickup( 3, tracknum );
|
|
}
|
|
|
|
wait( 0.05 );
|
|
}
|
|
}
|
|
|
|
function dust_kickup( index, trackside )
|
|
{
|
|
exploderName = "Train_dust_kickup_" + index + "_" + trackside;
|
|
exploder::exploder( exploderName );
|
|
wait( 5.5 );
|
|
exploder::stop_exploder( exploderName );
|
|
}
|
|
|
|
function car_move( tracknum )
|
|
{
|
|
self endon( "stop_kill" );
|
|
if ( tracknum == "left" )
|
|
{
|
|
train_position_start_water = getdvarint( "train_position_start_water_left", 205 );
|
|
}
|
|
else
|
|
{
|
|
train_position_start_water = getdvarint( "train_position_start_water_right", 205 );
|
|
}
|
|
for( i = 0; i < level.train_positions[tracknum].size; i++ )
|
|
{
|
|
if ( i == train_position_start_water )
|
|
{
|
|
playfxontag( level._effect[ "fx_water_train_mist_kick_up_metro" ], self, "tag_origin" );
|
|
}
|
|
self.origin = level.train_positions[tracknum][ i ];
|
|
self.angles = level.train_angles[tracknum][ i ];
|
|
if ( isdefined( self.rotate180 ) && self.rotate180 == true )
|
|
{
|
|
self.angles += ( 0, 180, 0 );
|
|
}
|
|
|
|
wait( 0.05 );
|
|
if ( i == 4 )
|
|
{
|
|
self Show();
|
|
}
|
|
}
|
|
}
|
|
|
|
function watch_player_touch()
|
|
{
|
|
self endon( "end_of_track" );
|
|
self endon( "stop_kill" );
|
|
self endon( "delete" );
|
|
self endon( "death" );
|
|
self.disableFinalKillcam = true;
|
|
|
|
for(;;)
|
|
{
|
|
self waittill( "touch", entity );
|
|
if ( isplayer( entity ) )
|
|
{
|
|
entity DoDamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function train_setup_clock()
|
|
{
|
|
metro_clock_1 = getent("MP_Metro_clock_1", "targetname");
|
|
metro_clock_2 = getent("MP_Metro_clock_2", "targetname");
|
|
|
|
if ( !isdefined( metro_clock_1 ) || !isdefined( metro_clock_2 ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
level.clockModel1 = util::spawn_model( "tag_origin", metro_clock_1.origin, metro_clock_1.angles );
|
|
level.clockModel1 clientfield::set( "mp_metro_train_timer", 1 );
|
|
|
|
level.clockModel2 = util::spawn_model( "tag_origin", metro_clock_2.origin, metro_clock_2.angles );
|
|
level.clockModel2 clientfield::set( "mp_metro_train_timer", 1 );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function security_door_close_think( killPlayers, waittime, scantime )
|
|
{
|
|
self endon( "end_kill_trigger" );
|
|
self.disableFinalKillcam = true;
|
|
door = self;
|
|
corpse_delay = 0;
|
|
if ( waittime > 0 )
|
|
{
|
|
wait( waittime );
|
|
}
|
|
timescanned = 0;
|
|
while( scantime > timescanned )
|
|
{
|
|
// iprintlnbold("doing it" );
|
|
wait( 0.2 );
|
|
timescanned += 0.2;
|
|
entities = GetDamageableEntArray( self.origin, 200 );
|
|
|
|
foreach( entity in entities )
|
|
{
|
|
if ( !entity IsTouching( self ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( !IsAlive( entity ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( IsDefined( entity.targetname ) )
|
|
{
|
|
if ( entity.targetname == "talon" )
|
|
{
|
|
entity notify( "death" );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( entity.helitype ) && entity.helitype == "qrdrone" )
|
|
{
|
|
watcher = entity.owner weaponobjects::getWeaponObjectWatcher( "qrdrone" );
|
|
watcher thread weaponobjects::waitAndDetonate( entity, 0.0, undefined );
|
|
continue;
|
|
}
|
|
|
|
if ( entity.classname == "grenade" )
|
|
{
|
|
if( !IsDefined( entity.name ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( !IsDefined( entity.owner ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( entity.name == "proximity_grenade_mp" )
|
|
{
|
|
watcher = entity.owner weaponobjects::getWatcherForWeapon( entity.name );
|
|
watcher thread weaponobjects::waitAndDetonate( entity, 0.0, undefined, "script_mover_mp" );
|
|
continue;
|
|
}
|
|
|
|
if( !entity.isEquipment )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
watcher = entity.owner weaponobjects::getWatcherForWeapon( entity.name );
|
|
|
|
if( !IsDefined( watcher ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
watcher thread weaponobjects::waitAndDetonate( entity, 0.0, undefined, "script_mover_mp" );
|
|
continue;
|
|
}
|
|
|
|
if ( entity.classname == "auto_turret" )
|
|
{
|
|
if ( !IsDefined( entity.damagedToDeath ) || !entity.damagedToDeath )
|
|
{
|
|
entity util::DoMaxDamage( self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if( IsVehicle( entity ) && ( !isdefined( entity.team ) || entity.team != "neutral" ) ) // vehicles are immune from MOD_CRUSH
|
|
{
|
|
entity kill();
|
|
continue;
|
|
}
|
|
|
|
if( killPlayers == false && IsPlayer( entity ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
entity DoDamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" );
|
|
|
|
if( IsPlayer( entity ) )
|
|
{
|
|
corpse_delay = GetTime() + 1000;
|
|
}
|
|
}
|
|
|
|
self destroy_supply_crates();
|
|
|
|
if ( GetTime() > corpse_delay )
|
|
{
|
|
self destroy_corpses();
|
|
}
|
|
|
|
if ( level.gameType == "ctf" )
|
|
{
|
|
foreach( flag in level.flags )
|
|
{
|
|
if ( flag.visuals[0] IsTouching( self ) )
|
|
{
|
|
flag ctf::returnFlag();
|
|
}
|
|
}
|
|
}
|
|
else if ( level.gameType == "sd" && !level.multiBomb )
|
|
{
|
|
if ( level.sdBomb.visuals[0] IsTouching( self ) )
|
|
{
|
|
level.sdBomb gameobjects::return_home();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function destroy_supply_crates()
|
|
{
|
|
crates = GetEntArray( "care_package", "script_noteworthy" );
|
|
|
|
foreach( crate in crates )
|
|
{
|
|
if ( DistanceSquared( crate.origin, self.origin ) < 200 * 200 )
|
|
{
|
|
if( crate IsTouching( self ) )
|
|
{
|
|
PlayFX( level._supply_drop_explosion_fx, crate.origin );
|
|
PlaySoundAtPosition( "wpn_grenade_explode", crate.origin );
|
|
wait ( 0.1 );
|
|
crate supplydrop::crateDelete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function destroy_corpses()
|
|
{
|
|
corpses = GetCorpseArray();
|
|
|
|
for ( i = 0; i < corpses.size; i++ )
|
|
{
|
|
if ( DistanceSquared( corpses[i].origin, self.origin ) < 200 * 200 )
|
|
{
|
|
corpses[i] delete();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function get_closest( org, array )
|
|
{
|
|
dist = 9999999;
|
|
|
|
distsq = dist*dist;
|
|
if( array.size < 1 )
|
|
{
|
|
return;
|
|
}
|
|
index = undefined;
|
|
for( i = 0;i < array.size;i++ )
|
|
{
|
|
newdistsq = distancesquared( array[ i ].origin, org );
|
|
if( newdistsq >= distsq )
|
|
{
|
|
continue;
|
|
}
|
|
distsq = newdistsq;
|
|
index = i;
|
|
}
|
|
return array[index];
|
|
}
|
|
|
|
|
|
|
|
|