#include maps\_utility; #include common_scripts\utility; #include maps\_anim; #include maps\_hud_util; precacheLevelStuff() { precacheString( &"VILLAGE_ASSAULT_OBJECTIVE_LOCATE_ALASAD" ); precacheString( &"SCRIPT_ARMOR_DAMAGE" ); precacheString( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1" ); precacheString( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1_PC" ); precacheShader( "black" ); precacheShader( "hud_icon_cobra" ); precacheShader( "popmenu_bg" ); precacheShader( "hud_dpad" ); precacheShader( "hud_arrow_right" ); precacheModel( "sundirection_arrow" ); precacheModel( "com_folding_chair" ); precacheModel( "com_flashlight_off" ); precacheModel( "com_flashlight_on" ); precacheItem( "mi28_ffar_village_assault" ); precacheItem( "flash_grenade" ); precacheItem( "colt45_alasad_killer" ); flag_init( "gave_air_support_hint" ); flag_init( "alasad_sequence_started" ); flag_init( "air_support_refueling" ); flag_init( "delete_attack_coord_hint" ); level.weaponClipModels = []; level.weaponClipModels[0] = "weapon_ak47_clip"; level.weaponClipModels[1] = "weapon_mp5_clip"; level.weaponClipModels[2] = "weapon_m16_clip"; level.weaponClipModels[3] = "weapon_g36_clip"; level.weaponClipModels[4] = "weapon_dragunov_clip"; level.weaponClipModels[5] = "weapon_g3_clip"; } setLevelDVars() { setSavedDvar( "r_specularColorScale", "1.8" ); if ( getdvar( "village_assault_debug_marker") == "" ) setdvar( "village_assault_debug_marker", "0" ); level.seekersUsingColors = false; level.BMP_Safety_Distance = 512 * 512; level.goodFriendlyDistanceFromPlayerSquared = 512 * 512; level.chopperSupportCallNextAudio = 0; level.buildingClearNextAudio = 0; level.air_support_hint_print_dialog_next = 0; level.chopperSupportHoverLocations = []; hoverEnts = getentarray( "chopper_location", "targetname" ); for( i = 0 ; i < hoverEnts.size ; i++ ) { level.chopperSupportHoverLocations[ level.chopperSupportHoverLocations.size ] = hoverEnts[ i ].origin; hoverEnts[ i ] delete(); } assert( level.chopperSupportHoverLocations.size > 0 ); level.cosine[ "25" ] = cos( 25 ); level.cosine[ "45" ] = cos( 45 ); level.cosine[ "55" ] = cos( 55 ); level.cosine[ "60" ] = cos( 60 ); level.cosine[ "70" ] = cos( 70 ); level.alasad_possible_objective_locations = []; level.alasad_possible_objective_locations_remaining[ 0 ] = "2"; level.alasad_possible_objective_locations_remaining[ 1 ] = "6"; level.next_genocide_audio = 0; level.genocide_audio[ 0 ] = "assault_killing_distance1"; level.genocide_audio[ 1 ] = "assault_killing_interior1"; level.genocide_audio[ 2 ] = "assault_killing_interior2"; level.genocide_audio[ 3 ] = "assault_killing_interior3"; level.timedAutosaveNumber = 0; level.timedAutosaveTime = undefined; skill = getdifficulty(); switch( skill ) { case "gimp": case "easy": level.timedAutosaveTime = 60; array_thread( getentarray( "bmp_spawn_trigger", "script_noteworthy" ), ::trigger_off ); break; case "medium": level.timedAutosaveTime = 120; break; case "hard": case "difficult": level.timedAutosaveTime = 180; break; case "fu": level.timedAutosaveTime = 0; break; } assert( isdefined( level.timedAutosaveTime ) ); } scriptCalls() { maps\village_assault_anim::main(); level thread maps\village_assault_amb::main(); maps\_compass::setupMiniMap("compass_map_village_assault"); array_thread( getentarray( "seek_player", "script_noteworthy" ), ::add_spawn_function, ::seek_player ); array_thread( getentarray( "indoor_enemy", "script_noteworthy" ), ::add_spawn_function, ::indoor_enemy ); array_thread( getentarray( "seek_player_smart", "script_noteworthy" ), ::add_spawn_function, ::seek_player_smart ); array_thread( getentarray( "dog", "script_noteworthy" ), ::add_spawn_function, ::seek_player_dog ); array_thread( getentarray( "enemy_color_hint_trigger", "targetname" ), ::enemy_color_hint_trigger_think ); array_thread( getentarray( "genocide_audio_trigger", "targetname" ), ::genocide_audio_trigger ); array_thread( getentarray( "dead_civilian", "targetname" ), ::dead_civilian ); array_thread( getentarray( "trigger_upstairs_guys", "targetname" ), ::trigger_upstairs_guys ); array_thread( getentarray( "alasad_barn_deletable", "script_noteworthy" ), ::alasad_deletable_hide ); array_thread( getentarray( "alasad_house_deletable", "script_noteworthy" ), ::alasad_deletable_hide ); add_hint_string( "call_air_support2", &"SCRIPT_PLATFORM_LEARN_CHOPPER_AIR_SUPPORT2", ::should_delete_attack_coord_hint ); thread chopper_air_support(); thread vehicle_patrol_init(); thread roaming_bmp(); thread timedAutosaves(); if ( getdvar( "village_assault_disable_gameplay") == "1" ) thread disable_gameplay(); wait 6.5; objective_add( 0, "current", &"VILLAGE_ASSAULT_OBJECTIVE_LOCATE_ALASAD", ( 0, 0, 0 ) ); } disable_gameplay() { array_thread( getentarray( "trigger_multiple", "classname" ), ::disable_gameplay_trigger ); array_thread( getentarray( "trigger_radius", "classname" ), ::disable_gameplay_trigger ); } movePlayerToLocation( sTargetname ) { assert( isdefined( sTargetname ) ); start = getent( sTargetname, "targetname" ); assert( isdefined( start ) ); assert( isdefined( level.player ) ); level.player setOrigin( start.origin ); level.player setPlayerAngles( ( 0, start.angles[ 1 ], 0 ) ); } disable_gameplay_trigger() { gameplayTrigger = false; if ( self.spawnflags & 32 ) gameplayTrigger = true; if ( isdefined( self.targetname ) ) { if ( self.targetname == "flood_and_secure" ) gameplayTrigger = true; else if ( self.targetname == "flood_spawner" ) gameplayTrigger = true; } if ( gameplayTrigger ) self thread trigger_off(); } spawn_starting_friendlies( sTargetname ) { level.friendlies = []; spawners = getentarray( sTargetname, "targetname" ); for( i = 0 ; i < spawners.size ; i++ ) { friend = spawners[ i ] stalingradSpawn(); if ( spawn_failed( friend ) ) assertMsg( "A friendly failed to spawn" ); friend.goalradius = 32; friend.fixednode = false; if ( issubstr( friend.classname, "price" ) ) { level.price = friend; } else if ( issubstr( friend.classname, "gaz" ) ) { level.gaz = friend; } else if ( issubstr( friend.classname, "russian" ) ) { level.opening_guy = friend; level.opening_guy.animname = "opening_guy"; } if ( friend isHero() ) friend thread magic_bullet_shield( undefined, 5.0 ); level.friendlies[ level.friendlies.size ] = friend; friend thread friendly_adjust_movement_speed(); friend thread friendly_bmp_damage_ignore_timer(); } assert( isdefined( level.price ) ); level.price.animname = "price"; level.price make_hero(); assert( isdefined( level.gaz ) ); level.gaz.animname = "gaz"; level.gaz make_hero(); //array_thread( getaiarray( "allies" ), ::replace_on_death ); assert( level.friendlies.size == spawners.size ); } friendly_bmp_damage_ignore_timer() { self endon( "death" ); for(;;) { self waittill( "damage", amount, attacker ); if ( !isdefined( attacker ) ) continue; if ( !isdefined( attacker.classname ) ) continue; if ( attacker.classname != "script_vehicle" ) continue; self.ignored_by_tank_cannon = true; wait randomfloatrange( 4.0, 6.0 ); self.ignored_by_tank_cannon = undefined; } } friendly_adjust_movement_speed() { self endon( "death" ); for(;;) { wait randomfloatrange( 1.0, 3.0 ); while( friendly_should_speed_up() ) { self.moveplaybackrate = 2.0; wait 0.05; } self.moveplaybackrate = 1.0; } } friendly_should_speed_up() { prof_begin( "friendly_movement_rate_math" ); if ( !isdefined( self.goalpos ) ) { prof_end( "friendly_movement_rate_math" ); return false; } if ( distanceSquared( self.origin, self.goalpos ) <= level.goodFriendlyDistanceFromPlayerSquared ) { prof_end( "friendly_movement_rate_math" ); return false; } // check if AI is visible in player's FOV if ( within_fov( level.player.origin, level.player getPlayerAngles(), self.origin, level.cosine[ "60" ] ) ) { prof_end( "friendly_movement_rate_math" ); return false; } prof_end( "friendly_movement_rate_math" ); return true; } isHero() { if ( !isdefined( self ) ) return false; if ( !isdefined( self.script_noteworthy ) ) return false; if ( self.script_noteworthy == "hero" ) return true; return false; } friendly_sight_distance( fDistance ) { dist = fDistance * fDistance; for( i = 0 ; i < level.friendlies.size ; i++ ) level.friendlies[ i ].maxsightdistsqrd = dist; } friendly_movement_speed( speed ) { for( i = 0 ; i < level.friendlies.size ; i++ ) level.friendlies[ i ].moveplaybackrate = speed; } friendly_stance( stance1, stance2, stance3 ) { for( i = 0 ; i < level.friendlies.size ; i++ ) { if ( isdefined ( stance3 ) ) level.friendlies[ i ] allowedStances( stance1, stance2, stance3 ); else if ( isdefined ( stance2 ) ) level.friendlies[ i ] allowedStances( stance1, stance2 ); else level.friendlies[ i ] allowedStances( stance1 ); } } distracted_guys_spawn() { script_org = getent( self.target, "targetname" ); assert( isdefined( script_org ) ); assert( script_org.classname == "script_origin" ); distractedGuyStruct = spawnStruct(); targeted = getentarray( script_org.target, "targetname" ); distractedGuyStruct.alert_triggers = []; distractedGuyStruct.spawners = []; for( i = 0 ; i < targeted.size ; i++ ) { if ( issubstr( targeted[ i ].classname, "trigger" ) ) { assert( isdefined( targeted[ i ].script_noteworthy ) ); distractedGuyStruct.alert_triggers[ distractedGuyStruct.alert_triggers.size ] = targeted[ i ]; } else if ( targeted[ i ] isSpawner() ) { assert( isdefined( targeted[ i ].script_animation ) ); distractedGuyStruct.spawners[ distractedGuyStruct.spawners.size ] = targeted[ i ]; } } assert( distractedGuyStruct.alert_triggers.size > 0 ); assert( distractedGuyStruct.spawners.size > 0 ); distractedGuyStruct.nodes = []; for( i = 0 ; i < distractedGuyStruct.spawners.size ; i++ ) { assert( isdefined( distractedGuyStruct.spawners[ i ].target ) ); node = getnode( distractedGuyStruct.spawners[ i ].target, "targetname" ); assert( isdefined( node ) ); distractedGuyStruct.nodes[ distractedGuyStruct.nodes.size ] = node; } assert( distractedGuyStruct.nodes.size > 0 ); assert( distractedGuyStruct.nodes.size == distractedGuyStruct.spawners.size ); self waittill( "trigger" ); // spawn the guys distractedGuyStruct.guys = []; for( i = 0 ; i < distractedGuyStruct.spawners.size ; i++ ) { spawned = distractedGuyStruct.spawners[ i ] stalingradSpawn(); if ( spawn_failed( spawned ) ) { assertMsg( "distracted guy failed to spawn" ); return; } distractedGuyStruct.guys[ distractedGuyStruct.guys.size ] = spawned; } assert( distractedGuyStruct.guys.size > 0 ); thread distractedGuys_animate( distractedGuyStruct ); } distractedGuys_animate( distractedGuyStruct ) { for( i = 0 ; i < distractedGuyStruct.alert_triggers.size ; i++ ) distractedGuyStruct.alert_triggers[ i ] thread distractedGuys_alert_trigger( distractedGuyStruct ); for( i = 0 ; i < distractedGuyStruct.guys.size ; i++ ) { distractedGuyStruct.guys[ i ].distracted = true; //distractedGuyStruct.guys[ i ].ignoreme = true; distractedGuyStruct.guys[ i ] thread alert_event_notify( distractedGuyStruct ); distractedGuyStruct.guys[ i ].animname = distractedGuyStruct.guys[ i ].script_animation; distractedGuyStruct.nodes[ i ] thread anim_loop_solo( distractedGuyStruct.guys[ i ], "idle", undefined, "stop_idle" ); distractedGuyStruct.guys[ i ].allowdeath = true; if ( isdefined( level.scr_anim[ distractedGuyStruct.guys[ i ].animname ][ "death" ] ) ) distractedGuyStruct.guys[ i ].deathanim = level.scr_anim[ distractedGuyStruct.guys[ i ].animname ][ "death" ]; } thread distractedGuys_alert( distractedGuyStruct ); } distractedGuys_alert_trigger( distractedGuyStruct ) { self waittill( self.script_noteworthy ); distractedGuyStruct notify( "alerted" ); } distractedGuys_alert( distractedGuyStruct ) { switch( distractedGuyStruct.guys.size ) { case 1: level waittill_any_ents( distractedGuyStruct, "alerted", distractedGuyStruct.guys[ 0 ] , "alerted", distractedGuyStruct.guys[ 0 ], "death", distractedGuyStruct.guys[ 0 ], "damage" ); break; case 2: level waittill_any_ents( distractedGuyStruct, "alerted", distractedGuyStruct.guys[ 0 ] , "alerted", distractedGuyStruct.guys[ 0 ], "death", distractedGuyStruct.guys[ 0 ], "damage", distractedGuyStruct.guys[ 1 ], "alerted", distractedGuyStruct.guys[ 1 ], "death", distractedGuyStruct.guys[ 1 ], "damage" ); break; } distractedGuyStruct notify( "alerted" ); wait randomfloatrange( 0, 1.3 ); for( i = 0 ; i < distractedGuyStruct.guys.size ; i++ ) { if ( !isalive( distractedGuyStruct.guys[ i ] ) ) continue; distractedGuyStruct.guys[ i ].distracted = undefined; //distractedGuyStruct.guys[ i ].ignoreme = false; distractedGuyStruct.guys[ i ] notify( "alerted" ); distractedGuyStruct.guys[ i ] notify( "stop_idle" ); distractedGuyStruct.guys[ i ].deathanim = undefined; if ( isdefined( level.scr_anim[ distractedGuyStruct.guys[ i ].animname ][ "react" ] ) ) distractedGuyStruct.nodes[ i ] thread anim_single_solo( distractedGuyStruct.guys[ i ], "react" ); else distractedGuyStruct.guys[ i ] stopanimscripted(); } } assasination() { targeted = getentarray( self.target, "targetname" ); script_org = undefined; assasinate_trigger = undefined; for( i = 0 ; i < targeted.size ; i++ ) { if ( targeted[ i ].classname == "script_origin" ) script_org = targeted[ i ]; if ( issubstr( targeted[ i ].classname, "trigger" ) ) assasinate_trigger = targeted[ i ]; } assert( isdefined( script_org ) ); assasinationStruct = spawnStruct(); if ( isdefined( assasinate_trigger ) ) assasinationStruct.assasinate_trigger = assasinate_trigger; targeted = getentarray( script_org.target, "targetname" ); assasinationStruct.assasination_triggers = []; assasinationStruct.spawners = []; for( i = 0 ; i < targeted.size ; i++ ) { if ( issubstr( targeted[ i ].classname, "trigger" ) ) { assert( isdefined( targeted[ i ].script_noteworthy ) ); assasinationStruct.assasination_triggers[ assasinationStruct.assasination_triggers.size ] = targeted[ i ]; } else if ( targeted[ i ] isSpawner() ) { assasinationStruct.spawners[ assasinationStruct.spawners.size ] = targeted[ i ]; } } assert( assasinationStruct.assasination_triggers.size > 0 ); assert( assasinationStruct.spawners.size > 0 ); for( i = 0 ; i < assasinationStruct.spawners.size ; i++ ) { assert( isdefined( assasinationStruct.spawners[ i ].target ) ); node = getnode( assasinationStruct.spawners[ i ].target, "targetname" ); assert( isdefined( node ) ); assasinationStruct.spawners[ i ].animnode = node; } self waittill( "trigger" ); // spawn the guys assasinationStruct.guys = []; for( i = 0 ; i < assasinationStruct.spawners.size ; i++ ) { spawned = assasinationStruct.spawners[ i ] stalingradSpawn(); if ( spawn_failed( spawned ) ) { assertMsg( "assasination guy failed to spawn" ); return; } assert( isdefined( assasinationStruct.spawners[ i ].animnode ) ); spawned.animnode = assasinationStruct.spawners[ i ].animnode; assasinationStruct.guys[ assasinationStruct.guys.size ] = spawned; } assert( assasinationStruct.guys.size > 0 ); assasinationStruct.executioners = []; allGuys = assasinationStruct.guys; for( i = 0 ; i < allGuys.size ; i++ ) { if ( allGuys[ i ].team != "axis" ) { //allGuys[ i ].ignoreme = true; continue; } assasinationStruct.executioners[ assasinationStruct.executioners.size ] = allGuys[ i ]; assasinationStruct.guys = array_remove( assasinationStruct.guys, allGuys[ i ] ); } assert( assasinationStruct.executioners.size > 0 ); assert( assasinationStruct.guys.size > 0 ); assert( assasinationStruct.guys.size + assasinationStruct.executioners.size == assasinationStruct.spawners.size ); thread assasination_think( assasinationStruct ); } assasination_think( assasinationStruct ) { for( i = 0 ; i < assasinationStruct.executioners.size ; i++ ) assasinationStruct.executioners[ i ] endon( "death" ); for( i = 0 ; i < assasinationStruct.guys.size ; i++ ) thread assasination_assasinated_idle( assasinationStruct, i ); for( i = 0 ; i < assasinationStruct.executioners.size ; i++ ) thread assasination_executioner_idle( assasinationStruct, i ); thread assasination_alert( assasinationStruct ); assasinationStruct waittill_any( "alerted", "assasinate" ); createthreatbiasgroup( "executioner" ); createthreatbiasgroup( "assasinated" ); setthreatbias( "assasinated", "executioner", 100000 ); for( i = 0 ; i < assasinationStruct.executioners.size ; i++ ) { assasinationStruct.executioners[ i ] setthreatbiasgroup( "executioner" ); assasinationStruct.executioners[ i ] notify( "stop_idle" ); assasinationStruct.executioners[ i ] stopanimscripted(); assasinationStruct.executioners[ i ].goalradius = 16; assasinationStruct.executioners[ i ] setGoalNode( assasinationStruct.executioners[ i ].animnode ); assasinationStruct.executioners[ i ].old_baseAccuracy = assasinationStruct.executioners[ i ].baseAccuracy; assasinationStruct.executioners[ i ].baseAccuracy = 1000; } for( i = 0 ; i < assasinationStruct.guys.size ; i++ ) { assasinationStruct.guys[ i ] setthreatbiasgroup( "assasinated" ); assasinationStruct.guys[ i ].deathanim = level.scr_anim[ "assasinated" ][ "knees_fall" ]; assasinationStruct.guys[ i ] thread assasination_ragdoll_death(); assasinationStruct.guys[ i ].allowdeath = true; //assasinationStruct.guys[ i ].ignoreme = false; } switch( assasinationStruct.guys.size ) { case 1: assasinationStruct.guys[ 0 ] waittill( "death" ); break; case 2: waittill_multiple_ents( assasinationStruct.guys[ 0 ], "death", assasinationStruct.guys[ 1 ], "death" ); break; case 3: waittill_multiple_ents( assasinationStruct.guys[ 0 ], "death", assasinationStruct.guys[ 1 ], "death", assasinationStruct.guys[ 2 ], "death" ); break; case 4: waittill_multiple_ents( assasinationStruct.guys[ 0 ], "death", assasinationStruct.guys[ 1 ], "death", assasinationStruct.guys[ 2 ], "death", assasinationStruct.guys[ 3 ], "death" ); break; } for( i = 0 ; i < assasinationStruct.executioners.size ; i++ ) { assasinationStruct.executioners[ i ].baseAccuracy = assasinationStruct.executioners[ i ].old_baseAccuracy; assasinationStruct.executioners[ i ].old_baseAccuracy = undefined; } } assasination_alert( assasinationStruct ) { for( i = 0 ; i < assasinationStruct.assasination_triggers.size ; i++ ) assasinationStruct.assasination_triggers[ i ] thread assasination_kill_trigger( assasinationStruct ); for( i = 0 ; i < assasinationStruct.executioners.size ; i++ ) { assasinationStruct.executioners[ i ] thread alert_event_notify( assasinationStruct ); thread assasination_alert_thread( assasinationStruct.executioners[ i ], assasinationStruct ); } } assasination_alert_thread( guy, assasinationStruct ) { level waittill_any_ents( assasinationStruct, "alerted", guy , "alerted", guy, "death", guy, "damage" ); assasinationStruct notify( "assasinate" ); } assasination_ragdoll_death() { self waittill( "death" ); wait 0.5; if ( isdefined( self ) ) self startRagDoll(); } assasination_assasinated_idle( assasinationStruct, guyIndex ) { assasinationStruct.guys[ guyIndex ] thread gun_remove(); assasinationStruct.guys[ guyIndex ].animname = "assasinated"; if ( randomint( 3 ) == 0 ) { if ( randomint( 3 ) == 0 ) assasinationStruct.guys[ guyIndex ].animnode anim_single_solo( assasinationStruct.guys[ guyIndex ], "stand_idle2" ); assasinationStruct.guys[ guyIndex ].animnode anim_single_solo( assasinationStruct.guys[ guyIndex ], "stand_fall" ); } assasinationStruct.guys[ guyIndex ].animnode thread anim_loop_solo( assasinationStruct.guys[ guyIndex ], "knees_idle", undefined, "stop_idle" ); } assasination_executioner_idle( assasinationStruct, guyIndex ) { assasinationStruct.executioners[ guyIndex ].allowdeath = true; assasinationStruct.executioners[ guyIndex ].animname = "executioner"; assasinationStruct.executioners[ guyIndex ].animnode thread anim_loop_solo( assasinationStruct.executioners[ guyIndex ], "idle", undefined, "stop_idle" ); } assasination_kill_trigger( assasinationStruct ) { self waittill( self.script_noteworthy ); assasinationStruct notify( "assasinate" ); } alert_event_notify( struct ) { struct endon( "alerted" ); self endon( "death" ); self thread add_event_listener( "grenade danger" ); self thread add_event_listener( "gunshot" ); self thread add_event_listener( "silenced_shot" ); self thread add_event_listener( "bulletwhizby" ); self thread add_event_listener( "projectile_impact" ); self waittill( "event_notify" ); struct notify( "alerted" ); } add_event_listener( sEventString ) { self endon( "death" ); self endon( "event_notify" ); self addAIEventListener( sEventString ); self waittill( sEventString ); self removeAIEventListener( sEventString ); self notify( "event_notify" ); } seek_player() { self endon( "death" ); if ( ( isdefined( self.distracted ) ) && ( self.distracted == true ) ) self waittill( "alerted" ); self.goalradius = 600; self setgoalentity( level.player ); } enemy_color_hint_trigger_think() { for(;;) { // trigger is hit - notify the targeted trigger to make enemies use color nodes self waittill( "trigger" ); getent( self.target, "targetname" ) notify( "trigger" ); level.seekersUsingColors = true; while( level.player isTouching( self ) ) wait 0.1; // player not in trigger anymore - make enemies use players goal pos level.seekersUsingColors = false; level notify( "seekers_chase_player" ); } } seek_player_smart() { self endon( "death" ); if ( ( isdefined( self.distracted ) ) && ( self.distracted == true ) ) self waittill( "alerted" ); self set_force_color( "r" ); for(;;) { if ( !level.seekersUsingColors ) { self.goalradius = 2000; self.pathenemyfightdist = 1500; self setEngagementMinDist( 1300, 1000 ); self setgoalentity( level.player ); } level waittill( "seekers_chase_player" ); } } seek_player_dog() { self.goalradius = 1000; self setgoalentity( level.player ); } indoor_enemy() { //self.engagemaxdist = 512; //self.engagemaxfalloffdist = 1024; } waittill_ai_in_volume_dead( volumeTargetname ) { volume = getent( volumeTargetname, "targetname" ); axis = getaiarray( "axis" ); volumeAxis = []; for( i = 0 ; i < axis.size ; i++ ) { if ( !axis[ i ] isTouching( volume ) ) continue; volumeAxis[ volumeAxis.size ] = axis[ i ]; } if( volumeAxis.size > 0 ) waittill_dead( volumeAxis ); } add_objective_building( aiGroupNum ) { if ( !isdefined( level._ai_group ) ) return; if ( !isdefined( level._ai_group[ aiGroupNum ] ) ) return; if ( !isdefined( level.buildings_remaining ) ) level.buildings_remaining = 0; level.buildings_remaining++; if ( !isdefined( level.suggested_objective_order ) ) level.suggested_objective_order = []; // Find the matching script_origin building location for this objective. It will have the same script_aigroup as the AI all_obj_locs = getentarray( "objective_location", "targetname" ); objective_location = undefined; for( i = 0 ; i < all_obj_locs.size ; i++ ) { assert( isdefined( all_obj_locs[ i ].script_aigroup ) ); if ( all_obj_locs[ i ].script_aigroup != aiGroupNum ) continue; objective_location = all_obj_locs[ i ].origin; break; } assert( isdefined( objective_location ) ); // add this objective to the suggested order objectiveIndex = level.suggested_objective_order.size; level.suggested_objective_order[ objectiveIndex ] = spawnStruct(); level.suggested_objective_order[ objectiveIndex ].aiGroupNum = aiGroupNum; level.suggested_objective_order[ objectiveIndex ].completed = false; level.suggested_objective_order[ objectiveIndex ].additionalPositionIndex = level.buildings_remaining; level.suggested_objective_order[ objectiveIndex ].location = objective_location; // Wait until all AI at this building objective are dead waittill_aigroupcleared( aiGroupNum ); wait randomfloatrange( 1.5, 3.0 ); arcademode_checkpoint( 4, "building_" + aiGroupNum ); if ( ( isdefined( level.alasad_objective_location ) ) && ( aiGroupNum == level.alasad_objective_location ) ) return; // Buildings cleared - update waypoints level.buildings_remaining--; level.suggested_objective_order[ objectiveIndex ].completed = true; thread objective_updateNextWaypoints(); if ( !flag( "alasad_sequence_started" ) ) { if ( level.buildingClearNextAudio == 0 ) { // Building clear. No sign of Al-Asad. Move on. level.gaz thread anim_single_solo( level.gaz, "nosign" ); // increase the ambient thread maps\_utility::set_ambient( "exterior3" ); } else if ( level.buildingClearNextAudio == 1 ) { // Building is clear. Move on to the next one. level.gaz thread anim_single_solo( level.gaz, "nextone" ); } else if ( level.buildingClearNextAudio == 2 ) { // This building's clear! Let's check the other buildings! level.gaz thread anim_single_solo( level.gaz, "checkother" ); } else if ( level.buildingClearNextAudio == 3 ) { // Building clear. Let's check the next one. level.gaz thread anim_single_solo( level.gaz, "checknext" ); // settle the ambient thread maps\_utility::set_ambient( "exterior1" ); } else if ( level.buildingClearNextAudio == 4 ) { // Building clear. No sign of Al-Asad. Move on. level.gaz thread anim_single_solo( level.gaz, "nosign" ); } level.buildingClearNextAudio++; } // Autosave the game at this point thread doAutoSave( "building_" + aiGroupNum + "_cleared" ); // if there is only one possible alasad location remaining then activate it now level.alasad_possible_objective_locations_remaining = array_remove( level.alasad_possible_objective_locations_remaining, aiGroupNum ); if ( level.alasad_possible_objective_locations_remaining.size > 1 ) return; if ( isdefined( level.alasad_sequence_init ) ) return; if ( level.alasad_possible_objective_locations_remaining[ 0 ] == "2" ) thread do_alasad( "house" ); else if ( level.alasad_possible_objective_locations_remaining[ 0 ] == "6" ) thread do_alasad( "barn" ); } objective_updateNextWaypoints() { numObjectivesDisplayed = 2; numObjectivesAdded = 0; // clear all objective waypoints for ( i = 0 ; i < level.suggested_objective_order.size ; i++ ) objective_additionalposition( 0, i, ( 0, 0, 0 ) ); // get the next locations to be shown for ( objectiveIndex = 0 ; objectiveIndex < level.suggested_objective_order.size ; objectiveIndex++ ) { if ( level.suggested_objective_order[ objectiveIndex ].completed ) continue; // add objective waypoint positionIndex = level.suggested_objective_order[ objectiveIndex ].additionalPositionIndex; location = level.suggested_objective_order[ objectiveIndex ].location; objective_additionalposition( 0, numObjectivesAdded + 1, location ); // make sure we only add as many waypoints as specified numObjectivesAdded++; if ( numObjectivesAdded == numObjectivesDisplayed ) return; assert( numObjectivesAdded < numObjectivesDisplayed ); } } chopper_air_support() { dialogIndex = 0; level.lastUsedWeapon = undefined; level.fake_chopper_ammo = 1; flag_init("ammo_cheat_for_chopper"); for(;;) { while( level.player getcurrentweapon() != "cobra_air_support" ) { level.lastUsedWeapon = level.player GetCurrentWeapon(); wait 0.05; } if(getdvar("player_sustainAmmo") == "0" && !flag("ammo_cheat_for_chopper")) ammo = level.player getAmmoCount( "cobra_air_support" ); else { flag_set("ammo_cheat_for_chopper"); //once cheat has been called maintain fake ammo. going in and out breaks things. - Nate ammo = level.fake_chopper_ammo; } if ( ( !isdefined( ammo ) ) || ( ammo <= 0 ) ) { // give player his weapon back chopper_air_support_giveBackWeapon(); if ( flag( "air_support_refueling" ) ) { if ( dialogIndex == 0 ) { // Negative, we are refueling at this time. Standby. thread radio_dialogue_queue( "refueling" ); dialogIndex = 1; } else { // We are rearming at this time. Standby. thread radio_dialogue_queue( "rearming" ); dialogIndex = 0; } } wait 1; continue; } thread chopper_air_support_activate(); while( level.player getcurrentweapon() == "cobra_air_support" ) wait 0.05; level notify( "air_support_canceled" ); thread chopper_air_support_deactive(); } } chopper_air_support_removeFunctionality() { level.player takeWeapon( "cobra_air_support" ); level notify( "air_support_canceled" ); level notify( "air_support_deleted" ); thread chopper_air_support_deactive(); if ( isdefined( level.chopper ) ) { level.chopper.delete_on_death = true; level.chopper notify( "death" ); } } chopper_air_support_activate() { level endon( "air_support_canceled" ); level endon( "air_support_called" ); thread chopper_air_support_paint_target(); thread air_support_hint_print_call(); // Make the arrow level.chopperAttackArrow = spawn( "script_model", ( 0, 0, 0 ) ); level.chopperAttackArrow setModel( "tag_origin" ); level.chopperAttackArrow.angles = ( -90, 0, 0 ); level.chopperAttackArrow.offset = 4; playfxontag( getfx( "air_support_fx_yellow" ), level.chopperAttackArrow, "tag_origin" ); level.playerActivatedAirSupport = true; coord = undefined; traceOffset = 15; traceLength = 15000; minValidLength = 300 * 300; trace = []; trace[ 0 ] = spawnStruct(); trace[ 0 ].offsetDir = "vertical"; trace[ 0 ].offsetDist = traceOffset; trace[ 1 ] = spawnStruct(); trace[ 1 ].offsetDir = "vertical"; trace[ 1 ].offsetDist = traceOffset * -1; trace[ 2 ] = spawnStruct(); trace[ 2 ].offsetDir = "horizontal"; trace[ 2 ].offsetDist = traceOffset; trace[ 3 ] = spawnStruct(); trace[ 3 ].offsetDir = "horizontal"; trace[ 3 ].offsetDist = traceOffset * -1; rotateTime = 0; for(;;) { wait 0.05; prof_begin( "spotting_marker" ); // Trace to where the player is looking direction = level.player getPlayerAngles(); direction_vec = anglesToForward( direction ); eye = level.player getEye(); for ( i = 0 ; i < trace.size ; i++ ) { start = eye; vec = undefined; if ( trace[ i ].offsetDir == "vertical" ) vec = anglesToUp( direction ); else if ( trace[ i ].offsetDir == "horizontal" ) vec = anglesToRight( direction ); assert( isdefined( vec ) ); start = start + vector_multiply( vec, trace[ i ].offsetDist ); trace[ i ].trace = bullettrace( start, start + vector_multiply( direction_vec , traceLength ), 0, undefined ); trace[ i ].length = distanceSquared( start, trace[ i ].trace[ "position" ] ); if ( getdvar( "village_assault_debug_marker") == "1" ) thread draw_line_for_time( start, trace[ i ].trace[ "position" ], 1, 1, 1, 0.05 ); } validLocations = []; validNormals = []; for ( i = 0 ; i < trace.size ; i++ ) { if ( trace[ i ].length < minValidLength ) continue; index = validLocations.size; validLocations[ index ] = trace[ i ].trace[ "position" ]; validNormals[ index ] = trace[ i ].trace[ "normal" ]; if ( getdvar( "village_assault_debug_marker") == "1" ) thread draw_line_for_time( level.player getEye(), validLocations[ index ], 0, 1, 0, 0.05 ); } // if all points are too close just use all of them since none are good if ( validLocations.size == 0 ) { for ( i = 0 ; i < trace.size ; i++ ) { validLocations[ i ] = trace[ i ].trace[ "position" ]; validNormals[ i ] = trace[ i ].trace[ "normal" ]; } } assert( validLocations.size > 0 ); if ( validLocations.size == 4 ) { fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ], validLocations[ 2 ], validLocations[ 3 ] ); fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ], validNormals[ 2 ], validNormals[ 3 ] ); } else if ( validLocations.size == 3 ) { fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ], validLocations[ 2 ] ); fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ], validNormals[ 2 ] ); } else if ( validLocations.size == 2 ) { fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ] ); fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ] ); } else { fxLocation = validLocations[ 0 ]; fxNormal = validNormals[ 0 ]; } if ( getdvar( "village_assault_debug_marker") == "1" ) thread draw_line_for_time( level.player getEye(), fxLocation, 1, 0, 0, 0.05 ); thread drawChopperAttackArrow( fxLocation, fxNormal, rotateTime ); rotateTime = 0.2; prof_end( "spotting_marker" ); } } findAveragePointVec( point1, point2, point3, point4 ) { assert( isdefined( point1 ) ); assert( isdefined( point2 ) ); if ( isdefined( point4 ) ) { x = findAveragePoint( point1[ 0 ], point2[ 0 ], point3[ 0 ], point4[ 0 ] ); y = findAveragePoint( point1[ 1 ], point2[ 1 ], point3[ 1 ], point4[ 1 ] ); z = findAveragePoint( point1[ 2 ], point2[ 2 ], point3[ 2 ], point4[ 2 ] ); } else if ( isdefined( point3 ) ) { x = findAveragePoint( point1[ 0 ], point2[ 0 ], point3[ 0 ] ); y = findAveragePoint( point1[ 1 ], point2[ 1 ], point3[ 1 ] ); z = findAveragePoint( point1[ 2 ], point2[ 2 ], point3[ 2 ] ); } else { x = findAveragePoint( point1[ 0 ], point2[ 0 ] ); y = findAveragePoint( point1[ 1 ], point2[ 1 ] ); z = findAveragePoint( point1[ 2 ], point2[ 2 ] ); } return( x, y, z ); } findAveragePoint( point1, point2, point3, point4 ) { assert( isdefined( point1 ) ); assert( isdefined( point2 ) ); if ( isdefined( point4 ) ) return ( ( point1 + point2 + point3 + point4 ) / 4 ); else if ( isdefined( point3 ) ) return ( ( point1 + point2 + point3 ) / 3 ); else return ( ( point1 + point2 ) / 2 ); } chopper_air_support_deactive() { thread delete_attack_coord_hint(); wait 0.05; if ( isdefined( level.chopperAttackArrow ) ) level.chopperAttackArrow delete(); } chopper_air_support_giveBackWeapon() { if ( ( isdefined( level.lastUsedWeapon ) ) && ( level.player HasWeapon( level.lastUsedWeapon ) ) ) { level.player switchToWeapon( level.lastUsedWeapon ); } else { weaponList = level.player GetWeaponsListPrimaries(); if ( isdefined( weaponList[ 0 ] ) ) level.player switchToWeapon( weaponList[ 0 ] ); } } chopper_air_support_paint_target() { level endon( "air_support_canceled" ); level.player waittill ( "weapon_fired" ); level.fake_chopper_ammo = 0; level.playerCalledAirSupport = true; thread chopper_air_support_mark(); // give player his weapon back chopper_air_support_giveBackWeapon(); thread chopper_air_support_call_chopper( level.chopperAttackArrow.origin ); level notify( "air_support_called" ); chopper_air_support_deactive(); if ( level.chopperSupportCallNextAudio == 0 ) thread radio_dialogue_queue( "ontheway" ); // Mosin Two-Five here. We're on the way. Standby for air support. else if ( level.chopperSupportCallNextAudio == 1 ) thread radio_dialogue_queue( "helicopteronway" ); // Helicopter is on the way. We'll handle it. Out. else if ( level.chopperSupportCallNextAudio == 2 ) thread radio_dialogue_queue( "wehavetarget" ); // This is Mosin Two-Five, we have the target. Standby. level.chopperSupportCallNextAudio++; if ( level.chopperSupportCallNextAudio > 2 ) level.chopperSupportCallNextAudio = 0; } chopper_dialog() { } chopper_air_support_mark() { marker = spawn( "script_model", level.chopperAttackArrow.origin ); marker setModel( "tag_origin" ); marker.angles = level.chopperAttackArrow.angles; wait 0.1; playfxontag( getfx( "air_support_fx_red" ), marker, "tag_origin" ); wait 5.0; marker delete(); } chopper_air_support_friendlyFire() { self endon( "death" ); chopper_accumulated_friendly_damage = 0; for(;;) { self waittill( "damage", amount, attacker, direction, point, type ); if ( attacker != level.player ) continue; if ( ( isdefined( type ) ) && ( !issubstr( tolower( type ), "bullet" ) ) ) break; if ( isdefined( amount ) && ( amount > 0 ) ) chopper_accumulated_friendly_damage += amount; if ( chopper_accumulated_friendly_damage >= 500 ) break; } thread maps\_friendlyfire::missionfail(); } chopper_air_support_call_chopper( coordinate ) { closestPoint = findBestChopperWaypoint( coordinate, 45 ); if ( closestPoint <= -1 ) { wait 0.05; closestPoint = findBestChopperWaypoint( coordinate, 70 ); if ( closestPoint <= -1 ) { wait 0.05; closestPoint = findBestChopperWaypoint( coordinate, 70, true ); } } assert( closestPoint > -1 ); if ( getdvar( "debug_chopper_air_support") == "1" ) print3d( level.chopperSupportHoverLocations[ closestPoint ] + ( 0, 0,20 ), "chosen", ( 0, 0, 1 ), 1.0, 3.0, 10000 ); // spawn the chopper level.chopper = maps\_vehicle::spawn_vehicle_from_targetname( "chopper" ); assert( isdefined( level.chopper ) ); level.chopper endon( "death" ); level.chopper thread chopper_air_support_friendlyFire(); returnToBasePos = level.chopper.origin; // fly chopper to that point and make it face the direction of the target eTarget = spawn( "script_origin", coordinate ); level.chopper setLookAtEnt( eTarget ); level.chopper setspeed( 65, 10, 20 ); level.chopper sethoverparams( 250, 60, 35 ); yawAngle = vectorToAngles( coordinate - level.chopperSupportHoverLocations[ closestPoint ] ); level.chopper setgoalyaw( yawAngle[ 1 ] ); level.chopper setvehgoalpos( level.chopperSupportHoverLocations[ closestPoint ], true ); level.chopper setNearGoalNotifyDist( 4000 ); level.chopper waittill( "near_goal" ); level.chopper thread chopper_ai_mode(); level.chopper settargetyaw( yawAngle[ 1 ] ); level.chopper waittill( "goal" ); // kill all the spawners nearby the coordinate killspawns = getentarray( "helicopter_force_kill_spawn", "targetname" ); for ( i = 0 ; i < killspawns.size ; i++ ) { if ( eTarget isTouching( killspawns[ i ] ) ) { assert( isdefined( killspawns[ i ].target ) ); trig = getentarray( killspawns[ i ].target, "targetname" ); for ( j = 0 ; j < trig.size ; j++ ) trig[ j ] notify( "trigger" ); } } level.chopper thread chopper_ai_mode_missiles( eTarget ); badplace_cylinder( "air_support_AOE", 30.0, eTarget.origin, 1050, 10000, "allies" ); thread chopper_air_support_end( returnToBasePos ); } player_activated_air_support() { return isdefined( level.playerActivatedAirSupport ); } player_called_air_support() { return isdefined( level.playerCalledAirSupport ); } delete_hint_print_activated_air_support() { if ( isdefined( level.air_support_hint_delete ) ) { level.air_support_hint_delete = undefined; return true; } return isdefined( level.playerActivatedAirSupport ); } delete_attack_coord_hint() { flag_set( "delete_attack_coord_hint" ); level waittill( "checked_should_delete_hint" ); flag_clear( "delete_attack_coord_hint" ); } should_delete_attack_coord_hint() { ans = flag( "delete_attack_coord_hint" ); level notify( "checked_should_delete_hint" ); return ans; } findBestChopperWaypoint( coordinate, fov_angle, bForceLocation ) { if ( getdvar( "debug_chopper_air_support") == "1" ) iprintln( "chopper deciding which location to fly to" ); playerCoordinate = level.player.origin; playerFaceAngle = level.player getPlayerAngles(); targetFaceAngle = playerFaceAngle + ( 0, 180, 0 ); cosine = cos( fov_angle ); if ( !isdefined( bForceLocation ) ) bForceLocation = false; closestPoint = -1; closestDist = 1000000000; minimumSafeDistance = 1000 * 1000; for( i = 0 ; i < level.chopperSupportHoverLocations.size ; i++ ) { p = level.chopperSupportHoverLocations[ i ]; if ( !bForceLocation ) { // dont use the point if it's not on the same side of the target as the player ( using imaginary perpindicular line to players facing direction ) if( !within_fov( flat_origin( coordinate ), flat_angle( targetFaceAngle ), flat_origin( p ), cosine ) ) continue; } // get the closest point on the segment to the point nearestPointOnLine = pointOnSegmentNearestToPoint( coordinate, playerCoordinate, p ); d = distanceSquared( nearestPointOnLine, p ); if ( !bForceLocation ) { // make sure the chopper wont fly to a location too close to the target if ( d < minimumSafeDistance ) continue; } if( d < closestDist ) { closestPoint = i; closestDist = d; } if ( getdvar( "debug_chopper_air_support") == "1" ) print3d( p, d, ( 1, 1, 1 ), 1.0, 3.0, 10000 ); } return closestPoint; } chopper_air_support_end( returnToBasePos ) { level endon( "air_support_deleted" ); flag_clear( "air_support_refueling" ); wait 30; flag_set( "air_support_refueling" ); // This is Two-Five. We have to refuel and rearm. We will not be available for some time. thread radio_dialogue_queue( "refuelandrearm" ); level notify( "air_support_over" ); flyHomeVec = vectorToAngles( returnToBasePos - level.chopper.origin ); if ( !isdefined( level.chopper ) ) return; level.chopper clearLookatEnt(); level.chopper setTargetYaw( flyHomeVec[ 1 ] ); level.chopper setVehGoalPos( returnToBasePos ); level.chopper waittill( "goal" ); level.chopper delete(); level.chopper = undefined; wait 20; flag_clear( "air_support_refueling" ); // Mosin Two-Five here. We are ready to attack and are standing by for new orders. thread radio_dialogue_queue( "readytoattack" ); level.player giveStartAmmo( "cobra_air_support" ); level.fake_chopper_ammo = 1; } chopper_ai_mode() { self thread chopper_ai_mode_aim_turret(); self thread chopper_ai_mode_shoot_turret(); self thread chopper_ai_mode_flares(); } chopper_ai_mode_aim_turret() { self endon( "death" ); level endon( "air_support_over" ); for(;;) { eTarget = maps\_helicopter_globals::getEnemyTarget( 6000, level.cosine[ "45" ], true, true, true, true ); if( isdefined( eTarget ) ) { eTargetOffset = ( 0, 0, 0 ); if ( isdefined( eTarget.script_targetoffset_z ) ) eTargetOffset += ( 0, 0, eTarget.script_targetoffset_z ); else if ( isSentient( eTarget ) ) eTargetOffset = ( 0, 0, 32 ); self setTurretTargetEnt( eTarget, eTargetOffset ); } wait randomfloatrange( 0.2, 1.0 ); } } chopper_ai_mode_shoot_turret() { self endon( "death" ); level endon( "air_support_over" ); for(;;) { randomShots = randomintrange( 30, 60 ); self setVehWeapon( "hind_turret" ); for( i = 0 ; i < randomShots ; i++ ) { self fireWeapon( "tag_flash" ); wait 0.05; } wait randomfloatrange( 1.0, 1.75 ); } } chopper_ai_mode_flares() { self endon( "death" ); level endon( "air_support_over" ); for(;;) { iNumFlares = randomintrange( 2, 8 ); thread maps\_helicopter_globals::flares_fire_burst( self, iNumFlares, 1, 5.0 ); wait randomfloatrange( 4.0, 8.0 ); } } chopper_ai_mode_missiles( eTarget ) { eTargetOriginal = eTarget; self endon( "death" ); level endon( "air_support_over" ); for(;;) { iShots = randomintrange( 1, 5 ); eTarget = maps\_helicopter_globals::getEnemyTarget( 6000, level.cosine[ "25" ], true, true, true, true ); if ( ( isdefined( eTarget ) ) && ( isdefined( eTarget.origin ) ) ) self maps\_helicopter_globals::fire_missile( "ffar_mi28_village_assault", iShots, eTarget ); else self maps\_helicopter_globals::fire_missile( "ffar_mi28_village_assault", iShots, eTargetOriginal ); wait randomfloatrange( 3.5, 6.0 ); } } drawChopperAttackArrow( coord, normal, rotateTime ) { assert( isdefined( level.chopperAttackArrow ) ); assert( isdefined( coord ) ); assert( isdefined( normal ) ); assert( isdefined( rotateTime ) ); coord += vector_multiply( normal, level.chopperAttackArrow.offset ); level.chopperAttackArrow.origin = coord; if ( rotateTime > 0 ) level.chopperAttackArrow rotateTo( vectortoangles( normal ), 0.2 ); else level.chopperAttackArrow.angles = vectortoangles( normal ); } getClosestInFOV( startOrigin, arrayEnts, fov_angle, minDistance ) { cos = cos( fov_angle ); closestEnt = undefined; secondClosestEnt = undefined; closestDist = 1000000000; for( i = 0 ; i < arrayEnts.size ; i++ ) { //if( !within_fov( flat_origin( startOrigin ), flat_angle( level.player getPlayerAngles() ), flat_origin( arrayEnts[ i ].origin ), cos ) ) // continue; d = distancesquared( startOrigin, arrayEnts[ i ].origin ); if ( d < minDistance ) continue; if( d < closestDist ) { secondClosestEnt = closestEnt; closestEnt = arrayEnts[ i ]; closestDist = d; } } array = []; array[ 0 ] = closestEnt; array[ 1 ] = secondClosestEnt; return array; } vehicle_c4_think() { iEntityNumber = self getentitynumber(); rearOrgOffset = (0, -33, 10); rearAngOffset = (0, 90, -90); frontOrgOffset = (129, 0, 35); frontAngOffset = (0, 90, 144); self maps\_c4::c4_location( "rear_hatch_open_jnt_left", rearOrgOffset, rearAngOffset ); self maps\_c4::c4_location( "tag_origin", frontOrgOffset, frontAngOffset ); self.rearC4location = spawn( "script_origin", self.origin ); self.frontC4location = spawn( "script_origin", self.origin ); self.rearC4location linkto( self, "rear_hatch_open_jnt_left", rearOrgOffset, rearAngOffset ); self.frontC4location linkto( self, "tag_origin", frontOrgOffset, frontAngOffset ); self waittill( "c4_detonation" ); self.frontC4location delete(); self.rearC4location delete(); self thread vehicle_death( iEntityNumber ); } vehicle_death( iEntityNumber ) { self notify( "clear_c4" ); setplayerignoreradiusdamage( true ); //----------------------- // FINAL EXPLOSION //----------------------- earthquake( 0.6, 2, self.origin, 2000 ); self notify( "death" ); thread play_sound_in_space( "exp_armor_vehicle", self gettagorigin( "tag_turret" ) ); AI = get_ai_within_radius( 1024, self.origin, "axis" ); if ( (isdefined(AI)) && (AI.size > 0) ) array_thread(AI, ::AI_stun, .85); radiusdamage( self.origin, 256, 200, 100 ); if ( distancesquared( self.origin, level.player.origin ) <= ( 256 * 256 ) ) level.player dodamage( level.player.health / 3, ( 0, 0, 0 ) ); } AI_stun( fAmount ) { self endon( "death" ); if( ( isdefined( self ) ) && ( isalive( self ) ) && ( self getFlashBangedStrength() == 0 ) ) self setFlashBanged( true, fAmount ); } get_ai_within_radius( fRadius, org, sTeam ) { if( isdefined( sTeam ) ) ai = getaiarray( sTeam ); else ai = getaiarray(); aDudes = []; for( i = 0 ; i < ai.size ; i++ ) { if ( distance( org, self.origin ) <= fRadius ) array_add( aDudes, ai[ i ] ); } return aDudes; } roaming_bmp() { bmp = maps\_vehicle::waittill_vehiclespawn( "roaming_bmp" ); assert( isdefined( bmp ) ); target_set( bmp, ( 0, 0, 32 ) ); target_setJavelinOnly( bmp, true ); bmp thread vehicle_patrol_think(); bmp thread vehicle_turret_think(); bmp thread vehicle_c4_think(); bmp thread maps\_vehicle::damage_hints(); bmp thread bmp_autosave_on_death(); bmp thread vehicle_death_think(); } getDamageType( type ) { //returns a simple damage type: melee, bullet, splash, or unknown if ( !isdefined( type ) ) return "unknown"; type = tolower( type ); switch( type ) { case "mod_explosive": case "mod_explosive_splash": return "c4"; case "mod_projectile": case "mod_projectile_splash": return "rocket"; case "mod_grenade": case "mod_grenade_splash": return "grenade"; case "unknown": return "unknown"; default: return "unknown"; } } vehicle_death_think() { self endon ("death"); for(;;) { self waittill( "damage", damage, attacker, direction_vec, point, type ); if (attacker != level.player) continue; if ( !isdefined( damage ) ) continue; if ( damage <= 0 ) continue; type = getDamageType( type ); assert( isdefined( type ) ); if ( ( type == "rocket" ) && ( damage >= 300 ) ) break; if ( ( type == "c4" ) && ( damage >= 250 ) ) break; } self notify( "c4_detonation" ); } vehicle_patrol_init() { level.aVehicleNodes = []; array1 = getvehiclenodearray( "go_forward", "script_noteworthy" ); array2 = getvehiclenodearray( "go_backward", "script_noteworthy" ); level.aVehicleNodes = array_merge( array1, array2 ); } vehicle_patrol_think() { level endon( "alasad_sequence_started" ); self endon( "death" ); ePathstart = self.attachedpath; self waittill( "reached_end_node" ); for(;;) { prof_begin( "bmp_logic" ); //----------------------- // REINITIALIZE ALL VARIABLES //----------------------- aLinked_nodes = []; eCurrentNode = undefined; go_backward_node = undefined; go_forward_node = undefined; eStartNode = undefined; closestEndNodes = undefined; //----------------------- // GET LAST NODE IN CHAIN (CURRENT POSITION //----------------------- assert( isdefined( ePathstart ) ); eCurrentNode = ePathstart get_last_ent_in_chain( "vehiclenode" ); //----------------------- // GET ALL NODES THAT ARE GROUPED WITH THIS PATH END //----------------------- aLinked_nodes = level.aVehicleNodes; aLinked_nodes = array_remove( aLinked_nodes, eCurrentNode); aVehicleNodes = level.aVehicleNodes; sScript_vehiclenodegroup = eCurrentNode.script_vehiclenodegroup; assert(isdefined(sScript_vehiclenodegroup)); for(i=0;i 0, "Ends of vehicle paths need to be grouped with at least one other chain of nodes for moving forward, backward or both"); for(i=0;i= go_forward_node.end.script_vehiclenodegroup ) ) eStartNode = go_forward_node; else if ( ( isdefined( go_backward_node ) ) && ( closestEndNodes[ 0 ].script_vehiclenodegroup <= go_backward_node.end.script_vehiclenodegroup ) ) eStartNode = go_backward_node; prof_end( "bmp_logic" ); //----------------------- // GO ON THE NEW PATH TO GET CLOSER TO PLAYER OTHERWISE STAY PUT //----------------------- if ( isdefined(eStartNode) ) { self attachpath( eStartNode ); ePathstart = eStartNode; wait randomfloatrange( 0.2, 1.2 ); self resumeSpeed( 100 ); self waittill( "reached_end_node" ); } else { wait randomfloatrange( 3, 6 ); } } } vehicle_turret_think() { level endon( "alasad_sequence_started" ); self endon( "death" ); eTarget = undefined; for(;;) { prof_begin( "bmp_logic" ); eTarget = maps\_helicopter_globals::getEnemyTarget( 3000, undefined, true, true, false, true ); prof_end( "bmp_logic" ); if ( isdefined( eTarget ) ) { self setTurretTargetEnt( eTarget, ( 0, 0, 32 ) ); self waittill_notify_or_timeout( "turret_rotate_stopped", randomfloatrange( 2.0, 3.0 ) ); iFireTime = weaponfiretime( "bmp_turret" ); assert( isdefined( iFireTime ) ); assert( iFireTime > 0 ); iShots = randomintrange( 3, 8 ); for( i = 0 ; i < iShots ; i++ ) { self fireWeapon(); wait iFireTime; } } wait randomfloat( 3.0, 6.0 ); } } doAutoSave( sSaveName ) { assert( isdefined( sSaveName ) ); thread autosave_by_name( sSaveName ); thread timedAutosaves(); } bmp_autosave_on_death() { self waittill( "death" ); if ( isdefined( self ) ) target_remove( self ); thread doAutoSave( "bmp_destroyed" ); } timedAutosaves() { level endon( "alasad_sequence_started" ); level notify( "timedAutosaveThread" ); level endon( "timedAutosaveThread" ); if ( level.timedAutosaveTime == 0 ) return; for(;;) { wait level.timedAutosaveTime; level.timedAutosaveNumber++; thread doAutoSave( "timed_autosave" + level.timedAutosaveNumber ); } } genocide_audio_trigger() { soundEnt = getent( self.target, "targetname" ); assert( isdefined( soundEnt ) ); self waittill( "trigger" ); if ( isdefined( self.script_delay ) ) wait self.script_delay; assert( isdefined( level.genocide_audio[ level.next_genocide_audio ] ) ); soundEnt playSound( level.genocide_audio[ level.next_genocide_audio ] ); level.next_genocide_audio++; } dead_civilian() { wait randomfloatrange( 0.05, 0.2 ); spawned = dronespawn( self ); spawned setContents( 0 ); spawned startRagDoll(); } air_support_hint_print_activate() { level endon( "alasad_sequence_started" ); while( !player_activated_air_support() ) { if ( level.air_support_hint_print_dialog_next == 0 ) { // Soap! Call in air support on that building! level.price thread anim_single_solo( level.price, "airsupport" ); } else if ( level.air_support_hint_print_dialog_next == 1 ) { // Use our air support to soften up that building! level.price thread anim_single_solo( level.price, "softenup" ); } else { // Mosin Two-Five here. We are ready to attack and are standing by for new orders. thread radio_dialogue_queue( "readytoattack" ); } level.air_support_hint_print_dialog_next++; if ( !flag( "gave_air_support_hint" ) ) { flag_set( "gave_air_support_hint" ); if ( isdefined( level.console ) && level.console || getdvarint("gpad_in_use")) thread display_air_support_hint_console(); else thread display_air_support_hint_pc(); } wait 5; level.air_support_hint_delete = true; wait 60; } } display_air_support_hint_console() { level endon( "clearing_hints" ); add_hint_background(); level.hintElem = createFontString( "default", 1.6 ); level.hintElem setPoint( "TOP", undefined, 0, 130 ); level.hintElem setText( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1" ); level.iconElem1 = createIcon( "hud_dpad", 32, 32 ); level.iconElem1 setPoint( "TOP", undefined, -32, 165 ); level.iconElem3 = createIcon( "hud_arrow_right", 24, 24 ); level.iconElem3 setPoint( "TOP", undefined, -31.5, 170 ); level.iconElem3.sort = 1; level.iconElem3.color = (1,1,0); level.iconElem3.alpha = .7; level.iconElem2 = createIcon( "hud_icon_cobra", 64, 32 ); level.iconElem2 setPoint( "TOP", undefined, 16, 165 ); wait 4; level.iconElem1 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 ); level.iconElem2 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 ); level.iconElem3 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 ); level.iconElem1 scaleovertime(1, 20, 20); level.iconElem2 scaleovertime(1, 20, 20); level.iconElem3 scaleovertime(1, 20, 20); wait .70; level.hintElem fadeovertime(.15); level.hintElem.alpha = 0; level.iconElem1 fadeovertime(.15); level.iconElem1.alpha = 0; level.iconElem2 fadeovertime(.15); level.iconElem2.alpha = 0; level.iconElem3 fadeovertime(.15); level.iconElem3.alpha = 0; level.hintbackground fadeovertime(.15); level.hintbackground.alpha = 0; wait 0.15; clear_hints(); } display_air_support_hint_pc() { level endon( "clearing_hints" ); add_hint_background(); level.hintElem = createFontString( "default", 1.6 ); level.hintElem setPoint( "TOP", undefined, 0, 130 ); level.hintElem setText( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1_PC" ); level.iconElem2 = createIcon( "hud_icon_cobra", 64, 32 ); level.iconElem2 setPoint( "TOP", undefined, 16, 165 ); wait 4; level.iconElem2 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 ); level.iconElem2 scaleovertime(1, 20, 20); wait .70; level.hintElem fadeovertime(.15); level.hintElem.alpha = 0; level.iconElem2 fadeovertime(.15); level.iconElem2.alpha = 0; level.hintbackground fadeovertime(.15); level.hintbackground.alpha = 0; wait 0.15; clear_hints(); } add_hint_background( double_line ) { if ( isdefined ( double_line ) ) level.hintbackground = createIcon( "popmenu_bg", 650, 50 ); else level.hintbackground = createIcon( "popmenu_bg", 650, 30 ); level.hintbackground.hidewheninmenu = true; level.hintbackground setPoint( "TOP", undefined, 0, 125 ); level.hintbackground.alpha = .5; } clear_hints() { level notify ( "clearing_hints" ); if ( isDefined( level.hintElem ) ) level.hintElem destroy(); if ( isDefined( level.iconElem1 ) ) level.iconElem1 destroy(); if ( isDefined( level.iconElem2 ) ) level.iconElem2 destroy(); if ( isDefined( level.iconElem3 ) ) level.iconElem3 destroy(); if ( isDefined( level.hintbackground ) ) level.hintbackground destroy(); } air_support_hint_print_call() { if ( player_called_air_support() ) return; level endon( "alasad_sequence_started" ); thread clear_hints(); thread display_hint( "call_air_support2" ); wait 5; level.air_support_hint_delete = true; } trigger_upstairs_guys() { assert( isdefined( self.target ) ); volume = getent( self.target, "targetname" ); assert( isdefined( volume ) ); assert( isdefined( volume.target ) ); node = getnode( volume.target, "targetname" ); assert( isdefined( node ) ); assert( isdefined( node.radius ) ); self waittill( "trigger" ); wait randomfloatrange( 5.0, 10.0 ); enemies = getaiarray( "axis" ); for( i = 0 ; i < enemies.size ; i++ ) { if ( !( enemies[ i ] istouching( volume ) ) ) continue; enemies[i].goalradius = node.radius; enemies[i] setgoalnode( node ); } } delete_dropped_weapons() { wc = []; wc = array_add( wc, "weapon_ak47" ); wc = array_add( wc, "weapon_beretta" ); wc = array_add( wc, "weapon_g36c" ); wc = array_add( wc, "weapon_m14" ); wc = array_add( wc, "weapon_m16" ); wc = array_add( wc, "weapon_m203" ); wc = array_add( wc, "weapon_rpg" ); wc = array_add( wc, "weapon_saw" ); wc = array_add( wc, "weapon_m4" ); wc = array_add( wc, "weapon_m40a3" ); wc = array_add( wc, "weapon_mp5" ); wc = array_add( wc, "weapon_mp5sd" ); wc = array_add( wc, "weapon_usp" ); wc = array_add( wc, "weapon_at4" ); wc = array_add( wc, "weapon_dragunov" ); wc = array_add( wc, "weapon_g3" ); wc = array_add( wc, "weapon_uzi" ); for( i = 0 ; i < wc.size ; i ++ ) { weapons = getentarray( wc[i], "classname" ); for( n = 0 ; n < weapons.size ; n ++ ) { if ( isdefined( weapons[n].targetname ) ) continue; weapons[n] delete(); } } } alasad_deletable_hide() { if ( isdefined( self.spawnflags ) && ( self.spawnflags & 1 ) ) self connectpaths(); self.origin -= ( 0, 0, 5000 ); } alasad_deletable_show() { self.origin += ( 0, 0, 5000 ); if ( isdefined( self.spawnflags ) && ( self.spawnflags & 1 ) ) self disconnectpaths(); } spawn_ai_and_make_dumb( spawnerTargetname, linkInPlace ) { spawner = getent( spawnerTargetname, "targetname" ); assert( isdefined( spawner ) ); if ( isdefined( spawner.script_drone ) ) { guy = droneSpawn( spawner ); } else { guy = spawner stalingradSpawn(); spawn_failed( guy ); guy.maxsightdistsqrd = 0; guy.ignoreme = true; guy.ignoreall = true; guy thread ignoreAllEnemies( true ); } guy.health = 100000; if ( isdefined( linkInPlace ) ) { dummy = spawn( "script_origin", spawner.origin ); guy linkto( dummy ); } return guy; } headshot( guy, killguy ) { if ( !isdefined( guy ) ) return; if ( !isAlive( guy ) ) return; if ( !isdefined( killguy ) ) killguy = true; playFX( getfx( "headshot" ), guy getTagOrigin( "tag_eye" ) ); if ( killguy ) guy doDamage( guy.health + 100, guy getTagOrigin( "tag_eye" ) ); } goBlack( fDelay, fFadeTimeIn, fFadeTimeOut ) { overlay = newHudElem(); overlay.x = 0; overlay.y = 0; overlay.alignX = "left"; overlay.alignY = "top"; overlay.horzAlign = "fullscreen"; overlay.vertAlign = "fullscreen"; overlay setshader ( "black", 640, 480 ); overlay.sort = 1; overlay.alpha = 0; assert( isdefined( fFadeTimeIn ) ); assert( isdefined( fFadeTimeOut ) ); assert( fFadeTimeIn >= 0 ); assert( fFadeTimeOut >= 0 ); if ( fFadeTimeIn > 0 ) overlay fadeOverTime( fFadeTimeIn ); overlay.alpha = 1.0; wait fFadeTimeIn; if ( !isdefined( fDelay ) ) return; assert( fDelay > 0 ); wait fDelay; level notify( "fade_from_black" ); wait 0.1; if ( fFadeTimeOut > 0 ) overlay fadeOverTime( fFadeTimeOut ); overlay.alpha = 0.0; wait fFadeTimeOut; overlay destroy(); } do_alasad( location ) { assert( isdefined( location ) ); level.alasad_sequence_init = true; struct = spawnStruct(); if ( location == "barn" ) { println( "Al Asad is in the ^3BARN" ); struct.nodeTargetname1 = "alasad_barn_node"; struct.nodeTargetname2 = "alasad_barn_node2"; struct.deletableNoteworthy = "alasad_barn_deletable"; struct.brushDoorTargetname = "alasad_barn_door"; struct.spawnersToDeleteKillspawner = 12; struct.friendlyColorTriggerTargetname1 = "alasad_barn_friendly_color_trigger"; struct.friendlyColorTriggerTargetname2 = "alasad_barn_last_friendly_trigger"; struct.AlAsadSpawnerTargetname = "alasad_spawner_barn"; struct.AlAsadFirstShotSpawnerTargetname = "alasad_barn_first_shot_spawner"; struct.AlAsadSecondShotSpawnerTargetname = "alasad_barn_second_shot_spawner"; struct.startSequenceTriggerTargetname = "alasad_barn_trigger"; struct.playerLocationSceneBTargetname = "alasad_barn_playerlocation"; struct.setupAreaTriggerTargetname = "alasad_barn_area"; struct.AItoDeleteAreaTargetname = "area_barn"; level.alasad_flashbang_location = getent( "alasad_barn_flash_location", "targetname" ).origin; level.alasad_objective_location = "6"; } else if ( location == "house" ) { println( "Al Asad is in the ^3HOUSE" ); struct.nodeTargetname1 = "alasad_house_node"; struct.nodeTargetname2 = "alasad_house_node2"; struct.deletableNoteworthy = "alasad_house_deletable"; struct.brushDoorTargetname = "alasad_house_door"; struct.spawnersToDeleteKillspawner = 2; struct.friendlyColorTriggerTargetname1 = "alasad_house_friendly_color_trigger"; struct.friendlyColorTriggerTargetname2 = "alasad_house_last_friendly_trigger"; struct.AlAsadSpawnerTargetname = "alasad_spawner_house"; struct.AlAsadFirstShotSpawnerTargetname = "alasad_house_first_shot_spawner"; struct.AlAsadSecondShotSpawnerTargetname = "alasad_house_second_shot_spawner"; struct.startSequenceTriggerTargetname = "alasad_house_trigger"; struct.playerLocationSceneBTargetname = "alasad_house_playerlocation"; struct.setupAreaTriggerTargetname = "alasad_house_area"; struct.AItoDeleteAreaTargetname = "area_grandmas_house"; level.alasad_flashbang_location = getent( "alasad_house_flash_location", "targetname" ).origin; level.alasad_objective_location = "2"; } assert( isdefined( struct ) ); assert( isdefined( struct.nodeTargetname1 ) ); assert( isdefined( struct.nodeTargetname2 ) ); assert( isdefined( struct.deletableNoteworthy ) ); assert( isdefined( struct.brushDoorTargetname ) ); assert( isdefined( struct.friendlyColorTriggerTargetname1 ) ); assert( isdefined( struct.friendlyColorTriggerTargetname2 ) ); assert( isdefined( struct.AlAsadSpawnerTargetname ) ); assert( isdefined( struct.AlAsadFirstShotSpawnerTargetname ) ); assert( isdefined( struct.AlAsadSecondShotSpawnerTargetname ) ); assert( isdefined( struct.startSequenceTriggerTargetname ) ); assert( isdefined( struct.playerLocationSceneBTargetname ) ); assert( isdefined( struct.setupAreaTriggerTargetname ) ); assert( isdefined( level.alasad_flashbang_location ) ); alasad_sequence_init( struct ); } alasad_sequence_init( struct ) { // prepares the correct location for the scene by removing spawners and setting up doors etc. array_thread( getentarray( struct.deletableNoteworthy, "script_noteworthy" ), ::alasad_deletable_show ); // get the first node struct.node = getnode( struct.nodeTargetname1, "targetname" ); assert( isdefined( struct.node ) ); // spawn the door and make it play frame 0 so it's shut struct.door = spawn_anim_model( "door" ); struct.node thread anim_first_frame_solo( struct.door, "interrogationA" ); // link the door to the model door that animates and hide the model door struct.brushmodel_door = getent( struct.brushDoorTargetname, "targetname" ); assert( isdefined( struct.brushmodel_door ) ); struct.brushmodel_door linkto( struct.door, "door_hinge_jnt" ); struct.door hide(); // delete AI and spawners with this noteworthy when the barn will be the location of al asad if ( isdefined( struct.spawnersToDeleteKillspawner ) ) thread maps\_spawner::kill_spawnerNum( struct.spawnersToDeleteKillspawner ); if ( isdefined( struct.AItoDeleteAreaTargetname ) ) { area = getent( struct.AItoDeleteAreaTargetname, "targetname" ); axis = getAIArray( "axis" ); for ( i = 0 ; i < axis.size ; i++ ) { if ( !axis[ i ] istouching( area ) ) continue; axis[ i ].dieQuietly = true; axis[ i ] doDamage( axis[ i ].health + 100, axis[ i ].origin ); } } alasad_sequence_wait( struct ); } alasad_sequence_wait( struct ) { // Waits for the player to get close to Al Asad's location and moves the friendlies to the door // If the player runs off the friendlies leave the door and go back to normal AI until the player returns level endon( "alasad_sequence_started" ); struct.alasad_area = getent( struct.setupAreaTriggerTargetname, "targetname" ); assert( isdefined( struct.alasad_area ) ); struct.color_trigger = getent( struct.friendlyColorTriggerTargetname1, "targetname" ); assert( isdefined( struct.color_trigger ) ); for(;;) { if ( level.player isTouching( struct.alasad_area ) ) { // make all friendlies orange color group and send them to the door array_thread( getAIArray( "allies" ), ::set_force_color, "o" ); struct.color_trigger notify( "trigger" ); thread alasad_sequence_ready( struct ); while( level.player isTouching( struct.alasad_area ) ) wait 0.05; } else { level notify( "alasad_sequence_canceled" ); // make all friendlies red color group again because player is leaving the area array_thread( getAIArray( "allies" ), ::set_force_color, "r" ); while( !level.player isTouching( struct.alasad_area ) ) wait 0.05; } } } alasad_sequence_ready( struct ) { level endon( "alasad_sequence_canceled" ); // get price into position struct.node thread anim_reach_solo( level.price, "interrogationA" ); // wait for the player to get close getent( struct.startSequenceTriggerTargetname, "targetname" ) waittill( "trigger" ); alasad_sequence_start( struct ); } alasad_sequence_start( struct ) { level notify( "alasad_sequence_started" ); level.air_support_hint_delete = true; // take away flash, grenade, smoke, etc removeWeaponFromPlayer( "fraggrenade" ); removeWeaponFromPlayer( "smoke_grenade_american" ); removeWeaponFromPlayer( "c4" ); removeWeaponFromPlayer( "flash_grenade" ); thread battlechatter_off( "allies" ); thread battlechatter_off( "axis" ); thread doAutoSave( "capturing_al_asad" ); //--------------- // SCENE A //--------------- // spawn and prepare Al Asad level.alasad = spawn_ai_and_make_dumb( struct.AlAsadSpawnerTargetname ); level.alasad thread removeWeapon(); level.alasad.animname = "alasad"; waittillframeend; // waittillframeend so that Al Asad can finish spawning before he gets teleported struct.node thread anim_teleport_solo( level.alasad, "interrogationA" ); // spawn the guys guarding Al Asad level.alasad_guard1 = spawn_ai_and_make_dumb( struct.AlAsadFirstShotSpawnerTargetname, true ); level.alasad_guard2 = spawn_ai_and_make_dumb( struct.AlAsadSecondShotSpawnerTargetname, true ); // spawn the phone phone = spawn_anim_model( "phone" ); struct.node thread anim_first_frame_solo( phone, "interrogationA" ); struct.guys = []; struct.guys[ struct.guys.size ] = level.price; // get them into position to start the sequence struct.node anim_reach( struct.guys, "interrogationA" ); struct.guys[ struct.guys.size ] = level.alasad; // give price his special weapon for the scene level.price animscripts\init::initWeapon( "colt45_alasad_killer", "sidearm" ); level.price.sidearm = "colt45_alasad_killer"; // wait until the player can see the sequence level.price waittill_player_lookat( level.cosine[ "60" ] ); flag_set( "alasad_sequence_started" ); level.price thread play_sound_on_entity( "scn_assault_interogation_enter" ); // Remember, we want Al-Asad alive. He's no good to us dead. Let's go. level.price thread anim_single_solo( level.price, "nogooddead" ); // start the seqence delayThread( 5.9, ::activate_trigger_with_targetname, struct.friendlyColorTriggerTargetname2 ); delayThread( 6.0, ::disconnectPathsWrapper, struct.brushmodel_door ); struct.guys[ struct.guys.size ] = struct.door; struct.guys[ struct.guys.size ] = phone; struct.node anim_single( struct.guys, "interrogationA" ); // take away ability to call air support thread chopper_air_support_removeFunctionality(); thread goBlack( 18.0, 0.0, 0.5 ); thread blackscreen1_dialog(); thread alasad_kill_axis(); level.player NightVisionForceOff(); //--------------- // SCENE B //--------------- objective_state( 0, "done" ); struct.node = getnode( struct.nodeTargetname2, "targetname" ); assert( isdefined( struct.node ) ); level.price detach( "weapon_m4grunt_sp_silencer", "tag_weapon_chest" ); level.price.a.weaponPos[ "chest" ] = "none"; // spawn the chair chair = spawn_anim_model( "chair" ); // first frame of next scene so it's ready struct.guys = []; struct.guys[ struct.guys.size ] = level.price; struct.guys[ struct.guys.size ] = level.gaz; struct.guys[ struct.guys.size ] = level.alasad; struct.guys[ struct.guys.size ] = chair; struct.guys[ struct.guys.size ] = phone; struct.node thread anim_first_frame( struct.guys, "interrogationB" ); // put the player in a good spot level.player freezeControls( true ); delete_dropped_weapons(); level.player takeAllWeapons(); movePlayerToLocation( struct.playerLocationSceneBTargetname ); level waittill( "fade_from_black" ); level.player freezeControls( false ); level.price thread alasad_execution_notes(); level.price thread alasad_cell_phone_sounds( phone ); level.gaz thread play_sound_on_entity( "scn_assault_interogation_pickup" ); level.price thread play_sound_on_entity( "scn_assault_interogation_beating" ); level.alasad thread play_sound_on_entity( "scn_assault_interogation_breathing" ); struct.node anim_single( struct.guys, "interrogationB" ); level.price.weaponInfo["m4_silencer"].position = "none"; } blackscreen1_dialog() { wait 2; level.player thread play_sound_on_entity( "scn_assault_interogation_black" ); // Why'd you do it? Where did you get the bomb? level.price thread delayThread( 0.0, ::anim_single_solo, level.price, "whydyoudoit" ); // It wasn't me!! level.alasad thread delayThread( 3.05, ::anim_single_solo, level.alasad, "wasntme1" ); // Who then? level.price thread delayThread( 5.3, ::anim_single_solo, level.price, "whothen" ); // It wasn't me!! level.alasad thread delayThread( 8.3, ::anim_single_solo, level.alasad, "wasntme2" ); // Who!? Give me a name! level.price thread delayThread( 10.85, ::anim_single_solo, level.price, "givemeaname" ); // A name! I - want - his - name! level.price thread delayThread( 13.65, ::anim_single_solo, level.price, "aname" ); wait 16; } blackscreen2_dialog() { wait 1; // Who was that sir? level.gaz thread anim_single_solo( level.gaz, "whowasthat" ); wait 2; // Zakhaev. level.price thread anim_single_solo( level.price, "zakhaev" ); wait 2; // Imran Zakhaev. level.price thread anim_single_solo( level.price, "imran" ); } alasad_execution_notes() { level.price waittillmatch( "single anim", "pistol_pickup" ); level.price detach( "weapon_colt1911_black", "tag_weapon_right" ); wait 0.2; level.price attach( "weapon_colt1911_black", "tag_weapon_right" ); level.price waittillmatch( "single anim", "fire" ); wait 3.5; level.player freezeControls( true ); thread goBlack( 60.0, 1.0, 0.5 ); thread blackscreen2_dialog(); wait 7; nextmission(); } alasad_cell_phone_sounds( phone ) { wait 2; thread alasad_cell_phone_ring( phone ); wait 7; phone notify( "stop ringing" ); wait 1; // Sir. It's his cell phone. level.gaz thread anim_single_solo( level.gaz, "cellphone" ); } alasad_cell_phone_ring( phone ) { phone endon( "stop ringing" ); for(;;) { level.gaz thread play_sound_on_entity( "scn_assault_mobile_ring" ); wait 2; } } alasad_notetracks( guy ) { // called from a notetrack sHandTag = "J_Mid_RI_3"; guy attach( "projectile_m84_flashbang_grenade", sHandTag ); wait 2.0; // price tosses in a flashbang guy detach( "projectile_m84_flashbang_grenade", sHandTag ); thread alasad_flashbang( 1.0 ); // price picks up pistol so need to replace the rifle guy waittillmatch( "single anim", "pistol_pickup" ); // price drops his gun guy waittillmatch( "single anim", "pistol_drop" ); guy gun_remove(); // al asad gets shot guy waittillmatch( "single anim", "fire" ); headshot( level.alasad, false ); } alasad_flashbang( fDelay ) { assert( isdefined( level.alasad_flashbang_location ) ); wait fDelay; playFX( getfx( "alasad_flash" ), level.alasad_flashbang_location ); thread play_sound_in_space( "flashbang_explode_default", level.alasad_flashbang_location ); // two guards get shot wait 1.0; headshot( level.alasad_guard1 ); wait 0.5; headshot( level.alasad_guard2 ); } alasad_kill_axis() { axis = getaiarray( "axis" ); for ( i = 0 ; i < axis.size ; i++ ) { if ( !isAlive( axis[ i ] ) ) continue; if ( axis[ i ] == level.alasad ) continue; if ( axis[ i ] == level.alasad_guard1 ) continue; if ( axis[ i ] == level.alasad_guard2 ) continue; axis[ i ].dieQuietly = true; axis[ i ] doDamage( axis[ i ].health + 100, axis[ i ].origin ); } } disconnectPathsWrapper( ent ) { ent connectPaths(); } opening_sequence() { assert( isdefined( level.opening_guy ) ); node = getnode( "opening_sequence_node", "targetname" ); assert( isdefined( node ) ); guys = []; guys[ 0 ] = level.price; guys[ 1 ] = level.opening_guy; node anim_first_frame( guys, "opening" ); wait 4.0; thread opening_sequence_notetracks( level.opening_guy ); thread opening_sequence_dialog( level.opening_guy ); node anim_single( guys, "opening" ); } opening_sequence_notetracks( guy ) { guy attach( "com_flashlight_off", "tag_inhand" ); guy waittillmatch( "single anim", "flash" ); thread opening_sequence_flashLight( guy ); guy waittillmatch( "single anim", "flash" ); thread opening_sequence_flashLight( guy ); guy waittillmatch( "single anim", "flash" ); thread opening_sequence_flashLight( guy ); guy waittillmatch( "single anim", "detach flashlight" ); guy detach( "com_flashlight_off", "tag_inhand" ); } opening_sequence_flashLight( guy ) { tagName = "tag_inhand"; modelOn = "com_flashlight_on"; modelOff = "com_flashlight_off"; // on if ( guy isModelAttached( modelOff, tagName ) ) guy detach( modelOff, tagName ); guy attach( modelOn, tagName ); guy thread flashlight_light( true ); wait 0.1; // off if ( guy isModelAttached( modelOn, tagName ) ) guy detach( modelOn, tagName ); guy attach( modelOff, tagName ); guy thread flashlight_light( false ); } opening_sequence_dialog( guy ) { wait 3; //There's Kamarov's man, let's go. level.price thread anim_single_solo( level.price, "kamarovsman" ); wait 5; //Al-Asad is in the village. The Ultranationalists are protecting him. guy thread anim_single_solo( guy, "asadinvillage" ); wait 4.5; //Perfect. Move out. level.price thread anim_single_solo( level.price, "perfect" ); wait 10; //What the bloody hell's going on up there? level.gaz thread anim_single_solo( level.gaz, "whatsgoingon" ); wait 2.5; //It's the Ultranationalists. They're killing the villagers. guy thread anim_single_solo( guy, "killingvillagers" ); wait 3.5; //Not for long they're not. level.gaz thread anim_single_solo( level.gaz, "notforlong" ); } isModelAttached( modelName, tagName ) { qAttached = false; modelName = tolower( modelName ); tagName = tolower( tagName ); assert( isdefined( modelName ) ); if ( !isdefined( tagName ) ) return qAttached; attachedModelCount = self getattachsize(); attachedModels = []; for ( i = 0 ; i < attachedModelCount ; i++ ) attachedModels[ i ] = tolower( self getAttachModelName( i ) ); for ( i = 0 ; i < attachedModels.size ; i++ ) { if ( attachedModels[ i ] != modelName ) continue; sName = tolower( self getattachtagname( i ) ); if ( tagName != sName ) continue; qAttached = true; break; } return qAttached; } flashlight_light( state ) { flash_light_tag = "tag_light"; if ( state ) { flashlight_fx_ent = spawn( "script_model", ( 0, 0, 0 ) ); flashlight_fx_ent setmodel( "tag_origin" ); flashlight_fx_ent hide(); flashlight_fx_ent linkto( self, flash_light_tag, ( 0, 0, 0 ), ( 0, 0, 0 ) ); self thread flashlight_light_death( flashlight_fx_ent ); playfxontag( level._effect[ "flashlight" ], flashlight_fx_ent, "tag_origin" ); } else self notify( "flashlight_off" ); } flashlight_light_death( flashlight_fx_ent ) { self waittill_either( "death", "flashlight_off" ); flashlight_fx_ent delete(); } removeWeaponFromPlayer( weaponName ) { assert( isdefined( weaponName ) ); if( level.player HasWeapon( weaponName ) ) level.player takeWeapon( weaponName ); } removeWeapon( optionalWeaponName ) { if( IsAI( self ) ) self gun_remove(); else { size = self getattachsize(); for ( i = 0; i < size; i++ ) { model = self getattachmodelname( i ); tag = self GetAttachTagName( i ); if ( isdefined( optionalWeaponName ) ) { if ( model == optionalWeaponName ) self detach( model, tag ); } else { if ( issubstr( tolower( model ), "weapon_" ) ) self detach( model, tag ); } } } }