#include maps\_utility; #include maps\_vehicle; #include common_scripts\utility; #include maps\_anim; #using_animtree( "generic_human" ); ENEMY_BASE_ACCURACY = 0.6; //######################################## // VISION SETS //######################################## vision_chase() { flag_wait( "visionset_chase" ); time = 6; maps\_utility::set_vision_set( "favela_chase", time ); //setExpFog( 708.893, 5902.43, 0.402663, 0.456692, 0.520202, 0.721229, 0, 0.562109, 0.600449, 0.678415, (0.89008, -0.302316, -0.341119), 0, 51.1533, 1.80097 ); } vision_torture() { flag_wait( "visionset_torture" ); time = 1; maps\_utility::set_vision_set( "favela_torture", time ); //setExpFog( 708.893, 5902.43, 0.402663, 0.456692, 0.520202, 0.721229, 0, 0.562109, 0.600449, 0.678415, (0.89008, -0.302316, -0.341119), 0, 51.1533, 1.80097 ); } //######################################## //######################################## movePlayerToStartPoint( sTargetname ) { assert( isdefined( sTargetname ) ); start = getent( sTargetname, "targetname" ); level.player SetOrigin( start.origin ); lookat = undefined; if ( isdefined( start.target ) ) { lookat = getent( start.target, "targetname" ); assert( isdefined( lookat ) ); } if ( isdefined( lookat ) ) level.player setPlayerAngles( vectorToAngles( lookat.origin - start.origin ) ); else level.player setPlayerAngles( start.angles ); } modify_battlechatter_times() { MULT = 0.25; // delay to make sure these get set at the level load first wait 0.1; // "contact to the north!" etc. anim.eventActionMinWait[ "threat" ][ "self" ] *= MULT; // 14000 anim.eventActionMinWait[ "threat" ][ "squad" ] *= MULT; // 10000 // "cover me!" / "suppressing fire!" / "let's go!" etc. anim.eventActionMinWait[ "order" ][ "self" ] *= MULT; // 8000; anim.eventActionMinWait[ "order" ][ "squad" ] *= MULT; // 10000; // "reloading!" / "grenade out!" anim.eventActionMinWait[ "inform" ][ "self" ] *= MULT; // 6000; anim.eventActionMinWait[ "inform" ][ "squad" ] *= MULT; // 8000; // specific categories of the above anim.eventTypeMinWait[ "inform" ][ "reloading" ] *= MULT; // 20000; anim.eventTypeMinWait[ "inform" ][ "killfirm" ] *= MULT; // 15000; // "Man down!" anim.eventTypeMinWait[ "reaction" ][ "casualty" ] *= MULT; // 14000; // this is the one that I think might make a big difference as long as these enemies have "hostile bursts" anim.eventTypeMinWait[ "reaction" ][ "taunt" ] *= MULT; // 30000; } adjustAccuracy() { self endon( "death" ); wait 0.2; self.baseaccuracy = ENEMY_BASE_ACCURACY; } start_traffic_group( delay, targetname1, targetname2, targetname3 ) { level endon( "stop_street_traffic" ); assert( isdefined( delay ) ); assert( isdefined( targetname1 ) ); carTargetNames[ 0 ] = targetname1; if ( isdefined( targetname2 ) ) carTargetNames[ 1 ] = targetname2; if ( isdefined( targetname3 ) ) carTargetNames[ 2 ] = targetname3; for(;;) { thread traffic_car_go( carTargetNames[ randomint( carTargetNames.size ) ] ); wait delay; } } stop_traffic() { level notify( "stop_street_traffic" ); thread delete_cars_far_away(); } delete_cars_far_away() { cars = getentarray( "script_vehicle", "code_classname" ); foreach( car in cars ) { if ( !car ent_flag_exist( "dont_delete_me" ) ) continue; if ( car ent_flag( "dont_delete_me" ) ) continue; car delete(); } } traffic_car_go( sTargetname ) { assert( isdefined( sTargetname ) ); car = spawn_vehicle_from_targetname_and_drive( sTargetname ); assert( isdefined( car ) ); car ent_flag_init( "dont_delete_me" ); car waittill( "reached_end_node" ); car delete(); } delete_ai_at_path_end() { self endon( "death" ); self waittill( "reached_path_end" ); delete_ai( self ); } delete_ai( ai ) { guys[ 0 ] = ai; level thread AI_delete_when_out_of_sight( guys, 512 ); } delete_ai_at_path_end_no_choke() { self.usechokepoints = false; self thread delete_ai_at_path_end(); } delete_ai_at_goal( ignoreCanSeeChecks ) { self endon( "death" ); self waittill( "goal" ); if ( isdefined( ignoreCanSeeChecks ) && ignoreCanSeeChecks ) { if ( isdefined( self.magic_bullet_shield ) ) self stop_magic_bullet_shield(); self delete(); } else delete_ai( self ); } dog_seek_player() { self endon( "death" ); if ( isdefined( self.target ) ) self waittill( "goal" ); self setgoalentity( level.player ); self.goalradius = 300; } seek_player() { self endon( "death" ); if ( isdefined( self.target ) ) self waittill( "goal" ); self setgoalentity( level.player ); self.goalradius = 1000; } gag_fence_dog() { trigger_wait( "fence_dog_gag", "targetname" ); // spawn the dog spawner = getent( "fence_dog_spawner", "targetname" ); dog = spawner stalingradSpawn(); spawn_failed( dog ); dog endon( "death" ); dog.animname = "dog"; old_maxsightdistsqrd = dog.maxsightdistsqrd; dog.maxsightdistsqrd = 0; dog set_ignoreall( true ); animNode = getent( "fence_dog_node", "targetname" ); dog setlookatEntity( level.player ); animNode anim_reach_solo( dog, "fence_attack" ); dog.allowdeath = true; animNode anim_single_solo( dog, "fence_attack" ); dog.maxsightdistsqrd = old_maxsightdistsqrd; dog set_ignoreall( false ); dog thread dog_seek_player(); wait 1; dog setlookatEntity(); } dont_see_player() { self endon( "death" ); self addAIEventListener( "bulletwhizby" ); self.usechokepoints = false; self.interval = 0; self.fovcosine = 0.7; self.pathenemyfightdist = 512; self waittill_either( "damage", "bulletwhizby" ); self.goalradius = level.default_goalradius; self setgoalpos( self.origin ); } window_smasher() { self endon( "death" ); self.dontevershoot = true; // get nearest window_smash ent window = self getWindowParts(); // wait until AI is at the window node windowNode = self getWindowNode(); self.goalradius = 16; self setGoalNode( windowNode ); // play melee anim windowNode thread anim_generic( self, "window_smash" ); thread open_window( window, 0.1 ); wait 0.3; self stopAnimScripted(); wait 0.3; self.dontevershoot = undefined; wait 1.0; self.goalradius = 75; } getWindowNode() { nodes = getnodearray( "window_smash_node", "targetname" ); index = get_closest_index( self.origin, nodes ); return nodes[ index ]; } getWindowParts() { windows = getentarray( "window_smash", "targetname" ); index = get_closest_index( self.origin + ( 0, 0, 48 ), windows ); windowEnt = windows[ index ]; windowParts = getentarray( windowEnt.target, "targetname" ); assert( windowParts.size == 2 ); leftWindow = undefined; rightWindow = undefined; foreach( part in windowParts ) { if ( part.script_noteworthy == "left" ) leftWindow = part; else if ( part.script_noteworthy == "right" ) rightWindow = part; } assert( isdefined( leftWindow ) ); assert( isdefined( rightWindow ) ); ents = []; ents[ "left" ] = leftWindow; ents[ "right" ] = rightWindow; return ents; } open_window( window, delay ) { if ( isdefined( delay ) ) wait delay; thread play_sound_in_space( "scn_favela_npc_open_shutters", window[ "left" ].origin ); window[ "left" ] rotateYaw( 155, 0.5, 0.0 ); window[ "right" ] rotateYaw( -155, 0.4, 0.0 ); wait 0.5; window[ "left" ] rotateYaw( -15, 1.0, 1.0 ); window[ "left" ] rotateYaw( 15, 1.0, 1.0 ); } play_sound_trigger() { assert( isdefined( self.script_noteworthy ) ); assert( isdefined( self.target ) ); soundEnt = getent( self.target, "targetname" ); assert( isdefined( soundEnt ) ); self waittill( "trigger" ); thread play_sound_in_space( self.script_noteworthy, soundEnt.origin ); } gag_civilian_window_1() { trigger_wait( "gag_civilian_window_1", "targetname" ); // spawn character spawner = getent( "window_civilian_spawner_1", "targetname" ); guy = spawner spawn_ai( true ); guy endon( "death" ); // play anim windowNode = getent( "civilian_window_node1", "targetname" ); windowNode anim_generic( guy, "civilian_window_1" ); // run away and delete runawayNode = getnode( "window_civilian_spawner_runto_node", "targetname" ); guy.goalradius = 16; guy setGoalNode( runawayNode ); delete_ai( self ); guy thread delete_ai_at_goal(); } ignored_until_goal() { // AI is ignored by enemy AI until he gets to his goal self endon( "death" ); self.ignoreme = true; self waittill( "goal" ); wait randomfloatrange( 1.0, 2.0 ); self.ignoreme = false; } ignore_and_delete_on_goal( ignoreCanSeeChecks ) { self thread set_ignoreme( true ); self thread set_ignoreall( true ); self thread delete_ai_at_goal( ignoreCanSeeChecks ); } faust_spawn_func() { if ( isdefined( level.faust ) ) { if ( isdefined( level.faust.magic_bullet_shield ) ) { level.faust stop_magic_bullet_shield(); wait 0.05; } level.faust delete(); level.faust = undefined; } level.faust = self; // he runs his path. When he gets to the end of his path he gets deleted level.faust endon( "death" ); level.faust set_ignoreall( true ); level.faust set_ignoreme( true ); level.faust thread magic_bullet_shield(); level.faust thread faust_spills_money(); level.faust thread faust_mission_fail(); level.faust waittill( "reached_path_end" ); if ( isdefined( level.faust.magic_bullet_shield ) ) level.faust stop_magic_bullet_shield(); wait 0.05; level.faust delete(); level.faust = undefined; } faust_spills_money() { self endon( "death" ); for(;;) { playfxontag( getfx( "cash_trail" ), self, "J_Hip_LE" ); wait randomfloatrange( 0.2, .5); } } faust_mission_fail() { self endon( "reached_path_end" ); for(;;) { self waittill( "damage", damage, attacker ); if ( !isdefined( attacker ) ) continue; if ( attacker != level.player ) continue; if ( damage <= 1 ) continue; break; } self stop_magic_bullet_shield(); wait 0.05; self kill( self.origin, level.player ); setdvar( "ui_deadquote", "@FAVELA_ROJAS_KILLED" ); maps\_utility::missionFailedWrapper(); } trigger_spawn_chance() { spawners = getentarray( self.target, "targetname" ); assert( spawners.size > 0 ); self waittill( "trigger" ); chance_percent = 25; if ( isdefined( self.script_noteworthy ) ) chance_percent = int( self.script_noteworthy ); if ( randomint( 100 ) > chance_percent ) return; spawners = array_removeundefined( spawners ); array_thread( spawners, ::spawn_ai ); } desert_eagle_guy() { self endon( "death" ); self forceUseWeapon( "deserteagle", "sidearm" ); anim.shootEnemyWrapper_func = animscripts\utility::ShootEnemyWrapper_shootNotify; self.weapon = self.sidearm; self.favoriteenemy = level.player; self.disablearrivals = true; self.disableexits = true; self.animname = "desert_eagle_guy"; self.baseaccuracy = 1; self.noAttackerAccuracyMod = true; self.accuracy = 1; self.goalradius = 16; self thread delayThread( 3.0, ::set_goalradius, 300 ); self thread delayThread( 3.0, ::set_goal_player ); self playsound( "generic_meleecharge_russian_" + randomintrange( 1, 8 ) ); while ( level.player.health > 0 ) { level waittill( "an_enemy_shot", guy ); if ( guy != self ) continue; num = 1; while ( num ) { wait .25; self shoot(); num -- ; } } self.ignoreme = true; } set_goal_player() { if ( !isAlive( self ) ) return; if ( !isAlive( level.player ) ) return; self setGoalPos( level.player.origin ); } process_ai_script_parameters() { if ( !isdefined( self.script_parameters ) ) return; parms = strtok( self.script_parameters, ":;, " ); foreach( parm in parms ) { parm = tolower( parm ); if ( parm == "balcony" ) self.deathFunction = ::try_balcony_death; } } try_balcony_death() { // always return false in this function because we want the death // animscript to continue after this function no matter what if ( !isdefined( self ) ) return false; if ( self.a.pose == "prone" ) // allow crouch return false; if ( !isdefined( self.prevnode ) ) return false; if ( !isdefined( self.prevnode.script_balcony ) ) return false; angleAI = self.angles[ 1 ]; angleNode = self.prevnode.angles[ 1 ]; angleDiff = abs( angleAI - angleNode ); if ( angleDiff > 15 ) return false; d = distance( self.origin, self.prevnode.origin ); if ( d > 16 ) return false; if ( !isdefined( level.last_balcony_death ) ) level.last_balcony_death = getTime(); elapsedTime = getTime() - level.last_balcony_death; // if one just happened within 5 seconds dont do it if ( elapsedTime < 5 * 1000 ) return false; deathAnims = []; deathAnims[0] = %death_rooftop_A; deathAnims[1] = %death_rooftop_B; deathAnims[2] = %death_rooftop_D; deathAnims[3] = %bog_b_rpg_fall_death; self.deathanim = deathAnims[ randomint( deathAnims.size ) ]; return false; } control_run_speed() { level endon( "runner_shot" ); self endon( "death" ); // speed and slows runner's run speed so the player can't catch him but also doesn't get left too far behind targetSpeed = undefined; //self.moveplaybackrate = 1.2; //self.sprint = true; flag_wait( "soap_control_run_speed" ); /* for(;;) { targetSpeed = self get_best_run_speed(); self thread set_run_speed( targetSpeed ); wait 0.2; } */ } get_best_run_speed() { ai_dist = distance( self.origin, self.last_set_goalnode.origin ); player_dist = distance( level.player.origin, self.last_set_goalnode.origin ); offset = ai_dist - player_dist; RATE_MIN = 1.0; RATE_MAX = 1.5; DISTANCE_MIN = -450; DISTANCE_MAX = 0; offset = cap_value( offset, DISTANCE_MIN, DISTANCE_MAX ); // player is far behind, normal run speed if ( offset < DISTANCE_MIN ) return RATE_MIN; // player is ahead of AI, max run speed if ( offset >= DISTANCE_MAX ) return RATE_MAX; // player is close behind the AI, control run speed to make sure AI stays ahead fraction = get_fraction( offset, DISTANCE_MIN, DISTANCE_MAX ); targetSpeed = RATE_MAX - ( ( RATE_MAX - RATE_MIN ) * fraction ); assert( targetSpeed > 0 ); return targetSpeed; } set_run_speed( targetSpeed ) { assert( isdefined( targetSpeed ) ); self.moveplaybackrate = targetSpeed; } get_fraction( value, min, max ) { fraction = abs( ( value - min ) / ( min - max ) ); fraction = abs( 1 - fraction ); fraction = cap_value( fraction, 0.0, 1.0 ); return fraction; } physics_drop() { assert( isdefined( self.target ) ); orgs = getentarray( self.target, "targetname" ); assert( orgs.size > 0 ); self waittill( "trigger" ); array_thread( orgs, ::physics_drop_model ); } physics_drop_model() { model = spawn( "script_model", self.origin ); model setModel( level.physics_drop_models[ randomint( level.physics_drop_models.size ) ] ); vec = anglesToForward( self.angles ); vec *= 2000; model PhysicsLaunchClient( model.origin + ( 0, 0, 0 ), vec ); } forklift_blocker() { forklift_before = getentarray( "forklift_before", "targetname" ); forklift_before_clip = getent( "forklift_before_clip", "targetname" ); forklift_after = getentarray( "forklift_after", "targetname" ); forklift_after_clip = getent( "forklift_after_clip", "targetname" ); // hide after array_call( forklift_after, ::hide ); forklift_after_clip notsolid(); flag_wait( "block_alley" ); // show after, hide before array_call( forklift_after, ::show ); forklift_after_clip solid(); array_call( forklift_before, ::delete ); forklift_before_clip delete(); } car_anims() { // attach hula girl tag = "tag_hulagirl_attach"; level.hula_girl = spawn_anim_model( "hula_girl", self getTagOrigin( tag ) ); level.hula_girl.angles = self getTagAngles( tag ); level.hula_girl linkTo( self, tag ); level.hula_girl setAnim( level.scr_anim[ "hula_girl" ][ "bobble" ] ); self setAnim( level.scr_anim[ "car" ][ "driving" ] ); self waittill( "reached_end_node" ); self clearAnim( level.scr_anim[ "car" ][ "driving" ], 1.0 ); level.hula_girl clearAnim( level.scr_anim[ "hula_girl" ][ "bobble" ], 1.0 ); level.hula_girl setAnim( level.scr_anim[ "hula_girl" ][ "bobble_stop" ] ); wait 1.55; level.hula_girl clearAnim( level.scr_anim[ "hula_girl" ][ "bobble_stop" ], 1.0 ); // opens the door when soap exists the vehicle flag_wait( "soap_exits_car" ); self setAnim( level.scr_anim[ "car" ][ "run_and_wave" ] ); self waittill( "door_open" ); self thread play_sound_on_entity( "scn_favela_player_door_open" ); self setAnim( level.scr_anim[ "car" ][ "door_open" ] ); } car_driver_anims() { driver = make_car_driver(); assert( isdefined( driver ) ); driver linkTo( self, "tag_driver" ); self thread anim_loop_solo( driver, "idle", "stop_drive_idle", "tag_driver" ); wait 13; self notify( "stop_drive_idle" ); self setanimknob( level.scr_anim[ "car" ][ "center2right" ], 1, 0, 1 ); self anim_single_solo( driver, "center2right", "tag_driver" ); wait 1; self clearAnim( level.scr_anim[ "car" ][ "center2right" ], 0 ); self setanimknob( level.scr_anim[ "car" ][ "right2center" ], 1, 0, 1 ); self anim_single_solo( driver, "right2center", "tag_driver" ); self clearAnim( level.scr_anim[ "car" ][ "right2center" ], 0 ); self thread anim_loop_solo( driver, "idle", "stop_drive_idle", "tag_driver" ); flag_wait( "opening_scene_started" ); self thread play_sound_on_entity( "scn_favela_driver_killed" ); self anim_single_solo( driver, "react", "tag_driver" ); } make_car_driver() { guy = spawn_targetname( "car_driver" ); model = spawn( "script_model", guy.origin ); model.angles = guy.angles; model setmodel( guy.model ); numAttached = guy getattachsize(); for ( i = 0; i < numAttached; i++ ) { modelname = guy getattachmodelname( i ); tagname = guy getattachtagname( i ); model attach( modelname, tagname, true ); } model.animname = "driver"; model UseAnimTree( #animtree ); guy delete(); return model; } trigger_cleanup() { assert( isdefined( self.target ) ); areas = getentarray( self.target, "targetname" ); assert( areas.size > 0 ); self waittill( "trigger" ); foreach( area in areas ) { array_thread( area get_ai_touching_volume( "axis" ), ::delete_ai_not_bullet_shielded ); } } delete_ai_not_bullet_shielded() { if ( isdefined( self.magic_bullet_shield ) ) return; self delete(); } bike_rider( pathTargetname ) { bike_path_start = getent( pathTargetname, "targetname" ); bike_path_end = getent( bike_path_start.target, "targetname" ); bike = spawn( "script_model", bike_path_start.origin ); bike setModel( "com_bike_animated" ); bike useAnimTree( level.scr_animtree[ "bike" ] ); rider = spawn( "script_model", bike.origin ); rider useAnimTree( #animtree ); if ( !isdefined( level.spawned_bike_rider ) ) { level.spawned_bike_rider = true; rider character\character_civilian_slum_male_aa::main(); } else { rider character\character_civilian_slum_male_ab::main(); } rider.origin = bike getTagOrigin( "j_frame" ); rider.origin += ( -12, 0, -30 ); rider.angles = bike getTagAngles( "j_frame" ); rider.angles += ( 0, 180, 0 ); rider linkTo( bike, "j_frame" ); ang = vectorToAngles( bike_path_start.origin - bike_path_end.origin ); bike.angles = ( 0, ang[ 1 ], 0 ); bike setanim( level.scr_anim[ "bike" ][ "pedal" ] ); rider setanim( level.scr_anim[ "generic" ][ "bike_rider" ] ); moveTime = 10; bike MoveTo( bike_path_end.origin, moveTime, 0, 0 ); wait moveTime; rider delete(); bike delete(); } potted_plant() { forward = anglesToForward( self.angles ); up = anglesToUp( self.angles ); pos = self.origin; trig = undefined; if ( isdefined( self.target ) ) trig = getent( self.target, "targetname" ); self thread potted_plant_damage(); if ( isdefined( trig ) ) self thread potted_plant_triggered( trig ); self waittill( "fall" ); fx = undefined; switch( self.model ) { case "com_potted_plant_small": fx = getfx( "plant_small_thrower" ); break; case "com_potted_plant_medium": fx = getfx( "plant_medium_thrower" ); break; case "com_potted_plant_large": fx = getfx( "plant_large_thrower" ); break; } assert( isdefined( fx ) ); self delete(); playFX( fx, pos, forward, up ); } potted_plant_damage() { self endon( "fall" ); self setCanDamage( true ); self waittill( "damage" ); self notify( "fall" ); } potted_plant_triggered( trig ) { self endon( "fall" ); trig waittill( "trigger" ); wait randomfloatrange( 0.0, 0.2 ); self notify( "fall" ); } play_fx_trig() { assert( isdefined( self.script_noteworthy ) ); fx = self.script_noteworthy; assert( isdefined( level._effect[ fx ] ) ); assert( isdefined( self.target ) ); fxEnt = getent( self.target, "targetname" ); fxID = getfx( fx ); for(;;) { self waittill( "trigger" ); playFX( fxID, fxEnt.origin ); wait 1.0; } } civilian_flee_walla() { self endon( "death" ); // civillians don't do wallas until you're in the favela if ( !flag( "civilians_walla" ) ) return; wait 0.05; while( self.alertLevelInt <= 1 ) wait 0.05; if ( !isdefined( level.nextWallaIndex ) ) level.nextWallaIndex = 0; elapsedTime = getTime() - level.lastWallaTime; if ( elapsedTime < 5000 ) return; level.lastWallaTime = getTime(); // walla animScene = level.fleeing_civilian_wallas[ level.nextWallaIndex ]; self.allowdeath = true; self thread anim_generic( self, animScene ); level.nextWallaIndex++; if ( level.nextWallaIndex >= level.fleeing_civilian_wallas.size ) nextWallaIndex = 0; } ending_car_fx( vehicle ) { exploder ( "car_crush_cash" ); wait 0.1; exploder ( "car_crush" ); playfxontag( getFX( "car_crush_glass_med" ), vehicle, "tag_window_left_glass_fx" ); playfxontag( getFX( "car_crush_glass_med" ), vehicle, "tag_window_right_glass_fx" ); playfxontag( getFX( "car_crush_glass_large" ), vehicle, "tag_windshield_back_glass_fx" ); playfxontag( getFX( "car_crush_glass_large" ), vehicle, "tag_windshield_front_glass_fx" ); } dive_through_glass( guy ) { PlayFXOnTag( getFX( "glass_dust_trail" ), guy, "J_SpineLower" ); guy thread maps\favela::ending_sequence_slowmo(); } delete_ai_during_blackscreen() { ai = getAIArray(); foreach( guy in ai ) { if ( isdefined( guy.magic_bullet_shield ) ) guy stop_magic_bullet_shield(); guy notify( "deleted" ); } array_call( getAIArray(), ::delete ); } curtain_pulldown( bWaitForPlayer ) { if ( !isdefined( bWaitForPlayer ) ) bWaitForPlayer = false; assert( isdefined( self.target ) ); node = self curtain_pulldown_getnode(); assert( isdefined( node ) ); curtain = spawn_anim_model( "curtain" ); node thread anim_first_frame_solo( curtain, "pulldown" ); self waittill( "spawned", guy ); if ( spawn_failed( guy ) ) return; guy endon( "death" ); guy.animname = "curtain_pull"; guy.disablepain = true; guy set_ignoreme( true ); guy.usechokepoints = false; wait 0.05; guy_and_curtain[ 0 ] = guy; guy_and_curtain[ 1 ] = curtain; node anim_reach_solo( guy, "pulldown" ); if ( bWaitForPlayer ) { node anim_first_frame_solo( guy, "pulldown" ); waittill_player_lookat( 0.9, undefined, true, 5.0 ); } // Don't allow guy to die until 1.5 seconds in so the curtain doesn't fall on it's own guy.allowdeath = false; guy thread allow_death_delayed( 1.5 ); node anim_single( guy_and_curtain, "pulldown" ); guy endon( "death" ); guy set_ignoreme( false ); guy.goalradius = 1000; guy setGoalPos( guy.origin ); guy.usechokepoints = true; } allow_death_delayed( delay ) { wait delay; if ( isdefined( self ) ) self.allowdeath = true; } curtain_pulldown_getnode() { nodes = getentarray( self.target, "targetname" ); foreach( node in nodes ) { if ( node.classname == "script_origin" ) return node; } assertMsg( "curtain pulldown guy doesn't target a script_origin" ); } car_screech_node() { self waittill( "trigger", vehicle ); assert( isdefined( vehicle ) ); sound[ 0 ] = "scn_favela_car_traffic_skid1"; sound[ 1 ] = "scn_favela_car_traffic_skid2"; sound[ 2 ] = "scn_favela_car_traffic_skid3"; if ( !isdefined( level.next_skid_sound ) ) level.next_skid_sound = 0; vehicle playSound( sound[ level.next_skid_sound ] ); level.next_skid_sound++; if ( level.next_skid_sound >= sound.size ) level.next_skid_sound = 0; } retreat_trigger() { assert( isdefined( self.target ) ); node = getnode( self.target, "targetname" ); assert( isdefined( node ) ); assert( isdefined( node.radius ) ); volume = getent( self.target, "targetname" ); assert( isdefined( volume ) ); self waittill( "trigger" ); // get all AI in the volume ai = volume get_ai_touching_volume( "axis" ); // make all ai touching the volume go to the specified node with it's radius foreach( guy in ai ) { guy.goalradius = node.radius; guy set_goal_node( node ); } } timed_favela_autosaves() { flag_wait( "player_entered_favela" ); while( !flag( "cleared_favela" ) ) { wait 60; if ( flag( "cleared_favela" ) ) return; thread autosave_by_name( "lower_favela" ); } } civilian_driver() { self.disablepain = true; self.a.nodeath = true; self.health = 10000000000; } faust_assistant_kill_player_monitor() { self endon( "death" ); distSq = 400 * 400; cos90 = cos( 90 ); for(;;) { wait 0.05; // player must be within range of Faust's assistant d = DistanceSquared( self.origin, level.player.origin ); if ( d > distSq ) continue; // player must be in front of Faust's assistant FOV = within_fov( self.origin, self.angles, level.player.origin, cos90 ); if ( !FOV ) continue; // Faust's assisstant should now kill the player for getting in front of him self thread faust_assistant_kill_player(); return; } } faust_assistant_kill_player() { self endon( "death" ); level.player endon( "death" ); // kill the player createThreatBiasGroup( "player" ); createThreatBiasGroup( "makarov" ); level.player setThreatBiasGroup( "player" ); self setThreatBiasGroup( "makarov" ); setThreatBias( "makarov", "player", 100000 ); self.maxsightdistsqrd = 8000 * 8000; self set_ignoreall( false ); self set_ignoreme( true ); self.goalradius = 16; self setGoalPos( self.origin ); level.player.health = 1; self waittill( "shooting" ); wait 0.05; if ( isalive( level.player ) ) level.player kill(); }