1658 lines
44 KiB
Plaintext
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;
|
|
}
|