cod5-sdk/raw/maps/ber3b_event_parliament.gsc

1620 lines
42 KiB
Plaintext

//
// file: ber3b_event_parliament.gsc
// description: reichstag parliament event script for berlin3b
// scripter: slayback
//
#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include maps\ber3b;
#include maps\ber3b_anim;
#include maps\ber3_util;
#include maps\_music;
#using_animtree( "generic_human" );
// -- STARTS --
// start at the beginning of the parliament event
event_parliament_start()
{
objectives_skip( 1 );
warp_players_underworld();
warp_friendlies( "struct_parliament_start_friends", "targetname" );
warp_players( "struct_parliament_start", "targetname" );
set_color_chain( "trig_script_color_allies_b7" );
level thread event_parliament_setup();
}
event_parliament_doors_start()
{
objectives_skip( 1 );
warp_players_underworld();
warp_friendlies( "struct_parliament_doors_start_friends", "targetname" );
warp_players( "struct_parliament_doors_start", "targetname" );
set_color_chain( "trig_script_color_allies_b27" );
level thread event_parliament_setup();
}
// -- END STARTS --
event_parliament_setup( skipto )
{
if( !IsDefined( skipto ) )
{
skipto = false;
}
// CODER_MOD
// DSL - Migrated fake fire over to the client side, so need to notify client scripts of state change
// rather than simply sending a notify to the level on the server side.
if(level.clientscripts)
{
maps\_utility::setClientSysState("levelNotify", "intro_fakefire_end");
}
else
{
level notify( "intro_fakefire_end" );
}
thread parliament_aa_tracers();
thread event_parliament_action( skipto );
thread balcony_playerhints();
thread first_balcony_action();
thread bazooka_team_init();
thread falling_eagle_director();
thread falling_eagle();
thread cleanup_forcecolor_redshirts( "c", "trig_parliament_exit", "targetname" );
}
parliament_aa_tracers()
{
emitters = GetEntArray( "org_parliament_aa_emitter", "targetname" );
ASSERTEX( array_validate( emitters ), "Couldn't find parliament AA tracer emitters." );
array_thread( emitters, maps\ber3b_fx::ambient_aaa_fx, "parliament_doors_open" );
level waittill( "parliament_doors_open" );
level thread delete_group( emitters, 1 );
}
event_parliament_action( skipto )
{
if( !IsDefined( skipto ) )
{
skipto = false;
}
trigger_wait( "trig_parliament_playerNearDoor", "targetname" );
level thread parliament_doors_open();
level waittill( "parliament_doors_open" );
set_color_chain( "trig_script_color_allies_b17");
trigger_wait( "trig_parliament_exit", "targetname" );
// send control to roof script
maps\ber3b_event_roof::event_roof_setup();
}
balcony_playerhints()
{
flag_init( "player_start_balcony_path_hint" );
flag_init( "player_found_balcony_stairs" );
flag_init( "player_reached_balcony" );
thread player_start_path_hint();
thread player_heading_upstairs();
thread player_reached_balcony();
//TUEY SET MUSIC STATE to PARLIAMENT_ROOM
setmusicstate("PARLIAMENT_ROOM");
level thread maps\ber3b_amb::play_crowd_sound();
trigger_wait( "trig_parliament_entrance", "targetname" );
// sarge go to special node and wave for the player
sargeWaveNode = getnode_safe( "node_sarge_parliament_hint", "targetname" );
level.sarge thread sarge_balcony_playerhint_anim();
level.sarge SetGoalPos( sargeWaveNode.origin, sargeWaveNode.angles );
flag_wait( "player_start_balcony_path_hint" );
set_objective( 2 );
thread balcony_breadcrumbs( 2 );
// "Chyort! More MGs!"
level.sarge playsound_generic_facial( "Ber3B_IGD_033A_REZN" );
// "Be on your guard - they'll fight to hold every strong point they can!"
level.sarge playsound_generic_facial( "Ber3B_IGD_034A_REZN" );
// "Right flank - Get up on that balcony!"
level.sarge thread playsound_generic_facial( "Ber3B_IGD_035A_REZN" );
if( !flag( "player_reached_balcony" ) )
{
// lines to bug player to go upstairs
lines[0] = "Ber3B_IGD_104A_REZN"; // "Move upstairs!"
lines[1] = "Ber3B_IGD_035A_REZN"; // "Right flank - Get up on that balcony!
lines[2] = "Ber3B_IGD_025A_REZN"; // "Flank them!"
thread bug_player( lines, 15, 25, "player_reached_balcony" );
}
}
player_start_path_hint()
{
trig = getent_safe( "trig_parliament_path_hint", "targetname" );
trig waittill( "trigger" );
flag_set( "player_start_balcony_path_hint" );
wait( 1 );
trig Delete();
}
player_heading_upstairs()
{
// wait for player to start heading upstairs
trig = getent( "trig_player_heading_upstairs", "targetname" );
trig waittill( "trigger" );
flag_set( "player_found_balcony_stairs" );
wait( 1 );
trig Delete();
}
player_reached_balcony()
{
trigger_wait( "trig_parliament_rightbalcony_entrance", "targetname" );
flag_set( "player_reached_balcony" );
}
balcony_breadcrumbs( obj )
{
Objective_Position( obj, ( 1536, 17592, 934 ) );
Objective_Ring( obj );
trigger_wait( "trig_player_heading_upstairs", "targetname" );
Objective_Position( obj, ( 1792, 17830, 1194 ) );
Objective_Ring( obj );
trigger_wait( "trig_parliament_rightbalcony_entrance", "targetname" );
Objective_Position( obj, ( 2249, 18604, 1170 ) );
Objective_Ring( obj );
}
sarge_balcony_playerhint_anim()
{
// sarge go to special node
self clear_force_color();
self.og_goalradius = level.sarge.goalradius;
self.goalradius = 32;
self.ignoreall = true;
self waittill( "goal" );
// let him orient to the angles specified in SetGoalPos
self waittill_notify_or_timeout( "orientdone", 3 );
if( !flag( "player_found_balcony_stairs" ) )
{
loopEnder = "stop_balconywave";
self.animname = "sarge";
self thread anim_loop_solo( self, "balconywave", undefined, loopEnder );
flag_wait( "player_found_balcony_stairs" );
self notify( loopEnder );
}
// reset sarge
self.goalradius = level.sarge.og_goalradius;
self.ignoreall = false;
self set_force_color( "b" );
}
first_balcony_action()
{
flag_init( "sarge_balcony_moveup_dialogue_done" );
flag_init( "sarge_balcony_molotov_throwers_dialogue_done" );
thread downstairs_door_opener();
// wait for player to get upstairs
trigger_wait( "trig_parliament_rightbalcony_entrance", "targetname" );
// start checking for player kills
requiredKills = 12;
// --TEMP for testing
//timeout = 5;
timeout = 300;
thread balcony_playerkills( requiredKills, timeout );
// make players and squad invisible on balcony
thread balcony_threatbiases();
// wait for objective requirements to be satisfied
flag_wait( "first_balcony_russians_moveup" );
// move Russians on the floor up
thread sarge_balcony_moveup_dialogue();
set_color_chain( "trig_script_color_allies_c1" );
// Germans retreat
getent_safe( "trig_script_fallback_400", "targetname" ) notify( "trigger" );
// kill spawner groups 19 and 20
getent_safe( "trig_script_killspawner_19", "targetname" ) notify( "trigger" );
getent_safe( "trig_script_killspawner_20", "targetname" ) notify( "trigger" );
thread balcony_podium_enemies_dialogue();
wait( 0.5 );
// molotov throwers spawn
balcony_spawn_molotov_throwers();
balcony_spawn_flamethrowers();
wait( 3 ); // let them run into position
thread sarge_balcony_molotov_throwers_dialogue();
Objective_AdditionalCurrent( 10 );
// "filler" enemies so the scene doesn't die down
thread spawn_podium_filler_enemies();
wait( 2 );
// failsafe thread in case players hang out upstairs, to spawn podium enemies
thread balcony_failsafe_spawn_podium_enemies( 6 );
// wait for molotov guys to die
balcony_enemies = get_ai_group_ai( "parliament_balcony_enemies" );
if( array_validate( balcony_enemies ) )
{
timeout = 120;
waittill_group_dies( balcony_enemies, timeout, 0, false );
}
// "We must advance!"
level.sarge playsound_generic_facial( "RU_rez_order_attack_infantry_07" );
trig1 = getent_safe( "trig_parliament_defensive_line_entrance", "targetname" );
trig2 = getent_safe( "trig_parliament_back_entrance", "targetname" );
thread waittill_player_downstairs( trig1, trig2 );
set_objective( 3 );
objective_position( 3, (2830, 18996, 1078) );
// open doors
level notify( "balcony_doors_getready" );
flag_init( "balcony_doors_opened" );
//TUEY SET MUSIC STATE TO DOWNTHESTAIRS
setmusicstate("DOWN_THE_STAIRS");
animSpot = getstruct_safe( "struct_parliament_first_balcony_dooropen_spot", "targetname" );
waitNode = getnode_safe( "node_balcony_dooropener_wait", "targetname" );
opener = get_closest_from_group( animSpot.origin, level.friends );
ASSERTEX( is_active_ai( opener ), "Couldn't find an AI close to the balcony door." );
// set up opener
openerHadBulletShield = false;
if( IsDefined( opener.magic_bullet_shield ) && opener.magic_bullet_shield )
{
openerHadBulletShield = true;
}
else
{
opener thread magic_bullet_shield_safe();
}
opener.ignoreme = true;
opener.ignoreall = true;
opener.og_goalradius = opener.goalradius;
opener.goalradius = 24;
// send to wait node
opener clear_force_color();
opener SetGoalNode( waitNode );
// remove chain trig that players may not have hit, and manually send to chain near door
trig = GetEnt( "trig_script_color_allies_b10", "targetname" );
if( IsDefined( trig ) )
{
trig thread scr_delete();
}
set_color_chain( "trig_script_color_allies_b14" );
//set_objective( 3 );
//Objective_Position( 3, animSpot.origin );
// wait for players to get close to either set of doors
thread balcony_doors_wait( animSpot );
thread downstairs_doors_wait();
flag_wait( "first_balcony_doors_startopen" );
// save
thread autosave_by_name( "ber2_pment_balcony_cleared" );
opener set_animname_custom( "first_balcony_dooropener" );
animSpot anim_reach_solo( opener, "shoulder" );
thread balcony_doors_open( opener );
animSpot anim_single_solo( opener, "shoulder" );
flag_wait( "balcony_doors_opened" );
// reset opener
if( !openerHadBulletShield )
{
opener thread stop_magic_bullet_shield_safe();
}
opener SetGoalPos( ( 2123, 19023, 874 ) );
opener thread delayThread( 10, ::set_force_color, "b" );
opener thread delayThread( 5, ::scr_ignoreme, 0 );
opener thread delayThread( 5, ::scr_ignoreall, 0 );
opener thread delayThread( 5, ::scr_reset_goalradius );
// send friendlies downstairs
if( !flag( "parliament_backdoor_used" ) )
{
set_color_chain( "trig_script_color_allies_b11" );
}
// objective breadcrumbs
ogMarker = GetStruct( "struct_objective9_marker", "targetname" );
Objective_Position( 3, trig1.origin );
// lines to bug player to go downstairs
lines[0] = "RU_0_order_move_forward_05"; // "Quickly, advance!"
lines[1] = "RU_rez_order_move_follow_00"; // "Follow me, now!"
lines[2] = "RU_1_order_attack_infantry_05"; // "We have them on the run!"
thread bug_player( lines, 15, 25, "stop_bugging_player" );
flag_wait( "player_downstairs" );
level notify( "stop_bugging_player" );
Objective_Position( 3, ogMarker.origin );
wait( 0.1 );
trig1 Delete();
trig2 Delete();
}
sarge_balcony_moveup_dialogue()
{
// "Their defenses cannot hold!"
level.sarge playsound_generic_facial( "RU_1_order_action_boost_07" );
// "Now's our chance, attack!"
level.sarge playsound_generic_facial( "RU_0_order_attack_infantry_04" );
flag_set( "sarge_balcony_moveup_dialogue_done" );
}
sarge_balcony_molotov_throwers_dialogue()
{
flag_wait( "sarge_balcony_moveup_dialogue_done" );
// "More Nazis!"
level.sarge playsound_generic_facial( "RU_1_threat_infantry_multiple_03" );
// "There - on the balcony!"
level.sarge playsound_generic_facial( "RU_rez_landmark_near_balcony_01" );
// "Kill them all!"
level.sarge playsound_generic_facial( "RU_rez_threat_infantry_exposed_08" );
flag_set( "sarge_balcony_molotov_throwers_dialogue_done" );
}
balcony_podium_enemies_dialogue()
{
trigger_wait( "trig_spawn_podium_enemies", "script_noteworthy" );
flag_wait_all( "sarge_balcony_moveup_dialogue_done", "sarge_balcony_molotov_throwers_dialogue_done" );
// "German reinforcements!"
level.sarge playsound_generic_facial( "RU_rez_threat_infantry_multiple_02" );
// "All together, comrades!"
level.sarge playsound_generic_facial( "RU_0_order_action_suppress_04" );
}
waittill_player_downstairs( trig1, trig2 )
{
level endon( "player_downstairs" );
thread waittill_player_downstairs_2( trig2 );
trig1 waittill( "trigger" );
flag_set( "player_downstairs" );
}
waittill_player_downstairs_2( trig2 )
{
level endon( "player_downstairs" );
trig2 waittill( "trigger" );
level thread balcony_player_using_parliament_backentrance();
wait( 0.1 );
flag_set( "player_downstairs" );
}
// in case players use the back entrance, this hits triggers in the other staircase, etc.
balcony_player_using_parliament_backentrance()
{
flag_set( "parliament_backdoor_used" );
// friendly movement
trig = GetEnt( "trig_script_color_allies_b10", "targetname" );
if( IsDefined( trig ) )
{
trig thread scr_delete();
}
trig = GetEnt( "trig_script_color_allies_b12", "targetname" );
if( IsDefined( trig ) )
{
trig thread scr_delete();
}
set_color_chain( "trig_script_color_allies_b13" );
// new friendly respawn spot
getent_safe( "trig_friendly_respawn_first_balcony_exit", "script_noteworthy" ) notify( "trigger" );
// spawn podium enemies
getent_safe( "trig_spawn_podium_enemies", "script_noteworthy" ) notify( "trigger" );
getent_safe( "trig_parliament_defensive_line_entrance", "targetname" ) notify( "trigger" );
parliament_mg_adjust();
}
parliament_mg_adjust()
{
mg = getent( "auto788", "targetname" );
mg.yawconvergencetime = 2.25; // default is 1.5
mg.convergencetime = 2.25; // default is 1.5
mg.suppressionTime = 2.0; // default is 3
}
balcony_doors_wait( animSpot )
{
level endon( "first_balcony_doors_startopen" );
waittill_player_within_range( animSpot.origin, 245 );
flag_set( "first_balcony_doors_startopen" );
}
downstairs_doors_wait()
{
level endon( "first_balcony_doors_startopen" );
trig = getent_safe( "trig_parliament_downstairs_door_proxcheck", "targetname" );
trig waittill( "trigger" );
trig Delete();
flag_set( "first_balcony_doors_startopen" );
}
downstairs_door_opener()
{
animSpot = getstruct_safe( "struct_parliament_downstairs_dooropen_spot", "targetname" );
waitNode1 = getnode_safe( "node_parliament_doors_downstairs_wait1", "targetname" );
// wait for these guys to spawn, should only be needed at dev start spot
while( !array_validate( get_allies_by_color( "c" ) ) )
{
wait( 0.1 );
}
// reserve a redshirt for this
opener = undefined;
redshirts = get_allies_by_color( "c" );
for( i = 0; i < redshirts.size; i++ )
{
if( is_active_ai( redshirts[i] ) )
{
opener = redshirts[i];
break;
}
}
ASSERTEX( is_active_ai( opener ), "Couldn't find a guy to open the door downstairs!" );
opener thread magic_bullet_shield_safe();
opener.grenadeawareness = 0;
opener.ignoreme = true;
opener.og_goalradius = opener.goalradius;
opener.goalradius = 24;
opener.name = "Pvt. Lofski";
// take him off the chain
opener clear_force_color();
opener SetGoalNode( waitNode1 );
// --TEMP for testing
//opener waittill( "goal" );
level waittill( "balcony_doors_getready" );
opener set_animname_custom( "downstairs_dooropener" );
animSpot anim_reach_solo( opener, "shoulder" );
// --TEMP for testing
//waittill_player_within_range( opener.origin, 256 );
flag_wait( "first_balcony_doors_startopen" );
// open door
flag_init( "downstairs_doors_opened" );
thread downstairs_doors_open( opener );
animSpot anim_single_solo( opener, "shoulder" );
flag_wait( "downstairs_doors_opened" );
// reset opener
opener thread stop_magic_bullet_shield_safe();
opener.grenadeawareness = 1;
opener.ignoreme = false;
opener.ignoreall = false;
opener.goalradius = opener.og_goalradius;
// send through door and kill off
opener SetGoalPos( ( 1344, 18624, 880 ) );
wait( 5 );
opener bloody_death( true, 3 );
}
downstairs_doors_open( opener )
{
doorLeft = getent_safe( "parl_1st_floor_door_left", "targetname" );
doorRight = getent_safe( "parl_1st_floor_door_right", "targetname" );
rotateTime = 0.24;
accelTime = rotateTime * 0.1;
decelTime = rotateTime * 0.5;
opener waittillmatch( "single anim", "bash" );
doorLeft ConnectPaths();
doorRight ConnectPaths();
doorLeft RotateYaw( 85, rotateTime, accelTime, decelTime );
doorRight RotateYaw( -85, rotateTime, accelTime, decelTime );
wait( rotateTime );
flag_set( "downstairs_doors_opened" );
}
bug_player( lines, minBugInterval, maxBugInterval, ender )
{
level endon( ender );
theLine = undefined;
lastLine = undefined;
maxTries = 10;
while( 1 )
{
wait( RandomFloatRange( minBugInterval, maxBugInterval ) );
foundOne = false;
tries = 0;
while( !foundOne )
{
theLine = get_random( lines );
if( !IsDefined( lastLine ) )
{
break;
}
else
{
if( tries < maxTries )
{
if( theLine != lastLine )
{
break;
}
}
// make sure we're not super unlucky
else
{
theLine = get_random( lines );
break;
}
}
tries++;
}
level.sarge playsound_generic_facial( theLine );
lastLine = theLine; // remember the latest line we played
}
}
balcony_playerkills( requiredKills, timeout )
{
level.balcony_playerkills = 0;
endTime = GetTime() + ( timeout * 1000 );
while( ( level.balcony_playerkills < requiredKills ) && ( GetTime() < endTime ) )
{
wait( 0.1 );
}
flag_set( "first_balcony_russians_moveup" );
}
balcony_threatbiases()
{
players = get_players();
for( i = 0; i < players.size; i++ )
{
players[i] SetThreatBiasGroup( "players" );
}
SetIgnoreMeGroup( "players", "parliament_floor_enemies" );
SetIgnoreMeGroup( "friends", "parliament_floor_enemies" );
}
balcony_spawn_molotov_throwers()
{
getent_safe( "trig_spawn_balcony_enemies", "targetname" ) notify( "trigger" );
thread kill_balcony_enemies();
}
kill_balcony_enemies()
{
trigger_wait( "trig_parliament_defensive_line_entrance", "targetname" );
wait( 5 );
ais = get_ai_group_ai( "parliament_balcony_enemies" );
for( i = 0; i < ais.size; i++ )
{
if( is_active_ai( ais[i] ) )
{
ais[i] DoDamage( ais[i].health + 1, ais[i].origin );
wait( RandomFloatRange( 3, 7 ) );
}
}
}
parliament_molotovguy_spawnfunc()
{
self endon( "death" );
self.ignoreme = true;
self.grenadeawareness = 0;
self.ignoresuppression = 1;
node = getnode_safe( self.target, "targetname" );
self SetGoalNode( node );
self waittill( "goal" );
self.allowdeath = true;
wait( RandomFloatRange( 0, 2 ) );
self.animname = "parliament_molotov_thrower";
anime = "molotov_throw_custom";
while( 1 )
{
forward = AnglesToForward( node.angles );
targetDist = RandomIntRange( 300, 700 );
target_pos = self.origin + vectorScale( forward, targetDist );
self maps\_grenade_toss::force_grenade_toss( target_pos, "molotov", undefined, anime );
wait( RandomFloatRange( 3, 6 ) );
}
}
// --- FLAMETHROWER GUYS ---
balcony_spawn_flamethrowers()
{
getent_safe( "trig_spawn_flamers", "targetname" ) notify( "trigger" );
thread balcony_kill_flamers();
}
balcony_kill_flamers()
{
trigger_wait( "trig_script_color_allies_b27", "targetname" );
flamers = get_ai_group_ai( "ai_parliament_flamer" );
array_thread( flamers, ::kill_flamer, 2, 4 );
}
kill_flamer( waitMin, waitMax )
{
self endon( "death" );
wait( RandomFloatRange( waitMin, waitMax ) );
players = get_players();
if( is_active_ai( self ) )
{
self DoDamage( self.health + 1, self.origin, players[0] );
}
}
// TFlames steez
flamer_setup()
{
self endon ("death");
// self disable_long_death(); // Uncomment if shooting in the looks like jokes.
self.ignoreme = true;
self.health = 10000;
//self thread wait_and_unignore(30);
//self thread wait_and_kill(60);
level thread flamer_blow( self );
}
flamer_blow( flamer )
{
total_dmg = 0;
while( 1 )
{
flamer waittill( "damage", amount, attacker, dir, point, mod );
if( IsPlayer( attacker ) )
{
if( flamer animscripts\utility::damageLocationIsAny( "torso_upper", "torso_lower", "head", "neck", "right_arm_upper", "right_arm_lower", "left_arm_upper", "left_arm_lower" ) )
{
break;
}
// If the flamethrower guy does not get damaged by the
// damagelocation above, calculate the total damage taken.
else
{
total_dmg += amount;
// Default AI health is 150
if( total_dmg > 150 )
{
// If killed by splash damage or an explosive type weapon, make the AI explode.
if( mod == "MOD_GRENADE_SPLASH" || mod == "MOD_EXPLOSIVE" || mod == "MOD_PROJECTILE" || mod == "MOD_PROJECTILE_SPLASH" )
{
break;
}
// Just kill the AI and do not explode since the AI was not killed by the damagelocation in the upper if statement.
flamer DoDamage( flamer.health * 10, flamer.origin );
return;
}
}
}
}
level thread flamer_blow_catch_splash_kills( flamer, attacker, 0.25 );
Earthquake( 0.2, 0.2, flamer.origin, 1500 );
PlayFX( level._effect["flameguy_explode"], flamer.origin + ( 0, 0, 50 ) );
flamer.health = 50;
attacker MagicGrenadeType( "stick_grenade", flamer.origin + ( -20, -25, 20 ), flamer.origin, 0.01 );
attacker MagicGrenadeType( "stick_grenade", flamer.origin + ( -25, -30, 10 ), flamer.origin, 0.01 );
spot = flamer.origin;
allies = GetAIArray( "allies" );
wait( 0.1 );
if( IsDefined( flamer ) && IsDefined( flamer.health ) && flamer.health > 0 )
{
flamer DoDamage( flamer.health * 10, flamer.origin );
flamer StartTanning();
}
wait( 0.1 );
attacker MagicGrenadeType( "molotov", spot + ( 0, 0, 5 ), spot + ( 0, 0, -1 ), 0.01 );
arcademode_assignpoints( "arcademode_score_kill", attacker );
}
// SRS 8/12/2008: catch splash damage off of flamethrower guys to give coop challenge XP
flamer_blow_catch_splash_kills( flamer, attacker, splashKillTimeWindow )
{
if( !IsDefined( level.flamerSplashKillsForChallenge ) )
{
level.flamerSplashKillsForChallenge = 2; // flamer + 2 = challenge complete
}
grenadeDist = 256;
if( !IsDefined( attacker.flamerSplashKills ) )
{
attacker.flamerSplashKills = [];
}
flamerIndex = attacker.flamerSplashKills.size;
attacker.flamerSplashKills[flamerIndex] = 0;
closeGuys = [];
ais = GetAIArray( "axis" );
for( i = 0; i < ais.size; i++ )
{
// SRS 9/1/2008: if close enough, and not the flamer...
if( ( Distance( ais[i].origin, flamer.origin ) <= grenadeDist ) && ( ais[i] != flamer ) )
{
// add to array
closeGuys[closeGuys.size] = ais[i];
}
}
// if there's not enough guys nearby to possibly complete the challenge, don't worry about it
if( closeGuys.size >= level.flamerSplashKillsForChallenge )
{
array_thread( closeGuys, ::flamer_blow_splash_kill_watcher, attacker, flamerIndex, splashKillTimeWindow );
}
}
flamer_blow_splash_kill_watcher( attacker, flamerIndex, splashKillTimeWindow )
{
endTime = GetTime() + ( splashKillTimeWindow * 1000 );
while( IsAlive( self ) && endTime > GetTime() )
{
wait( 0.05 );
}
// if dead, see if we credit the player for the splash kill
if( !IsAlive( self ) )
{
if( IsDefined( self.attacker ) && self.attacker == attacker )
{
if( IsDefined( self.damagemod ) && ( self.damagemod == "MOD_GRENADE" || self.damagemod == "MOD_GRENADE_SPLASH" || self.damagemod == "MOD_EXPLOSIVE" || self.damagemod == "MOD_BURNED" ) )
{
attacker.flamerSplashKills[flamerIndex]++;
// do coop points
if( attacker.flamerSplashKills[flamerIndex] >= level.flamerSplashKillsForChallenge )
{
if( !IsDefined( attacker.gaveFlamerPoints ) )
{
attacker.gaveFlamerPoints = true;
// give points
attacker maps\_challenges_coop::processChallenge( "ch_backdraft_1" );
}
}
}
}
}
}
// --- END FLAMETHROWER GUYS ---
spawn_podium_filler_enemies()
{
getent_safe( "trig_spawn_podium_filler_enemies", "script_noteworthy" ) notify( "trigger" );
// stop when the rest of the podium enemies spawn
trigger_wait( "trig_spawn_podium_enemies", "script_noteworthy" );
getent_safe( "trig_killspawner_21", "targetname" ) notify( "trigger" );
}
balcony_failsafe_spawn_podium_enemies( axisLowerLimit )
{
trig = getent_safe( "trig_spawn_podium_enemies", "script_noteworthy" );
trig endon( "trigger" );
while( 1 )
{
axis = GetAIArray( "axis" );
if( !IsDefined( axis ) )
{
break;
}
if( axis.size < axisLowerLimit )
{
break;
}
wait( 1 );
}
trig notify( "trigger" );
}
balcony_doors_open( opener )
{
doorLeft = getent_safe( "sb_model_balcony_door_left", "targetname" );
doorRight = getent_safe( "sb_model_balcony_door_right", "targetname" );
rotateTime = 0.24;
accelTime = rotateTime * 0.1;
decelTime = rotateTime * 0.5;
opener waittillmatch( "single anim", "door_hit" );
doorLeft ConnectPaths();
doorRight ConnectPaths();
doorLeft RotateYaw( 110, rotateTime, accelTime, decelTime );
doorRight RotateYaw( -110, rotateTime, accelTime, decelTime );
wait( rotateTime );
flag_set( "balcony_doors_opened" );
}
parliament_enemy_spawnfunc()
{
if( IsDefined( self.script_string ) && self.script_string == "balcony_guy" )
{
self thread parliament_molotovguy_spawnfunc();
}
// special guys should always stand so they look/act smarter
if( IsSubStr( self.classname, "panzerschrek" ) || IsSubStr( self.classname, "flamethrower" ) )
{
self AllowedStances( "stand" );
}
self waittill( "death" );
if( IsDefined( self.attacker ) && IsPlayer( self.attacker ) )
{
if( !IsDefined( level.balcony_playerkills ) )
{
level.balcony_playerkills = 0;
}
level.balcony_playerkills++;
}
}
bazooka_team_init()
{
trig = getent_safe( "trig_parliament_bazookateam", "targetname" );
trig waittill( "trigger" );
thread bazooka_team( trig );
}
bazooka_team( trig )
{
spawner_primary = getent_safe( trig.target, "targetname" );
spawner_secondary = getent_safe( spawner_primary.target, "targetname" );
node_primary = getnode_safe( spawner_primary.target, "targetname" );
node_secondary = getnode_safe( spawner_secondary.target, "targetname" );
trig Delete();
guy_primary = spawn_guy( spawner_primary );
guy_secondary = spawn_guy( spawner_secondary );
guys[0] = guy_primary;
guys[1] = guy_secondary;
guys bazookateam_setup_ais();
guys bazookateam_runto_nodes( node_primary, node_secondary );
guy_primary.animname = "fireteam_bazooka_primary";
guy_secondary.animname = "fireteam_bazooka_secondary";
guy_primary SetCanDamage( false );
// collect aimSpots
aimSpots = GetEntArray( node_primary.target, "targetname" );
/*
for( i = 0; i < aimSpots.size; i++ )
{
thread draw_line_until_notify( guy_primary.origin, aimSpots[i].origin, 0, 255, 255, level, "bazookateam_done_firing" );
}
*/
explosionRadius = 215;
flag_set( "bazookateam_keep_firing" );
// MikeD yeaaa!
guy_primary.shoot_notify = "bazooka_shot";
for( i = 0; i < aimSpots.size; i++ )
{
// guys reload bazooka
guys bazookateam_reload();
guy_primary thread bazookateam_fire_dialogue();
wait( 1 );
aimSpot = aimSpots[RandomInt( aimSpots.size )];
guy_primary AllowedStances( "stand" );
wait( 0.8 );
guy_primary.ignoreall = false;
guy_primary SetEntityTarget( aimSpot );
// MikeD yeaaa!
guy_primary waittill( "bazooka_shot" );
level notify( "bazookateam_fire" );
wait( 0.05 );
guy_primary ClearEntityTarget();
guy_primary AllowedStances( "crouch" );
// if we're not stopping...
if( flag( "bazookateam_keep_firing" ) )
{
wait( RandomFloatRange( 3, 6 ) );
}
else
{
// give him some time after shooting
wait( 2 );
//guy_secondary say_dialogue( "fireteam_bazooka_secondary", "bazooka_done" );
// switch weapon
guy_primary gun_switchto( guy_primary.secondaryweapon, "right" );
break;
}
}
guy_primary.shoot_notify = undefined;
// wait a few seconds
wait( 3 );
guys bazookateam_reset_ais();
array_thread( guys, ::bloody_death, true, 2 );
}
// self = a bazooka team AI
bazookateam_fire_dialogue()
{
dialogueString = undefined;
if( RandomInt( 100 ) < 50 )
{
dialogueString = "bazooka_firing_1";
}
else
{
dialogueString = "bazooka_firing_2";
}
self say_dialogue( "fireteam_bazooka_primary", "bazooka_firing_2" );
}
// TODO put in anims when we get them
// self = the bazookateam AI array
bazookateam_reload()
{
anime = "bazooka_reload";
level thread bazooka_reload_rocket_attach( self );
level thread anim_single( self, anime );
level waittill( anime );
}
bazooka_reload_rocket_attach( guys )
{
animname = "fireteam_bazooka_primary";
rocketModel = "weapon_ger_panzershreck_rocket";
attachTag = "tag_inhand";
attachNote = "attach clip left";
detachNote = "detach clip left";
guy = undefined;
for( i = 0; i < guys.size; i++ )
{
if( guys[i].animname == animname )
{
guy = guys[i];
break;
}
}
ASSERTEX( IsDefined( guy ), "Couldn't find the bazooka guy with animname " + animname );
guy endon( "death" );
guy waittillmatch( "single anim", attachNote );
guy Attach( rocketModel, attachTag );
guy thread bazooka_rocket_deathdetach( rocketModel, attachTag );
guy waittillmatch( "single anim", detachNote );
guy Detach( rocketModel, attachTag );
guy notify( "rocket_detached" );
}
bazooka_rocket_deathdetach( rocketModel, attachTag )
{
self endon( "rocket_detached" );
self waittill( "death" );
self Detach( rocketModel, attachTag );
}
// self = the bazooka team AI array
bazookateam_setup_ais()
{
self[0].bazookateam_role = "primary";
self[1].bazookateam_role = "secondary";
for( i = 0; i < self.size; i++ )
{
guy = self[i];
guy.og_goalradius = guy.goalradius;
guy.goalradius = 12;
guy.ignoreme = true;
guy.ignoreall = true;
guy.og_grenadeawareness = guy.grenadeawareness;
guy.grenadeawareness = 0;
guy PushPlayer( true );
guy thread magic_bullet_shield();
}
}
// self = the bazooka team AI array
bazookateam_reset_ais()
{
for( i = 0; i < self.size; i++ )
{
guy = self[i];
if( !is_active_ai( guy ) )
{
continue;
}
guy.goalradius = guy.og_goalradius;
guy.ignoreme = false;
guy.ignoreall = false;
guy.grenadeawareness = guy.og_grenadeawareness;
guy PushPlayer( false );
guy notify( "stop magic bullet shield" );
guy SetCanDamage( true );
guy AllowedStances( "stand", "crouch", "prone" );
}
}
// self = an array of bazooka guys
bazookateam_runto_nodes( nodePrimary, nodeSecondary )
{
self[0] SetGoalNode( nodePrimary );
self[1] SetGoalNode( nodeSecondary );
array_thread( self, ::bazooka_guy_reached_node );
numReached = 0;
while( numReached < self.size )
{
level waittill( "bazooka_guy_reached_node" );
numReached++;
}
}
// self = an AI
bazooka_guy_reached_node()
{
self endon( "death" );
self waittill( "goal" );
level notify( "bazooka_guy_reached_node" );
self AllowedStances( "crouch" );
}
falling_eagle_director()
{
trigger_wait( "trig_parliament_rightbalcony_entrance", "targetname" );
wait( 1 );
level notify( "eagle_slip" );
flag_clear( "bazookateam_keep_firing" );
}
falling_eagle()
{
eagle = getent_safe( "smodel_parliament_eagle", "targetname" );
pieces["lamp_base_jnt"] = getent_safe( "smodel_parliament_spotlight", "targetname" );
pieces["bookcase01_jnt"] = getent_safe( "smodel_parliament_bookshelf_1", "targetname" );
pieces["bookcase02_jnt"] = getent_safe( "smodel_parliament_bookshelf_2", "targetname" );
pieces["bookcase03_jnt"] = getent_safe( "smodel_parliament_bookshelf_3", "targetname" );
pieces["bookcase04_jnt"] = getent_safe( "smodel_parliament_bookshelf_4", "targetname" );
pieces["bookcase05_jnt"] = getent_safe( "smodel_parliament_bookshelf_5", "targetname" );
pieces["bookcase06_jnt"] = getent_safe( "smodel_parliament_bookshelf_6", "targetname" );
pieces["bookcase07_jnt"] = getent_safe( "smodel_parliament_bookshelf_7", "targetname" );
pieces["bookcase08_jnt"] = getent_safe( "smodel_parliament_bookshelf_8", "targetname" );
pieces["bookcase09_jnt"] = getent_safe( "smodel_parliament_bookshelf_9", "targetname" );
pieces["bookcase10_jnt"] = getent_safe( "smodel_parliament_bookshelf_10", "targetname" );
keys = GetArrayKeys( pieces );
for( i = 0; i < pieces.size; i++ )
{
pieces[keys[i]] LinkTo( eagle, keys[i] );
}
rocketStart = ( 1144, 17688, 984 );
rocketTime = 1.5;
thread eagle_reaction_dialogue();
level waittill( "eagle_slip" );
MagicBullet( "panzerschrek", rocketStart, eagle.origin );
wait( rocketTime );
PlayFX( level._effect["eagle_support_break"], eagle.origin );
eagle thread parliament_eagle_anim( "parliament_eagle", "slip", "eagle_slip_anim" );
eagle_fall_wait();
killtrig = GetEnt( "trig_killspawner_22", "targetname" );
if( IsDefined( killtrig ) )
{
killtrig notify( "trigger" );
}
//kevin adding notify. This has to be here to make these go off.
level notify( "arty_strike" );
thread arty_strike_on_players( .35, 2, 500 );
if( !level.player_shot_eagle )
{
MagicBullet( "panzerschrek", rocketStart, eagle.origin );
wait( rocketTime );
}
fxSpot = getstruct_safe( "struct_parliament_eaglefall_fxspot", "targetname" );
PlayFX( level._effect["eagle_fall_impact"], fxSpot.origin );
PlayFX( level._effect["eagle_support_break"], eagle.origin );
eagle thread parliament_eagle_anim( "parliament_eagle", "fall", "eagle_fall_anim" );
// wait for the eagle to fall
wait( 0.6 );
podiumtrig = getent_safe( "trig_parliament_podium_area", "targetname" );
RadiusDamage( podiumtrig.origin, podiumtrig.radius, 5000, 5000 );
thread kill_axis_in_trigger( podiumtrig, 0 );
thread parliament_podiumdoor_clean_rogue_ai();
wait( 5 );
podiumtrig Delete();
}
eagle_reaction_dialogue()
{
level waittill( "eagle_slip" );
wait( 2 );
sarge_giveorder( "eagle_loosening" );
trigger_wait( "trig_parliament_defensive_line_entrance", "targetname" );
guy1 = get_randomfriend_notsarge();
guy1 say_dialogue( "eagle_redshirt2", "aim_for_eagle", true );
level thread eagle_bringdown_dialogue();
flag_wait( "eagle_fall" );
// "As this symbol of their decadence plummets, so too will their wretched Reich."
level.sarge playsound_generic_facial( "Ber3B_IGD_049A_REZN" );
}
eagle_bringdown_dialogue()
{
level endon( "eagle_fall" );
// "Concentrate fire!"
level.sarge playsound_generic_facial( "Ber1_IGD_022A_REZN" );
// "By the eagle!"
level.sarge playsound_generic_facial( "RU_rez_landmark_near_eagle_00" );
// "Dmitri - take it down!"
level.sarge playsound_generic_facial( "See1_IGD_049A_REZN" );
// "Use the panzerschreks!"
level.sarge playsound_generic_facial( "See1_IGD_300A_REZN" );
}
eagle_fall_wait()
{
level.player_shot_eagle = false;
// wait until players hit the floor of the parliament
trigger_wait( "trig_parliament_defensive_line_entrance", "targetname" );
thread eagle_fall_proxtrigger();
thread eagle_fall_dmgtrigger();
level waittill( "eagle_fall" );
}
eagle_fall_proxtrigger()
{
level endon( "eagle_fall" );
trigger_wait( "trig_parliament_approaching_podium", "targetname" );
flag_set( "eagle_fall" );
}
eagle_fall_dmgtrigger()
{
level endon( "eagle_fall" );
dmgtrig = getent_safe( "trig_damage_parliament_eagle", "targetname" );
dmgtrig waittill( "trigger" );
level.player_shot_eagle = true;
flag_set( "eagle_fall" );
dmgtrig Delete();
}
parliament_podiumdoor_clean_rogue_ai()
{
axis = GetAIArray( "axis" );
for( i = 0; i < axis.size; i++ )
{
guy = axis[i];
// if he's north of the door...
if( guy.origin[1] > 20360 )
{
// clean him up
guy bloody_death( true, 0 );
}
}
}
parliament_doors_open()
{
//TUEY Set music state to PARLIAMENT_CLEARED
setmusicstate("PARLIAMENT_CLEARED");
doorLeft = GetEnt( "sbmodel_pment_door_left", "targetname" );
doorRight = GetEnt( "sbmodel_pment_door_right", "targetname" );
doorNodeLeft = getnode_safe( "node_parliament_door_left", "targetname" );
doorNodeRight = getnode_safe( "node_parliament_door_right", "targetname" );
// wait for players to get close to the door area
trigger_wait( "trig_parliament_playerNearDoor", "targetname" );
thread battlechatter_off( "allies" );
thread battlechatter_off( "axis" );
// get the animspot
animSpot = getent_safe( "org_parliamentdoors_animref", "targetname" );
thread parliament_doorrunners();
// set up the AIs to push the doors open
pushers[0] = get_closest_from_group( animSpot.origin, level.friends, level.sarge, "parliament_russian_backup_1" );
pushers[0] parliament_doorpusher_setup();
pushers[0].animname = "parliament_doorpusher_1";
pushers[1] = get_closest_from_group( animSpot.origin, level.friends, level.sarge, "parliament_russian_backup_2" );
pushers[1] parliament_doorpusher_setup();
pushers[1].animname = "parliament_doorpusher_2";
pushers[2] = level.sarge;
pushers[2] parliament_doorpusher_setup();
pushers[2].animname = "parliament_doorpusher_3";
thread parliament_doors_open_sarge_dialogue();
// spawn the germans who will push back
spawners = GetEntArray( "spawner_parliament_doorholder", "targetname" );
ASSERTEX( IsDefined( spawners ) && spawners.size == 3, "Couldn't find enough parliament door holder enemy spawners." );
germans = [];
for( i = 0; i < spawners.size; i++ )
{
enemy = spawn_guy( spawners[i] );
enemy parliament_doorpusher_setup();
enemy.nodeathragdoll = true;
enemy.animname = "parliament_doorholder_" + ( i + 1 );
enemy.deathanim = level.scr_anim[enemy.animname]["doorbreach"];
enemy thread magic_bullet_shield_safe();
enemy SetGoalPos( enemy.origin );
germans[i] = enemy;
}
ASSERTEX( IsDefined( germans ) && germans.size == 3, "Couldn't find enough parliament door holder enemies - one or more spawns must have failed." );
// reach the door holders to their spots
level.door_reachers = 0;
pushers[0] thread parliament_doors_reach_wait( doorNodeLeft );
pushers[1] thread parliament_doors_reach_wait( doorNodeRight );
pushers[2] thread parliament_doors_reach_wait();
animSpot thread anim_reach_solo( pushers[2], "doorpush" );
while( level.door_reachers < pushers.size )
{
wait( 0.05 );
}
// start pushing the door open
doorLeft thread reichstag_dooranim( "parliament_door_left", "doorpush", "parliamentdoor_anim", false );
doorRight thread reichstag_dooranim( "parliament_door_right", "doorpush", "parliamentdoor_anim", false );
animSpot anim_single( pushers, "doorpush" );
level notify( "parliament_doors_opening" );
// now open the doors
doorLeft thread reichstag_dooranim( "parliament_door_left", "doorbreach", "parliamentdoor_anim", true );
doorRight thread reichstag_dooranim( "parliament_door_right", "doorbreach", "parliamentdoor_anim", true );
//Kevins audio notify
level notify ("door_music_stinger");
array_thread( germans, ::parliament_doors_kill_doorholder, animSpot );
animSpot anim_single( pushers, "doorbreach" );
pushers[0] AllowedStances( "stand", "crouch", "prone" );
pushers[1] AllowedStances( "stand", "crouch", "prone" );
// reset AIs to previous values and re-add to friends array
for( i = 0; i < pushers.size; i++ )
{
pushers[i] parliament_doorpusher_reset();
}
// "Go!... Everyone! Through the doors!"
level.sarge thread playsound_generic_facial( "Ber3B_IGD_042A_REZN" );
thread battlechatter_on( "allies" );
thread battlechatter_on( "axis" );
level notify( "parliament_doors_open" );
//TUEY Set Music State to THROUGH_THE_DOOR
setmusicstate("THROUGH_THE_DOOR");
}
parliament_doors_open_sarge_dialogue()
{
// "You two! Get those doors open."
level.sarge playsound_generic_facial( "Ber3B_IGD_036A_REZN" );
// "Get them open now!"
level.sarge playsound_generic_facial( "Ber3B_IGD_039A_REZN" );
}
// self = an AI
parliament_doors_reach_wait( reachNode )
{
if( IsDefined( reachNode ) )
{
self.goalradius = 24;
self SetGoalNode( reachNode );
self waittill( "goal" );
}
else
{
self waittill( "anim_reach_complete" );
}
level.door_reachers++;
}
// self = the AI we're setting up
parliament_doorpusher_setup()
{
if( level.friends array_contains_element( self ) )
{
self.removed_from_friends = true;
level.friends = array_remove( level.friends, self );
}
self clear_force_color();
self.og_animname = self.animname;
self.og_goalradius = self.goalradius;
self.ignoreall = true;
self.ignoreme = true;
self.pacifist = true;
self PushPlayer( true );
// make sure the the pusher cannot be killed
// No need to do it for heroes
if( self != level.sarge && self.health < 9999 )
{
self thread magic_bullet_shield();
}
}
// self = the AI
parliament_doorpusher_reset()
{
if( IsDefined( self.removed_from_friends ) && self.removed_from_friends )
{
level.friends = array_add( level.friends, self );
}
self set_force_color( "b" );
if( IsDefined( self.og_animname ) )
{
self.animname = self.og_animname;
}
self.ignoreall = false;
self.ignoreme = false;
self.pacifist = false;
self PushPlayer( false );
}
// self = a doorholder ai
parliament_doors_kill_doorholder( animSpot )
{
self thread stop_magic_bullet_shield_safe();
self maps\_anim::set_start_pos( "doorbreach", animSpot.origin, animSpot.angles, undefined );
self animscripts\shared::DropAllAIWeapons();
self DoDamage( self.health + 5, (0,0,0) );
}
parliament_doorrunners()
{
runners = get_spawners_and_spawn_group( "spawner_parliament_doorrunner", "targetname" );
array_thread( runners, ::door_runner_think );
}
door_runner_think()
{
self endon( "death" );
self.goalradius = 24;
self.ignoreall = true;
self.ignoreme = true;
self.pacifist = true;
self thread magic_bullet_shield_safe();
self SetGoalPos( self.origin );
// lock him in place
org = Spawn( "script_origin", self.origin );
self LinkTo( org );
// HACK get a notetrack for this
level waittill( "parliament_doors_opening" );
wait( 8.75 );
self Unlink();
org Delete();
self SetGoalNode( getnode_safe( self.target, "targetname" ) );
self thread stop_magic_bullet_shield_safe();
self thread ignore_til_goal();
}