3205 lines
No EOL
64 KiB
Text
3205 lines
No EOL
64 KiB
Text
#include maps\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\pel2_util;
|
|
#include maps\_anim;
|
|
#include maps\_music;
|
|
#include maps\_busing;
|
|
|
|
// pel2_forest script
|
|
|
|
main()
|
|
{
|
|
|
|
autosave_by_name( "Pel2 forest begin" );
|
|
|
|
//Tuey Change Music State to AFTERBUNKER
|
|
setmusicstate("AFTERBUNKER");
|
|
|
|
maps\_debug::set_event_printname( "Dunes" );
|
|
|
|
battlechatter_off();
|
|
|
|
play_vo( level.roebuck, "vo", "half_a_mile_north" );
|
|
|
|
// spawn and move forest tanks
|
|
level thread forest_tanks();
|
|
|
|
level thread bomber_crash();
|
|
level thread admin_mg_guys();
|
|
|
|
level thread trig_grass_admin_camo_guys();
|
|
level thread dunes_flame_tree();
|
|
level thread forest_ambient_bombers();
|
|
level thread dunes_ambush_beat_2_timeout();
|
|
level thread dunes_ambush_beat_3_timeout();
|
|
|
|
for( i = 0; i < level.heroes.size; i++ )
|
|
{
|
|
level.heroes[i] set_force_color( "g" );
|
|
level.heroes[i] thread set_pacifist_on();
|
|
level.heroes[i] setcandamage( true );
|
|
}
|
|
|
|
set_color_chain( "chain_forest" );
|
|
|
|
forest_mid();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// 2nd part of ambush happens after a bit if player doesn't move up
|
|
//
|
|
///////////////////////////////
|
|
|
|
dunes_ambush_beat_2_timeout()
|
|
{
|
|
|
|
level endon( "trig_grass_admin_camo_guys_2" );
|
|
|
|
flag_wait( "trig_grass_admin_camo_guys" );
|
|
|
|
wait( RandomIntRange( 8, 11 ) );
|
|
|
|
trig = getent( "trig_grass_admin_camo_guys_2", "script_noteworthy" );
|
|
if( isdefined( trig ) )
|
|
{
|
|
quick_text( "ambush_beat_2 timed out!", 3, true );
|
|
trig notify( "trigger" );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// 3rd part of ambush happens after a bit if player doesn't move up
|
|
//
|
|
///////////////////////////////
|
|
|
|
dunes_ambush_beat_3_timeout()
|
|
{
|
|
|
|
level endon( "trig_grass_admin_camo_guys_3" );
|
|
|
|
flag_wait( "trig_grass_admin_camo_guys_2" );
|
|
|
|
wait( RandomIntRange( 10, 13 ) );
|
|
|
|
trig = getent( "trig_grass_admin_camo_guys_3", "script_noteworthy" );
|
|
if( isdefined( trig ) )
|
|
{
|
|
quick_text( "ambush_beat_3 timed out!", 3, true );
|
|
trig notify( "trigger" );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Handles tree sniper
|
|
//
|
|
///////////////////////////////
|
|
|
|
dunes_flame_tree()
|
|
{
|
|
|
|
// DEBUG
|
|
// dunes_flame_tree_debug();
|
|
|
|
// spawn in tree sniper
|
|
tree_trig = getent( "trig_grass_admin_tree_guy", "script_noteworthy" );
|
|
tree_trig notify( "trigger" );
|
|
wait( 0.05 );
|
|
guy = get_ai_group_ai( "tree_guy" )[0];
|
|
guy thread dune_flame_tree_guy_strat();
|
|
guy thread dune_flame_tree_guy_death();
|
|
|
|
tree = getent( "dunes_flame_tree", "script_noteworthy" );
|
|
tree thread dunes_flame_tree_notify();
|
|
tree thread dunes_flame_tree_achievement();
|
|
|
|
fake_orig = getstruct( "flame_tree_orig", "targetname" );
|
|
fake_orig_2 = getstruct( "flame_tree_orig_2", "targetname" );
|
|
|
|
// play the looping fx of fronds that hide the tree sniper
|
|
model_tag_origin = spawn( "script_model", fake_orig.origin );
|
|
model_tag_origin setmodel("tag_origin");
|
|
model_tag_origin.angles = fake_orig.angles;
|
|
// model_tag_origin linkto( tree, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) );
|
|
playfxontag( level._effect["sniper_leaf_loop"], model_tag_origin, "TAG_ORIGIN" );
|
|
|
|
flag_wait( "trig_grass_admin_camo_guys_2" );
|
|
|
|
set_color_chain( "chain_forest_banzai_2" );
|
|
|
|
// delete the looping fx
|
|
// model_tag_origin unlink();
|
|
model_tag_origin delete();
|
|
|
|
wait( 0.05 );
|
|
|
|
// guy "throws" fronds aside so he can attack
|
|
orig = getent( "test_orig", "targetname" );
|
|
playfx( level._effect["sniper_leaf_canned"], tree.origin );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//dunes_flame_tree_debug()
|
|
//{
|
|
//
|
|
//// spawn in tree sniper
|
|
// tree_trig = getent( "trig_grass_admin_tree_guy", "script_noteworthy" );
|
|
// tree_trig notify( "trigger" );
|
|
// wait( 0.05 );
|
|
// guy = get_ai_group_ai( "tree_guy" )[0];
|
|
// guy thread dune_flame_tree_guy_strat();
|
|
// guy thread dune_flame_tree_guy_death();
|
|
//
|
|
// tree = getent( "dunes_flame_tree", "script_noteworthy" );
|
|
// tree thread dunes_flame_tree_notify();
|
|
// tree thread dunes_flame_tree_achievement();
|
|
//
|
|
// fake_orig = getstruct( "flame_tree_orig", "targetname" );
|
|
// fake_orig_2 = getstruct( "flame_tree_orig_2", "targetname" );
|
|
//
|
|
// while( 1 )
|
|
// {
|
|
// // play the looping fx of fronds that hide the tree sniper
|
|
// model_tag_origin = spawn( "script_model", fake_orig.origin );
|
|
// model_tag_origin setmodel("tag_origin");
|
|
// model_tag_origin.angles = fake_orig.angles;
|
|
// // model_tag_origin linkto( tree, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) );
|
|
// playfxontag( level._effect["sniper_leaf_loop"], model_tag_origin, "TAG_ORIGIN" );
|
|
//
|
|
// wait( 3 );
|
|
//
|
|
//
|
|
// // delete the looping fx
|
|
// // model_tag_origin unlink();
|
|
// model_tag_origin delete();
|
|
//
|
|
// wait( 0.05 );
|
|
//
|
|
// // guy "throws" fronds aside so he can attack
|
|
// playfx( level._effect["sniper_leaf_canned"], tree.origin );
|
|
//
|
|
// wait( 2 );
|
|
//
|
|
// }
|
|
//
|
|
//}
|
|
|
|
|
|
|
|
dune_flame_tree_guy_death()
|
|
{
|
|
|
|
self waittill_either( "death", "fake tree death" );
|
|
flag_set( "flame_tree_guy_dead" );
|
|
|
|
}
|
|
|
|
|
|
dunes_flame_tree_notify()
|
|
{
|
|
|
|
level endon( "trig_admin_back" );
|
|
|
|
flag_wait( "grass_admin_surprise" );
|
|
|
|
wait( 0.05 );
|
|
|
|
guy = get_ai_group_ai( "tree_guy" )[0];
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
self waittill( "broken", broken_notify, attacker );
|
|
|
|
if( broken_notify == "hideout_fronds_dmg0" )
|
|
{
|
|
|
|
flag_set( "flame_tree_flamed" );
|
|
|
|
tree = getent( "dunes_flame_tree", "script_noteworthy" );
|
|
//tree playsound( "flame_ignite_tree" );
|
|
playsoundatposition("flame_ignite_tree", tree.origin);
|
|
|
|
//TUEY - When we get entity playsound fixed, this will work...but it doesn't for now , so I'm commenting it out.
|
|
//level thread maps\pel2_amb::play_flame_tree_loop(tree);
|
|
|
|
if( isdefined( guy ) && isalive( guy ) )
|
|
{
|
|
|
|
guy thread animscripts\death::flame_death_fx();
|
|
guy thread tree_guy_flame_sound();
|
|
guy setcandamage( true );
|
|
guy notify( "fake tree death", attacker );
|
|
|
|
// give player achievement for torching tree guy
|
|
if( IsDefined( level.last_tree_attacker ) )
|
|
{
|
|
level.last_tree_attacker giveachievement_wrapper( "PEL2_ACHIEVEMENT_TREE" );
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// monitor destructible tree for flame tree achievement
|
|
//
|
|
///////////////////////////////
|
|
|
|
dunes_flame_tree_achievement()
|
|
{
|
|
|
|
//level endon( "flame_tree_flamed" );
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
self waittill( "damage", amount, attacker, direction_vec, point, type );
|
|
|
|
type = tolower( type );
|
|
|
|
if( IsPlayer( attacker ) && type == "mod_burned" )
|
|
{
|
|
level.last_tree_attacker = attacker;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
tree_guy_flame_sound()
|
|
{
|
|
// TEMP!
|
|
temp_orig = spawn( "script_origin", self.origin );
|
|
temp_orig playsound( "body_burn_vo" );
|
|
|
|
temp_orig waittill( "body_burn_vo" );
|
|
|
|
temp_orig delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// handles much of the sanddune ambush
|
|
//
|
|
///////////////////////////////
|
|
|
|
trig_grass_admin_camo_guys()
|
|
{
|
|
|
|
simple_spawn( "grass_admin_camo_guys", ::grass_admin_camo_guys_strat );
|
|
wait_network_frame(); // CLIENTSIDE to help snapshot size
|
|
simple_spawn( "grass_admin_camo_guys_2", ::grass_admin_camo_guys_strat_2 );
|
|
wait_network_frame(); // CLIENTSIDE to help snapshot size
|
|
simple_spawn( "grass_admin_camo_guys_3", ::grass_admin_camo_guys_strat_3 );
|
|
|
|
// wait till player is close enough (flag set on trigger)
|
|
flag_wait( "trig_grass_admin_camo_guys");
|
|
|
|
flag_set( "grass_admin_surprise" );
|
|
|
|
battlechatter_on( "axis" );
|
|
|
|
level thread grass_ambush_vo_1();
|
|
|
|
array_thread( level.heroes, ::set_pacifist_off );
|
|
|
|
//Tuey Play another VO at grass location
|
|
playsoundatposition("japanese_yell_ambush", (2686.6, -5004, 135));
|
|
|
|
//Tuey Moved Music to ambush instead of on crashing plane
|
|
//TUEY Set's Music to BOMBER
|
|
setmusicstate("BOMBER");
|
|
|
|
waittill_aigroupcleared( "grass_admin_camo_ai" );
|
|
waittill_aigroupcleared( "tree_guy" );
|
|
|
|
flag_set( "grass_ambush_done" );
|
|
|
|
trig = getent( "trig_forest_end", "script_flag" );
|
|
if( isdefined( trig ) )
|
|
{
|
|
trig notify( "trigger" );
|
|
}
|
|
|
|
battlechatter_on();
|
|
|
|
set_color_chain( "trig_start_admin_delete" );
|
|
|
|
}
|
|
|
|
|
|
|
|
dune_flame_tree_guy_strat()
|
|
{
|
|
|
|
self.script_noteworthy = "dont_kill_me";
|
|
|
|
self setcandamage( false );
|
|
self disableaimassist();
|
|
self allowedstances ( "prone" );
|
|
self.a.pose = "prone";
|
|
self.ignoreme = 1;
|
|
self.ignoreall = 1;
|
|
self.pacifist = 1;
|
|
self.pacifistwait = 0.05;
|
|
self.activatecrosshair = false;
|
|
self.drawoncompass = false;
|
|
self.grenadeawareness = 0;
|
|
|
|
flag_wait( "trig_grass_admin_camo_guys_2" );
|
|
|
|
self setcandamage( true );
|
|
|
|
self allowedstances ( "crouch" );
|
|
self.a.pose = "crouch";
|
|
self enableaimassist();
|
|
self.activatecrosshair = true;
|
|
self.drawoncompass = true;
|
|
self.ignoreall = 0;
|
|
self.pacifist = 0;
|
|
|
|
self thread accuracy_increase_over_time();
|
|
|
|
wait( 3 );
|
|
|
|
self.ignoreme = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
accuracy_increase_over_time()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
old_accuracy = self.baseaccuracy;
|
|
|
|
self.baseaccuracy = 0.05;
|
|
|
|
while( self.baseaccuracy < old_accuracy )
|
|
{
|
|
self.baseaccuracy += 0.05;
|
|
wait( RandomIntRange( 3, 5 ) );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
grass_ambush_vo_1()
|
|
{
|
|
|
|
guys = get_ai_group_ai( "e3_extra_ai" );
|
|
redshirt_5 = level.extra_hero;
|
|
redshirt_6 = guys[0];
|
|
|
|
level.roebuck thread grass_ambush_vo_2();
|
|
|
|
flag_wait( "grass_admin_surprise" );
|
|
|
|
wait( 1 );
|
|
|
|
play_vo( redshirt_5, "vo", "roebuck_theyre_in" );
|
|
wait( 2.1 );
|
|
|
|
// tree guy is revealed
|
|
flag_wait( "trig_grass_admin_camo_guys_2" );
|
|
|
|
wait( 0.3 );
|
|
|
|
play_vo( level.polonsky, "vo", "up_there_in_tree" );
|
|
wait( 1.5 );
|
|
play_vo( level.polonsky, "vo", "shit!" );
|
|
|
|
flag_wait( "flame_tree_affects_grass" );
|
|
|
|
wait( 0.75 );
|
|
|
|
play_vo( level.polonsky, "vo", "more_of_them" );
|
|
|
|
flag_wait( "grass_ambush_done" );
|
|
|
|
wait( 1.5 );
|
|
|
|
//play_vo( redshirt_5, "vo", "fuckin_believe_that" );
|
|
//wait( 1.8 );
|
|
play_vo( level.polonsky, "vo", "just_waiting_for_us" );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
grass_ambush_vo_2()
|
|
{
|
|
|
|
flag_wait( "grass_admin_surprise" );
|
|
wait( 2.1 );
|
|
|
|
play_vo( self, "vo", "over_there_mumble" );
|
|
|
|
}
|
|
|
|
|
|
|
|
grass_admin_camo_guys_strat()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
// so kill_all_ai skips this guy
|
|
self.script_noteworthy = "dont_kill_me";
|
|
|
|
// keep him stealthy
|
|
self maps\pel2::init_ambush_fields();
|
|
|
|
// set flag(s) if he's damaged
|
|
self thread grass_admin_surprise_damage( "grass_admin_surprise_damage", "trig_grass_admin_camo_guys" );
|
|
|
|
flag_wait_either( "grass_admin_surprise", "grass_admin_surprise_damage" );
|
|
|
|
// stagger their emergence times if necessary
|
|
if( isdefined( self.script_float ) )
|
|
{
|
|
wait( self.script_float );
|
|
}
|
|
|
|
// make him active again
|
|
self maps\pel2::clear_ambush_fields();
|
|
|
|
self thread maps\pel2::grass_surprise_half_shield( 1.8 );
|
|
self thread maps\pel2::grass_camo_ignore_delay( 1.8 );
|
|
|
|
// choose which variant anim to use
|
|
prone_anim = maps\pel2::choose_prone_to_run_anim_variant();
|
|
level.animtimefudge = 0.05;
|
|
self play_anim_end_early( prone_anim, level.animtimefudge );
|
|
|
|
if( isdefined( self.script_noteworthy ) && self.script_noteworthy == "pel2_no_banzai" )
|
|
{
|
|
self allowedstances( "crouch" );
|
|
wait( RandomIntRange( 4, 7 ) );
|
|
}
|
|
|
|
self thread maps\_banzai::banzai_force();
|
|
|
|
}
|
|
|
|
|
|
|
|
grass_admin_camo_guys_strat_2()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
// so kill_all_ai skips this guy
|
|
self.script_noteworthy = "dont_kill_me";
|
|
|
|
// keep him stealthy
|
|
self maps\pel2::init_ambush_fields();
|
|
|
|
// set flag(s) if he's damaged
|
|
self thread grass_admin_surprise_damage( "admin_camo_guys_2_startled" );
|
|
self thread grass_admin_surprise_proximity();
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
if( flag( "flame_tree_flamed" ) || flag( "flame_tree_guy_dead" ) || flag( "admin_camo_guys_2_startled" ) || flag( "trig_forest_end" ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// if he's been damaged or player got in close proximity
|
|
if( self.pel2_startled )
|
|
{
|
|
break;
|
|
}
|
|
|
|
wait( 0.1 );
|
|
}
|
|
|
|
|
|
// if the tree was actually flamed, wait for the burning fronds to scorch the ground
|
|
if( flag( "flame_tree_flamed" ) && !self.pel2_startled )
|
|
{
|
|
wait( 3.5 );
|
|
}
|
|
// if the guy was killed any other way
|
|
else if( !self.pel2_startled )
|
|
{
|
|
wait( RandomFloatRange( 1.0, 1.7 ) );
|
|
}
|
|
|
|
flag_set( "flame_tree_affects_grass" );
|
|
|
|
// stagger their emergence times if necessary
|
|
if( isdefined( self.script_float ) && !self.pel2_startled )
|
|
{
|
|
wait( self.script_float );
|
|
}
|
|
|
|
// make him active again
|
|
self maps\pel2::clear_ambush_fields();
|
|
|
|
self thread maps\pel2::grass_surprise_half_shield( 2.4 );
|
|
self thread maps\pel2::grass_camo_ignore_delay( 2.4 );
|
|
|
|
// choose which variant anim to use
|
|
prone_anim = maps\pel2::choose_prone_to_run_anim_variant();
|
|
level.animtimefudge = 0.05;
|
|
self play_anim_end_early( prone_anim, level.animtimefudge );
|
|
|
|
self thread maps\_banzai::banzai_force();
|
|
|
|
}
|
|
|
|
|
|
|
|
grass_admin_camo_guys_strat_3()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
// so kill_all_ai skips this guy
|
|
self.script_noteworthy = "dont_kill_me";
|
|
|
|
// keep him stealthy
|
|
self maps\pel2::init_ambush_fields();
|
|
|
|
// set flag(s) if he's damaged
|
|
self thread grass_admin_surprise_damage();
|
|
self thread grass_admin_surprise_proximity();
|
|
|
|
while( 1 )
|
|
{
|
|
// if player moves up
|
|
if( flag( "trig_grass_admin_camo_guys_3" ) )
|
|
{
|
|
break;
|
|
}
|
|
// if he's been damaged
|
|
if( self.pel2_startled )
|
|
{
|
|
break;
|
|
}
|
|
|
|
wait( 0.1 );
|
|
}
|
|
|
|
// stagger their emergence times if necessary
|
|
if( !self.pel2_startled && isdefined( self.script_float ) )
|
|
{
|
|
wait( self.script_float );
|
|
}
|
|
|
|
// make him active again
|
|
self maps\pel2::clear_ambush_fields();
|
|
|
|
self thread maps\pel2::grass_surprise_half_shield( 2.4 );
|
|
self thread maps\pel2::grass_camo_ignore_delay( 1.25 );
|
|
|
|
// choose which variant anim to use
|
|
prone_anim = maps\pel2::choose_prone_to_run_anim_variant();
|
|
level.animtimefudge = 0.05;
|
|
self play_anim_end_early( prone_anim, level.animtimefudge );
|
|
|
|
wait( RandomFloatRange( 2.8, 4.5 ) );
|
|
|
|
self.banzai_no_wait = 1;
|
|
self.ignoresuppression = 1;
|
|
self thread maps\_banzai::banzai_force();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// sets flag(s) if guy has been damaged
|
|
//
|
|
///////////////////////////////
|
|
|
|
grass_admin_surprise_damage( flag_name, alt_flag_name )
|
|
{
|
|
|
|
level endon( "trig_ditch_guys" );
|
|
self endon( "clear_ambush_fields" );
|
|
|
|
self waittill( "damage", damage, attacker );
|
|
|
|
if( self.health <= 0 && isplayer( attacker ) )
|
|
{
|
|
attacker giveachievement_wrapper( "ANY_ACHIEVEMENT_GRASSJAP" );
|
|
}
|
|
|
|
if( isdefined( flag_name ) )
|
|
{
|
|
flag_set( flag_name );
|
|
}
|
|
if( isdefined( alt_flag_name ) )
|
|
{
|
|
flag_set( alt_flag_name );
|
|
}
|
|
|
|
self.pel2_startled = true;
|
|
|
|
}
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// checks if player(s) are near ambush guy
|
|
//
|
|
///////////////////////////////
|
|
grass_admin_surprise_proximity()
|
|
{
|
|
|
|
level endon( "trig_ditch_guys" );
|
|
self endon( "clear_ambush_fields" );
|
|
|
|
self endon( "death" );
|
|
|
|
startled = false;
|
|
|
|
while( !startled )
|
|
{
|
|
|
|
players = get_players();
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( distanceSquared( players[i].origin, self.origin ) < (125*125) )
|
|
{
|
|
startled = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( startled )
|
|
{
|
|
break;
|
|
}
|
|
|
|
wait( 0.5 );
|
|
|
|
}
|
|
|
|
self.pel2_startled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
admin_mg_guys()
|
|
{
|
|
//trigger_wait( "trig_admin_mg_guys", "script_noteworthy" );
|
|
flag_wait( "trig_grass_admin_camo_guys_3" );
|
|
wait( 1 );
|
|
|
|
simple_floodspawn( "admin_mg_guys", ::admin_mg_guys_strat );
|
|
wait_network_frame();
|
|
simple_floodspawn( "admin_bottom_right_spawners" );
|
|
}
|
|
|
|
|
|
|
|
admin_mg_guys_strat()
|
|
{
|
|
self endon( "death" );
|
|
self.ignoresuppression = true;
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// marines that join the player's squad in beginning of event 3
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_friendlies()
|
|
{
|
|
|
|
flag_wait( "trig_forest_friendlies" );
|
|
|
|
event_text( "forest_friendlies" );
|
|
|
|
guys = simple_spawn( "friend_forest_spawner", ::friend_forest_spawner_strat );
|
|
|
|
}
|
|
|
|
|
|
|
|
friend_forest_spawner_strat()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
self disable_replace_on_death();
|
|
|
|
wait( 0.5 ); // wait for simple_spawn to finish adding its own targetname so we can overwrite it
|
|
self.targetname = "friendly_squad";
|
|
|
|
flag_wait( "trig_flame_bunker_exit" );
|
|
|
|
self set_force_color( "y" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Drones on ridge to left in destroyed forest area
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_drones()
|
|
{
|
|
|
|
// start drones
|
|
trig = getent( "trig_forest_drones", "script_noteworthy" );
|
|
trig notify( "trigger" );
|
|
|
|
|
|
level waittill( "end_forest_drones" );
|
|
|
|
trig = getent( "trig_forest_drones_2", "script_noteworthy" );
|
|
trig notify( "trigger" );
|
|
|
|
extra_text( "forest_drones_2" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Spawn in the forest tanks on the ridge
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_tanks()
|
|
{
|
|
|
|
maps\_vehicle::create_vehicle_from_spawngroup_and_gopath( 31 );
|
|
|
|
wait( 0.05 );
|
|
|
|
level thread forest_tank_1_strat();
|
|
level thread forest_tank_2_strat();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Forest tank's strategy
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_tank_1_strat()
|
|
{
|
|
|
|
tank = getent( "forest_tank", "targetname" );
|
|
|
|
//tank RemoveVehicleFromCompass();
|
|
|
|
tank veh_stop_at_node( "forest_tank_1_stop", 6, 6 );
|
|
|
|
level notify( "end_forest_drones" );
|
|
|
|
wait( 1.5 );
|
|
|
|
tank resumespeed( 6 );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Forest tank's strategy
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_tank_2_strat()
|
|
{
|
|
|
|
tank = getent( "forest_tank_2", "targetname" );
|
|
|
|
//tank RemoveVehicleFromCompass();
|
|
|
|
tank veh_stop_at_node( "forest_tank_2_stop", 6, 6 );
|
|
|
|
wait( 5 );
|
|
|
|
tank resumespeed( 6 );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// birds that fly out of bushes
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_birds()
|
|
{
|
|
|
|
//bird_orig = getstruct( "orig_forest_birds", "targetname" );
|
|
bird_orig = (1632, -5736, -76 );
|
|
playfx( level._effect["birds_fly"], bird_orig );
|
|
|
|
wait( 0.6 );
|
|
|
|
//bird_orig = getstruct( "orig_forest_birds_2", "targetname" );
|
|
bird_orig = (2117, -6083, -76 );
|
|
playfx( level._effect["birds_fly"], bird_orig );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Bombers that precede the squadron that gets shot down
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_ambient_bombers()
|
|
{
|
|
|
|
wait( 0.3 ); // CLIENTSIDE to help snapshot size
|
|
|
|
plane_1 = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "forest_plane_4" );
|
|
plane_2 = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "forest_plane_5" );
|
|
plane_3 = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "forest_plane_6" );
|
|
|
|
plane_1 playloopsound( "bombers" );
|
|
plane_2 playloopsound( "bombers" );
|
|
plane_3 playloopsound( "bombers" );
|
|
|
|
level thread forest_ambient_aa();
|
|
level thread ambient_high_bombers();
|
|
|
|
}
|
|
|
|
|
|
|
|
forest_ambient_aa()
|
|
{
|
|
|
|
aa_gun = maps\_vehicle::spawn_vehicle_from_targetname( "aaGun_forest_1" );
|
|
aa_gun_2 = maps\_vehicle::spawn_vehicle_from_targetname( "aaGun_forest_2" );
|
|
aa_gun_3 = maps\_vehicle::spawn_vehicle_from_targetname( "aaGun_forest_3" );
|
|
|
|
aa_gun thread maps\pel2_airfield::aa_move_target( "aaGun_forest_1_target" );
|
|
wait( randomfloatrange( 0.5, 1.5 ) );
|
|
aa_gun_2 thread maps\pel2_airfield::aa_move_target( "aaGun_forest_2_target" );
|
|
wait( randomfloatrange( 0.5, 1.5 ) );
|
|
aa_gun_3 thread maps\pel2_airfield::aa_move_target( "aaGun_forest_3_target" );
|
|
|
|
|
|
flag_wait( "admin_back" );
|
|
|
|
// delete aa guns
|
|
aa_gun notify("change target");
|
|
wait( 0.05 );
|
|
aa_gun delete();
|
|
|
|
aa_gun_2 notify("change target");
|
|
wait( 0.05 );
|
|
aa_gun_2 delete();
|
|
|
|
aa_gun_3 notify("change target");
|
|
wait( 0.05 );
|
|
aa_gun_3 delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Enemies that are setting up a roadblock near between forest and admin building
|
|
//
|
|
///////////////////////////////
|
|
|
|
forest_mid()
|
|
{
|
|
|
|
// flag is set on trigger...
|
|
flag_wait( "trig_forest_mid" );
|
|
|
|
level thread ambush_squad_walk_to_chain();
|
|
set_color_chain( "chain_forest_banzai" );
|
|
|
|
// clean up old ai
|
|
level thread forest_ai_cleanup();
|
|
|
|
level thread admin_ai_pen();
|
|
|
|
// flag is set on trigger...
|
|
flag_wait( "trig_forest_end" );
|
|
|
|
level notify( "end_forest_drones_2" );
|
|
|
|
battlechatter_on();
|
|
|
|
players_speed_set( 1.0, 2.5 );
|
|
|
|
array_thread( level.heroes, ::set_pacifist_off );
|
|
|
|
level thread admin_truck_victim();
|
|
wait_network_frame();
|
|
level thread collectible_corpse();
|
|
|
|
// prepare for building battle
|
|
building_battle();
|
|
|
|
}
|
|
|
|
|
|
|
|
admin_truck_victim()
|
|
{
|
|
|
|
guy = simple_spawn_single( "admin_truck_victim" );
|
|
|
|
// he's not set to forcespawn, so his spawn could fail
|
|
if( !isdefined( guy ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
guy.ignoreme = true;
|
|
guy.animname = "stand";
|
|
//guy.deathanim = level.scr_anim["stand"]["explode_back13"];
|
|
guy.deathanim = level.scr_anim["stand"]["explode_stand_2"];
|
|
|
|
flag_wait( "admin_truck_exploded" );
|
|
|
|
guy dodamage( guy.health + 1, (0,0,0) );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Have guys walk to their chain nodes right before the ambush happens.
|
|
//
|
|
///////////////////////////////
|
|
|
|
ambush_squad_walk_to_chain()
|
|
{
|
|
|
|
allies = getaiarray( "allies" );
|
|
for( i = 0; i < allies.size; i++ )
|
|
{
|
|
allies[i].old_walkdist = allies[i].walkdist;
|
|
allies[i].walkdist = 10000;
|
|
allies[i].disableArrivals = true;
|
|
allies[i].disableExits = true;
|
|
}
|
|
|
|
flag_wait( "grass_admin_surprise" );
|
|
|
|
wait( 1.2 );
|
|
|
|
allies = getaiarray( "allies" );
|
|
for( i = 0; i < allies.size; i++ )
|
|
{
|
|
allies[i].walkdist = allies[i].old_walkdist;
|
|
allies[i].disableArrivals = false;
|
|
allies[i].disableExits = false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
forest_ai_cleanup()
|
|
{
|
|
|
|
quick_text( "kill all ai", 3, true );
|
|
kill_all_ai();
|
|
|
|
// take off their "friendly_squad" targetnames so kill_all_ai will kill them later on
|
|
forest_friendlies = get_ai_group_ai( "e3_extra_ai" );
|
|
for( i = 0; i < forest_friendlies.size; i++ )
|
|
{
|
|
forest_friendlies[i].targetname = "forest_friendly";
|
|
}
|
|
|
|
// take care of "fake dead" flamer
|
|
if( isdefined ( level.flamer ) && level.flamer.health )
|
|
{
|
|
|
|
level notify( "stop_flamer_fake_death" );
|
|
|
|
level.flamer notify( "stop_flamebunker_death_loop" );
|
|
|
|
level.flamer setcandamage( true );
|
|
level.flamer stop_magic_bullet_shield();
|
|
level.flamer dodamage( level.flamer.health + 1, (0,0,0) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Handles battle in/around large building
|
|
//
|
|
///////////////////////////////
|
|
|
|
building_battle()
|
|
{
|
|
|
|
flag_wait( "trig_ditch_guys" );
|
|
|
|
autosave_by_name( "Pel2 admin begin" );
|
|
|
|
maps\_debug::set_event_printname( "Admin Building" );
|
|
|
|
event_text( "ditch_guys" );
|
|
|
|
level notify ( "obj_forest_complete" );
|
|
|
|
// make heroes not damageable
|
|
for( i = 0; i < level.heroes.size; i++ )
|
|
{
|
|
level.heroes[i] setcandamage( false );
|
|
level.heroes[i] disable_ai_color();
|
|
}
|
|
|
|
level thread admin_heroes_initial_cover();
|
|
level thread spawn_admin_pickup_weapons();
|
|
|
|
set_color_chain( "color_admin_start" );
|
|
|
|
building_mgs();
|
|
|
|
e3_extras_break_off_chain();
|
|
|
|
wait_network_frame();
|
|
|
|
level.ditch_spawner_a = simple_spawn_single( "ditch_spawner_a", ::ditch_spawner_a_strat );
|
|
level.ditch_spawner_b = simple_spawn_single( "ditch_spawner_b", ::ditch_spawner_b_strat );
|
|
simple_spawn_single( "ditch_spawner_c", ::helmet_guy_strat );
|
|
|
|
wait_network_frame();
|
|
|
|
simple_spawn_single( "admin_bazooka", ::admin_bazooka_strat );
|
|
simple_spawn( "friend_admin_spawner" );
|
|
|
|
level thread building_battle_vo();
|
|
level thread admin_script_exploders();
|
|
level thread flame_guy_explode();
|
|
level thread bunker_last_spawners();
|
|
level thread building_axis_check();
|
|
level thread rifle_grenade_respawn();
|
|
|
|
// Wii optimizations
|
|
if( !level.wii )
|
|
{
|
|
level thread admin_extra_middle_spawner();
|
|
}
|
|
|
|
ambush_guys_restore_targetnames();
|
|
|
|
wait( 1.25 );
|
|
|
|
simple_floodspawn( "admin_mid_left_spawners" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// took this spawner off a dedicated trigger_radius spawn_trig and piggybacked it here to save an ent
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_extra_middle_spawner()
|
|
{
|
|
|
|
trigger_wait( "trig_admin_extra_middle_spawner", "script_noteworthy" );
|
|
|
|
wait( 1.25 );
|
|
|
|
simple_spawn_single( "admin_extra_middle_spawner" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// reset their targetnames (earlier were set to "dont_kill_me" so kill_all_ai() would work
|
|
//
|
|
///////////////////////////////
|
|
|
|
ambush_guys_restore_targetnames()
|
|
{
|
|
|
|
guys = get_ai_group_ai( "grass_admin_camo_ai" );
|
|
tree_guy = get_ai_group_ai( "tree_guy" );
|
|
guys = array_combine( guys, tree_guy );
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
guys[i].targetname = "dune_ambush_guy";
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
building_battle_vo()
|
|
{
|
|
|
|
//TUEY set custom bus to ADMIN
|
|
setbusstate("ADMIN");
|
|
|
|
play_vo( level.roebuck, "vo", "holed_up" );
|
|
|
|
// flag set on trigger
|
|
flag_wait( "helmet_shot_vignette" );
|
|
|
|
|
|
level thread battlechatter_off( "allies" );
|
|
play_vo( level.roebuck, "vo", "whats_the_skinny" );
|
|
|
|
wait( getanimlength( level.scr_anim["berm"]["berm_guy_2"] ) - 2.35 );
|
|
|
|
play_vo( level.roebuck, "vo", "roebuck_yeah" );
|
|
wait( 1.25 );
|
|
play_vo( level.roebuck, "vo", "supply_truck" );
|
|
wait( 2.0 );
|
|
play_vo( level.roebuck, "vo", "follow_me" );
|
|
wait( 1.75 );
|
|
battlechatter_on( "allies" );
|
|
|
|
//TUEY set custom bus to ADMIN
|
|
setbusstate("RESET");
|
|
|
|
level thread building_battle_vo_2();
|
|
|
|
// flag wait for going into building...
|
|
flag_wait( "trig_bunker_last_spawners" );
|
|
|
|
level thread battlechatter_off( "allies" );
|
|
play_vo( level.roebuck, "vo", "move_into_building" );
|
|
wait( 2 );
|
|
play_vo( level.roebuck, "vo", "dont_give_em" );
|
|
|
|
wait( 1.25 );
|
|
|
|
play_vo( level.roebuck, "vo", "clear_em" );
|
|
battlechatter_on( "allies" );
|
|
|
|
// when going up the stairs...
|
|
flag_wait( "friendly_chain_admin_last" );
|
|
|
|
|
|
level thread battlechatter_off( "allies" );
|
|
play_vo( level.roebuck, "vo", "nearly_there" );
|
|
wait( 1.8 );
|
|
play_vo( level.roebuck, "vo", "one_last_push" );
|
|
battlechatter_on( "allies" );
|
|
|
|
}
|
|
|
|
|
|
|
|
building_battle_vo_2()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "near_rifle_gren_box" );
|
|
|
|
level endon( "trig_bunker_last_spawners" );
|
|
|
|
battlechatter_off( "allies" );
|
|
|
|
play_vo( level.roebuck, "vo", "load_up_rifle_gren" );
|
|
wait( 2 );
|
|
play_vo( level.roebuck, "vo", "hell_yeah" );
|
|
|
|
battlechatter_on( "allies" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Have heroes take some special cover, then eventually get back on color chain
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_heroes_initial_cover()
|
|
{
|
|
|
|
nodes = getnodearray( "node_heroes_admin_initial", "targetname" );
|
|
assertex( nodes.size >= level.heroes.size, "not enough goal_nodes for admin initial heroes" );
|
|
|
|
for( i = 0; i < level.heroes.size; i++ )
|
|
{
|
|
level.heroes[i] thread admin_heroes_initial_cover_think( nodes[i] );
|
|
}
|
|
|
|
trigger_wait( "chain_heroes_admin_initial", "targetname" );
|
|
|
|
|
|
level notify( "end_admin_heroes_initial_cover_think" );
|
|
|
|
// put the heroes back on the chain
|
|
for( i = 0; i < level.heroes.size; i++ )
|
|
{
|
|
level.heroes[i] enable_ai_color();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// make them wait using script_delay like they normally would if the next chain weren't custom scripted
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_heroes_initial_cover_think( new_node )
|
|
{
|
|
|
|
level endon( "end_admin_heroes_initial_cover_think" );
|
|
|
|
if( isdefined( self.node ) && isdefined( self.node.script_delay ) )
|
|
{
|
|
wait( self.node.script_delay );
|
|
}
|
|
|
|
self setgoalnode( new_node );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin_script_exploders()
|
|
{
|
|
|
|
level thread wall_explode_damage( "exploder_400" );
|
|
//level thread wall_explode_damage( "exploder_401" );
|
|
level thread wall_explode_damage( "exploder_405" );
|
|
|
|
level thread mg_sandbags_explode();
|
|
level thread mg_sandbags_explode_2();
|
|
|
|
}
|
|
|
|
|
|
|
|
wall_explode_damage( trig_name )
|
|
{
|
|
|
|
level endon( "friendly_chain_admin_last" );
|
|
|
|
trigger_wait( trig_name, "targetname" );
|
|
|
|
orig = getstruct( "orig_" + trig_name, "targetname" );
|
|
|
|
radiusdamage( orig.origin, 120, 130, 80 );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Exploder stuff for admin center sandbag mg
|
|
//
|
|
///////////////////////////////
|
|
|
|
mg_sandbags_explode()
|
|
{
|
|
|
|
trig = getent( "trig_admin_sandbag_explode", "targetname" );
|
|
|
|
total_damage = 0;
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
trig waittill( "damage", damage, attacker, direction_vec, point, cause );
|
|
|
|
// if the attacker is a player
|
|
if( isplayer( attacker ) && damage > 220 )
|
|
{
|
|
|
|
total_damage += damage;
|
|
|
|
//quick_text( "sandbag dmg: " + damage + " total: " + total_damage, 4, true );
|
|
|
|
// set off the exploder chunks
|
|
exploder( 404 );
|
|
|
|
// delete bipod
|
|
brush = getent( "admin_sandbag_bipod", "targetname" );
|
|
brush delete();
|
|
|
|
// delete mg & kill its owner
|
|
mg_sandbag_cleanup( "admin_mg_l", 205 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
wait( 0.05 );
|
|
|
|
}
|
|
|
|
trig delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Exploder stuff for admin right sandbag mg
|
|
//
|
|
///////////////////////////////
|
|
|
|
mg_sandbags_explode_2()
|
|
{
|
|
|
|
trig = getent( "trig_admin_sandbag_explode_2", "targetname" );
|
|
|
|
total_damage = 0;
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
trig waittill( "damage", damage, attacker, direction_vec, point, cause );
|
|
|
|
// if the attacker is a player
|
|
if( isplayer( attacker ) && damage > 220 )
|
|
{
|
|
|
|
total_damage += damage;
|
|
|
|
//quick_text( "sandbag dmg: " + damage + " total: " + total_damage, 4, true );
|
|
|
|
// set off the exploder chunks
|
|
exploder( 406 );
|
|
|
|
// delete bipod
|
|
brush = getent( "admin_sandbag_bipod_2", "targetname" );
|
|
brush delete();
|
|
|
|
// delete mg & kill its owner
|
|
mg_sandbag_cleanup( "admin_mg_r", 206 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
wait( 0.05 );
|
|
|
|
}
|
|
|
|
trig delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
mg_killspawners()
|
|
{
|
|
|
|
trigger_wait( "admin_mg_killspawner", "targetname" );
|
|
|
|
maps\_spawner::kill_spawnernum( 205 );
|
|
maps\_spawner::kill_spawnernum( 206 );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// bazooka guy at berm that fires up at the admin building
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_bazooka_strat()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
self.ignoreme = true;
|
|
self setcandamage( false );
|
|
self.pacifist = true;
|
|
self.pacifistwait = 0.05;
|
|
self.ignoresuppression = true;
|
|
self.suppressionwait = 0;
|
|
self.grenadeawareness = 0;
|
|
|
|
self set_force_cover( "none" );
|
|
|
|
// flag set on trigger
|
|
flag_wait( "helmet_shot_vignette" );
|
|
|
|
orig_1 = getstruct( "orig_admin_bazooka_1", "targetname" );
|
|
orig_ent_1 = spawn( "script_origin", orig_1.origin );
|
|
orig_ent_1.health = 1000000; // so cover_behavior.gsc is happy
|
|
orig_2 = getstruct( "orig_admin_bazooka_2", "targetname" );
|
|
orig_ent_2 = spawn( "script_origin", orig_2.origin );
|
|
orig_ent_2.health = 1000000; // so cover_behavior.gsc is happy
|
|
|
|
origins = [];
|
|
origins[0] = orig_ent_1;
|
|
origins[1] = orig_ent_2;
|
|
|
|
orig_index = 0;
|
|
|
|
self SetEntityTarget( origins[orig_index] );
|
|
|
|
// give more rockets than default
|
|
self.a.rockets = 7;
|
|
|
|
starting_rockets = self.a.rockets;
|
|
|
|
while( 1 && !flag( "admin_back" ) && !flag( "berm_climb" ) )
|
|
{
|
|
|
|
// a rocket has been fired
|
|
if( starting_rockets != self.a.rockets )
|
|
{
|
|
|
|
self ClearEntityTarget();
|
|
|
|
wait( RandomIntRange( 6, 9 ) );
|
|
|
|
level thread bazooka_lookat_touching();
|
|
|
|
trig = getent( "trig_bazooka_lookat", "targetname" );
|
|
trig waittill( "trigger" );
|
|
|
|
// if event is over, don't fire on building
|
|
if( flag( "top_floor_retreat" ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
orig_index = !orig_index;
|
|
self SetEntityTarget( origins[orig_index] );
|
|
starting_rockets = self.a.rockets;
|
|
|
|
}
|
|
|
|
if( !self.a.rockets )
|
|
{
|
|
break;
|
|
}
|
|
|
|
wait( 0.5 );
|
|
|
|
}
|
|
|
|
self setcandamage( true );
|
|
|
|
self ClearEntityTarget();
|
|
|
|
orig_ent_1 delete();
|
|
orig_ent_2 delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
bazooka_lookat_touching()
|
|
{
|
|
|
|
level endon( "friendly_chain_admin_last" );
|
|
|
|
trig = getent( "trig_bazooka_lookat", "targetname" );
|
|
|
|
wait( 0.05 );
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
if( any_player_IsTouching( trig ) )
|
|
{
|
|
quick_text( "inside bazooka lookat", 3, true );
|
|
trig notify( "trigger" );
|
|
break;
|
|
}
|
|
|
|
wait( 0.25 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// behavior for admin mgs
|
|
//
|
|
///////////////////////////////
|
|
|
|
building_mgs()
|
|
{
|
|
|
|
// so guys don't hop off
|
|
turret = getent( "admin_mg_r", "targetname" );
|
|
turret setturretignoregoals( true );
|
|
|
|
turret setTurretTeam( "axis" );
|
|
turret SetMode( "auto_nonai" );
|
|
turret thread maps\_mgturret::burst_fire_unmanned();
|
|
|
|
turret thread mg_fire_at_truck();
|
|
level thread building_mg_attack_player_in_open();
|
|
|
|
turret = getent( "admin_mg_l", "targetname" );
|
|
turret setturretignoregoals( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
building_mg_attack_player_in_open()
|
|
{
|
|
|
|
level endon( "trig_bunker_last_spawners" );
|
|
|
|
flag_wait( "admin_mg_done" );
|
|
|
|
vol = getent( "vol_admin_attack_player", "targetname" );
|
|
player_being_targeted = false;
|
|
|
|
// old_bias_number = undefined;
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
player_touching = get_player_touching( vol );
|
|
|
|
turret = getent( "admin_mg_r", "targetname" );
|
|
// turret may have been destroyed by rifle grenade
|
|
if( !isdefined( turret ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// if a player is in the volume
|
|
if( isdefined( player_touching ) )
|
|
{
|
|
|
|
mg_owner = turret getturretowner();
|
|
|
|
// if there is a guy on the turret
|
|
if( isdefined( mg_owner ) )
|
|
{
|
|
|
|
// turning this off; threat bias on the guy doesn't seem to do anything if he's on an auto_ai turret
|
|
// have admin_mg_left_threat_group pay more attention to players
|
|
// old_bias_number = GetThreatBias( "players", "admin_mg_left_threat_group" );
|
|
// setthreatbias( "players", "admin_mg_left_threat_group", 30000 );
|
|
// setthreatbias( "heroes", "admin_mg_left_threat_group", 0 );
|
|
|
|
// mg_owner.pacifist = true;
|
|
turret SetTargetEntity( player_touching );
|
|
|
|
player_being_targeted = true;
|
|
|
|
}
|
|
|
|
}
|
|
// if he was being targeted, but left the volume, put the threat back to its original value
|
|
else if( !isdefined( player_touching ) && player_being_targeted )
|
|
{
|
|
|
|
// setthreatbias( "players", "admin_mg_left_threat_group", old_bias_number );
|
|
// mg_owner = turret getturretowner();
|
|
// if( isdefined( mg_owner ) )
|
|
// {
|
|
// mg_owner.pacifist = false;
|
|
// }
|
|
|
|
turret cleartargetentity();
|
|
player_being_targeted = false;
|
|
}
|
|
|
|
|
|
if( player_being_targeted )
|
|
{
|
|
wait( 3 );
|
|
}
|
|
else
|
|
{
|
|
wait( 1 );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mg_fire_at_truck()
|
|
{
|
|
|
|
orig = getent( "admin_truck_target", "targetname" );
|
|
level thread flame_move_target( orig, 4 );
|
|
|
|
quick_text( "mg on orig", 3, true );
|
|
|
|
self SetTargetEntity( orig );
|
|
|
|
wait( 3 );
|
|
|
|
level thread truck_blocker_explode( self );
|
|
|
|
wait( 10 );
|
|
|
|
quick_text( "mg done", 3, true );
|
|
|
|
self cleartargetentity();
|
|
wait( 2 );
|
|
self SetMode( "auto_ai" );
|
|
//self notify( "death" );
|
|
|
|
flag_set( "admin_mg_done" );
|
|
|
|
}
|
|
|
|
|
|
|
|
truck_blocker_explode( turret )
|
|
{
|
|
|
|
truck = getent( "admin_truck", "script_noteworthy" );
|
|
|
|
while( !truck.exploded )
|
|
{
|
|
wait( 0.05 );
|
|
}
|
|
|
|
earthquake( 0.3, 1.25, truck.origin , 1300 );
|
|
|
|
flag_set( "admin_truck_exploded" );
|
|
|
|
}
|
|
|
|
|
|
|
|
flame_guy_explode()
|
|
{
|
|
|
|
flamer = simple_spawn_single( "admin_flamer_guy" );
|
|
|
|
flamer.targetname = "friendly_squad";
|
|
flamer.goalradius = 30;
|
|
flamer.pacifist = true;
|
|
flamer.pacifistwait = 0.05;
|
|
flamer.ignoreme = true;
|
|
//flamer.ignoresuppression = true;
|
|
flamer.dropweapon = false;
|
|
flamer setcandamage( false );
|
|
flamer thread magic_bullet_shield();
|
|
|
|
goal = getnode( "node_berm_flame_cover_2", "targetname" );
|
|
|
|
flamer setgoalnode( goal );
|
|
flamer waittill( "goal" );
|
|
|
|
BadPlacesEnable( 0 );
|
|
|
|
flamer thread flamer_fire_towards_building();
|
|
|
|
// waittill player moves forward enough
|
|
trigger_wait( "trig_flamer_explode_ready", "targetname" );
|
|
|
|
level thread trig_override( "trig_flamer_explode_lookat" );
|
|
// wait for player to look in the flamer guy's direction
|
|
trigger_wait( "trig_flamer_explode_lookat", "targetname" );
|
|
|
|
quick_text( "flamer death", 3.5, true );
|
|
|
|
level notify( "stop_flamer_target_building" );
|
|
flamer ClearEntityTarget();
|
|
flamer StopShoot();
|
|
|
|
// play initial tank explosion
|
|
playfx( level._effect["flamer_explosion"], flamer.origin );
|
|
playsoundatposition ("flame_pre_explosion", flamer.origin);
|
|
|
|
// fire that spawns on the guy & charring behavior
|
|
flamer thread animscripts\death::flame_death_fx();
|
|
|
|
flamer.animname = "berm";
|
|
level thread anim_single_solo( flamer, "flamer_death", undefined, flamer );
|
|
|
|
wait( 2.5 );
|
|
|
|
// play second tank explosion
|
|
playfx( level._effect["flamer_explosion"], flamer.origin );
|
|
earthquake( 0.5, 1.0, flamer.origin, 1700 );
|
|
PlayRumbleOnPosition( "explosion_generic", flamer.origin );
|
|
|
|
playsoundatposition ("flame_explosion", flamer.origin);
|
|
flamer stop_magic_bullet_shield();
|
|
flamer setcandamage( true );
|
|
flamer.allowdeath = 1;
|
|
|
|
// so he always gibs
|
|
flamer.a.gib_ref = "right_leg";
|
|
flamer.deathanim = level.scr_anim["berm"]["flamer_death_2"];
|
|
flamer dodamage( flamer.health + 50, (0,0,0) );
|
|
|
|
BadPlacesEnable( 1 );
|
|
|
|
// delete aim origin that the flamer was targeting
|
|
aim_origin = getent( "orig_flamer_target_admin_converted", "targetname" );
|
|
aim_origin delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
flamer_fire_towards_building()
|
|
{
|
|
|
|
self.ignoresuppression = 1;
|
|
|
|
fire_spot = convert_aiming_struct_to_origin( "orig_flamer_target_admin" );
|
|
self thread flame_burst_admin( fire_spot, "stop_flamer_target_building" );
|
|
|
|
}
|
|
|
|
|
|
|
|
flame_burst_admin( fire_spot, flag_notify )
|
|
{
|
|
|
|
level endon( flag_notify );
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
self SetEntityTarget( fire_spot );
|
|
wait( RandomFloatRange( 3.5, 4.5 ) );
|
|
self ClearEntityTarget();
|
|
self StopShoot();
|
|
wait( RandomFloatRange( 1.2, 1.9 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// if building is cleared out, have berm guys climb over and advance
|
|
//
|
|
///////////////////////////////
|
|
|
|
building_axis_check()
|
|
{
|
|
|
|
level endon( "trig_bunker_last_spawners" );
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
wait( 1 );
|
|
|
|
// if building is mostly cleared out, have berm guys climb over and advance
|
|
if ( axis_in_building() < 3 && get_ai_group_ai( "admin_mg_ai" ).size == 0 )
|
|
{
|
|
// check this just in case
|
|
if( !flag( "berm_climb" ) )
|
|
{
|
|
level thread berm_ai_climb();
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Returns the number of alive axis is touching the trigger volume
|
|
//
|
|
///////////////////////////////
|
|
|
|
axis_in_building()
|
|
{
|
|
|
|
trig = getent( "trig_admin_building_volume", "targetname" );
|
|
guys = getaiarray( "axis" );
|
|
|
|
axis_count = 0;
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
// if there is an axis alive inside the trigger
|
|
if( guys[i] istouching( trig ) )
|
|
{
|
|
axis_count++;
|
|
}
|
|
}
|
|
|
|
|
|
return axis_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Remove extra dudes from color chain and send them behind berm
|
|
//
|
|
///////////////////////////////
|
|
|
|
e3_extras_break_off_chain()
|
|
{
|
|
|
|
guys = get_ai_group_ai( "e3_extra_ai" );
|
|
nodes = getnodearray( "node_berm_extra", "targetname" );
|
|
assertex( nodes.size >= guys.size, "not enough goal_nodes for e3_extras" );
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
guys[i] thread e3_extras_break_off_strat( nodes[i] );
|
|
}
|
|
|
|
level thread e3_extras_break_off_strat_2();
|
|
|
|
}
|
|
|
|
|
|
|
|
e3_extras_break_off_strat( goal_node )
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
// emulate script_wait behavior that automatically works on color chains
|
|
if( isdefined( self.node ) && isdefined( self.node.script_delay ) )
|
|
{
|
|
wait( self.node.script_delay );
|
|
}
|
|
|
|
self disable_ai_color();
|
|
|
|
// this flag will probably never be hit before the above node wait, but check just in case so their goalnode behavior doesn't get messed up
|
|
if( !flag( "friendly_chain_admin_3" ) )
|
|
{
|
|
self.ignoreme = true;
|
|
self setgoalnode( goal_node );
|
|
|
|
self waittill( "goal" );
|
|
|
|
self.ignoreme = false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// send them back up to the berm once player is far enough into the event
|
|
//
|
|
///////////////////////////////
|
|
|
|
e3_extras_break_off_strat_2()
|
|
{
|
|
|
|
flag_wait( "friendly_chain_admin_3" );
|
|
|
|
guys = get_ai_group_ai( "e3_extra_ai" );
|
|
nodes = getnodearray( "node_berm_extra_2", "script_noteworthy" );
|
|
assertex( nodes.size >= guys.size, "not enough goal_nodes for e3_extras" );
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
guys[i] setgoalnode( nodes[i] );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Cluster color reinforcements before letting them join the battle
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_ai_pen()
|
|
{
|
|
|
|
level endon( "friendly_chain_admin_last" );
|
|
|
|
trigger_wait( "trigger_admin_wave", "script_noteworthy" );
|
|
|
|
flag_set( "trig_ditch_guys" );
|
|
|
|
trig_pen = getent( "trig_admin_ai_pen", "targetname" );
|
|
pen_brush = getent( "blocker_admin_ai", "targetname" );
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
// get alive color spawners
|
|
guys = get_specific_ai( "friend_admin_ai" );
|
|
guys_to_send_out = [];
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
|
|
// check if they're touching the trig
|
|
if( guys[i] istouching( trig_pen ) )
|
|
{
|
|
|
|
guys_to_send_out[guys_to_send_out.size] = guys[i];
|
|
|
|
// if enough guys are touching
|
|
if( guys_to_send_out.size >= 2 )
|
|
{
|
|
|
|
// turn off brush so they can get out
|
|
pen_brush notsolid();
|
|
pen_brush connectpaths();
|
|
|
|
array_thread( guys_to_send_out, ::admin_ai_pen_strat );
|
|
|
|
wait( 4.5 );
|
|
|
|
// turn its collision back on
|
|
pen_brush solid();
|
|
pen_brush disconnectpaths();
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
wait( 1 );
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Strategy for admin color reinforcements
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_ai_pen_strat()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
// don't let him die without a color set, otherwise no one will spawn in to take his place...
|
|
self setcandamage( false );
|
|
|
|
// force him to run out, even if no color chain nodes are open
|
|
self disable_ai_color();
|
|
self setgoalpos( ( 1706, -2424, -115.2 ) );
|
|
|
|
self.ignoresuppression = 1;
|
|
self.ignoreme = 1;
|
|
|
|
wait( 3.5 );
|
|
|
|
// put him back on the color chain
|
|
self enable_ai_color();
|
|
self.ignoresuppression = 0;
|
|
|
|
// wait till he gets to better cover, so mgs don't tear him up right away
|
|
wait( 3 );
|
|
self.ignoreme = 0;
|
|
self setcandamage( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Berm guy A
|
|
//
|
|
///////////////////////////////
|
|
|
|
ditch_spawner_a_strat()
|
|
{
|
|
|
|
self thread magic_bullet_shield();
|
|
|
|
self.goalradius = 200;
|
|
self.ignoreme = 1;
|
|
self.animname = "berm";
|
|
|
|
goal_node = getnode( "node_berm_a", "targetname" );
|
|
|
|
self thread anim_loop_solo( self, "berm_guy_1_idle", undefined, "stop_berm_idle", goal_node );
|
|
|
|
// flag set on trigger
|
|
flag_wait( "helmet_shot_vignette" );
|
|
|
|
// so roebuck's VO can have a chance to play first
|
|
wait( 0.4 );
|
|
|
|
self notify( "stop_berm_idle" );
|
|
|
|
anim_single_solo( self, "berm_guy_1", undefined, goal_node );
|
|
|
|
self stop_magic_bullet_shield();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Berm guy B
|
|
//
|
|
///////////////////////////////
|
|
|
|
ditch_spawner_b_strat()
|
|
{
|
|
|
|
self thread magic_bullet_shield();
|
|
|
|
self.goalradius = 200;
|
|
self.ignoreme = 1;
|
|
self.animname = "berm";
|
|
|
|
goal_node = getnode( "node_berm_a", "targetname" );
|
|
|
|
self thread anim_loop_solo( self, "berm_guy_2_idle", undefined, "stop_berm_idle", goal_node );
|
|
|
|
// flag set on trigger
|
|
flag_wait( "helmet_shot_vignette" );
|
|
|
|
// so roebuck's VO can have a chance to play first
|
|
wait( 0.4 );
|
|
|
|
self notify( "stop_berm_idle" );
|
|
|
|
anim_single_solo( self, "berm_guy_2", undefined, goal_node );
|
|
|
|
self stop_magic_bullet_shield();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Helmet shot guy behavior
|
|
//
|
|
///////////////////////////////
|
|
|
|
helmet_guy_strat()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
self.goalradius = 200;
|
|
self.ignoreme = 1;
|
|
self.animname = "berm";
|
|
|
|
goal_node = getnode( "node_berm_c", "targetname" );
|
|
|
|
self thread helmet_vignette_trig();
|
|
|
|
self thread anim_loop_solo( self, "helmet_loop", undefined, "stop_helmet_loop", goal_node );
|
|
|
|
// flag set on trigger
|
|
flag_wait( "helmet_shot_vignette" );
|
|
|
|
self notify( "stop_helmet_loop" );
|
|
|
|
quick_text( "helmet shot", 3.5, true );
|
|
|
|
self allowedstances( "crouch" );
|
|
|
|
anim_single_solo( self, "helmet_shot", undefined, goal_node );
|
|
|
|
level notify( "helmet_shot_done" );
|
|
|
|
self.allowdeath = 1;
|
|
|
|
level thread anim_loop_solo( self, "helmet_loop", undefined, "stop_berm_idle", goal_node );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// When to trigger the helmet shot anim
|
|
//
|
|
///////////////////////////////
|
|
|
|
helmet_vignette_trig()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "helmet_shot_vignette" );
|
|
self allowedstances( "prone", "crouch", "stand" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Spawners near back room on first floor
|
|
//
|
|
///////////////////////////////
|
|
|
|
bunker_last_spawners()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "trig_bunker_last_spawners" );
|
|
|
|
quick_text( "bunker_last_spawners", 2, true );
|
|
|
|
autosave_by_name( "pel2 admin last spawners" );
|
|
|
|
level notify( "stop_admin_mgs" );
|
|
|
|
// make heroes damageable
|
|
for( i = 0; i < level.heroes.size; i++ )
|
|
{
|
|
level.heroes[i] setcandamage( true );
|
|
}
|
|
|
|
simple_spawn( "bunker_last_spawners" );
|
|
wait_network_frame();
|
|
simple_spawn_single( "friend_admin_spawner_2" );
|
|
wait_network_frame(); // CLIENTSIDE to help snapshot size
|
|
simple_spawn( "admin_2nd_floor_extra_spawners" );
|
|
|
|
level thread bunker_last_ai_monitor();
|
|
level thread admin_back();
|
|
level thread far_right_ai_retreat();
|
|
level thread top_floor_retreat();
|
|
level thread maps\pel2_airfield::airfield_vo();
|
|
|
|
if( !flag( "berm_climb" ) )
|
|
{
|
|
level thread berm_ai_climb();
|
|
}
|
|
|
|
// delete old friendly chains
|
|
delete_noteworthy_ents( "friendly_chain_admin_2" );
|
|
|
|
flag_wait_either( "top_floor_retreat", "bunker_last_ai_dead" );
|
|
|
|
flag_set( "friendly_chain_admin_last" );
|
|
quick_text( "friendly_chain_admin_last", 1.5, true );
|
|
|
|
// killspawn for mg spawners if the mgs weren't blown up by the rifle grenade
|
|
maps\_spawner::kill_spawnernum( 205 );
|
|
maps\_spawner::kill_spawnernum( 206 );
|
|
|
|
level thread guys_ascend_admin_stairs();
|
|
|
|
//Tuey Change Music State
|
|
setmusicstate("POST_ADMIN");
|
|
|
|
// remove pen brush; all guys should be allowed to advance now no matter what
|
|
pen_brush = getent( "blocker_admin_ai", "targetname" );
|
|
pen_brush notsolid();
|
|
pen_brush connectpaths();
|
|
|
|
// delete old friendly chains
|
|
delete_noteworthy_ents( "friendly_chain_admin_3" );
|
|
|
|
airfield_first_read();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// handles getting the squad up the stairs smoothly
|
|
//
|
|
///////////////////////////////
|
|
|
|
guys_ascend_admin_stairs()
|
|
{
|
|
|
|
// stop reinforcements for now
|
|
// trig = getent( "friendly_respawn_clear_admin", "script_noteworthy" );
|
|
// trig notify( "trigger" );
|
|
|
|
level thread admin_staircase_run_cycle();
|
|
|
|
// move guys upstairs
|
|
set_color_chain( "friendly_chain_admin_last" );
|
|
|
|
nodes = getnodearray( "nodes_admin_first_floor", "targetname" );
|
|
allies = getaiarray( "allies" );
|
|
green_allies = [];
|
|
|
|
for( i = 0; i < allies.size; i++ )
|
|
{
|
|
if( isdefined( allies[i].script_forcecolor ) && allies[i].script_forcecolor == "g" )
|
|
{
|
|
green_allies = add_to_array( green_allies, allies[i] );
|
|
}
|
|
}
|
|
|
|
|
|
assertex( nodes.size >= green_allies.size, "more guys than admin nodes!" );
|
|
|
|
for( i = 0; i < green_allies.size; i++ )
|
|
{
|
|
green_allies[i].goalradius = 20;
|
|
green_allies[i] disable_ai_color();
|
|
green_allies[i] setgoalnode( nodes[i] );
|
|
green_allies[i] thread staircase_wait_thread();
|
|
}
|
|
|
|
|
|
// player entered room with staircase
|
|
flag_wait( "trig_admin_near_staircase" );
|
|
|
|
set_color_chain( "friendly_chain_admin_last" );
|
|
|
|
for( i = 0; i < green_allies.size; i++ )
|
|
{
|
|
if( isdefined( green_allies[i] ) && isalive( green_allies[i] ) )
|
|
{
|
|
green_allies[i] thread staircase_dont_bunch_up();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// determines when to put the guys back on the color chain, which will make them run up the stairs.
|
|
//
|
|
///////////////////////////////
|
|
|
|
staircase_dont_bunch_up()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
// while( 1 )
|
|
//if this flag is hit, set everyone to run the stairs up regardless of waiting
|
|
while( !flag( "move_wave_2_1" ) )
|
|
{
|
|
|
|
// make sure he's made it to his first floor goal, and that no one else is heading towards the stairs
|
|
if( isdefined( self.pel2_staircase_wait ) && !level.guy_going_towards_stairs && no_guys_going_to_stairs_nearby( self ) && vol_near_staircase_clear() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
wait( 0.1 );
|
|
}
|
|
|
|
self.this_guy_going_towards_stairs = true;
|
|
level.guy_going_towards_stairs = true;
|
|
level thread guy_going_towards_stairs_falsify_delay();
|
|
|
|
self enable_ai_color();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// help space out how often the guys can go up the staircase by using a mandatory delay
|
|
//
|
|
///////////////////////////////
|
|
|
|
guy_going_towards_stairs_falsify_delay()
|
|
{
|
|
|
|
wait( 1.5 );
|
|
level.guy_going_towards_stairs = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// each guy that's waiting to go up the stairs will check if anyone else around him is going before he himself can go
|
|
//
|
|
///////////////////////////////
|
|
|
|
no_guys_going_to_stairs_nearby( guy )
|
|
{
|
|
|
|
allies = getaiarray( "allies" );
|
|
green_allies = [];
|
|
|
|
for( i = 0; i < allies.size; i++ )
|
|
{
|
|
if( isdefined( allies[i].script_forcecolor ) && allies[i].script_forcecolor == "g" )
|
|
{
|
|
green_allies = add_to_array( green_allies, allies[i] );
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < green_allies.size; i++ )
|
|
{
|
|
|
|
if( green_allies[i] == guy )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if a guy is going to the stairs and is close to guy, then return false so guy doesn't attempt to go up the stairs
|
|
if( distancesquared( guy.origin, green_allies[i].origin ) < (190*190) )
|
|
{
|
|
if( isdefined( green_allies[i].this_guy_going_towards_stairs ) && green_allies[i].this_guy_going_towards_stairs )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// no one nearby is attempting to run up the stairs
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// returns true if no one is near the base of the stairs, meaning it's clear to go towards
|
|
//
|
|
///////////////////////////////
|
|
|
|
vol_near_staircase_clear()
|
|
{
|
|
|
|
guys = getAIarrayTouchingVolume( "allies", "vol_near_staircase" );
|
|
|
|
if( guys.size )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// sets a field once the guy has reached his first floor goal near the staircase
|
|
//
|
|
///////////////////////////////
|
|
|
|
staircase_wait_thread()
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
self waittill( "goal" );
|
|
|
|
self.pel2_staircase_wait = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// guys use special run cycle on stairs
|
|
//
|
|
///////////////////////////////
|
|
|
|
admin_staircase_run_cycle()
|
|
{
|
|
|
|
trig = getent( "trig_admin_stairs", "targetname" );
|
|
while( 1 )
|
|
{
|
|
|
|
trig waittill( "trigger", triggerer );
|
|
if( !isdefined( triggerer.pel2_on_stairs ) )
|
|
{
|
|
triggerer thread on_stairs_strat( trig );
|
|
triggerer.pel2_on_stairs = true;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// this thread is run on the guy as soon as he hits the stairway trigger
|
|
//
|
|
///////////////////////////////
|
|
|
|
on_stairs_strat( trig )
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
self.animname = "stairs";
|
|
self set_run_anim( "run_up_stairs" );
|
|
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
// determine when he's finished traversing the staircase
|
|
if( !(self istouching( trig ) ) )
|
|
{
|
|
|
|
self clear_run_anim();
|
|
|
|
self.this_guy_going_towards_stairs = false;
|
|
|
|
if ( self == level.roebuck )
|
|
{
|
|
level.roebuck set_generic_run_anim( "roebuck_run", true );
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
wait( 0.05 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// sets a flag when bunker_last_ai aigroup has been killed
|
|
//
|
|
///////////////////////////////
|
|
|
|
bunker_last_ai_monitor()
|
|
{
|
|
waittill_aigroupcleared( "bunker_last_ai" );
|
|
flag_set( "bunker_last_ai_dead" );
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Few marines climb over berm and assault admin building head on
|
|
//
|
|
///////////////////////////////
|
|
|
|
berm_ai_climb()
|
|
{
|
|
|
|
flag_set( "berm_climb" );
|
|
|
|
quick_text( "jump over berm", undefined, true );
|
|
|
|
// remove blocker so guys can climb berm
|
|
blocker = getent( "blocker_admin_berm", "targetname" );
|
|
blocker notsolid();
|
|
blocker connectpaths();
|
|
|
|
helmet_brush = getent( "blocker_admin_helmet", "targetname" );
|
|
helmet_brush notsolid();
|
|
helmet_brush connectpaths();
|
|
|
|
nodes = getnodearray( "node_berm_over", "script_noteworthy" );
|
|
guys = get_ai_group_ai( "berm_ai" );
|
|
assertex( nodes.size >= guys.size, "not enough nodes for berm_ai!" );
|
|
|
|
temp_goal = ( 2330, -1954, 12.1 );
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
guys[i] setgoalpos( temp_goal );
|
|
guys[i] thread berm_ai_climb_helper( nodes[i] );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
berm_ai_climb_helper( goal_node )
|
|
{
|
|
self.ignoresuppression = 1;
|
|
self.ignoreall = 1;
|
|
self.goalradius = 50;
|
|
self waittill( "goal" );
|
|
|
|
self setgoalnode( goal_node );
|
|
self waittill( "goal" );
|
|
|
|
self.ignoresuppression = 0;
|
|
self.ignoreall = 0;
|
|
self.goalradius = 400;
|
|
}
|
|
|
|
|
|
|
|
admin_back()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "trig_admin_back" );
|
|
|
|
autosave_by_name( "pel2 admin back" );
|
|
|
|
flag_set( "admin_back" );
|
|
|
|
level thread maps\pel2_airfield::airfield_mortars();
|
|
level thread maps\pel2_airfield::aa_ambient_fire();
|
|
|
|
wait( 1 );
|
|
|
|
set_color_chain( "chain_admin_back" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Handles the initial read of the airfield
|
|
//
|
|
///////////////////////////////
|
|
|
|
airfield_first_read()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "trig_airfield_first_read" );
|
|
|
|
// cleanup ai
|
|
kill_admin_ai();
|
|
|
|
maps\pel2_airfield::main();
|
|
|
|
}
|
|
|
|
|
|
|
|
kill_admin_ai()
|
|
{
|
|
|
|
//axis
|
|
kill_aigroup( "bunker_far_right_ai" );
|
|
kill_aigroup( "admin_left_ai" );
|
|
kill_aigroup( "admin_mid_ai" );
|
|
kill_aigroup( "admin_mid_left_ai" );
|
|
kill_aigroup( "admin_3rd_floor_ai" );
|
|
kill_aigroup( "grass_admin_camo_ai" );
|
|
|
|
//allies
|
|
kill_aigroup( "e3_extra_ai" );
|
|
kill_aigroup( "berm_ai" );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Get 2nd floor admin axis to retreat out the back (and get deleted)
|
|
//
|
|
///////////////////////////////
|
|
|
|
top_floor_retreat()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "trig_top_floor_retreat" );
|
|
|
|
flag_set( "top_floor_retreat" );
|
|
|
|
guys = get_ai_group_ai( "admin_mg_ai" );
|
|
guys_2 = get_ai_group_ai( "admin_2nd_floor_ai" );
|
|
guys = array_combine( guys, guys_2 );
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
guys[i] thread top_floor_retreat_strat( i );
|
|
}
|
|
|
|
// bazooka guy may have been waiting to fire. notify the lookat trig one last time and then delete it
|
|
trig = getent( "trig_bazooka_lookat", "targetname" );
|
|
trig notify( "trigger" );
|
|
|
|
wait( 0.05 );
|
|
|
|
trig delete();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
top_floor_retreat_strat( index )
|
|
{
|
|
|
|
self endon( "death" );
|
|
|
|
self.goalradius = 30;
|
|
// self.pacifist = 1;
|
|
self.ignoresuppression = 1;
|
|
self StopUSeturret();
|
|
|
|
if( index%2 )
|
|
{
|
|
goal = getnode( "node_admin_retreat_top_1", "targetname" );
|
|
}
|
|
else
|
|
{
|
|
goal = getnode( "node_admin_retreat_top_2", "targetname" );
|
|
}
|
|
|
|
|
|
self setgoalnode( goal );
|
|
|
|
self waittill( "goal" );
|
|
|
|
self delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// Guys on the far right retreat back into the admin building when the player is on the far left
|
|
//
|
|
///////////////////////////////
|
|
|
|
far_right_ai_retreat()
|
|
{
|
|
|
|
extra_text( "far_right_ai_retreat" );
|
|
|
|
guys = get_ai_group_ai( "bunker_far_right_ai" );
|
|
|
|
for( i = 0; i < guys.size; i++ )
|
|
{
|
|
guys[i].goalradius = 300;
|
|
|
|
goal_pos = ( ( 3000, -1386, 37 ) );
|
|
guys[i] setgoalpos( goal_pos );
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// The plane in the middle of the airfield crashes there at the building of e4
|
|
//
|
|
///////////////////////////////
|
|
#using_animtree ("pel2_truck_crash");
|
|
bomber_crash()
|
|
{
|
|
|
|
// flag set on trigger
|
|
flag_wait( "trig_forest_plane_crash" );
|
|
|
|
plane_1 = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "forest_plane_1" );
|
|
plane_2 = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "forest_plane_2" );
|
|
// plane that crashes
|
|
wait_network_frame();
|
|
crash_plane = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "airfield_crash_plane" );
|
|
|
|
//Tuey - Changed these to loops
|
|
plane_1 playloopsound( "bombers" );
|
|
plane_2 playloopsound( "bombers" );
|
|
|
|
//Tuey - Scripted sounds to plane so that it moves with it
|
|
crash_plane playsound("bomber_die_scripted");
|
|
crash_plane playloopsound( "bombers_bass");
|
|
|
|
//Tuey - Added shockwave effect to the explosion to get you to turn around.
|
|
|
|
level thread maps\pel2_amb::plane_crash_move_shockwave();
|
|
|
|
hit_node = getvehiclenode( "forest_plane_hit", "script_noteworthy" );
|
|
hit_node waittill( "trigger" );
|
|
|
|
level thread bomber_rumble();
|
|
|
|
PlayFXOnTag( level._effect["bomber_wing_hit"], crash_plane,"tag_wingmidR" );
|
|
|
|
rumble_node = getvehiclenode( "forest_crash_rumble", "script_noteworthy" );
|
|
rumble_node waittill( "trigger" );
|
|
|
|
bomber_quake( 4.0 );
|
|
level thread forest_birds();
|
|
|
|
vnode = getvehiclenode( "node_palm_hit", "script_noteworthy" );
|
|
vnode waittill( "trigger" );
|
|
|
|
bomber_crash_treefx();
|
|
|
|
anim_node = getnode( "node_bomber_crash", "targetname" );
|
|
|
|
rig_model = getent( "bomber_crash_rig_model", "targetname" );
|
|
rig_model UseAnimTree( #animtree );
|
|
rig_model.animname = "forest";
|
|
|
|
level thread anim_single_solo( rig_model, "bomber_clip_trees", undefined, anim_node );
|
|
|
|
level thread bomber_crash_vo();
|
|
|
|
crash_plane waittill( "reached_end_node" );
|
|
|
|
//TUEY Crash Sound
|
|
crash_plane playsound ("bomber_crash", "sound_done");
|
|
|
|
//bomber_quake( 2.0 );
|
|
|
|
// smoke/fire fx on crashed plane
|
|
level thread maps\pel2_airfield::airfield_plane_fire();
|
|
|
|
crash_plane waittill("sound_done");
|
|
crash_plane delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
bomber_rumble()
|
|
{
|
|
|
|
trig = getent( "trig_bomber_rumble", "targetname" );
|
|
|
|
players = get_players();
|
|
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( players[i] istouching( trig ) )
|
|
{
|
|
PlayRumbleOnPosition( "pel2_bomber", players[i].origin );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bomber_crash_treefx()
|
|
{
|
|
|
|
tree_top_1 = getent( "bomber_crash_treetop_1", "targetname" );
|
|
tree_top_1 delete();
|
|
tree_top_2 = getent( "bomber_crash_treetop_2", "targetname" );
|
|
tree_top_2 delete();
|
|
|
|
orig_2 = getstruct( "bomber_crash_treetop_fx_2", "targetname" );
|
|
playfx( level._effect["bomber_crash_treetop"], orig_2.origin, anglestoforward( orig_2.angles ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
bomber_quake( time_to_rumble )
|
|
{
|
|
|
|
trig = getent( "trig_bomber_rumble", "targetname" );
|
|
|
|
players = get_players();
|
|
|
|
// TODO this shouldn't be off of each player
|
|
for( i = 0; i < players.size; i++ )
|
|
{
|
|
if( players[i] istouching( trig ) )
|
|
{
|
|
earthquake( 0.25, time_to_rumble, players[i].origin, 1500 );
|
|
// Tuey - Added bass sweetner to rumble the room when the plane goes overhead
|
|
playsoundatposition("plane_rumble", (0,0,0));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bomber_crash_vo()
|
|
{
|
|
|
|
level endon( "grass_admin_surprise" );
|
|
|
|
if( !flag( "grass_admin_surprise" ) )
|
|
{
|
|
|
|
play_vo( level.polonsky, "vo", "bastards_just_took" );
|
|
|
|
wait( 2.75 );
|
|
|
|
play_vo( level.roebuck, "vo", "every_plane_we_lose" );
|
|
|
|
wait( 5 );
|
|
|
|
play_vo( level.roebuck, "vo", "lets_pick_it_up" );
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// some script models of bombers high up in the sky for ambience
|
|
//
|
|
///////////////////////////////
|
|
|
|
ambient_high_bombers()
|
|
{
|
|
|
|
level endon( "pacing_vignette_started" );
|
|
|
|
// two groups, for variation
|
|
origs = getstructarray( "orig_ambient_high_bomber", "targetname" );
|
|
origs_2 = getstructarray( "orig_ambient_high_bomber_2", "targetname" );
|
|
|
|
just_had_four_bombers = false;
|
|
|
|
for( j = 0; j < 50; j++ )
|
|
{
|
|
|
|
if( randomint( 4 ) || just_had_four_bombers )
|
|
{
|
|
for( i = 0; i < origs.size; i++ )
|
|
{
|
|
level thread ambient_high_bomber_path( origs[i] );
|
|
}
|
|
|
|
just_had_four_bombers = false;
|
|
|
|
}
|
|
else
|
|
{
|
|
for( i = 0; i < origs_2.size; i++ )
|
|
{
|
|
level thread ambient_high_bomber_path( origs_2[i] );
|
|
}
|
|
|
|
just_had_four_bombers = true;
|
|
|
|
}
|
|
|
|
wait( RandomIntRange( 15, 18 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ambient_high_bomber_path( start_point )
|
|
{
|
|
|
|
ambient_bomber = spawn( "script_model", start_point.origin );
|
|
ambient_bomber setmodel( "vehicle_usa_aircraft_b17_dist" );
|
|
ambient_bomber.angles = start_point.angles;
|
|
|
|
target_spot = getstruct( start_point.target, "targetname" );
|
|
|
|
ambient_bomber moveto( target_spot.origin, 49 );
|
|
|
|
ambient_bomber waittill( "movedone" );
|
|
|
|
ambient_bomber delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// infinite respawn rifle_grenade for player to use
|
|
//
|
|
///////////////////////////////
|
|
|
|
rifle_grenade_respawn()
|
|
{
|
|
|
|
level thread players_rifle_gren_pickup();
|
|
|
|
respawn_origin = (1676.1, -1352.1, 51.4);
|
|
respawn_rifle_gren = spawn( "weapon_m1garand_gl", respawn_origin, 1 );
|
|
respawn_angles = (0, 276.2, -90);
|
|
respawn_rifle_gren.angles = respawn_angles;
|
|
|
|
// glowy model
|
|
glowy_model = spawn( "script_model", respawn_origin );
|
|
glowy_model.angles = respawn_angles;
|
|
glowy_model SetModel( "weapon_usa_m1garand_rifle_grenade_obj" );
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
if( !isdefined( respawn_rifle_gren ) )
|
|
{
|
|
|
|
// remove glowy model once the rifle grenade garand is picked up
|
|
if( isdefined( glowy_model ) )
|
|
{
|
|
glowy_model delete();
|
|
}
|
|
|
|
respawn_rifle_gren = spawn( "weapon_m1garand_gl", respawn_origin, 1 );
|
|
respawn_rifle_gren.angles = respawn_angles;
|
|
|
|
wait( 2 );
|
|
}
|
|
|
|
wait( 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// sets up hud text for rifle grenade pickup
|
|
//
|
|
///////////////////////////////
|
|
|
|
players_rifle_gren_pickup()
|
|
{
|
|
|
|
players = get_players();
|
|
array_thread( players, ::players_rifle_gren_pickup_watch );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// checks for when the player picks up an m7 launcher for the first time
|
|
//
|
|
///////////////////////////////
|
|
|
|
players_rifle_gren_pickup_watch()
|
|
{
|
|
|
|
while( 1 )
|
|
{
|
|
|
|
if( self hasweapon( "m1garand_gl" ) )
|
|
{
|
|
self thread do_rifle_gren_hud_elem();
|
|
break;
|
|
}
|
|
|
|
wait( 0.15 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// creates & displays the rifle grenade hud text/hint
|
|
//
|
|
///////////////////////////////
|
|
|
|
do_rifle_gren_hud_elem()
|
|
{
|
|
|
|
// the text
|
|
elem_text = newclienthudelem( self );
|
|
|
|
elem_text.label = &"PEL2_RIFLE_GRENADE_TEXT";
|
|
|
|
elem_text.x = 260;
|
|
elem_text.y = 190;
|
|
elem_text.alpha = 0;
|
|
|
|
elem_text.foreground = true;
|
|
|
|
// fade into white
|
|
elem_text FadeOverTime( 0.2 );
|
|
elem_text.alpha = 1;
|
|
|
|
// the icon
|
|
elem = newclienthudelem( self );
|
|
|
|
elem.x = 288;
|
|
elem.y = 204;
|
|
elem.alpha = 0;
|
|
|
|
elem.foreground = true;
|
|
elem SetShader( "hud_icon_grenade_launcher_dpad", 64, 64 );
|
|
|
|
// fade into white
|
|
elem FadeOverTime( 0.2 );
|
|
elem.alpha = 1;
|
|
|
|
|
|
wait( 4.5 );
|
|
|
|
elem_text FadeOverTime( 1.0 );
|
|
elem_text.alpha = 0;
|
|
|
|
|
|
elem MoveOverTime( 1.5 );
|
|
elem.y = 430;
|
|
elem.x = elem.x + 4;
|
|
elem ScaleOverTime( 1.5, 8, 8 );
|
|
|
|
wait( 1.2 );
|
|
|
|
elem FadeOverTime( 0.2 );
|
|
elem.alpha = 0;
|
|
wait( 0.2 );
|
|
elem destroy();
|
|
elem_text destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////
|
|
//
|
|
// spawn these manually when the event starts, to save on entities at load time
|
|
//
|
|
///////////////////////////////
|
|
|
|
spawn_admin_pickup_weapons()
|
|
{
|
|
|
|
admin_weapons = [];
|
|
|
|
// rifle grenades near truck
|
|
admin_weapons[0] = spawnstruct();
|
|
admin_weapons[0].weapon_name = "weapon_m1garand_gl";
|
|
admin_weapons[0].origin = (1676.1, -1352.1, 51.4);
|
|
admin_weapons[0].angles = (0, 276.2, -90);
|
|
|
|
admin_weapons[1] = spawnstruct();
|
|
admin_weapons[1].weapon_name = "weapon_m1garand_gl";
|
|
admin_weapons[1].origin = (1657, -1337.1, 42.6);
|
|
admin_weapons[1].angles = (299.998, 18.1176, -120.214);
|
|
|
|
spawn_pickup_weapons( admin_weapons );
|
|
|
|
}
|
|
|
|
|
|
|
|
#using_animtree( "generic_human" );
|
|
collectible_corpse()
|
|
{
|
|
|
|
orig = getstruct( "orig_collectible_loop", "targetname" );
|
|
|
|
corpse = spawn( "script_model", orig.origin );
|
|
corpse.angles = orig.angles;
|
|
corpse character\char_jap_pel2_rifle::main();
|
|
corpse detach( corpse.gearModel );
|
|
corpse UseAnimTree( #animtree );
|
|
corpse.animname = "collectible";
|
|
corpse.targetname = "collectible_corpse";
|
|
|
|
level thread anim_loop_solo( corpse, "collectible_loop", undefined, "stop_collectible_loop", orig );
|
|
|
|
} |