cod5-sdk/raw/maps/ber1_event1.gsc
2008-11-20 00:00:00 +00:00

3963 lines
81 KiB
Text

// scripting by Bloodlust
// level design by BSouds
#include maps\_anim;
#include maps\_utility;
#include maps\ber1_util;
#include maps\pel2_util;
#include common_scripts\utility;
#include maps\_music;
#using_animtree("generic_human");
// main function for handling Event 1
main()
{
train_ride();
}
train_ride()
{
//Kevin's notify for train sounds.
SetClientSysState("levelNotify","train_ride");
level thread trainride_vo();
level thread exit_train_pathing();
level thread populate_katyusha_crews();
//disable player weapons
players = get_players();
for( i = 0; i < players.size; i++ )
{
players[i] disableWeapons();
}
russians = getaiarray( "allies" );
russians = put_reznov_in_spot_8( russians );
for( i = 0; i < russians.size; i++ )
{
russians[i].animname = "russian_" + (i);
russians[i].ignoreall = true;
russians[i].ignoreme = true;
// to prevent clipping issue
if( russians[i].animname == "russian_10" )
{
russians[i] detach( russians[i].gearModel );
}
}
//TUEY set music state to INTRO
setmusicstate("INTRO");
boxcar = getEnt( "boxcar_intro", "targetname" );
boxcar.animname = "boxcar";
org = boxcar getTagOrigin( "tag_origin" );
boxcar thread maps\ber1_anim::close_traincar_door();
link_train_cars();
level thread unload_train_drones();
wait_network_frame();
event1_threads();
spawn_tanks();
players = get_players();
players[0] thread train_turbulence();
// Jesse: Changed the order of linkTo and the anim_single calls to prevent crazy flipping guys
for( i = 0; i < russians.size; i++ )
{
russians[i] linkTo( boxcar, "tag_origin" );
}
// Squad Anims for getting out of the train
/////////////////////////////
// delayed_guys = undefined;
for( i = 0; i < russians.size; i++ )
{
anime = "train_intro_" + i;
// russians[i] thread event1_unlink_at_animation_end( anime , boxcar );
// guys that have 3 anims to play (includes idle) to exit the train
if( i == 3 || i == 5 || i == 7 )
{
// delayed_guys = add_to_array( delayed_guys, russians[i] );
russians[i] thread train_exit_triple_anim( boxcar, i );
}
// guys that have 2 anims to play to exit the train
else
{
russians[i] thread train_exit_double_anim( boxcar );
// play their intro animations
// boxcar thread anim_single_solo_earlyout( russians[i], anime, "tag_origin", undefined, undefined, undefined, 0.25 );
}
}
players = get_Players();
link_players_to_train( boxcar, players );
boxcar thread move_train( boxcar );
// TRAIN IS STOPPED
/////////////////////
flag_wait( "train_has_stopped" );
wait( 6 );
unlink_players_from_train( players );
// level thread delayed_train_exit( boxcar, delayed_guys );
intro_barrage();
}
train_exit_double_anim( boxcar )
{
boxcar anim_single_solo( self, "train_intro", "tag_origin" );
self Unlink();
boxcar anim_single_solo_earlyout( self, "train_intro_exit", "tag_origin", undefined, undefined, undefined, 0.25 );
}
train_exit_triple_anim( boxcar, index )
{
boxcar anim_single_solo( self, "train_intro", "tag_origin" );
self Unlink();
// stagger the guys by having them play the same idle over again
if( index == 3 )
{
// self thread guzzo_print_3d( "wait guy 1" );
level thread anim_loop_solo( self, "train_intro_idle", "tag_origin", "end_train_idle_1", boxcar );
wait( 4 );
level notify( "end_train_idle_1" );
}
if( index == 5 )
{
// self thread guzzo_print_3d( "wait guy 2" );
level thread anim_loop_solo( self, "train_intro_idle", "tag_origin", "end_train_idle_2", boxcar );
wait( 4.5 );
level notify( "end_train_idle_2" );
}
if( index == 7 )
{
// self thread guzzo_print_3d( "wait guy 3" );
level thread anim_loop_solo( self, "train_intro_idle", "tag_origin", "end_train_idle_3", boxcar );
wait( 5 );
level notify( "end_train_idle_3" );
}
boxcar anim_single_solo_earlyout( self, "train_intro_exit", "tag_origin", undefined, undefined, undefined, 0.25 );
}
///////////////////
//
// handles guys that exit the train slightly later in order to avoid bunching up
//
///////////////////////////////
//delayed_train_exit( boxcar, guys )
//{
//
// boxcar anim_single( guys, "train_intro_idle", "tag_origin" );
//
//// wait( 4.85 );
//// boxcar thread anim_single_earlyout( guys_to_animate, "train_intro_delayed", "tag_origin", undefined, undefined, undefined, 0.25 );
//
//
// // get the guys that are meant to exit later
// for( i = 0; i < guys.size; i++ )
// {
//
// if( isdefined( guys_to_check[i].animname ) && ( guys_to_check[i].animname == "russian_3" ) )
// {
// boxcar thread anim_single_solo_earlyout( guys_to_check[i], "train_intro_delayed", "tag_origin", undefined, undefined, undefined, 0.25 );
// }
// else if( isdefined( guys_to_check[i].animname ) && ( guys_to_check[i].animname == "russian_5" ) )
// {
// wait( 1 );
// boxcar thread anim_single_solo_earlyout( guys_to_check[i], "train_intro_delayed", "tag_origin", undefined, undefined, undefined, 0.25 );
// }
// else if( isdefined( guys_to_check[i].animname ) && ( guys_to_check[i].animname == "russian_7" ) )
// {
// wait( 1 );
// boxcar thread anim_single_solo_earlyout( guys_to_check[i], "train_intro_delayed", "tag_origin", undefined, undefined, undefined, 0.25 );
// }
//
// }
//
//}
event1_unlink_at_animation_end( anime, boxcar )
{
anim_time = GetAnimLength( level.scr_anim[self.animname][anime] );
wait( anim_time - 0.25 );
// boxcar waittill( anime );
self Unlink();
}
link_players_to_train( boxcar, players )
{
// link players to their start points for the train ride
level.train_attach_points = [];
for( i = 0; i < 4; i++ )
{
level.train_attach_points[i] = getent( "player_train_start" + i, "targetname" );
level.train_attach_points[i] linkTo( boxcar );
}
for( i = 0; i < players.size; i++ )
{
players[i] setOrigin( level.train_attach_points[i].origin );
players[i] playerLinkTo( level.train_attach_points[i] );
}
level.players_linked_to_train = true;
}
unlink_players_from_train( players )
{
level.players_linked_to_train = false;
// unlink player and start points
for( i = 0; i < 4; i++ )
{
level.train_attach_points[i] unlink();
}
for(i = 0; i < players.size; i++)
{
players[i] unlink();
players[i] enableWeapons();
}
// delete player start points
for( i = 0; i < 4; i++ )
{
level.train_attach_points[i] delete();
}
}
populate_katyusha_crews()
{
// LEFT TRUCK
left_truck = getent( "katyusha_left_truck", "targetname" );
// driver
guy_1 = Spawn( "script_model", left_truck.origin );
guy_1 character\char_rus_r_rifle::main();
guy_1 UseAnimTree( #animtree );
guy_1.animname = "truck";
guy_1 detach( guy_1.hatModel );
guy_1 detach( guy_1.gearModel );
left_truck thread anim_loop_solo( guy_1, "driver_sit_idle", "tag_driver", "stop_temp_loop" );
// CENTER TRUCK
center_truck = getent( "katyusha_center_truck", "targetname" );
// // guy in back
// guy_2 = Spawn( "script_model", center_truck.origin );
// guy_2 character\char_rus_r_rifle::main();
// guy_2 UseAnimTree( #animtree );
// guy_2.animname = "truck";
// guy_2 detach( guy_2.hatModel );
// guy_2 detach( guy_2.gearModel );
//
// spot = getstruct( "orig_katyusha_back", "targetname" );
// center_truck thread anim_loop_solo( guy_2, "katyusha_idle_1", undefined, "stop_temp_loop", spot );
// driver
guy_3 = Spawn( "script_model", center_truck.origin );
guy_3 character\char_rus_r_rifle::main();
guy_3 UseAnimTree( #animtree );
guy_3.animname = "truck";
guy_3 detach( guy_3.hatModel );
guy_3 detach( guy_3.gearModel );
center_truck thread anim_loop_solo( guy_3, "driver_sit_idle", "tag_driver", "stop_temp_loop" );
// RIGHT TRUCK
right_truck = getent( "katyusha_right_truck", "targetname" );
// driver
guy_4 = Spawn( "script_model", right_truck.origin );
guy_4 character\char_rus_r_rifle::main();
guy_4 UseAnimTree( #animtree );
guy_4.animname = "truck";
guy_4 detach( guy_4.hatModel );
guy_4 detach( guy_4.gearModel );
right_truck thread anim_loop_solo( guy_4, "driver_sit_idle", "tag_driver", "stop_temp_loop" );
flag_wait( "office_door_kick_trigger" );
// TODO
// at some point, just delete these guys
guy_1 delete();
// guy_2 delete();
guy_3 delete();
guy_4 delete();
}
///////////////////
//
// put reznov in index 8 of the array, so he is in the correct position for the animation
//
///////////////////////////////
put_reznov_in_spot_8( ai_array )
{
// get reznov's index
for( i = 0; i < ai_array.size; i++ )
{
if( ai_array[i] == level.reznov )
{
break;
}
}
reznov_index = i;
// swap their places in the array (we can always assume the heros are in spots 0,1,2 in the array initially, as they're not spawners)
assertex( !is_in_array( level.heroes, ai_array[8] ), "a hero is in spot 8 of the allies array, not good!" );
ai_array[reznov_index] = ai_array[8];
ai_array[8] = level.reznov;
return ai_array;
}
exit_train_pathing()
{
allies = getaiarray( "allies" );
trig = getent( "exit_boxcar_trigger", "targetname" );
// println( "***" );
// println( "*** exit_train debug guys: " + allies.size );
for( i = 0; i < allies.size; i++ )
{
allies[i].disablearrivals = true;
allies[i].disableexits = true;
allies[i] thread exit_train_pathing_assign( trig );
}
}
exit_train_pathing_assign( trig )
{
while( 1 )
{
if( self istouching( trig ) )
{
self.exit_train_pathing_num = level.exit_train_pathing_num;
level.exit_train_pathing_num++;
self.goalradius = 20;
goal_node = getnode( "exit_train_pathing_" + self.exit_train_pathing_num, "targetname" );
self setgoalnode( goal_node );
self thread delay_exits_arrivals_on();
println( "***" );
println( "*** exit_train debug: " + self.exit_train_pathing_num );
break;
}
wait( 0.05 );
}
}
delay_exits_arrivals_on()
{
self endon( "death" );
wait( 3 );
self.disablearrivals = false;
self.disableexits = false;
}
berm_pathing()
{
allies = getaiarray( "allies" );
for( i = 0; i < allies.size; i++ )
{
if( isdefined( allies[i].exit_train_pathing_num ) )
{
goal_node = getnode( "berm_pathing_" + allies[i].exit_train_pathing_num, "targetname" );
allies[i] thread berm_pathing_think( goal_node );
}
}
}
berm_pathing_think( goal_node )
{
self endon( "death" );
if( self.exit_train_pathing_num > 3 && self.exit_train_pathing_num <= 7 )
{
wait( 0.9 );
}
else if( self.exit_train_pathing_num > 7 && self.exit_train_pathing_num <= 11 )
{
wait( 1.7 );
}
else if( self.exit_train_pathing_num > 11 && self.exit_train_pathing_num <= 15 )
{
wait( 2.6 );
}
if( isdefined( self.node ) && isdefined( self.node.script_delay ) )
{
wait( self.node.script_delay );
}
self.goalradius = 20;
self setgoalnode( goal_node );
self waittill( "goal" );
if( isdefined( goal_node.script_delay ) )
{
wait( goal_node.script_delay );
}
new_goal = getnode( "ruins_pathing_" + self.exit_train_pathing_num, "targetname" );
self setgoalnode( new_goal );
if( !isdefined( self.script_no_respawn ) )
{
self thread replace_on_death();
}
if( self == level.chernov || self == level.reznov || self == level.commissar )
{
self set_force_color( "c" );
}
else
{
if( self.exit_train_pathing_num < 8 )
{
self set_force_color( "r" );
}
else
{
self set_force_color( "y" );
}
}
}
trainride_vo()
{
battlechatter_off();
wait( 6.25 );
play_vo( level.reznov, "russian_0", "on_your_feet" );
wait( 7 );
play_vo( level.chernov, "russian_0", "fuhrers_bday" );
wait( 7.9 );
play_vo( level.chernov, "russian_0", "with_your_bullets" );
wait( 3 );
play_vo( level.chernov, "russian_0", "do_the_same" );
wait( 3 );
}
berm_vo()
{
level endon( "move_tank_3_2" );
wait( 1 );
play_vo( level.reznov, "vo", "charge!!!" );
wait( RandomIntRange( 7, 9 ) );
play_vo( level.reznov, "vo", "keep_moving" );
battlechatter_on();
}
ruins_vo()
{
level endon( "start_clocktower_vo" );
flag_wait( "move_tank_3_2" );
play_vo( level.commissar, "vo", "move_up_tanks" );
wait( 3 );
play_vo( level.reznov, "vo", "use_for_cover" );
if(NumRemoteClients()) // Clear up space in the snapshot for coop by doing bad things to our allies.
{
allies = getaiarray( "allies" );
for(i = 0; i < allies.size; i ++)
{
if(!is_in_array( level.heroes, allies[i] ))
{
allies[i] disable_replace_on_death();
allies[i] thread bloody_death( true, 12 + RandomFloat(31) ); // Poor red Squad, they never stood a chance in coop.
}
}
}
// wait till the battle kicks off
flag_wait( "ruins_battle_2" );
play_vo( level.reznov, "vo", "the_rats" );
wait( 2.2 );
play_vo( level.reznov, "vo", "clear_every" );
wait( 2.2 );
play_vo( level.reznov, "vo", "more_upper_floor" );
// wait till the retreat
flag_wait( "ruins_retreat_trig" );
play_vo( level.chernov, "vo", "they_are_running" );
wait( 2.4 );
play_vo( level.reznov, "vo", "of_course" );
wait( 4 );
play_vo( level.reznov, "vo", "wipe_them_out" );
}
clocktower_vo()
{
level notify( "start_clocktower_vo" );
play_vo( level.chernov, "vo", "setup_defenses" );
wait( 3.75 );
play_vo( level.reznov, "vo", "mg!!!" );
wait( randomfloatrange( 1.5, 2.4 ) );
play_vo( level.reznov, "vo", "stay_in_cover" );
wait( randomfloatrange( 3.0, 3.75 ) );
play_vo( level.reznov, "vo", "panzerschrek!" );
wait( randomfloatrange( 2.0, 3.5 ) );
// only play if player is not on the 2nd floor already
players = get_players();
if( isdefined( players[0] ) && players[0].origin[2] > -260 )
{
play_vo( level.reznov, "vo", "find_a_better" );
wait( 2 );
}
level thread clocktower_2_vo();
}
clocktower_2_vo()
{
weakening_vo_played = false;
last_chosen_index = undefined;
while( !flag( "move_tanks_3" ) )
{
skipping_wait = false;
if( !weakening_vo_played )
{
schreks_and_mgs_count = get_ai_group_count( "tank_suppressor_ai" ) + get_ai_group_count( "office_mgs" );
if( schreks_and_mgs_count <= 2 )
{
play_vo( level.reznov, "vo", "they_are_weakening" );
weakening_vo_played = true;
wait( randomfloatrange( 5.5, 7.0 ) );
}
}
vo_index = randomint( 11 );
// make sure we don't play the same line twice in a row
if( isdefined( last_chosen_index ) )
{
while( last_chosen_index == vo_index )
{
vo_index = randomint( 11 );
wait( 0.05 );
}
}
switch( vo_index )
{
case 0:
// only play this if some have been killed
schreks_and_mgs_count = get_ai_group_count( "tank_suppressor_ai" ) + get_ai_group_count( "office_mgs" );
if( schreks_and_mgs_count < 3 )
{
play_vo( level.reznov, "vo", "they_are_still_holding" );
skipping_wait = true;
wait( 0.05 );
}
break;
case 1:
play_vo( level.reznov, "vo", "destroy_every_last" );
break;
case 2:
// only play this if there are p-schreks remaining
schreks_count = get_ai_group_ai( "tank_suppressor_ai" );
if( schreks_count.size )
{
play_vo( level.reznov, "vo", "watch_for_panzers" );
}
else
{
skipping_wait = true;
wait( 0.05 );
}
break;
case 3:
play_vo( level.reznov, "vo", "break_their_line" );
break;
case 4:
play_vo( level.reznov, "vo", "concentrate_fire" );
break;
case 5:
play_vo( level.reznov, "vo", "finish_them" );
break;
case 6:
play_vo( level.reznov, "vo", "keep_fire_on" );
break;
case 7:
// only play this if there are p-schreks remaining
schreks_count = get_ai_group_ai( "tank_suppressor_ai" );
if( schreks_count.size )
{
play_vo( level.reznov, "vo", "panzerschrek!" );
}
else
{
skipping_wait = true;
wait( 0.05 );
}
break;
case 8:
play_vo( level.reznov, "vo", "quickly_dimitri" );
break;
case 9:
play_vo( level.reznov, "vo", "fire_again" );
break;
case 10:
play_vo( level.reznov, "vo", "take_it_out" );
break;
} // end switch
last_chosen_index = vo_index;
if( !skipping_wait )
{
wait( randomfloatrange( 9, 14.0 ) );
}
} // end while
}
wall_crumble_vo()
{
play_vo( level.chernov, "vo", "how_are_we_to" );
wait( 3 );
play_vo( level.chernov, "vo", "brute_force" );
}
spawn_tanks()
{
maps\_vehicle::create_vehicle_from_spawngroup_and_gopath( 0 );
flag_set( "spawn_tanks" );
}
intro_barrage()
{
// no need waving on an empty boxcar...
level.waver1 notify( "stop_whistle" );
// flag set on trigger
flag_wait( "katyusha_wait" );
flag_set( "calling_intro_barrage" );
quick_text( "katyusha_barrage", 3, true );
level thread intro_barrage_quake();
// time the aftermath with the rockets hitting the ground, plus a little bit of time
wait( 4 );
org = getStruct( "aftermath_origin", "targetname" );
playfx( level._effect["barrage_aftermath"], org.origin );
flag_wait( "intro_barrage_complete" );
level thread berm_vo();
blocker = getent( "brush_barrage_blocker", "targetname" );
blocker connectpaths();
blocker delete();
autosave_by_name( "Ber1 ruins start" );
//Tuey Set music state to First Fight
setmusicstate("FIRST_FIGHT");
flag_set( "ruins_charge" );
flag_set( "objective_ruins" );
flag_set( "move_tanks_1" );
level thread ruins_vo();
// reset drone run speed
level.drone_run_speed = 120;
level.waver1 playsound( "sgt_yell" );
wait( 2 );
berm_pathing();
level thread spawn_ruins_pickup_weapons();
level thread reset_squad_ignore_state();
}
intro_barrage_quake()
{
wait( 1.9 );
PlayRumbleOnPosition( "ber1_barrage", (-101, -5393, -502.3) );
wait( 1.9 );
earthquake( 0.5, 2.5, (-101, -5393, -502.3), 1000 );
}
ruins_battle()
{
level thread shutter_open_init();
level thread rejoin_squad();
level thread rejoin_squad_2();
level thread save_mid_ruins();
// flag set on trigger
flag_wait( "ruins_battle_start" );
quick_text( "ruins_battle_start" );
maps\_debug::set_event_printname( "Ruins" );
// Wii optimizations
if( !level.wii && !NumRemoteClients())
{
simple_spawn( "ruins_retreaters_initial" );
}
wait( 1.5 );
simple_floodspawn( "ruins_retreaters_right" );
wait_network_frame(); // CLIENTSIDE to help snapshot size
simple_floodspawn( "ruins_retreaters_left" );
wait_network_frame(); // CLIENTSIDE to help snapshot size
// Wii optimizations
if( !level.wii && !NumRemoteClients())
{
simple_spawn( "ruins_retreaters_center" );
}
// Wii optimizations
if( level.wii )
{
thin_out_ruins_allies_for_wii( 2 );
}
// flag set on trigger
flag_wait( "ruins_battle_2" );
quick_text( "ruins_battle_2" );
set_color_chain( "colortrig_r2" );
ruins_battle_2();
}
ruins_battle_2()
{
level thread trig_clocktower_vo();
wait( 1 );
// Wii optimizations
if( level.wii )
{
thin_out_ruins_allies_for_wii( 2 );
}
simple_floodspawn( "ruins_house_guys" );
wait_network_frame(); // CLIENTSIDE to help snapshot size
// SetIgnoreMeGroup( "players", "panzershreck_threat" );
// Wii optimizations
if( !level.wii )
{
simple_floodspawn( "office_gunners", ::ruins_gunners_strat );
}
else
{
level thread wii_wait_to_spawn_clock_gunners();
}
// kick off next wave if most house guys have been killed
level thread ruins_retreat_trig_early();
// flag set on trigger
flag_wait( "ruins_retreat_trig" );
level thread ruins_retreat_reaction();
autosave_by_name( "Ber1 ruins retreat" );
simple_floodspawn( "office_defend_spawners" );
objective_string( 2, &"BER1_CLEAR_CLOCKTOWER" );
objective_position( 2, (944, -368, -229.6) );
clock_tower_battle();
}
wii_wait_to_spawn_clock_gunners()
{
flag_wait( "ruins_retreat_trig" );
simple_floodspawn( "office_gunners", ::ruins_gunners_strat );
}
thin_out_ruins_allies_for_wii( guys_to_kill )
{
guys_thinned_out = 0;
allies = getaiarray( "allies" );
for( i = 0; i < allies.size; i++ )
{
if( isdefined( allies[i].script_no_respawn ) )
{
println( "wii script optimization: about to kill off guy at: " + allies[i].origin );
allies[i] thread bloody_death( true );
guys_thinned_out++;
if( guys_thinned_out == guys_to_kill )
{
break;
}
}
}
}
trig_clocktower_vo()
{
trigger_wait( "trig_clocktower_vo", "script_noteworthy" );
clocktower_vo();
}
///////////////////
//
// have guys fallback, killspawn floodspawners, and send up friendlies
//
///////////////////////////////
ruins_retreat_reaction()
{
// killspawner
trig = getent( "trig_killspawner_100", "targetname" );
if( isdefined( trig ) )
{
trig notify( "trigger" );
}
// notify comes from script_notify on color chain trigger further past the buildings
level endon( "trig_chain_ruins_end" );
// only move up guys if enough of the building axis have been killed (if the player moves far ahead enough though the squad will move up)
while( 1 )
{
left_ai = get_ai_group_count( "ruins_retreaters_left_ai" );
right_ai = get_ai_group_count( "ruins_retreaters_right_ai" );
top_ai = get_ai_group_count( "ruins_house_ai" );
total_ai_count = left_ai + right_ai + top_ai;
if( total_ai_count < 6 )
{
break;
}
wait( 0.75 );
}
// fallback guys
trig = getent( "trig_fallback_100", "targetname" );
trig notify( "trigger" );
trig = getent( "trig_fallback_101", "targetname" );
trig notify( "trigger" );
//give fallbackers a bit of a headstart before moving up friendlies
wait( RandomFloatRange( 0.75, 1.5 ) );
// color chain
trig = getent( "colortrig_r3", "targetname" );
if( isdefined( trig ) )
{
trig notify( "trigger" );
}
}
///////////////////
//
// Handles the clock tower battle and when it's over
//
///////////////////////////////
clock_tower_battle()
{
setup_clock_mgs();
level thread office_panzers_target_tanks();
level thread clock_tower_exploders();
level thread tank_shreck_ricochet();
level thread office_mgs_threatbias();
blocker = getent( "blocker_clock_tank_2", "targetname" );
blocker notsolid();
blocker connectpaths();
num_regular_guys_to_kill = undefined;
// Wii optimizations
if( level.wii )
{
wait( 1 ); // should wait a bit b/c on the wii the gunners are spawned on the preceding frame
num_regular_guys_to_kill = 4; // wii has less spawners here, so adjust accordingly
}
else
{
num_regular_guys_to_kill = 7;
}
while( 1 )
{
clock_ai = get_ai_group_count( "office_guys" );
schreks_and_mgs_count = get_ai_group_count( "tank_suppressor_ai" ) + get_ai_group_count( "office_mgs" );
if( clock_ai < num_regular_guys_to_kill || !schreks_and_mgs_count )
{
break;
}
wait( 0.5 );
}
quick_text( "moving tank up to shoot clocktower!" );
level thread chain_closer_to_clock_tower();
flag_set( "move_tanks_3" );
level thread office_guys_retreat_inside();
flag_wait( "office_wall_done" );
office_building();
}
///////////////////
//
// handles walls that explode
//
///////////////////////////////
clock_tower_exploders()
{
level thread clock_tower_exploder_110();
level thread clock_tower_exploder_111();
level thread clock_tower_exploder_112();
level thread clock_tower_exploder_113();
}
///////////////////
//
// make sure clocktower mg guys don't jump off the mgs
//
///////////////////////////////
setup_clock_mgs()
{
mg = getent( "office_mg_door", "script_noteworthy" );
mg setturretignoregoals( true );
mg = getent( "ruins_mg", "script_noteworthy" );
mg setturretignoregoals( true );
}
clock_tower_exploder_110()
{
// notify from flag on trigger
level endon( "tank_go_through_wall" );
dmg_trigger = getent( "exploder_110", "targetname" );
dmg_trigger waittill( "trigger" );
mg_sandbag_cleanup( "auto1955", 103 );
dmg_trigger delete();
}
clock_tower_exploder_111()
{
// notify from flag on trigger
level endon( "tank_go_through_wall" );
dmg_trigger = getent( "exploder_111", "targetname" );
dmg_trigger waittill( "trigger" );
radiusdamage( (991.2, -755.2, -51.5), 120, 130, 80 );
dmg_trigger delete();
}
clock_tower_exploder_112()
{
// notify from flag on trigger
level endon( "tank_go_through_wall" );
dmg_trigger = getent( "exploder_112", "targetname" );
dmg_trigger waittill( "trigger" );
radiusdamage( (987.2, -757.2, 67.5), 120, 130, 80 );
dmg_trigger delete();
}
clock_tower_exploder_113()
{
// notify from flag on trigger
level endon( "tank_go_through_wall" );
dmg_trigger = getent( "exploder_113", "targetname" );
dmg_trigger waittill( "trigger" );
mg_sandbag_cleanup( "office_shelf_mg", 104 );
dmg_trigger delete();
}
office_panzers_target_tanks()
{
wait( randomintrange( 3, 5 ) );
// get the origins moving so the guys appear to fire at new locations every time
shrek_target = getent( "orig_office_panzers_targets_1", "targetname" );
shrek_target.health = 1000000;
level thread flame_move_target( shrek_target, 6 );
shrek_target = getent( "orig_office_panzers_targets_2", "targetname" );
shrek_target.health = 1000000;
level thread flame_move_target( shrek_target, 6 );
shrek_target = getent( "orig_office_panzers_targets_3", "targetname" );
shrek_target.health = 1000000;
level thread flame_move_target( shrek_target, 6 );
simple_spawn( "tank_suppressor_spawner", ::tank_suppressor_spawner_strat );
flag_wait( "move_tanks_3" );
guys = get_ai_group_ai( "tank_suppressor_ai" );
for( i = 0; i < guys.size; i++ )
{
guys[i] ClearEntityTarget();
if( guys[i].script_noteworthy == "orig_office_panzers_targets_1" )
{
goal = getnode( "orig_office_panzers_targets_1", "targetname" );
}
else
{
goal = getnode( "orig_office_panzers_targets_2", "targetname" );
}
guys[i] thread guy_run_to_node_and_delete( goal );
}
}
tank_suppressor_spawner_strat()
{
self endon( "death" );
level endon( "move_tanks_3" );
//self thread tank_suppressor_spawner_death();
self.ignoreme = true;
self.ignoresuppression = true;
self.a.rockets = 100;
target = getent( self.script_noteworthy, "targetname" );
while( 1 )
{
wait( RandomFloatRange( 1, 2.5 ) );
self SetEntityTarget( target );
wait( RandomIntRange( 5, 8 ) );
self ClearEntityTarget();
}
}
///////////////////
//
// keeps track of how many of these guys were killed
//
///////////////////////////////
//tank_suppressor_spawner_death()
//{
// self waittill( "death" );
//}
guy_run_to_node_and_delete( node )
{
self endon( "death" );
self setgoalnode( node );
self waittill( "goal" );
self delete();
}
///////////////////
//
// move color chain closer to clocktower
//
///////////////////////////////
chain_closer_to_clock_tower()
{
wait( RandomIntRange( 4, 6 ) );
set_color_chain( "chain_closer_to_clock_tower" );
}
///////////////////
//
// have the guys outside of the office building retreat inside when the tanks move up
//
///////////////////////////////
office_guys_retreat_inside()
{
//TUEY SET MUSIC STATE TO TANK_ROLLS_IN
setmusicstate("TANK_ROLLS_IN");
// turn off spawners
maps\_spawner::kill_spawnernum( 101 );
maps\_spawner::kill_spawnernum( 104 );
retreat_nodes = getnodearray( "node_office_retreat", "targetname" );
guys_in_volume = getAIarrayTouchingVolume( "axis", "vol_office_outside" );
quick_text( "retreating " + guys_in_volume.size + " guys to office" );
for( i = 0; i < guys_in_volume.size; i++ )
{
// in case there are more retreat guys than nodes...
if( !isdefined( retreat_nodes[i] ) )
{
break;
}
guys_in_volume[i].goalradius = 30;
guys_in_volume[i].ignoresuppression = true;
guys_in_volume[i] setgoalnode( retreat_nodes[i] );
}
getent( "vol_office_outside", "targetname" ) delete();
// failsafe for this guy
panzer_killer = get_specific_single_ai( "office_panzer_killer_ai" );
if( isdefined( panzer_killer ) )
{
panzer_killer setcandamage( true );
}
}
///////////////////
//
// kick off next wave if most house guys have been killed
//
///////////////////////////////
ruins_retreat_trig_early()
{
while( 1 )
{
left_ai = get_ai_group_count( "ruins_retreaters_left_ai" );
right_ai = get_ai_group_count( "ruins_retreaters_right_ai" );
top_ai = get_ai_group_count( "ruins_house_ai" );
total_ai_count = left_ai + right_ai + top_ai;
if( total_ai_count < 5 )
{
quick_text( "ruins_retreat_trig_early!" );
break;
}
wait( 0.75 );
}
trig = getent( "ruins_retreat_trig", "script_noteworthy" );
if( isdefined( trig ) )
{
trig notify( "trigger" );
}
}
ruins_gunners_strat()
{
level endon( "start_office_building" );
self setthreatbiasgroup( "office_gunner_threat" );
self waittill( "death" );
wait( randomfloatrange( 0.25, 0.9 ) );
if( !level.playing_reznov_yes_vo )
{
level.playing_reznov_yes_vo = true;
play_vo( level.reznov, "vo", "yes!!!" );
wait( 2 );
level.playing_reznov_yes_vo = false;
}
}
///////////////////
//
// used for ruins skipto only
//
///////////////////////////////
ruins_split_color_squads()
{
allies = getaiarray( "allies" );
for (i = 0; i < allies.size; i++)
{
allies[i] thread replace_on_death();
// if is an even number of the array
if ( i % 2 == 0 )
{
allies[i] set_force_color("y");
}
else // odd
{
allies[i] set_force_color("r");
}
}
set_color_heroes( "c" );
}
///////////////////
//
// sets up shutters that open
//
///////////////////////////////
shutter_open_init()
{
shutter_pair_1 = [];
shutter_pair_1[0] = getent( "l_shutter3", "script_noteworthy" );
shutter_pair_1[1] = getent( "r_shutter3", "script_noteworthy" );
level thread shutterpair_open_watch( shutter_pair_1 );
shutter_pair_3 = [];
shutter_pair_3[0] = getent( "l_shutter1", "script_noteworthy" );
shutter_pair_3[1] = getent( "r_shutter1", "script_noteworthy" );
level thread shutterpair_open_watch( shutter_pair_3 );
}
///////////////////
//
// this opens the shutter when AI are nearby
//
///////////////////////////////
shutterpair_open_watch( shutterpair )
{
while( 1 )
{
axis = getaiarray( "axis" );
for (i = 0; i < axis.size; i++)
{
if ( distancesquared(axis[i].origin, shutterpair[0].origin) < 70 * 70 )
{
shutterpair_open( shutterpair );
return;
}
else if ( distancesquared(axis[i].origin, shutterpair[1].origin) < 70 * 70 )
{
shutterpair_open( shutterpair );
return;
}
}
wait( 0.2 );
}
}
// actually open the shutters
shutterpair_open( shutterpair )
{
// get the origin that points to the shutter
shutterpair[0].linker = getent( shutterpair[0].targetname, "target" );
shutterpair[1].linker = getent( shutterpair[1].targetname, "target" );
// link to the point
shutterpair[0] linkto ( shutterpair[0].linker );
shutterpair[1] linkto ( shutterpair[1].linker );
wait( randomfloatrange( 0.1, 1.25 ) );
level thread shutterpair_move( shutterpair );
}
// sometime the left one will open first, sometimes the second
shutterpair_move( shutterpair )
{
if( randomint( 2 ) )
{
shutterpair_move_bounce( shutterpair[0].linker, randomfloatrange(165, 170) * (-1), randomfloatrange(0.4, 0.6) );
shutterpair[0] playsound( "window_shutter" );
wait ( randomfloatrange(0.1, 0.3) );
shutterpair_move_bounce( shutterpair[1].linker, randomfloatrange(165, 170), randomfloatrange(0.4, 0.6) );
shutterpair[1] playsound( "window_shutter" );
}
else
{
shutterpair_move_bounce( shutterpair[1].linker, randomfloatrange(165, 170), randomfloatrange(0.4, 0.6) );
shutterpair[1] playsound( "window_shutter" );
wait( randomfloatrange(0.1, 0.3) );
shutterpair_move_bounce( shutterpair[0].linker, randomfloatrange(165, 170) * (-1), randomfloatrange(0.4, 0.6) );
shutterpair[0] playsound( "window_shutter" );
}
}
// this actually opens them then bouces them against the wall a bit
shutterpair_move_bounce( obj, yaw, time )
{
obj rotateyaw( yaw, time );
obj waittill ( "rotatedone" );
if ( yaw > 0 )
{
obj rotateyaw( randomfloatrange(3, 10) * (-1), time * 10 );
}
else
{
obj rotateyaw( randomfloatrange(3, 10), time * 10 );
}
}
// link all the train cars together to be moved
link_train_cars()
{
boxcar = getEnt( "boxcar_intro", "targetname" );
traincars = getEntArray( "intro_traincar", "script_noteworthy" );
for( i = 0; i < traincars.size; i++ )
{
traincars[i] linkTo( boxcar, "tag_origin" );
}
// lightfx_points = getEntArray( "boxcar_light_fx", "targetname" );
// for(i = 0; i < lightfx_points.size; i++)
// {
// lightfx_points[i] linkTo( boxcar, "tag_origin" );
// lightfx_points[i] thread do_boxcar_sun_rays();
// wait_network_frame();
// }
smoketrail_points = getEntArray( "boxcar_smoke_fx", "targetname" );
for(i = 0; i < smoketrail_points.size; i++)
{
smoketrail_points[i] linkTo( boxcar, "tag_origin" );
smoketrail_points[i] thread do_boxcar_smoketrail_fx();
wait_network_frame();
}
}
//// play sunbeam fx inside the boxcar
//do_boxcar_sun_rays()
//{
// fxmodel = spawn( "script_model", self.origin ); // spawn a script model
// fxmodel setmodel ( "tag_origin" ); // set it to "tag_origin" which is a model with just a "tag_origin" tag
// fxmodel linkTo ( self ); // link it to the parent enitiy which should move with the train
//
// // play fx on tag should move the fx with the model, and when the ent is deleted, the fx will go away with it
// while( 1 )
// {
// playFXontag( level._effect["train_sun_rays"], fxmodel, "tag_origin" );
// wait( 0.5 );
//
// }
//
// // instead of ending the thread with this notify, we'll wait until this notify then delete the model
// flag_wait( "calling_intro_barrage" );
//
// fxmodel delete();
// self delete();
//}
// fake a smoke trail on the train
do_boxcar_smoketrail_fx()
{
while( !flag( "train_door_opened") )
{
playFX( level._effect["train_smoke_trail_fx"], self.origin );
wait( 0.3 );
}
wait( 1 );
self delete();
}
// move the train for the intro rail
// self = the boxcar the players start in
move_train( boxcar )
{
// TEMP OFF
//players = get_players();
//array_thread( players, ::player_jolt_view );
PlayRumbleOnPosition( "ber1_train", boxcar.origin );
level thread player_shake_view();
dest = getStruct( "train_stop", "targetname" );
self moveto( dest.origin, 11.5, 0, 5 );
while( self.origin != dest.origin )
{
wait( 0.1 );
}
flag_set( "train_has_stopped" );
}
player_shake_view()
{
level waittill ( "train slowing" );
host = get_players()[0];
earthquake(0.5, 2.5, host.origin, 4000);
wait( 1 );
earthquake(0.4, 2.5, host.origin, 4000);
wait( 1 );
earthquake(0.3, 2.5, host.origin, 4000);
wait( 1 );
earthquake(0.2, 2.5, host.origin, 4000);
wait( 1 );
earthquake(0.1, 2.5, host.origin, 4000);
}
player_jolt_view()
{
level waittill ("train slowing");
self endon ("death");
self endon ("disconnect");
org = spawn ("script_origin", self.origin);
//org.angles = self.angles;
//org linkto (self);
self playerSetGroundReferenceEnt( org );
org rotatepitch(-25, 1.0, 0.2);
org waittill ("rotatedone");
wait 2.75;
org rotatepitch(25, 2, 1.5);
org waittill ("rotatedone");
self playerSetGroundReferenceEnt( undefined );
}
///////////////////
//
// shake the player's camera
//
///////////////////////////////
train_turbulence()
{
level endon( "train_has_stopped" );
while( 1 )
{
scale = 0.1;
source = self getOrigin();
duration = ( (randomfloat(1) * 0.75) + 0.05 );
radius = 1500;
earthquake( scale, duration, source, radius );
wait( duration );
}
}
event1_threads()
{
level thread katyushas();
level thread train_wavers();
level thread intro_house_collapse();
level thread move_tanks();
level thread ruins_battle();
}
katyusha_trucks()
{
level thread katyusha_intro_trucks();
level thread katyusha_intro_truck_left_trigger();
level thread katyusha_intro_truck_center_trigger();
level thread rear_katyushas();
}
///////////////////
//
// fire rockets from the trucks behind the train as it comes to a stop
//
///////////////////////////////
rear_katyushas()
{
trigger_wait( "fire_rear_katyushas", "targetname" );
for( i = 0; i < 5; i++ )
{
level thread fire_katyusha_rockets( 6, "katyusha_distant", true, false );
wait( randomfloatrange( 0.5, 1 ) );
}
}
///////////////////
//
// handles the Katyusha rockets throughout the level
//
///////////////////////////////
katyushas()
{
thread katyusha_monitor();
level thread katyusha_trucks();
wait_network_frame();
level thread ambient_rockets( "katyusha_distant", "train_door_opened", true, true );
level thread ambient_rockets( "katyusha_close", "calling_intro_barrage", true, true );
flag_wait( "katyusha_wait" );
//client notify for Kevins audio
SetClientSysState("levelNotify","fake_battle_done");
for(i = 0; i < 8; i++)
{
level thread fire_katyusha_rockets( 8, "katyusha_barrage", true, true, 1500 );
}
wait( 5 );
flag_set( "intro_barrage_complete" );
level thread ambient_rockets( "katyusha_random", "surrender_begin", true, true );
}
// fire rockets from the Katyusha trucks in front of the train
katyusha_intro_trucks()
{
level thread katyusha_trucks_fire( "fire_left_truck_rockets", "katyusha_left_truck", 2000, 210 );
wait_network_frame();
level thread katyusha_trucks_fire( "fire_center_truck_rockets", "katyusha_center_truck", 2250, 135 );
wait_network_frame();
level thread katyusha_trucks_fire( "fire_right_truck_rockets", "katyusha_right_truck", 2200, 210 );
}
// forward left hand side Katyusha truck
katyusha_intro_truck_left_trigger()
{
trigger_wait( "katyusha_left_trigger", "targetname" );
level notify( "fire_left_truck_rockets" );
}
// forward center Katyusha truck (the one on the road)
// and the forward right side truck
katyusha_intro_truck_center_trigger()
{
trigger_wait( "exit_boxcar_trigger", "targetname" );
level notify( "fire_center_truck_rockets" );
wait( randomfloatrange( 1.5, 2.5 ) );
level notify( "fire_right_truck_rockets" );
}
// setup the forward Katyusha trucks and rockets then fire them
// catenary is the flatness of the rockets trajectory
// z_moveto_offset is helps determine how to move them along the truck's platform
katyusha_trucks_fire( notice, truck_name, catenary, z_moveto_offset )
{
truck = getEnt( truck_name, "targetname" );
truck_rockets = [];
tag = undefined;
tag_pos = undefined;
tag_angles = undefined;
rocket = undefined;
numRockets = 16;
if(NumRemoteClients())
{
numRockets = 8;
}
for(i = 0; i < numRockets; i++)
{
if(i <= 9)
{
tag = "tag_rocket0" + i;
tag_pos = truck getTagOrigin(tag);
tag_angles = truck getTagAngles(tag);
}
else
{
tag = "tag_rocket" + i;
tag_pos = truck getTagOrigin(tag);
tag_angles = truck getTagAngles(tag);
}
if( isDefined( tag_pos ) )
{
while(!rocket_ok())
{
wait_network_frame();
}
rocket = spawn("script_model", tag_pos);
level._numRockets ++;
rocket.angles = ( tag_angles );
rocket setmodel("katyusha_rocket");
truck_rockets[truck_rockets.size] = rocket;
}
}
targets = getStructArray(truck_name + "_targets", "targetname");
target = targets[randomInt(targets.size)];
close_targets = [];
for(i = 0; i < targets.size; i++)
{
dist = distancesquared(target.origin, targets[i].origin);
if(dist <= 512*512)
{
close_targets[close_targets.size] = targets[i];
}
}
level waittill(notice);
for(i = 0; i < truck_rockets.size; i++)
{
target_pos = close_targets[randomInt(close_targets.size)];
truck_rockets[i] thread fire_intro_truck_rockets( target_pos, truck, tag_pos, catenary, z_moveto_offset );
}
}
// move the rocket and play the fx
//self = the rocket
fire_intro_truck_rockets( target_pos, truck, tag_pos, catenary, z_moveto_offset )
{
wait( randomfloatrange( 1, 3 ) );
self thread fire_rocket( target_pos.origin, tag_pos, true, catenary, z_moveto_offset );
self playsound( "katyusha_launch_rocket" );
playFxOnTag( level._effect["rocket_launch"], self, "tag_fx" );
wait( 0.1 );
//**self playloopsound( "katy_rocket_run" );
playFxOnTag( level._effect["rocket_trail"], self, "tag_fx" );
}
// make the left side house collapse
intro_house_collapse()
{
org_node = getNode( "introhouse_animnode", "targetname" );
pieces = getEntArray( "introhouse_chunk", "targetname" );
fx_org = getStruct( "introhouse_fx", "targetname" );
flag_wait( "calling_intro_barrage" );
wait( 4.25 );
structs = getStructArray( "katyusha_introhouse", "targetname" );
for( i = 0; i < structs.size; i++ )
{
playFX( level._effect["rocket_explode"], structs[i].origin );
playSoundAtPosition( "shell_explode_default", structs[i].origin );
}
wait( randomfloatrange( 0.5, 1.3 ) );
level thread maps\_anim::anim_ents( pieces, "collapse", undefined, undefined, org_node, "intro_house" );
//client notify for Kevins audio
SetClientSysState( "levelNotify","house1_collapse" );
wait( randomfloatrange( 1.5, 2 ) );
playfx( level._effect["intro_house_collapse"], fx_org.origin );
}
///////////////////
//
// reset some fields
//
///////////////////////////////
reset_squad_ignore_state()
{
guys = getAIArray( "allies" );
for(i = 0; i < guys.size; i++)
{
guys[i].ignoreme = false;
guys[i].ignoreall = false;
}
}
///////////////////
//
// rejoin the squad on the Red color group
//
///////////////////////////////
rejoin_squad()
{
level endon( "trig_chain_ruins_end" );
trigger_wait( "colortrig_r3", "targetname" );
set_color_allies( "r" );
set_color_heroes( "c" );
}
///////////////////
//
// rejoin the squad on the Red color group
//
///////////////////////////////
rejoin_squad_2()
{
level endon( "start_office_building" );
trigger_wait( "chain_ruins_end", "targetname" );
set_color_allies( "r" );
set_color_heroes( "c" );
}
// wait for players to clear out the office building
office_building()
{
autosave_by_name( "Ber1 office pacing" );
level thread office_crawlers();
level thread office_objective_update();
flag_wait( "start_office_building" );
// get everyone back on the red chain
set_color_allies( "r" );
old_color_trig = getent( "chain_ruins_end", "targetname" );
if( isdefined( old_color_trig ) )
{
old_color_trig delete();
}
if( !flag( "in_office_building" ) )
{
set_color_chain( "colortrig_r4" );
}
level thread office_building_entry_vo();
level thread make_sure_only_have_8_guys();
level thread kill_all_axis_ai_bloody();
level thread cafe_area();
}
cafe_area()
{
// flag set on trigger
flag_wait( "surrender_start" );
level thread delete_drones();
if( !is_german_build() )
{
level thread execution_vignette();
}
else
{
flag_set( "execution_over" );
allies = simple_spawn( "execution_allies", ::execution_allies_german_safe_strat );
}
maps\ber1_event2::main();
}
office_building_entry_vo()
{
wait( randomfloatrange( 0.7, 1.4 ) );
play_vo( level.commissar, "vo", "move_forward" );
wait( 3 );
play_vo( level.reznov, "vo", "this_way_into_building" );
flag_wait( "in_office_building" );
play_vo( level.reznov, "vo", "upstairs" );
wait( 3 );
play_vo( level.chernov, "vo", "there_are_survivors" );
wait( 3 );
play_vo( level.commissar, "vo", "these_animals" );
wait( 6 );
play_vo( level.commissar, "vo", "deserve_none" );
}
make_sure_only_have_8_guys()
{
allies = getaiarray( "allies" );
regular_guys_taken_off = 0;
left_behind_guys = [];
left_behind_nodes = getnodearray( "node_ruins_guys_left_behind", "script_noteworthy" );
// take them off the color chain
// POLISH TODO make them go to cover nodes so it looks more realistic?
for( i = 0; i < allies.size; i++ )
{
// non-respawners dont need to follow to next event
if( isdefined( allies[i].script_no_respawn ) )
{
allies[i] disable_ai_color();
if( isdefined( left_behind_nodes[i] ) )
{
allies[i] setgoalnode( left_behind_nodes[i] );
}
else
{
allies[i] setgoalpos( allies[i].origin );
}
left_behind_guys[left_behind_guys.size] = allies[i];
}
else if( regular_guys_taken_off < 2 )
{
if( !is_in_array( level.heroes, allies[i] ) )
{
allies[i] disable_ai_color();
if( isdefined( left_behind_nodes[i] ) )
{
allies[i] setgoalnode( left_behind_nodes[i] );
}
else
{
allies[i] setgoalpos( allies[i].origin );
}
regular_guys_taken_off++;
left_behind_guys[left_behind_guys.size] = allies[i];
}
}
}
// wait till next event, then kill them if they're still alive
flag_wait( "tank_wall_crumble" );
wait( 5 );
for( i = 0; i < left_behind_guys.size; i++ )
{
if( isdefined( left_behind_guys[i] ) && isalive( left_behind_guys[i] ) )
{
left_behind_guys[i] thread bloody_death( true );
}
}
}
///////////////////
//
// injured guys on the 2nd floor of clock tower building, after the tanks have assaulted it
//
///////////////////////////////
office_crawlers()
{
flag_wait( "office_crawlers" );
crawls = [];
crawls[0]["crawl"] = "crawl_1";
crawls[0]["crawl_death"] = level.scr_anim["office"]["crawl_1_death"];
crawls[1]["crawl"] = "crawl_2";
crawls[1]["crawl_death"] = level.scr_anim["office"]["crawl_2_death"];
crawls[2]["crawl"] = "crawl_3";
crawls[2]["crawl_death"] = level.scr_anim["office"]["crawl_3_death"];
crawls[3]["crawl"] = "crawl_4";
crawls[3]["crawl_death"] = level.scr_anim["office"]["crawl_4_death"];
crawls = array_randomize( crawls );
level thread office_crawler_1( crawls[0] );
level thread office_crawler_2( crawls[1] );
level thread office_crawler_3( crawls[2] );
}
office_crawler_1( crawl_array )
{
guy = simple_spawn_single( "office_crawler_1" );
guy endon( "death" );
guy thread crawler_ignore_delay( 6 );
anim_node = getnode( "node_office_crawl_1", "targetname" );
guy.health = 5;
guy.animname = "office";
guy.allowdeath = true;
guy.deathanim = crawl_array["crawl_death"];
guy animscripts\shared::placeWeaponOn( guy.primaryweapon, "none");
anim_single_solo( guy, crawl_array["crawl"], undefined, anim_node );
guy dodamage( 1000, ( 0, 0, 0 ) );
}
office_crawler_2( crawl_array )
{
wait( 0.5 );
guy = simple_spawn_single( "office_crawler_2" );
guy endon( "death" );
guy thread crawler_ignore_delay( 6 );
anim_node = getnode( "node_office_crawl_2", "targetname" );
guy.health = 5;
guy.animname = "office";
guy.allowdeath = true;
guy.deathanim = crawl_array["crawl_death"];
guy animscripts\shared::placeWeaponOn( guy.primaryweapon, "none");
anim_single_solo( guy, crawl_array["crawl"], undefined, anim_node );
guy dodamage( 1000, ( 0, 0, 0 ) );
}
office_crawler_3( crawl_array )
{
wait( 0.5 );
guy = simple_spawn_single( "office_crawler_3" );
guy endon( "death" );
guy thread crawler_ignore_delay( 6 );
anim_node = getnode( "node_office_crawl_3", "targetname" );
guy.health = 5;
guy.animname = "office";
guy.allowdeath = true;
guy.deathanim = crawl_array["crawl_death"];
guy animscripts\shared::placeWeaponOn( guy.primaryweapon, "none");
anim_single_solo( guy, crawl_array["crawl"], undefined, anim_node );
guy dodamage( 1000, ( 0, 0, 0 ) );
}
crawler_ignore_delay( wait_time )
{
self endon( "death" );
wait( wait_time );
self.ignoreme = 0;
}
office_objective_update()
{
// flag set on trigger
flag_wait( "office_door_kick_trigger" );
flag_set( "objective_office_2" );
autosave_by_name( "Ber1 office execution" );
}
///////////////////
//
// play anim of office wall crumbling
//
///////////////////////////////
office_wall_crumble()
{
autosave_by_name( "Ber1 office crumble" );
shelf = getEnt("office_mg_shelf", "targetname");
shelf delete();
level thread kill_mgs( "office_shelf_mg", "targetname" );
// kills guys that stand on the brush models are being deleted
kill_noteworthy_group( "office_right_gunner" );
kill_noteworthy_group( "office_right_gunner_beneath" );
wait ( 0.2 );
fx = getStruct( "office_building_fx", "targetname" );
playFX( level._effect["office_collapse"], fx.origin );
//delete wall pieces
pieces = getEntArray( "office_wall_chunk", "targetname" );
for ( i = 0; i < pieces.size; i++ )
{
pieces[i] delete();
}
exploder( 102 );
wait( 0.7 );
playFX( level._effect["explosion_papers"], fx.origin );
flag_set( "office_wall_done" );
}
///////////////////
//
// make the office building MG42s love or hate the players
// if inside one of the houses, dont fire on the player
//
///////////////////////////////
office_mgs_threatbias()
{
vol_1 = getEnt( "left_house_vol", "targetname" );
vol_2 = getEnt( "right_house_vol", "targetname" );
while( !flag( "move_tanks_3" ) )
{
players = get_players();
for(i = 0; i < players.size; i++)
{
if( players[i] isTouching( vol_1 ) || players[i] isTouching( vol_2 ) )
{
SetIgnoreMeGroup( "players", "office_gunner_threat" );
}
else
{
setthreatbias( "players", "office_gunner_threat", -600 );
}
}
wait( 0.75 );
}
vol_1 delete();
vol_2 delete();
}
///////////////////
//
// the guys that wave you on into the ruins
//
///////////////////////////////
train_wavers()
{
level thread train_waver_1();
level thread train_waver_2();
}
train_waver_1()
{
level.waver1 = simple_spawn_single( "train_waver1", ::intro_waver1_strat );
flag_wait( "train_door_opened" );
level.waver1 thread anim_loop_solo( level.waver1, "wave1", undefined, "stop_whistle" );
wait( randomintrange( 5, 8 ) );
level.waver1 notify( "stop_whistle" );
level.waver1.goalradius = 60;
level.waver1 stop_magic_bullet_shield();
level.waver1.ignoreall = false;
level.waver1.ignoreme = false;
level.waver1.exit_train_pathing_num = 13;
goal_node = getnode( "exit_train_pathing_" + level.waver1.exit_train_pathing_num, "targetname" );
level.waver1 setgoalnode( goal_node );
flag_wait( "ruins_charge" );
wait( 2.6 );
goal_node = getnode( "berm_pathing_" + level.waver1.exit_train_pathing_num, "targetname" );
level.waver1 thread berm_pathing_think( goal_node );
}
train_waver_2()
{
level.waver2 = simple_spawn_single( "train_waver2", ::intro_waver2_strat );
flag_wait( "train_door_opened" );
level.waver2 thread anim_loop_solo( level.waver2, "wave2", undefined, "stop_whistle" );
flag_wait( "calling_intro_barrage" );
level.waver2 notify( "stop_whistle" );
flag_wait( "ruins_charge" );
level.waver2 notify( "join_squad" );
level.waver2.goalradius = 60;
level.waver2 stop_magic_bullet_shield();
level.waver2.ignoreall = false;
level.waver2.ignoreme = false;
level.waver2.exit_train_pathing_num = 14;
wait( 2.6 );
goal_node = getnode( "berm_pathing_" + level.waver2.exit_train_pathing_num, "targetname" );
level.waver2 thread berm_pathing_think( goal_node );
}
intro_waver1_strat()
{
self.animname = "russian";
self.goalradius = 16;
self.ignoreall = true;
self.ignoreme = true;
self.allowdeath = true;
self thread magic_bullet_shield();
}
intro_waver2_strat()
{
self.animname = "russian";
self.goalradius = 16;
self.ignoreall = true;
self.ignoreme = true;
self.allowdeath = true;
self thread magic_bullet_shield();
}
// soldiers yelling as they charge the ruins
//squad_battle_cries()
//{
// wait( randomfloat( 2 ) );
// self playsound("russian_battle_cry");
//}
///////////////////
//
// move the tanks throughout Event 1
//
///////////////////////////////
move_tanks()
{
level thread tank_1();
level thread tank_2();
level thread tank_3();
}
// handles the actions of Tank 1
tank_1()
{
flag_wait( "spawn_tanks" );
wait( 0.05 );
tank = getEnt( "ev1_tank1", "targetname" );
tank maps\_vehicle::godon();
tank.rollingdeath = 1;
tank thread tank_rolling_death();
tank thread maps\_vehicle::mgoff();
tank veh_stop_at_node( "tank1_stop1" );
flag_wait( "move_tanks_1" );
tank resumespeed( 8 );
tank veh_stop_at_node( "tank1_stop2" );
flag_wait( "move_tanks_2" );
tank resumespeed( 8 );
// split this so we can start in the middle of the ruins
tank1_part2( tank );
}
// handles the actions of Tank 2
tank_2()
{
flag_wait( "spawn_tanks" );
wait( 0.05 );
tank = getEnt( "ev1_tank2","targetname" );
tank maps\_vehicle::godon();
tank thread maps\_vehicle::mgoff();
tank veh_stop_at_node( "tank2_stop1" );
flag_wait( "move_tanks_1" );
tank resumespeed( 8 );
tank veh_stop_at_node( "tank2_stop2" );
flag_wait( "move_tanks_2" );
tank resumespeed( 8 );
// split so we can start in mid ruins
tank2_part2( tank );
}
// handles the actions of Tank 3
tank_3()
{
flag_wait( "spawn_tanks" );
wait( 0.05 );
tank = getEnt( "tank_3","targetname" );
tank maps\_vehicle::godon();
tank thread tank_3_shoot_strat();
tank thread maps\_vehicle::mgoff();
tank veh_stop_at_node( "tank_3_stop_1" );
flag_wait( "move_tanks_1" );
tank resumespeed( 8 );
tank veh_stop_at_node( "tank_3_stop_2" );
flag_wait( "move_tank_3_2" );
tank resumespeed( 8 );
tank veh_stop_at_node( "tank_3_stop_3" );
flag_wait( "ruins_battle_2" );
tank resumespeed( 8 );
tank veh_stop_at_node( "tank_3_stop_4" );
flag_wait( "chimney_collapsed" );
tank tank_reset_turret( 2.5 );
wait( RandomFloatRange( 0.75, 1.9 ) );
tank resumespeed( 8 );
tank waittill( "reached_end_node" );
flag_set( "ruins_tank_at_end" );
}
tank_rolling_death()
{
self waittill( "death" );
while( 1 )
{
if ( ( self getspeedMPH() ) == 0 )
{
break;
}
wait( 0.05 );
}
wait( 0.05 );
// manually notify this cuz i'm not really using crashpaths. kill() in _vehicle wants this notify when the tank is dead & done moving
self notify( "deathrolloff" );
}
///////////////////
//
// middle tank (that moves up with squad) shoot strat as it moves up through the ruins
//
///////////////////////////////
tank_3_shoot_strat()
{
chimney_targ = getstruct( "orig_ruins_tank_target_chimney", "targetname" );
random_targs = [];
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_1", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_2", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_3", "targetname" );
flag_wait( "move_tank_3_2" );
wait( 2 );
while( !flag( "ruins_battle_2" ) )
{
self tank_fire_at_struct( random_targs[randomint(random_targs.size)] );
// if flag is set while firing at struct, don't wait for wait(), just break out now
if( flag( "ruins_battle_2" ) )
{
break;
}
wait( RandomIntRange( 5, 7 ) );
}
wait( 3 );
// Blows up chimney if player doesn't look at the lookat trigger but moves far ahead enough
level thread trig_override( "trig_lookat_chimney" );
// wait for player to look at the bookcase area
trigger_wait( "trig_lookat_chimney", "targetname" );
self tank_fire_at_struct( chimney_targ );
level thread maps\ber1_anim::ruins_chimney();
flag_set( "chimney_collapsed" );
// waittill it gets to the end of its path
flag_wait( "ruins_tank_at_end" );
level thread tank_3_gets_shot();
random_targs = [];
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_4", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_5", "targetname" );
// fire at the office building
fire_count = 0;
while( fire_count < 2 )
{
self tank_fire_at_struct( random_targs[randomint(random_targs.size)] );
wait( RandomIntRange( 4, 5 ) );
fire_count++;
}
flag_set( "tank_3_ready_to_die" );
}
tank_3_gets_shot()
{
level endon( "execution_over" );
guy = simple_spawn_single( "office_panzer_killer" );
guy setcandamage( false );
guy.ignoreme = true;
guy.ignoresuppression = true;
guy.pacifist = true;
guy.pacifistwait = 0.05;
tank = getent( "tank_3", "targetname" );
flag_wait( "tank_3_ready_to_die" );
goal = getnode( "node_panzer_killer", "targetname" );
guy setgoalnode( goal );
guy waittill( "goal" );
wait( 0.5 );
orig = getent( "orig_tank_3_death", "targetname" );
orig.health = 100000;
guy SetEntityTarget( orig );
level thread tank_3_gets_shot_failsafe( tank );
while( !flag( "tank_3_shot_failsafe" ) )
{
tank waittill( "damage", damage_amount, attacker, direction_vec, point, type );
if( attacker == guy )
{
radiusdamage( tank.origin, 50, tank.health + 50, tank.health + 50 );
break;
}
}
level thread tanks_torn_apart_vo();
level notify( "tank_3_dead" );
guy ClearEntityTarget();
guy setcandamage( true );
guy endon( "death" );
flag_wait( "move_tanks_3" );
goal = getnode( "auto4068", "targetname" );
guy thread guy_run_to_node_and_delete( goal );
}
tank_3_gets_shot_failsafe( tank )
{
level endon( "tank_3_dead" );
wait( 8 );
quick_text( "tank_3_gets_shot_failsafe" );
flag_set( "tank_3_shot_failsafe" );
rocket_origin = getstruct( "orig_panzer_killer_failsafe", "targetname" );
level thread fire_shrecks( rocket_origin, tank, undefined, "rpg_impact_boom", 0.9 );
wait( 0.9 );
radiusdamage( tank.origin, 50, tank.health + 50, tank.health + 50 );
}
tanks_torn_apart_vo()
{
wait( RandomFloatRange( 1.4, 2.5 ) );
play_vo( level.reznov, "vo", "tanks_torn_apart" );
}
tank1_part2( tank )
{
tank veh_stop_at_node( "tank1_stop3" );
tank thread tanks_fire_at_office();
flag_wait( "move_tanks_3" );
tank tank_reset_turret( 1.5 );
tank resumespeed( 10 );
tank veh_stop_at_node( "tank1_fire_at_wall" );
println( "tank firing at wall!" );
crumble = getstruct( "make_office_wall_crumble", "targetname" );
tank setTurretTargetVec( crumble.origin );
tank waittill_notify_or_timeout( "turret_on_target", 3 );
wait( 0.4 );
tank fireWeapon();
level thread office_wall_crumble();
wait( 1.25 );
tank resumespeed( 2 );
final_target = getstruct( "tank1_final_target", "targetname" );
tank setTurretTargetVec( final_target.origin );
wait( randomfloatrange( 1, 1.2 ) );
level notify( "tank_shreck_ricochet" );
flag_set( "tank1_disabled" );
// TODO need some kind of failsafe here
while( !flag( "tank1_destroyed" ) )
{
tank waittill( "damage", amount, attacker );
if( attacker == level.shrek_bounce_guy )
{
radiusdamage( tank.origin, 50, tank.health + 50, tank.health + 50 );
flag_set( "tank1_destroyed" );
}
}
}
///////////////////
//
// middle tank (that moves up with squad) shoot strat when at the end of its path
//
///////////////////////////////
tanks_fire_at_office()
{
level endon( "move_tanks_3" );
random_targs = [];
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_4", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_5", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_6", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_7", "targetname" );
random_targs[random_targs.size] = getstruct( "orig_ruins_tank_target_8", "targetname" );
while( 1 )
{
self tank_fire_at_struct( random_targs[randomint( random_targs.size)] );
wait( randomIntRange( 5, 7 ) );
}
}
tank2_part2( tank )
{
tank veh_stop_at_node( "tank2_stop3" );
tank thread tanks_fire_at_office();
flag_wait( "move_tanks_3" );
tank thread tank_reset_turret( 2 );
wait( 2.5 );
tank resumespeed( 10 );
tank veh_stop_at_node( "tank2_stop4" );
wall_hole = getstruct( "office_wall_hole", "targetname" );
tank setTurretTargetVec( wall_hole.origin );
tank waittill_notify_or_timeout( "turret_on_target", 3 );
wait( 0.4 );
tank fireWeapon();
wait( 0.1 );
playfx( level._effect["tank_shell_explode"], wall_hole.origin );
wait( randomfloatrange( 4, 5.5 ) );
ground = getstruct( "tank2_target", "targetname" );
tank setTurretTargetVec( ground.origin );
tank waittill_notify_or_timeout( "turret_on_target", 3 );
wait( 0.4 );
tank fireWeapon();
wait( 0.1 );
playfx( level._effect["tank_shell_explode"], ground.origin );
// waittill tank 1 has been disabled by the rocket
///////////////
flag_wait( "tank1_disabled" );
finger1 = getStruct( "finger_shreck", "targetname" );
tank setTurretTargetVec( finger1.origin );
tank waittill_notify_or_timeout( "turret_on_target", 3 );
wait( 0.4 );
tank fireWeapon();
flag_wait( "tank1_destroyed" );
window = getstruct( "office_lower_window", "targetname" );
tank setTurretTargetVec( window.origin );
tank waittill( "turret_on_target" );
wait( 0.4 );
tank fireWeapon();
wait( 0.1 );
exploder( 101 );
kill_guys_in_vol_119();
wait( 0.5 );
tank tank_reset_turret( 3 );
flag_set( "start_office_building" );
wait( 5.5 );
level thread clock_tank_blocker_delay();
tank resumespeed( 5 );
tank veh_stop_at_node( "tank2_stop5" );
flag_wait( "start_office_building" );
maps\_debug::set_event_printname( "Office" );
// tank moves up to the surrender area to break through the wall
tank2_surrender( tank );
}
clock_tank_blocker_delay()
{
wait( 4.5 );
blocker = getent( "blocker_clock_tank_2", "targetname" );
blocker solid();
blocker disconnectpaths();
wait( 2 );
maps\ber1_tankride::remove_tank_blocker( "blocker_clock_tank_1" );
wait( 3.5 );
blocker connectpaths();
blocker delete();
}
tank2_surrender( tank )
{
tank resumespeed( 5 );
tank veh_stop_at_node( "node_wait_pre_crumble" );
// flag set on trigger
flag_wait( "surrender_start" );
tank resumespeed( 5 );
turn_turret_struct = getstruct( "turn_turret", "targetname" );
tank SetTurretTargetVec( turn_turret_struct.origin );
tank veh_stop_at_node( "node_wait_pre_crumble_1" );
flag_wait( "execution_over" );
wait( randomfloatrange( 0.8, 1.5 ) );
tank resumespeed( 5 );
tank veh_stop_at_node( "node_wait_pre_crumble_2" );
// flag set on trigger
flag_wait( "tank_go_through_wall" );
level thread wall_crumble_vo();
tank resumespeed( 5 );
// ai cleanup
kill_all_axis_ai();
flag_wait( "tank_ambush" );
panzershrek_1_spawn = getstruct( "ps1_spawn", "targetname" );
level thread fire_shrecks( panzershrek_1_spawn, tank, (0,0,50), "iron_gate_explo", 1.1 );
//panzershrek_1_spawn playSound( "weap_pnzr_fire" );
set_color_chain( "colortrig_r8" );
flag_set( "objective_surrender" );
tank setTurretTargetVec( panzershrek_1_spawn.origin );
tank waittill_notify_or_timeout( "turret_on_target", 5 );
tank fireWeapon();
wait( randomfloatrange( 1.5, 2 ) );
level thread fire_shrecks( panzershrek_1_spawn, tank, (0,0,50), "rpg_impact_boom", 1.1 );
//panzershrek_1_spawn playsound( "weap_pnzr_fire" );
wait( 1.1 );
radiusdamage( tank.origin, 50, tank.health + 50, tank.health + 50 );
}
kill_guys_in_vol_119()
{
guys = getAIarrayTouchingVolume( "axis", "vol_119" );
for( i = 0; i < guys.size; i++ )
{
if( IsDefined( guys[i].magic_bullet_shield ) && guys[i].magic_bullet_shield )
{
continue;
}
guys[i] dodamage( guys[i].health + 50, (0,0,0) );
}
}
#using_animtree ("generic_human");
execution_vignette()
{
battlechatter_off();
anim_node = getnode( "execution_start", "targetname" );
allies = simple_spawn( "execution_allies", ::execution_allies_strat );
assertex( allies.size == 2, "execution_allies != 2" );
allies[0].animname = "execution_ally_1";
allies[1].animname = "execution_ally_2";
axis = simple_spawn( "execution_axis", ::execution_axis_strat );
assertex( axis.size == 4, "execution_axis != 4" );
axis[0].animname = "execution_axis_1";
axis[1].animname = "execution_axis_2";
axis[2].animname = "execution_axis_3";
axis[3].animname = "execution_axis_4";
axis[1] thread execution_half_shield();
anim_guys = array_combine( allies, axis );
level thread execution_vignette_interrupt_watch();
level thread execution_vignette_interrupt_end_watch();
level endon( "execution_over" );
anim_single( anim_guys, "execution", undefined, undefined, anim_node );
for( i = 0; i < axis.size; i++ )
{
if( isalive( axis[i] ) )
{
axis[i].a.nodeath = true;
axis[i] dodamage( axis[i].health, (0,0,0) );
}
}
flag_set( "execution_over" );
battlechatter_on();
}
execution_axis_strat()
{
self animscripts\shared::placeWeaponOn( self.primaryweapon, "none");
self.ignoreme = true;
self.ignoreall = true;
self.pacifist = true;
self.pacifistwait = 0.05;
self.grenadeawareness = 0;
self.allowdeath = true;
self.health = 1;
self endon( "death" );
// at this point the vignette is far enough along, we don't want any reaction from these guys if the player shoots them
wait( 7.75 );
quick_text( "nodeath here" );
self.a.nodeath = true;
}
execution_allies_strat()
{
self.ignoreme = true;
self.pacifist = true;
self.pacifistwait = 0.05;
self.grenadeawareness = 0;
self setcandamage( false );
flag_wait( "execution_over" );
self.goalradius = 70;
self.ignoreme = false;
self.pacifist = false;
self.pacifistwait = 20; // _spawner default
self maps\_gameskill::grenadeAwareness(); // set to default
self.walkdist = 1000;
goal_node = getnode( self.script_noteworthy, "targetname" );
self setgoalnode( goal_node );
flag_wait( "objective_surrender" );
self.walkdist = 16;
self set_force_color( "r" );
self thread replace_on_death();
self setcandamage( true );
}
execution_allies_german_safe_strat()
{
self setcandamage( false );
goal_node = getnode( self.script_noteworthy, "targetname" );
self setgoalnode( goal_node );
flag_wait( "objective_surrender" );
self setcandamage( true );
self set_force_color( "r" );
self thread replace_on_death();
}
execution_vignette_interrupt_watch()
{
level endon( "execution_over" );
//flag_wait_all( "execution_right_over", "execution_left_over" );
while( 1 )
{
axis = get_ai_group_ai( "execution_axis_ai" );
if( !axis.size )
{
break;
}
wait( 0.05 );
}
allies = get_ai_group_ai( "execution_ally_ai" );
for( i = 0; i < allies.size; i++ )
{
allies[i] notify( "killanimscript" );
}
flag_set( "execution_over" );
}
execution_vignette_interrupt_end_watch()
{
wait( 10 );
axis = get_ai_group_ai( "execution_axis_ai" );
// return if guy 2 is still alive; we want the rest of the anim to play out
for( i = 0; i < axis.size; i++ )
{
if( axis[i].animname == "execution_axis_2" )
{
return;
}
}
level notify( "stop_execution_half_shields" );
// if guy 2 has been killed, make sure all the rest are dead so the anim can end
for( i = 0; i < axis.size; i++ )
{
if( isalive( axis[i] ) )
{
axis[i].a.nodeath = true;
axis[i] dodamage( axis[i].health, (0,0,0) );
}
}
}
///////////////////
//
// Protect the execution guy from all damage except from the player
//
///////////////////////////////
execution_half_shield()
{
level endon( "stop_execution_half_shields" );
self endon( "death" );
self.pel2_real_health = self.health;
self.health = 10000;
attacker = undefined;
while( self.health > 0 )
{
self waittill( "damage", amount, attacker, direction_vec, point, type, modelName, tagName );
type = tolower( type );
// if it's not the player, and also a bullet weapon (non-player friendlies should still be able to kill them with their grenades)
if( !isplayer(attacker) && issubstr( type, "bullet" ) )
{
//iprintln( "attacked by non-player!" );
self.health = 10000; // give back health for these things
}
else
{
self.health = self.pel2_real_health;
self dodamage( amount, (0,0,0) );
self.pel2_real_health = self.health;
// put ff shield back on
self.health = 10000;
}
}
}
///////////////////
//
// bounce the shreck off the tank in front of the office building
//
///////////////////////////////
tank_shreck_ricochet()
{
shreck = getEnt( "tank1_shreck", "targetname" );
shreck hide();
level waittill( "tank_shreck_ricochet" );
level.shrek_bounce_guy = simple_spawn_single( "shrek_bounce_spawner", ::shrek_bounce_spawner_strat );
wait( 2.3 );
level notify( "bounce_shrek_fired" );
vnode = getVehicleNode( "auto4365", "targetname" );
shreck attachPath( vnode );
shreck startPath();
shreck show();
playFxOnTag( level._effect["shreck_trail"], shreck, "tag_fx" );
shreck playloopsound( "rpg_rocket" );
vnode = getVehicleNode( "ricochet", "script_noteworthy" );
vnode waittill( "trigger" );
thread play_sound_in_space( "tank_shreck_ricochet", shreck.origin, true );
playFX( level._effect["schrek_bounce_off_tank"], shreck.origin );
shreck waittill( "reached_end_node" );
shreck hide();
playfx( level._effect["shreck_explode"], shreck.origin );
shreck stoploopsound(.1);
shreck playsound( "rpg_impact_boom" );
radiusdamage( shreck.origin, 128, 300, 35 );
earthquake( 0.5, 1.5, shreck.origin, 512 );
wait( 3 );
shreck delete();
}
shrek_bounce_spawner_strat()
{
self setcandamage( false );
self.pacifist = true;
self.pacifistwait = 0.05;
self.ignoresuppression = true;
self.ignoreme = true;
self.a.rockets = 7;
level waittill( "bounce_shrek_fired" );
wait( 1 );
goal = getnode( "node_shrek_bounce_end", "targetname" );
self setgoalnode( goal );
self waittill( "goal" );
wait( 1 );
goal = getnode( self.target, "targetname" );
self setgoalnode( goal );
self waittill( "goal" );
tank = getent( "ev1_tank1", "targetname" );
self SetEntityTarget( tank );
// TODO hax for coop failing
wait( 2 );
self shoot();
level thread tank_1_death_failsafe();
goal = getnode( "node_shrek_bounce_end", "targetname" );
self setgoalnode( goal );
self waittill( "goal" );
self delete();
}
tank_1_death_failsafe()
{
wait( 1 );
tank = getEnt( "ev1_tank1", "targetname" );
if( !flag( "tank1_destroyed" ) )
{
radiusdamage( tank.origin, 50, tank.health + 50, tank.health + 50 );
flag_set( "tank1_destroyed" );
}
}
// call the threads for the train drone intro
unload_train_drones()
{
if(!NumRemoteClients()) // If were running over the network, reduce number of drones
{
level thread unload_and_make_drones("boxcar_a", 5);
// level thread unload_and_make_drones("boxcar_b", 6);
level thread unload_and_make_drones("boxcar_d", 7);
level thread unload_and_make_drones("boxcar_e", 7);
}
}
// spawn in script_models, play the unload anim, turn them into drones
#using_animtree ("generic_human");
unload_and_make_drones( boxcar_name, num )
{
pos = undefined;
wait( randomfloatrange( 1.5, 3 ) );
boxcar = getEnt( boxcar_name, "targetname" );
org = boxcar getTagOrigin( "tag_origin" );
boxcar.animname = "boxcar";
for( i = 0; i < num; i++ )
{
sd_struct = getStruct( boxcar_name + "_" + i, "targetname" );
if( isDefined( sd_struct ) )
{
pos = sd_struct;
subdrone = spawn( "script_model", sd_struct.origin );
subdrone.angles = sd_struct.angles;
subdrone.targetname = "drone_" + boxcar_name;
subdrone.target = subdrone.targetname + i;
subdrone.script_noteworthy = i;
subdrone.animname = "russian" + (i);
subdrone character\char_rus_r_rifle::main();
subdrone attach( "weapon_rus_mosinnagant_rifle", "tag_weapon_right" );
subdrone UseAnimTree(#animtree);
}
else
{
continue;
}
}
boxcar thread maps\ber1_anim::open_drone_traincar_door();
drones = getEntArray( "drone_" + boxcar_name, "targetname" );
for( i = 0; i < drones.size; i++ )
{
drones[i] hide();
drones[i] linkTo( boxcar, "tag_origin" );
}
boxcar thread anim_single( drones, "train_intro", "tag_origin" );
flag_wait( "train_door_opened" );
for( i = 0; i < drones.size; i++ )
{
drones[i] show();
drones[i] thread unload_boxcars();
}
}
// turn the animated script_models into drones
#using_animtree ("fakeShooters");
unload_boxcars()
{
self waittill( "guy_unlink" );
self UseAnimTree(#animtree);
self setcandamage( true );
self.animname = "drone";
self.a = spawnstruct();
self makeFakeAI();
self.team = "allies";
// if self.targetname = "drone_boxcar_b"
// and self.script_noteworthy = "7"
// then self.target = "drone_boxcar_b7"
// there must be a script_struct with a targetname of "drone_boxcar_b7"
// for the new drone to target and run to!
self.target = self.targetname + self.script_noteworthy;
self.targetname = "drone";
self.drone_run_cycle = %combat_run_fast_3;
self.fakeDeath = true;
self.health = 35;
self thread maps\_drones::drone_setName();
self thread maps\_drones::drones_clear_variables();
structarray_add( level.drones[self.team], self );
level notify ( "new_drone" );
self thread maps\_drones::build_struct_targeted_origins();
self thread maps\_drones::drone_runChain( self );
flag_wait( "ruins_charge" );
wait( randomfloatrange( 0.5, 2 ) );
self notify( "drone out of cover" );
}
// ambient rockets until notifed to stop
ambient_rockets( targets, endon_flag, geotrail, far, lob_factor )
{
while( !flag(endon_flag) )
{
thread fire_katyusha_rockets( 6, targets, geotrail, far, lob_factor );
wait randomfloatrange(5, 8);
}
}
katyusha_monitor()
{
level._numRockets = 0;
if(NumRemoteClients())
{
while(1)
{
wait_network_frame();
level._numRockets = 0;
}
}
}
rocket_ok()
{
if(NumRemoteClients() && level._numRockets > 4)
{
return false;
}
return true;
}
// fire the Katyusha rockets
fire_katyusha_rockets( amount, targets_name, geotrail, far, lob_factor )
{
katyusha_id = randomint( 6 );
truck = getEnt( "katyusha_truck" + katyusha_id, "targetname" );
targets = getStructArray( targets_name + "_truck" + katyusha_id, "targetname" );
rocket_target = targets[randomInt(targets.size)];
close_targets = [];
for(i = 0; i < targets.size; i++)
{
dist_sqrd = distancesquared( rocket_target.origin, targets[i].origin );
if( dist_sqrd <= 512*512 )
{
close_targets[close_targets.size] = targets[i];
}
}
for(i = 0; i < amount; i++)
{
dest = close_targets[randomInt(close_targets.size)];
//wait randomfloatrange(.112, .192);
//Kevin changed it to just wait
wait( 0.2 );
x = randomint( 15 );
if( x <= 9 )
{
tag = "tag_rocket0" + x;
}
else
{
tag = "tag_rocket" + x;
}
tag_org = truck getTagOrigin( tag );
pos_angles = truck getTagAngles( tag );
while(!rocket_ok())
{
wait_network_frame();
}
rocket = spawn( "script_model", tag_org );
level._numRockets ++;
rocket.angles = ( pos_angles );
rocket setmodel( "katyusha_rocket" );
rocket playsound( "katyusha_launch_rocket" );
playFxOnTag( level._effect["rocket_launch"], rocket, "tag_fx" );
if( geotrail )
{
playFxOnTag( level._effect["rocket_trail"], rocket, "tag_fx" );
}
// sound of rocket flying through the air
// TEMP OFF
//rocket playloopsound("katy_rocket_run");
if( isdefined( lob_factor ) )
{
rocket thread fire_rocket( dest.origin, tag_org, far, lob_factor );
}
else
{
rocket thread fire_rocket( dest.origin, tag_org, far, 2200 );
}
if(NumRemoteClients()) // If we're network cooped, give the network some breathing room
{
if(i % 2)
{
wait_network_frame();
}
}
}
}
// fire the katyusha rockets
fire_rocket( target_pos, tag_org, far, catenary, z_moveto_offset )
{
if( !isdefined( z_moveto_offset ) )
{
z_moveto_offset = 110;
}
// move the rocket flatly along the rocket rack
moveto_pos = tag_org + ( 0, 200, z_moveto_offset );
self moveTo( moveto_pos, 0.2 );
wait( 0.2 );
// get the rocket's new position
// this is where the trajectory math will begin
start_pos = self.origin;
///////// Math Section
// Reverse the gravity so it's negative, you could change the gravity
// by just putting a number in there, but if you keep the dvar, then the
// user will see it change.
gravity = getDvarInt("g_gravity") * -1;
// Get the distance
dist = distance( start_pos, target_pos );
// Figure out the time depending on how fast we are going to
// throw the object... 2200 changes the "strength" of the velocity.
// To make it more lofty, lower the number.
// To make it more of a bee-line throw, increase the number.
// Katyushas need a flatter trajectory due to the rocket rack
time = dist / catenary; // 2200 is default for ambient rockets
time_to_wait = time / 3;
// Get the delta between the 2 points.
delta = target_pos - start_pos;
// Here's the math I stole from the grenade code. :) First figure out
// the drop we're going to need using gravity and time squared.
drop = 0.5 * gravity * (time * time);
// Now figure out the trajectory to throw the object at in order to
// hit our map, taking drop and time into account.
velocity = ((delta[0] / time), (delta[1] / time), (delta[2] - drop) / time);
///////// End Math Section
self MoveGravity( velocity, time );
self playloopsound("katy_rocket_run",.1);
// from pel1
self rotatepitch( 100, time );
self thread rotate_rocket_at_midpoint( time_to_wait );
wait( time );
//Kevin Stopping the looped sound
self stoploopsound(1);
if(far)
{
playFX(level._effect["rocket_explode_far"], self.origin);
}
else
{
playFX(level._effect["rocket_explode"], self.origin);
}
earthquake( 0.3, 2, self.origin, 512 );
//Kevin putting a wait the same time as the loop fade
//I had to do this or all the rockets clip on impact.
//I put the wait before the delete so the particle isn't delayed.
wait 1;
self delete();
}
// make the Katyusha rocket's nose follow the flight path
rotate_rocket_at_midpoint( time )
{
wait( time );
self rotatePitch( 20, time / 1.5 );
}
///////////////////
//
// piggybacking autosaves onto other triggers, to save entities
//
///////////////////////////////
save_mid_ruins()
{
trigger_wait( "colortrig_r2", "targetname" );
autosave_by_name( "Ber1 midruins" );
}
///////////////////
//
// spawn these manually when the event starts, to save on entities at load time
//
///////////////////////////////
spawn_ruins_pickup_weapons()
{
ruins_weapons = [];
ruins_weapons[0] = spawnstruct();
ruins_weapons[0].weapon_name = "weapon_panzerschrek";
ruins_weapons[0].origin = (1427.9, -1695.4, -234.5);
ruins_weapons[0].angles = (287.17, 355.56, -50.1497);
ruins_weapons[0].count = 3;
ruins_weapons[1] = spawnstruct();
ruins_weapons[1].weapon_name = "weapon_panzerschrek";
ruins_weapons[1].origin = (571.5, -1579.8, -230.5);
ruins_weapons[1].angles = (287.17, 48.8599, -50.1497);
ruins_weapons[1].count = 3;
spawn_pickup_weapons( ruins_weapons );
}