IW4-Dump-Files/maps/favela_escape.gsc

1658 lines
44 KiB
Plaintext

#include maps\_utility;
#include common_scripts\utility;
#include maps\_anim;
#include maps\_hud_util;
#include maps\favela_escape_code;
#using_animtree( "generic_human" );
CONST_CHICKEN_ACHIEVEMENT_NUM = 7;
CONST_CHICKEN_ACHIEVEMENT_TIME = 10;
main()
{
SoundSetTimeScaleFactor( "Music", 0 );
SoundSetTimeScaleFactor( "Announcer", 0 );
SoundSetTimeScaleFactor( "local3", 0 );
level.friendly_baseaccuracy = 0.5;
level.respawn_friendlies_force_vision_check = true;
// so burning vehicles don't block friendly progression up the skinny streets
level.destructible_badplace_radius_multiplier = 0.75;
//level.destructible_explosion_radius_multiplier = 0.85;
level.destructible_health_drain_amount_multiplier = 1.75; // burn faster
// don't track choppers on the minimap since we're doing a lot of fakery
SetSavedDvar( "compassHideVehicles", "1" );
weapons = [];
sounds = [];
weapons[ weapons.size ] = "ak47_drone_sound";
sounds[ "ak47_drone_sound" ] = "drone_ak47_fire_npc";
weapons[ weapons.size ] = "uzi_drone_sound";
sounds[ "uzi_drone_sound" ] = "drone_miniuzi_fire_npc";
weapons[ weapons.size ] = "glock_drone_sound";
sounds[ "glock_drone_sound" ] = "drone_glock_fire_npc";
weapons[ weapons.size ] = "fal_drone_sound";
sounds[ "fal_drone_sound" ] = "drone_fnfal_fire_npc";
level.scriptedweapons = weapons;
level.scriptedweaponsounds = sounds;
level.cosine[ "45" ] = cos( 45 );
maps\createart\favela_escape_art::main(); // Redundant now, since all this currently does is fog, and we moved that to favela_escape_fog. Keeping it in case the artists are expecting it to be there at some point.
maps\createart\favela_escape_fog::main();
maps\createfx\favela_escape_fx::main();
maps\favela_escape_precache::main();
maps\favela_escape_fx::main();
precache_scripted_assets();
init_level_flags();
init_weaponClipModels();
build_starts();
maps\_hiding_door_anims::main();
maps\_rambo::main();
level.airliner = airliner_setup();
level.friendly_startup_thread = ::favela_escape_friendly_startup_thread;
setup_color_friendly_spawners();
maps\_drone_ai::init();
maps\_load::main();
flag_set( "respawn_friendlies" );
thread triggered_hostile_bursts_setup();
thread setup_friends();
thread setup_enemies();
thread setup_vehicles();
maps\favela_escape_anim::main();
thread maps\favela_escape_amb::main();
thread move_stuff_at_levelstart();
thread deletetrigs();
thread maps\favela_escape_fx::bird_startle_trigs();
thread airliner_flyby_trigs();
maps\_compass::setupMiniMap("compass_map_favela_escape");
thread favela_escape_objectives();
thread enemy_cleanup();
thread chicken_achievement();
}
chicken_achievement()
{
level.chickens_killed = [];
destructible_toy = GetEntArray( "destructible_toy", "targetname" );
chickens = [];
foreach( item in destructible_toy )
{
if( issubstr( item.destructible_type, "toy_chicken" ) )
chickens[ chickens.size ] = item;
}
array_thread( chickens, ::chicken_achievement_think );
}
chicken_achievement_think()
{
self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, dflags );
if( !isplayer( attacker ) )
return;
level.chickens_killed[ level.chickens_killed.size ] = gettime();
if( level.chickens_killed.size < CONST_CHICKEN_ACHIEVEMENT_NUM )
return;
time1 = level.chickens_killed[ level.chickens_killed.size - CONST_CHICKEN_ACHIEVEMENT_NUM ];
time2 = level.chickens_killed[ level.chickens_killed.size - 1 ];
if( ( time2 - time1 ) > CONST_CHICKEN_ACHIEVEMENT_TIME * 1000 )
return;
maps\_utility::giveachievement_wrapper( "COLONEL_SANDERSON" );
}
precache_scripted_assets()
{
PrecacheItem( "uzi" );
PrecacheItem( "smoke_grenade_american" );
PrecacheItem( "rpg_straight" );
PrecacheItem( "rpg_straight_short_life" );
PrecacheItem( "freerunner" );
PrecacheItem( "ak47_drone_sound" );
PrecacheItem( "uzi_drone_sound" );
PrecacheItem( "glock_drone_sound" );
PrecacheItem( "fal_drone_sound" );
PrecacheShellshock( "favela_escape_player_recovery" );
PrecacheString( &"FAVELA_ESCAPE_SOLORUN_KEEP_MOVING" );
PrecacheString( &"FAVELA_ESCAPE_HINT_SPRINT" );
PrecacheString( &"FAVELA_ESCAPE_HINT_SPRINT_PC" );
PrecacheString( &"FAVELA_ESCAPE_HINT_SPRINT_PC_ALT" );
PrecacheString( &"FAVELA_ESCAPE_CHOPPER_TIMER" );
PrecacheString( &"FAVELA_ESCAPE_CHOPPER_TIMER_EXPIRED" );
PrecacheString( &"FAVELA_ESCAPE_DEADQUOTE_FAILED_CHOPPER_JUMP" );
}
init_level_flags()
{
flag_init( "friends_setup" );
//flag_init( "scripted_dialogue" );
flag_init( "introscreen_start_dialogue" );
flag_init( "radiotower_runpath_dialogue_done" );
flag_init( "radiotower_start" );
flag_init( "radiotower_vehicles_start" );
flag_init( "radiotower_escape_technical_1_arrival" );
flag_init( "radiotower_escape_technical_2_arrival" );
flag_init( "radiotower_vehicle1_donut_done" );
flag_init( "radiotower_enemies_retreat" );
flag_init( "radiotower_exit" );
flag_init( "hind_turret_shutdown" );
flag_init( "hind_fire" );
flag_init( "hind_reveal_rpg_dodge" );
flag_init( "hind_reveal_dodgestop" );
flag_init( "hind_reveal_bugout" );
flag_init( "market_introdialogue_done" );
flag_init( "market_chopper_spawned" );
flag_init( "market_evac_chopper_spawned" );
flag_init( "market_evac_chopper_bugout" );
flag_init( "market_evac_player_near_soccerfield" );
flag_init( "market_evac_chopper_incoming" );
flag_init( "market_evac_ambush_start" );
flag_init( "market_evac_enemies_depleted" );
flag_init( "market_evac_chopper_leaves_scene" );
flag_init( "market_evac_follow_sarge_climb" );
flag_init( "market_evac_soap_climbed_up" );
flag_init( "market_evac_player_mantled" );
flag_init( "market_evac_player_on_roof" );
flag_init( "roofrun_done" );
flag_init( "roofrun_sarge_bigjumped" );
flag_init( "roofrun_player_bigjump_start" );
flag_init( "player_jump_watcher_stop" );
flag_init( "player_fell_normally" );
flag_init( "bigjump_sargeplayer_interact_start" );
flag_init( "player_bigjump_done" );
flag_init( "player_recovery_blackscreen" );
flag_init( "player_recovery_done" );
flag_init( "solorun_objective_display" );
flag_init( "solorun_start" );
flag_init( "solorun_mob_start_shooting" );
flag_init( "solorun_player_at_balcony" );
flag_init( "solorun_player_progression_stalled" );
flag_init( "solorun_timer_start" );
flag_init( "timer_expired" );
flag_init( "chopperjump_player_jump" );
flag_init( "solorun_player_boarded_chopper" );
flag_init( "level_faded_to_black" );
}
init_weaponClipModels()
{
level.weaponClipModels = [];
level.weaponClipModels[0] = "weapon_ak47_tactical_clip";
level.weaponClipModels[1] = "weapon_rpd_clip";
level.weaponClipModels[2] = "weapon_m16_clip";
level.weaponClipModels[3] = "weapon_skorpion_clip";
level.weaponClipModels[4] = "weapon_saw_clip";
}
move_stuff_at_levelstart()
{
level.market_evac_helperClips = GetEntArray( "sbmodel_market_evac_helperclip", "targetname" );
foreach( clip in level.market_evac_helperClips )
{
clip ConnectPaths();
}
// create a badplace for one of the street alleys so friendlies don't choose a path through there
Badplace_Cylinder( "street_uphill_alley", -1, ( -388, 524, 1016 ), 90, 128, "allies" );
}
setup_friends()
{
friends = GetEntArray( "starting_allies", "script_noteworthy" );
foreach( guy in friends )
{
if( IsDefined( guy.targetname ) )
{
// MacTavish
if( guy.targetname == "sarge" )
{
//guy thread magic_bullet_shield();
guy.animname = "sarge";
guy.isHero = true;
level.sarge = guy;
}
// Ghost
else if( guy.targetname == "hero1" )
{
//guy thread magic_bullet_shield();
guy.animname = "hero1";
guy.isHero = true;
level.hero1 = guy;
}
}
if( IsDefined( guy.isHero ) )
{
// heroes are invincible
guy thread magic_bullet_shield();
}
else
{
guy thread replace_on_death(); // only have to do this for first spawned guys, others will do it automatically in color respawn system
}
guy scr_accuracy( level.friendly_baseaccuracy );
guy scr_usechokepoints( true );
guy friend_add();
}
// run on everyone else who spawns
add_global_spawn_function( "allies", ::scr_usechokepoints, true );
flag_set( "friends_setup" );
}
setup_enemies()
{
add_global_spawn_function( "axis", ::scr_usechokepoints, true );
deleters = GetEntArray( "delete_at_path_end", "script_noteworthy" );
array_thread( deleters, ::add_spawn_function, ::delete_at_path_end );
ignorers2 = GetEntArray( "ignore_til_pathend_or_damage", "script_noteworthy" );
array_thread( ignorers2, ::add_spawn_function, ::ignore_til_pathend_or_damage );
ignore_and_deleters = GetEntArray( "ignore_and_delete_at_path_end", "script_noteworthy" );
array_thread( ignore_and_deleters, ::add_spawn_function, ::ignore_and_delete_at_path_end );
seekers = GetEntArray( "playerseek_at_path_end", "script_noteworthy" );
array_thread( seekers, ::add_spawn_function, ::playerseek_at_path_end );
smashers1 = GetEntArray( "window_smash_stop_inside", "script_noteworthy" );
array_thread( smashers1, ::add_spawn_function, ::window_smash_stop_inside );
chaoticAboves = GetEntArray( "chaotic_above_shooter", "script_noteworthy" );
array_thread( chaoticAboves, ::add_spawn_function, ::chaotic_above_shooter );
solorunChasers = GetEntArray( "solorun_chaser_spawner", "script_noteworthy" );
array_thread( solorunChasers, ::add_spawn_function, ::solorun_chaser_spawnfunc );
noBackShooters = GetEntArray( "dont_shoot_player_in_back", "script_noteworthy" );
array_thread( noBackShooters, ::add_spawn_function, ::dont_shoot_player_in_back );
guy = GetEnt( "spawner_vista2_endhouse", "script_noteworthy" );
guy thread add_spawn_function( ::ai_unlimited_rocket_ammo );
roofRunners = GetEntArray( "solorun_roofrunner", "script_noteworthy" );
array_thread( roofRunners, ::add_spawn_function, ::dont_shoot_player_in_back );
array_thread( roofRunners, ::add_spawn_function, ::delete_at_path_end );
}
setup_vehicles()
{
solorunChoppers = GetEntArray( "solorun_chopper", "script_noteworthy" );
array_thread( solorunChoppers, ::add_spawn_function, ::solorun_chopper_spawnfunc );
}
favela_escape_objectives()
{
flag_wait( "radiotower_start" );
obj1_set = false; // hack to make Soap-less start points work with objectives
if( IsDefined( level.sarge ) )
{
Objective_Add( 1, "current", &"FAVELA_ESCAPE_OBJ_FOLLOW_SOAP" );
Objective_OnEntity( 1, level.sarge );
Objective_SetPointerTextOverride( 1, &"FAVELA_ESCAPE_OBJ_FOLLOW_MARKER" );
obj1_set = true;
}
flag_wait( "market_introdialogue_done" );
if( obj1_set )
{
Objective_String( 1, &"FAVELA_ESCAPE_OBJ_FLEE_RADIOTOWER" );
Objective_Position( 1, ( -3154, -1875, 1096 ) );
Objective_SetPointerTextOverride( 1, "" ); // reset to default
}
flag_wait( "market_evac_chopper_incoming" );
Objective_Complete( 1 );
Objective_Add( 2, "current", &"FAVELA_ESCAPE_OBJ_MARKET_ESCAPE", ( -3937, -1051, 1241 ) );
// start point hack
if( IsDefined( level.chopper ) )
{
Objective_OnEntity( 2, level.chopper );
}
thread market_evac_chopper_obj_update_pos( 2 );
flag_wait( "solorun_objective_display" );
//flag_wait( "solorun_start" );
Objective_Complete( 2 );
Objective_Add( 3, "current", &"FAVELA_ESCAPE_OBJ_GET_BACK_TO_ROOF", ( -5924, -870, 816 ) );
thread solorun_houses_obj_update_pos( 3 );
thread solorun_houses_obj_turnoff_compass();
flag_wait( "solorun_player_at_balcony" );
Objective_Complete( 3 );
Objective_Add( 4, "current", &"FAVELA_ESCAPE_OBJ_GET_TO_CHOPPER", ( -8192, 2128, 704 ) );
thread solorun_roof_obj_update_pos( 4 );
flag_wait( "solorun_player_boarded_chopper" );
Objective_Complete( 4 );
}
solorun_houses_obj_turnoff_compass()
{
// turn off compass while running through buildings
trigger_wait( "solorun_houses_obj_update_0", "script_noteworthy" );
SetSavedDvar( "compass", 0 );
flag_wait( "solorun_player_at_balcony" );
SetSavedDvar( "compass", 1 );
}
market_evac_chopper_obj_update_pos( objID )
{
level endon( "solorun_start" );
flag_wait( "market_evac_chopper_leaves_scene" );
//Objective_Position( objID, ( -5897, -948, 1216 ) );
//flag_wait( "market_evac_follow_sarge_climb" );
Objective_State( 1, "active" );
Objective_Current( 1 );
Objective_OnEntity( 1, level.sarge );
flag_wait( "roofrun_player_at_start_loc" );
while( IsDefined( level.chopper ) )
{
wait( 0.05 );
}
chopper = undefined;
while( !IsDefined( chopper ) )
{
wait( 0.05 );
chopper = get_vehicle( "veh_chopper_roofrun", "targetname" );
}
Objective_State( 1, "done" );
Objective_State( objID, "active" );
Objective_Current( objID );
Objective_OnEntity( objID, chopper );
flag_wait( "player_recovery_blackscreen" );
Objective_Position( objID, ( -6370.5, -944, 1044 ) );
}
solorun_houses_obj_update_pos( objID )
{
level endon( "solorun_player_at_balcony" );
trigger_wait( "solorun_houses_obj_update_0", "script_noteworthy" );
Objective_Position( objID, ( -4756, -384, 808 ) );
//trigger_wait( "solorun_houses_obj_update_1", "script_noteworthy" );
//Objective_Position( objID, ( -4756, -384, 808 ) );
trigger_wait( "solorun_houses_obj_update_2", "script_noteworthy" );
Objective_Position( objID, ( -4760, 880, 804 ) );
trigger_wait( "solorun_houses_obj_update_3", "script_noteworthy" );
Objective_Position( objID, ( -5112, 864, 944 ) );
}
solorun_roof_obj_update_pos( objID )
{
level endon( "solorun_player_boarded_chopper" );
trigger_wait( "objective_breadcrumb_update_1", "script_noteworthy" );
Objective_Position( objID, ( -8312, 1440, 416 ) );
trigger_wait( "objective_breadcrumb_update_2", "script_noteworthy" );
Objective_Position( objID, ( -9152, 1408, 352 ) );
trigger_wait( "objective_breadcrumb_update_3", "script_noteworthy" );
Objective_Position( objID, ( -9086, 2224, -152 ) );
trigger_wait_targetname( "trig_end_glass_break" );
Objective_OnEntity( objID, level.chopperladder, ( 0, 0, -85 ) );
//Objective_SetPointerTextOverride( objID, &"FAVELA_ESCAPE_OBJ_JUMP_MARKER" );
}
// --------------------------
// -- STARTS --
// --------------------------
build_starts()
{
default_start( ::start_radiotower );
add_start( "intro", ::start_radiotower, "map start" );
add_start( "street", ::start_street, "street after radiotower" );
add_start( "street_mid", ::start_street_mid, "street after first chopper reveal" );
add_start( "street_vista2", ::start_street_vista2, "street second vista area" );
add_start( "market", ::start_market, "market start" );
add_start( "market_evac", ::start_market_evac, "market evac goes wrong" );
add_start( "market_evac_escape", ::start_market_evac_escape, "friendlies climb up to rooftops" );
add_start( "roofrun", ::start_roofrun, "roofrun start" );
add_start( "roofrun_bigjump", ::start_roofrun_player_jump, "roofrun player jump" );
add_start( "solorun", ::start_solorun, "player solo run" );
add_start( "solorun_rooftops", ::start_solorun_rooftops, "player solo run rooftops" );
add_start( "solorun_chopper", ::start_solorun_chopper, "player jump to chopper" );
add_start( "test", ::start_favela_escape_test, "[dev test]" );
}
start_favela_escape_test()
{
level.player.ignoreme = true;
level.player teleport_to_origin( ( 4892, 292, 1134 ), ( 0, 180, 0 ) );
thread radiotower_enemy_vehicles();
/* market evac
delaythread( 0.05, ::market_evac_playermantle_helper, 1148 );
trigger_off( "sbmodel_market_evac_playerblock", "targetname" );
level.player teleport_to_origin( ( -3128, -2888, 1064 ), ( 0, 90, 0 ) );
chopper = spawn_chopper( 6, false );
path2start = GetStruct( "struct_market_evac_chopper_path2", "targetname" );
path2nextnode = GetStruct( path2start.target, "targetname" );
chopper thread market_evac_chopper_bugout_path( path2start );
*/
/*
level.player teleport_to_origin( ( -6226, -874, 788 ), ( 0, 300, 0 ) );
thread bigjump_angrymob();
*/
/*
spawner = GetEnt( "spawner_vista2_endhouse", "script_noteworthy" );
guy = spawner spawn_ai();
remove_all_flood_spawners();
thread vista2_endhouse_jumpthru();
level.player teleport_to_origin( ( -972, 1740, 1124 ), ( 0, 180, 0 ) );
level.hero1 teleport_to_origin( ( -796, 1716, 1124 ), ( 0, 180, 0 ) );
*/
}
start_radiotower()
{
level thread radiotower();
}
start_street()
{
flag_set( "radiotower_start" );
flag_set( "radiotower_enemies_retreat" );
flag_set( "radiotower_escape_technical_2_arrival" );
thread radiotower_gate_open( false );
level.sarge set_force_color( "b" );
warp_friends_and_player( "struct_start_street" );
trigger_activate_targetname( "trig_script_color_allies_b5" );
thread street();
thread autosave_by_name( "street_start" );
}
start_street_mid()
{
flag_set( "radiotower_start" );
level.sarge set_force_color( "b" );
warp_friends_and_player( "struct_start_street_mid" );
thread street();
}
start_street_vista2()
{
flag_set( "radiotower_start" );
level.sarge set_force_color( "b" );
warp_friends_and_player( "struct_start_street_vista2" );
trigger_activate_targetname( "uphill_advance_3" );
thread street( "vista2" );
}
start_market()
{
flag_set( "radiotower_start" );
level.sarge set_force_color( "b" );
warp_friends_and_player( "struct_start_market" );
trigger_activate_targetname( "trig_spawn_market_start" );
trigger_activate_targetname( "uphill_advance_6" );
thread friendly_colors( "market" );
thread market();
// let enemies spawn and run to nodes
trigger_off( "market_advance_1", "targetname" );
wait( 10 );
trigger_on( "market_advance_1", "targetname" );
trigger_activate_targetname_safe( "market_advance_1" );
}
start_market_evac()
{
flag_set( "radiotower_start" );
flag_set( "market_introdialogue_done" );
remove_nonhero_friends( 1 );
guys = get_nonhero_friends();
redshirt = guys[0];
level.sarge set_force_color( "b" );
level.hero1 set_force_color( "b" );
//redshirt set_force_color( "p" );
redshirt disable_replace_on_death();
redshirt notify( "death" );
redshirt Delete();
// fake chopper spawn
flag_set( "market_advance_4" );
thread market_fake_choppers();
warp_friends_and_player( "struct_start_market_evac" );
thread market_evac();
}
start_market_evac_escape()
{
flag_set( "radiotower_start" );
remove_nonhero_friends( 1 );
guys = get_nonhero_friends();
redshirt = guys[0];
struct = GetStruct( "struct_start_market_evac_escape_player", "targetname" );
level.player teleport_to_origin( struct.origin, struct.angles );
sargeNode = GetNode( "node_sarge_preclimb", "targetname" );
hero1Node = GetNode( "node_hero1_preclimb", "targetname" );
redshirtNode = GetNode( "node_redshirt_preclimb", "targetname" );
array_thread( level.friends, ::set_temp_goalradius, 128 );
redshirt = get_single_redshirt();
level.sarge ForceTeleport( sargeNode.origin, sargeNode.angles );
level.hero1 ForceTeleport( hero1Node.origin, hero1Node.angles );
redshirt ForceTeleport( redshirtNode.origin, redshirtNode.angles );
level.sarge SetGoalNode( sargeNode );
level.hero1 SetGoalNode( hero1Node );
redshirt SetGoalNode( redshirtNode );
array_thread( level.friends, ::ent_flag_init, "climbing_ok" );
waittillframeend;
array_thread( level.friends, ::ent_flag_set, "climbing_ok" );
thread favesc_waveoff_music();
thread market_evac_escape();
}
start_roofrun()
{
flag_set( "radiotower_start" );
remove_nonhero_friends( 1 );
guys = get_nonhero_friends();
redshirt = guys[0];
redshirt magic_bullet_shield();
array_thread( level.friends, ::clear_force_color );
sargenode = GetNode( "node_roofrun_sarge_waitforplayer", "targetname" );
hero1node = GetNode( "node_roofrun_hero1_waitforplayer", "targetname" );
redshirtnode = GetNode( "node_roofrun_redshirt_waitforplayer", "targetname" );
level.sarge thread teleport_to_origin( sargenode.origin, sargenode.angles );
level.hero1 thread teleport_to_origin( hero1node.origin, hero1node.angles );
redshirt thread teleport_to_origin( redshirtnode.origin, redshirtnode.angles );
level.player teleport_to_origin( ( -3552, -992, 1194 ), ( 0, 180, 0 ) );
array_thread( level.friends, ::ent_flag_init, "roofrun_start" );
array_thread( level.friends, ::ent_flag_init, "climbing_ok" );
waittillframeend;
array_thread( level.friends, ::ent_flag_set, "roofrun_start" );
array_thread( level.friends, ::ent_flag_set, "climbing_ok" );
waittillframeend;
thread favesc_waveoff_music();
thread roofrun();
}
start_roofrun_player_jump()
{
flag_set( "radiotower_start" );
flag_set( "market_introdialogue_done" );
flag_set( "market_evac_chopper_incoming" );
flag_set( "market_evac_player_on_roof" );
remove_nonhero_friends( 1 );
guys = get_nonhero_friends();
redshirt = guys[0];
level.runnersDone = 0;
array_thread( level.friends, ::ent_flag_init, "roofrun_start" );
sargeorg = GetStruct( "roofrun_sarge_waitforplayer", "targetname" );
level.sarge teleport_to_origin( sargeorg.origin, sargeorg.angles );
playerorg = GetStruct( "struct_start_roofrun_player_jump_player", "targetname" );
level.player teleport_to_origin( playerorg.origin, playerorg.angles );
wait( 0.05 );
array_thread( level.friends, ::ent_flag_set, "roofrun_start" );
waittillframeend;
level.sarge thread roofrun_sarge( true );
redshirt thread roofrun_redshirt( true );
level.hero1 thread roofrun_hero1( true );
thread roofrun_player_bigjump();
flag_wait( "player_recovery_done" );
// level progression
thread solorun();
}
start_solorun()
{
flag_set( "solorun_objective_display" );
flag_set( "radiotower_start" );
flag_set( "market_introdialogue_done" );
flag_set( "market_evac_chopper_incoming" );
flag_set( "market_evac_player_on_roof" );
delete_all_friends();
level.player TakeAllWeapons();
playerorg = GetStruct( "struct_solorun_beginning_start_player", "targetname" );
level.player thread teleport_to_origin( playerorg.origin, playerorg.angles );
thread favesc_finalrun_music();
thread solorun();
}
start_solorun_rooftops()
{
flag_set( "solorun_objective_display" );
flag_set( "radiotower_start" );
flag_set( "market_introdialogue_done" );
flag_set( "market_evac_chopper_incoming" );
flag_set( "market_evac_player_on_roof" );
flag_set( "solorun_start" );
delete_all_friends();
level.player TakeAllWeapons();
playerorg = GetStruct( "struct_solorun_rooftops_start_player", "targetname" );
level.player teleport_to_origin( playerorg.origin, playerorg.angles );
thread solorun( "rooftops" );
}
start_solorun_chopper()
{
flag_set( "radiotower_start" );
flag_set( "market_evac_player_on_roof" );
flag_set( "solorun_player_at_balcony" );
delete_all_friends();
level.player TakeAllWeapons();
playerorg = GetStruct( "struct_solorun_chopper_start_player", "targetname" );
level.player teleport_to_origin( playerorg.origin, playerorg.angles );
thread solorun( "chopperjump" );
}
// ------------------
// --- RADIOTOWER ---
// ------------------
radiotower()
{
thread intro_rojas_crucified();
thread favesc_combat_music();
thread radiotower_crowd_walla();
thread radiotower_runup_scout();
thread radiotower_runup_friendlies_ignore();
thread radiotower_friendly_colors();
thread radiotower_doorkick_1();
thread radiotower_curtainpull_1();
thread radiotower_hiding_door_guy_cleanup();
thread radiotower_stop_roof_respawners();
flag_set( "radiotower_start" );
battlechatter_off( "allies" );
// make all redshirts invincible for a while
array_thread( get_nonhero_friends(), ::magic_bullet_shield );
thread radiotower_runpath_dialogue();
if( GetDvar( "introscreen" ) != "0" )
{
level waittill( "introscreen_complete" );
}
else
{
flag_set( "introscreen_start_dialogue" );
}
sarge_postintro_walkspot = GetNode( "node_sarge_post_intro_goal", "targetname" );
level.sarge SetGoalNode( sarge_postintro_walkspot );
hero1_postintro_walkspot = GetNode( "node_hero1_post_intro_goal", "targetname" );
level.hero1 SetGoalNode( hero1_postintro_walkspot );
// after player moves forward, trigger color chain
trigger_wait_targetname( "trig_intro_playerturnedcorner" );
trigger_activate_targetname( "trig_script_color_allies_b0" );
// player gets to end of little path
trigger_wait_targetname( "trig_radiotower_brushpath_end" );
// nonheroes are mortal again
array_thread( get_nonhero_friends(), ::stop_magic_bullet_shield_safe );
thread radiotower_enemy_vehicles_prethink();
delaythread( 0.75, ::radiotower_escape_dialogue );
thread radiotower_enemies_retreat();
// level progression
trigger_wait_targetname( "trig_radiotower_exit" );
flag_set( "radiotower_exit" );
thread autosave_by_name( "street_start" );
thread vista1_walla();
thread street();
}
intro_rojas_crucified()
{
level endon( "radiotower_exit" );
level endon( "cleaning_up_rojas" );
animref = GetEnt( "intro_rojas_beaten_animref", "targetname" );
spawner = GetEnt( animref.target, "targetname" );
ASSERT( IsDefined( animref ) && IsDefined( spawner ) );
spawner.script_drone = undefined;
//spawner.script_drone_override = true;
rojas = spawner spawn_ai( true );
ASSERT( IsDefined( rojas ) );
restraints = spawn_anim_model( "rojas_restraints" );
idleAnime = "intro_rojas_idle";
deathAnime = "intro_rojas_death";
animref thread anim_generic_loop( rojas, idleAnime );
animref thread anim_loop_solo( restraints, "idle" );
level thread intro_rojas_crucified_cleanup( rojas, animref, restraints );
rojas.grenadeAmmo = 0;
rojas.dropWeapon = false;
rojas set_battlechatter( false );
rojas.allowDeath = false;
rojas.a.nodeath = true;
rojas.skipDeathAnim = true;
rojas.noragdoll = true;
rojas.takedamage = true;
rojas.animname = "generic";
rojas.health = 5000;
rojas disable_pain();
rojas add_damage_function( ::bloody_pain );
while( 1 )
{
rojas waittill( "damage", amount, who );
if( amount <= 1 )
{
continue;
}
if( IsPlayer( who ) )
{
break;
}
}
animref anim_stopanimscripted();
rojas anim_stopanimscripted();
rojas.allowDeath = true;
rojas.a.nodeath = true;
rojas.takedamage = false;
//rojas.anim_mode = "nophysics";//zonly_physics, nophysics, none gravity
// rojas animmode( "nophysics" );
rojas delaycall( 0.1, ::Kill );
// animref thread anim_generic( rojas, deathAnime );
animref thread anim_custom_animmode_solo( rojas, "nophysics", deathAnime );
// wait 0.05;
// rojas animmode( "nophysics" );
}
intro_rojas_crucified_cleanup( rojas, animref, restraints )
{
flag_wait( "radiotower_exit" );
level notify( "cleaning_up_rojas" );
if( IsDefined( rojas ) )
{
rojas anim_stopanimscripted();
}
animref anim_stopanimscripted();
restraints anim_stopanimscripted();
wait( 0.05 );
if( IsDefined( rojas ) )
{
rojas Delete();
}
animref Delete();
restraints Delete();
}
// ---------------
// --- STREETS ---
// ---------------
street( startPoint )
{
thread friendly_colors( startPoint );
thread street_dialogue();
thread vista1_door1_kick();
thread vista1_wavingguy();
thread street_roof1_doorkick();
thread street_mid_intersection_clearout();
thread vista2_walla();
thread vista2_technical_prethink();
thread vista2_endhouse_jumpthru();
thread vista2_firsthalf_enemies_retreat();
thread vista2_leftbalcony_enemies_magicgrenade();
// level progression
thread market();
}
friendly_colors( startPoint )
{
street_trigPrefix = "street_advance";
street_numTrigs = 5;
uphill_trigPrefix = "uphill_advance";
uphill_numTrigs = 6;
market_trigPrefix = "market_advance";
market_numTrigs = 6;
if( !IsDefined( startPoint ) )
{
// MAIN LOGIC
thread color_flags_advance( street_trigPrefix, street_numTrigs );
flag_wait( street_trigPrefix + "_" + street_numTrigs );
thread color_flags_advance( uphill_trigPrefix, uphill_numTrigs );
flag_wait( uphill_trigPrefix + "_" + uphill_numTrigs );
thread color_flags_advance( market_trigPrefix, market_numTrigs );
flag_wait( market_trigPrefix + "_" + market_numTrigs );
}
else
{
// SPECIAL CASE ALTERNATE LOGIC FOR START POINTS
if( startPoint == "vista2" )
{
// start from the third trigger in the uphill chain
thread color_flags_advance( uphill_trigPrefix, uphill_numTrigs, 3 );
flag_wait( uphill_trigPrefix + "_" + uphill_numTrigs );
thread color_flags_advance( market_trigPrefix, market_numTrigs );
flag_wait( market_trigPrefix + "_" + market_numTrigs );
}
if( startPoint == "market" )
{
// start from the last trigger in the uphill chain
thread color_flags_advance( uphill_trigPrefix, uphill_numTrigs, 6 );
flag_wait( uphill_trigPrefix + "_" + uphill_numTrigs );
thread color_flags_advance( market_trigPrefix, market_numTrigs );
flag_wait( market_trigPrefix + "_" + market_numTrigs );
}
}
}
// --------------
// --- MARKET ---
// --------------
market()
{
thread market_dialogue();
thread market_fake_choppers();
// allies using chokepoints in the market causes bad behavior
array_thread( level.friends, ::scr_usechokepoints, false );
remove_global_spawn_function( "allies", ::scr_usechokepoints );
thread market_hero1_change_color();
thread market_kill_extra_redshirts();
thread market_door1();
// level progression
thread market_evac();
}
market_fake_choppers()
{
flag_wait( "market_advance_4" );
fakechopper = maps\_vehicle::spawn_vehicle_from_targetname( "vehicle_market_fake_chopper_1" );
flag_wait( "market_chopper_spawned" );
wait( 1 );
fakechopper Delete();
flag_wait( "market_chopper_leaving_scene" ); // a vehiclenode on the chopper path sets this script_flag
wait( 5 );
fakechopper = maps\_vehicle::spawn_vehicle_from_targetname( "vehicle_market_fake_chopper_2" );
flag_wait( "market_evac_chopper_spawned" );
wait( 4 );
fakechopper Delete();
}
market_evac()
{
flag_wait( "market_evac_start" );
thread market_evac_dialogue();
level notify( "color_flags_advance_stop" );
// warp friendlies forward if the player has slammed through this area
warpSpots = GetStructArray( "struct_market_evac_friendly_warp", "targetname" );
ASSERT( warpSpots.size >= level.friends.size );
foreach( idx, guy in level.friends )
{
guy thread market_evac_friend_teleport( warpSpots[ idx ] );
}
// spawn an invincible redshirt if one's not alive right now
nonheroes = get_nonhero_friends();
redshirt = undefined;
if( !nonhero_is_valid( nonheroes ) )
{
// if guys are here now it means they're meleeing, so throw them away and spawn the new guy
if( nonheroes.size )
{
foreach( guy in nonheroes )
{
guy friend_remove();
guy disable_ai_color();
guys = [];
guys[ 0 ] = guy;
thread AI_delete_when_out_of_sight( guys, 1000 );
}
}
// if we don't have any more redshirts, spawn an emergency guy
spawner = GetEnt( "market_evac_redshirt_spawner", "targetname" );
guy = spawner spawn_ai();
ASSERTEX( IsDefined( guy ), "Couldn't spawn emergency friendly for market evac escape." );
guy friend_add();
redshirt = guy;
}
else
{
redshirt = nonheroes[ 0 ];
}
// stop color replacements
maps\_colors::kill_color_replacements();
redshirt magic_bullet_shield_safe();
// redshirt becomes a pink guy
redshirt set_force_color( "p" );
player_speed_percent( 85, 1 );
array_thread( level.friends, ::scr_moveplaybackrate, 1.25 );
battlechatter_off( "allies" );
level thread market_evac_chopper();
level thread market_evac_enemy_foreshadowing();
// "There's Nikolai's Pave Low! Let's go!"
level.sarge delaythread( 2, ::dialogue, "favesc_cmt_therespavelow" );
thread market_evac_friends();
flag_wait( "market_evac_chopper_incoming" );
autosave_by_name( "market_evac_chopper_incoming" );
// keep the redshirt alive, because it looks a lot better when he runs to his climb spot
// with the rest of the squad
nonheroes = get_nonhero_friends();
foreach( guy in nonheroes )
{
guy magic_bullet_shield_safe();
}
delaythread( 0.5, ::market_evac_fakefire_rpgs );
delaythread( 4, ::market_evac_fakefire_smallarms );
thread market_evac_enemies();
flag_set( "market_evac_ambush_start" );
player_speed_percent( 90, 1 );
SetSavedDvar( "ai_friendlyFireBlockDuration", "0" );
flag_wait( "market_evac_enemies_depleted" );
// level progression
thread market_evac_escape();
}
market_evac_friend_teleport( warpSpot )
{
if( Distance( self.origin, level.player.origin ) < 800 )
{
return;
}
if( self != level.sarge && self != level.hero1 )
{
// a meleeing nonhero is going to be replaced later so we don't have to teleport him
if( IsDefined( self.melee ) )
{
return;
}
}
self teleport_to_node( warpSpot );
}
nonhero_is_valid( nonheroes )
{
if( !nonheroes.size )
{
return false;
}
guy = nonheroes[ 0 ];
if( !IsAlive( guy ) )
{
return false;
}
if( IsDefined( guy.melee ) )
{
return false;
}
return true;
}
market_evac_friends()
{
flag_wait( "market_evac_friendlies_go_outside" );
// head outside heat style to predefined nodes
array_thread( level.friends, ::market_evac_friend_outside_setup );
sargeNode = GetNode( "node_sarge_soccerfield_cover", "targetname" );
hero1Node = GetNode( "node_hero1_soccerfield_cover", "targetname" );
redshirtNode = GetNode( "node_redshirt_soccerfield_cover", "targetname" );
redshirt = get_single_redshirt();
level.sarge thread market_evac_friend_runexactpath( sargeNode );
level.hero1 thread market_evac_friend_runexactpath( hero1Node );
redshirt thread market_evac_friend_runexactpath( redshirtNode );
flag_wait( "market_evac_enemies_depleted" );
}
market_evac_friend_outside_setup()
{
self thread clear_force_color();
self thread enable_heat_behavior();
self thread be_less_scared();
self thread set_temp_goalradius( 256 );
self thread disable_arrivals();
self thread set_fixednode_false();
self thread pathrandompercent_set( 0 );
self thread scr_usechokepoints( false );
}
market_evac_friend_runexactpath( startnode )
{
self ent_flag_init( "climbing_ok" );
nodes = get_targeted_line_array( startnode );
// first node in the chain is specially handled
nodes = array_remove( nodes, startnode );
self SetGoalNode( startnode );
// wait til we want to start moving forward
flag_wait( "market_evac_enemies_depleted" );
// always move while shooting
self thread scr_disable_dontshootwhilemoving();
// SUPER accurate - normal scale is 0 to 1 but there are lots of other factors too
self thread scr_accuracy( 5.0 );
foreach( node in nodes )
{
self SetGoalNode( node );
self waittill( "goal" );
}
self disable_heat_behavior();
self ent_flag_set( "climbing_ok" );
}
market_evac_escape()
{
array_thread( level.friends, ::scr_moveplaybackrate, 1 );
player_speed_percent( 90, 1 );
//trigger_activate_targetname_safe( "trig_script_color_allies_b30" );
thread market_evac_remove_helperclip();
// "Come on! We've got to get to the rooftops, this way!"
level.sarge thread dialogue( "favesc_cmt_gettorooftops" );
delaythread( 15, ::market_evac_bugplayer );
//let player get close before friendlies climb
flag_wait( "market_evac_friendlies_start_climbing" );
zTest = 1148;
thread market_evac_playermantle_watch( zTest );
thread market_evac_playermantle_helper( zTest );
thread market_evac_friendlies_climb();
flag_wait( "market_evac_player_on_roof" );
// level progression
thread roofrun();
}
market_evac_friendlies_climb()
{
animref = GetStruct( "market_evac_friendlies_climb_animspot", "targetname" );
animref2 = GetStruct( "market_evac_friendlies_climb_animspot_2", "targetname" );
animeL = "favela_escape_rooftop_traverse_L";
animeR = "favela_escape_rooftop_traverse_R";
animeM = "favela_escape_rooftop_traverse_M";
animeM_idle = "favela_escape_rooftop_traverse_M_idle";
animeM_idle_2_run = "favela_escape_rooftop_traverse_M_idle_2_run";
redshirt = get_single_redshirt();
array_thread( level.friends, ::ent_flag_init, "roofrun_start" );
redshirt magic_bullet_shield_safe();
array_thread( level.friends, ::ignore_everything );
array_thread( level.friends, ::set_temp_goalradius, 32 );
array_thread( level.friends, ::scr_walkDistFacingMotion, 16 ); // per jiesang
hero1Node = GetNode( "node_roofrun_hero1_waitforplayer", "targetname" );
redshirtNode = GetNode( "node_roofrun_redshirt_waitforplayer", "targetname" );
array_thread( level.friends, ::clear_force_color );
level.friendliesClimbing = 0;
level.hero1 thread market_evac_friendly_climb( animref2, animeL, hero1Node );
redshirt thread market_evac_friendly_climb( animref, animeR, redshirtNode );
level.sarge thread market_evac_sarge_climb( animref, animeM, animeM_idle, animeM_idle_2_run );
// wait for all friendlies to climb up
while( level.friendliesClimbing < level.friends.size )
{
wait( 0.05 );
}
// remove player blocking clip
trigger_off( "sbmodel_market_evac_playerblock", "targetname" );
}
market_evac_friendly_climb( animref, anime, node )
{
// wait to finish the exact path running through the soccer field
self ent_flag_wait( "climbing_ok" );
animref anim_generic_reach( self, anime );
level.friendliesClimbing++;
animref anim_generic( self, anime );
self SetGoalNode( node );
wait( 0.05 );
self ent_flag_set( "roofrun_start" );
}
market_evac_sarge_climb( animref, anime, anime_idle, anime_idle_2_run )
{
// wait to finish the exact path running through the soccer field
self ent_flag_wait( "climbing_ok" );
flag_set( "market_evac_follow_sarge_climb" );
animref anim_generic_reach( self, anime );
level.friendliesClimbing++;
animref anim_generic( self, anime );
if( market_evac_sarge_should_idle() )
{
self SetGoalPos( self.origin );
animref thread anim_generic_loop( self, anime_idle, "sarge_idle_stop" );
while( market_evac_sarge_should_idle() )
{
wait( 0.05 );
}
animref notify( "sarge_idle_stop" );
animref anim_generic( self, anime_idle_2_run );
}
sargeNode = GetNode( "node_roofrun_sarge_waitforplayer", "targetname" );
self SetGoalNode( sargeNode );
wait( 0.05 );
self ent_flag_set( "roofrun_start" );
}
market_evac_sarge_should_idle()
{
if( flag( "market_evac_player_mantled" ) )
{
return false;
}
trig = GetEnt( "trig_market_evac_mantlehelper", "targetname" );
if( level.player IsTouching( trig ) )
{
return false;
}
return true;
}
// ----------------
// --- ROOF RUN ---
// ----------------
roofrun()
{
autosave_by_name( "roofrun_start" );
level.runnersDone = 0;
thread roofrun_waitfor_finish();
battlechatter_off( "allies" );
flag_wait( "roofrun_player_at_start_loc" );
thread roofrun_chopper_cargodoor_open();
delaythread( 3, ::roofrun_walla );
// TODO I think this stuff needs adjustment based on distance
player_speed_percent( 90, 1 );
setSavedDvar( "player_sprintUnlimited", "1" );
array_thread( level.friends, ::scr_animplaybackrate, 1.135 );
foreach( index, guy in level.friends )
{
guy.animname = "freerunner";
guy thread roofrun_friendly_generic();
if( guy == level.sarge )
{
guy thread roofrun_sarge();
}
else if( guy == level.hero1 )
{
guy thread roofrun_hero1();
}
else
{
guy thread roofrun_redshirt();
}
}
thread roofrun_dialogue();
//thread roofrun_modulate_playerspeed( level.sarge );
thread roofrun_player_bigjump();
flag_wait( "player_recovery_done" );
// level progression
thread solorun();
}
roofrun_chopper_cargodoor_open()
{
chopperSpawner = GetEnt( "veh_chopper_roofrun", "targetname" );
chopper = undefined;
if( IsDefined( chopperSpawner.last_spawned_vehicle ) )
{
chopper = chopperSpawner.last_spawned_vehicle;
}
else
{
chopperSpawner waittill( "spawned", chopper );
}
chopper.animname = "chopper";
chopper waittill( "reached_dynamic_path_end" );
flag_wait( "player_near_bigjump" );
chopper PlaySound( "pavelow_door_open" );
chopper anim_single_solo( chopper, "cargodoor_open" );
}
// ----------------
// --- SOLO RUN ---
// ----------------
solorun( start )
{
flag_set( "solorun_start" );
waitBeforeJump = undefined;
if( !IsDefined( start ) )
{
start = "normal";
}
player_speed_percent( 100, 0.1 );
player_sprint_multiplier_blend( 1.5, 0.1 );
setSavedDvar( "player_sprintUnlimited", "1" );
// sprinty hands
level.player GiveWeapon( "freerunner" );
level.player SwitchToWeapon( "freerunner" );
if( start == "chopperjump" )
{
thread rooftop_slide_exploder();
thread rooftop_slide_glassbreak();
waitBeforeJump = false;
thread solorun_chopperjump( waitBeforeJump );
}
else if( start == "rooftops" )
{
thread solorun_balcony_save();
thread solorun_player_difficulty_adjustment();
thread solorun_sprint_tracker();
thread solorun_playerhurt_replacehint();
thread solorun_player_progression_tracker();
thread player_bullet_whizbys();
thread solorun_dialogue( false );
thread solorun_rooftop_squibs();
thread solorun_timer_prethink();
thread solorun_chasers_remove();
thread solorun_rooftop_chopper_fakefire();
thread solorun_chopper_audio();
thread rooftop_slide_exploder();
thread rooftop_slide_glassbreak();
thread rooftop_slide_deleteaxis();
thread solorun_chopperjump( waitBeforeJump );
}
else
{
thread solorun_start_playerfail( 0.75 );
thread solorun_civilian_doorshut();
thread solorun_balcony_save();
thread solorun_player_difficulty_adjustment();
thread solorun_sprint_tracker();
thread solorun_playerhurt_replacehint();
thread solorun_player_progression_tracker();
thread player_bullet_whizbys();
thread solorun_dialogue();
thread solorun_rooftop_squibs();
thread solorun_timer_prethink();
thread solorun_chasers_remove();
thread solorun_rooftop_chopper_fakefire();
thread solorun_chopper_audio();
thread rooftop_slide_exploder();
thread rooftop_slide_glassbreak();
thread rooftop_slide_deleteaxis();
thread solorun_chopperjump( waitBeforeJump );
}
flag_wait( "solorun_player_boarded_chopper" );
wait( 8 );
fadeTime = 4;
blackTime = 4;
// fade to black
black_overlay = create_client_overlay( "black", 0, level.player );
black_overlay FadeOverTime( fadeTime );
black_overlay.alpha = 1;
wait( fadeTime );
flag_set( "level_faded_to_black" );
wait( blackTime );
nextmission();
}
solorun_balcony_save()
{
flag_wait( "solorun_player_near_balcony" );
if( solorun_balcony_save_aicheck() )
{
maps\_autosave::_autosave_game_now();
}
}
// mostly copied from _autosave::autoSaveThreatCheck(), with some omissions
solorun_balcony_save_aicheck()
{
volume = GetEnt( "vol_solorun_ai_behind_player_near_balcony", "targetname" );
enemies = GetAISpeciesArray( "bad_guys", "all" );
foreach ( enemy in enemies )
{
if ( !IsDefined( enemy.enemy ) )
{
continue;
}
if ( !IsPlayer( enemy.enemy ) )
{
continue;
}
// is trying to melee the player
if ( IsDefined( enemy.Melee ) && IsDefined( enemy.melee.target ) && IsPlayer( enemy.melee.target ) )
{
/# maps\_autosave::AutoSavePrint( "autosave failed: AI meleeing player" ); #/
return( false );
}
if ( enemy.finalAccuracy < 0.021 && enemy.finalAccuracy > -1 )
{
// enemy lacks the accuracy to be a threat
continue;
}
// level specific! he's in the room behind the player
if( volume IsTouching( enemy ) )
{
/# maps\_autosave::AutoSavePrint( "autosave failed: AI are in a volume close behind the player" ); #/
return false;
}
/* we want CanSee checks here, this area is too squirrelly for distance checks to work well
proximity_threat = false;
foreach ( player in level.players )
{
dist = Distance( enemy.origin, player.origin );
if ( dist < 360 )
{
/# maps\_autosave::AutoSavePrint( "autosave failed: AI too close to player" ); #/
return false;
}
else
if ( dist < 1000 )
{
proximity_threat = true;
}
}
if ( !proximity_threat )
{
// enemy isn't close enough to be a threat
continue;
}
*/
// recently shot at the player
if ( enemy.a.lastShootTime > GetTime() - 500 )
{
if ( enemy animscripts\utility::canSeeEnemy( 0 ) && enemy CanShootEnemy( 0 ) )
{
/# maps\_autosave::AutoSavePrint( "autosave failed: AI firing on player" ); #/
return false;
}
}
if ( IsDefined( enemy.a.aimIdleThread ) && enemy animscripts\utility::canSeeEnemy( 0 ) && enemy CanShootEnemy( 0 ) )
{
/# maps\_autosave::AutoSavePrint( "autosave failed: AI aiming at player" ); #/
return false;
}
}
if ( player_is_near_live_grenade() )
{
return false;
}
return true;
}