#include maps\_utility; #include animscripts\utility; #include common_scripts\utility; #include maps\_hud_util; main() { flag_init( "coop_game" ); flag_init( "coop_revive" ); flag_init( "coop_alldowned" ); flag_init( "coop_show_constant_icon" ); flag_init( "coop_fail_when_all_dead" ); setDvarIfUninitialized( "coop_revive", 1 ); setDvarIfUninitialized( "coop_show_constant_icon", 1 ); //later on - hopefully this flag will be set through some real time method //so that the 2nd player can jump in and out of a game at any moment...right //now this check only happens at the load of each level and doesn't get checked again if ( is_coop() ) flag_set( "coop_game" ); if ( getdvar( "coop_revive", 1 ) == "1" ) flag_set( "coop_revive" ); flag_set( "coop_show_constant_icon" ); // "Partner down" precacheString( &"SCRIPT_COOP_BLEEDING_OUT_PARTNER" ); // "Bleeding out" precacheString( &"SCRIPT_COOP_BLEEDING_OUT" ); // "Reviving partner..." precacheString( &"SCRIPT_COOP_REVIVING_PARTNER" ); // "Being revived..." precacheString( &"SCRIPT_COOP_REVIVING" ); // "Hold ^3[{+usereload}]^7 to revive" precacheString( &"SCRIPT_COOP_REVIVE" ); precacheShader( "hint_health" ); precacheShader( "coop_player_location" ); precacheShader( "coop_player_location_fire" ); level.coop_icon_green = ( 0.635, 0.929, 0.604 ); level.coop_icon_yellow = ( 1, 1, 0.2 ); level.coop_icon_orange = ( 1, .65, 0.2 ); level.coop_icon_red = ( 1, 0.2, 0.2 ); level.coop_icon_white = ( 1, 1, 1 ); level.coop_icon_downed = level.coop_icon_yellow; level.coop_icon_shoot = level.coop_icon_green; level.coop_icon_damage = level.coop_icon_orange; level.coop_icon_blinktime = 7; // how long the non-downed player's hud icon should blink after the downed player presses the nag button level.coop_icon_blinkcrement = 0.375; // how long each "blink" lasts level.coop_revive_nag_hud_refreshtime = 20; level.revive_hud_base_offset = 75; level.revive_bar_base_offset = 15; if ( !issplitscreen() ) level.revive_hud_base_offset = 120; foreach( player in level.players ) player.reviving_buddy = false; // Used to keep one player alive for a few seconds when the other player goes down level.coop_last_player_downed_time = 0; thread downed_player_manager(); thread player_coop_check_mission_ended(); } player_coop_proc() { //this checks to see if we're already running the process if ( !flag( "coop_game" ) ) return; level endon( "coop_game" ); if ( self ent_flag( "coop_proc_running" ) ) return; if ( !isdefined( self.original_maxhealth ) ) self.original_maxhealth = self.maxhealth; if ( !flag( "coop_revive" ) ) return; level endon( "coop_revive" ); self thread player_coop_proc_ended(); switch( level.gameskill ) { case 0: case 1: self.coop.bleedout_time_default = 120; level.coop_bleedout_stage2_multiplier = 0.5; level.coop_bleedout_stage3_multiplier = 0.25; break; case 2: self.coop.bleedout_time_default = 90; level.coop_bleedout_stage2_multiplier = 0.66; level.coop_bleedout_stage3_multiplier = 0.33; break; case 3: self.coop.bleedout_time_default = 60; level.coop_bleedout_stage2_multiplier = 0.5; level.coop_bleedout_stage3_multiplier = 0.25; break; } self ent_flag_set( "coop_proc_running" ); self EnableDeathShield( true ); assertex( self ent_flag_exist( "coop_downed" ), "Didnt have flag set" ); self ent_flag_clear( "coop_downed" ); self ent_flag_clear( "coop_pause_bleedout_timer" ); self thread player_setup_icon(); self endon( "death" ); my_id = self.unique_id; while ( 1 ) { self waittill( "deathshield", damage, attacker, direction, point, type, modelName, tagName, partName, dflags, weaponName ); // we're already downed if ( self ent_flag( "coop_downed" ) ) continue; death_array = []; death_array[ "damage" ] = damage; death_array[ "player" ] = self; // Only want to set this on the *second* player to go down. // We want to know the most recent reason for a player to be killed, rather than something that // happened to the first player potentially almost 2 minutes ago (or whatever the revive time is). buddy = get_other_player( self ); if ( buddy ent_flag( "coop_downed" ) ) { self.coop_death_reason = []; self.coop_death_reason[ "attacker" ] = attacker; self.coop_death_reason[ "cause" ] = type; self.coop_death_reason[ "weapon_name" ] = weaponName; } level.downed_players[ self.unique_id ] = death_array; self try_crush_player( attacker, type ); // the downed_player_manager will down the player level notify( "player_downed" ); } } try_crush_player( attacker, type ) { if ( !Isdefined( attacker ) ) { return; } if ( !Isdefined( type ) ) { return; } if ( type != "MOD_CRUSH" ) { return; } // If a vehicle crushed the player, make sure the vehicle is moving before we kill, if not, then the player should live if ( IsDefined( attacker.vehicletype ) ) { speed = attacker Vehicle_GetSpeed(); if ( abs( speed ) == 0 ) { return; } } if ( flag( "special_op_terminated" ) ) { return; } attacker maps\_specialops::so_crush_player( self, type ); } downed_player_manager() { for ( ;; ) { // the array will be refilled when a player is downed level.downed_players = []; level waittill( "player_downed" ); assertex( isdefined( level.player_downed_death_buffer_time ), "level.player_downed_death_buffer_time didnt get defined!" ); // wait until the end of the frame so the array will have all players that were downed in it waittillframeend; if ( gettime() < level.coop_last_player_downed_time + level.player_downed_death_buffer_time * 1000 ) { // cant die until this time has passed continue; } level.coop_last_player_downed_time = gettime(); // figure out which player to down highest_damage = 0; downed_player = undefined; // randomize it so either player can be downed if they tie on damage level.downed_players = array_randomize( level.downed_players ); foreach ( unique_id, array in level.downed_players ) { //Print3d( array[ "player" ] geteye(), array[ "damage" ], (1,0,0), 1, 1, 500 ); if ( array[ "damage" ] >= highest_damage ) { downed_player = array[ "player" ]; } } assertex( isdefined( downed_player ), "Downed_player was not defined!" ); downed_player thread player_coop_downed(); // the remaining player gets slightly buffed thread maps\_gameskill::resetSkill(); } } create_fresh_friendly_icon( material ) { if ( isdefined( self.friendlyIcon ) ) self.friendlyIcon Destroy(); self.friendlyIcon = NewClientHudElem( self ); self.friendlyIcon SetShader( material, 1, 1 ); self.friendlyIcon SetWayPoint( true, true, false ); self.friendlyIcon SetWaypointIconOffscreenOnly(); self.friendlyIcon SetTargetEnt( get_other_player( self ) ); self.friendlyIcon.material = material; self.friendlyIcon.hidewheninmenu = true; if ( flag( "coop_show_constant_icon" ) ) self.friendlyIcon.alpha = 1.0; else self.friendlyIcon.alpha = 0.0; } rebuild_friendly_icon( color, material, non_rotating ) { if ( isdefined( self.noFriendlyHudIcon ) ) return; assertex( isdefined( color ), "rebuild_friendly_icon requires a valid color to be passed in." ); assertex( isdefined( material ), "rebuild_friendly_icon requires a valid material to be passed in."); // Rebuild from scratch if it doesn't exist or the material has changed. if ( !isdefined( self.friendlyIcon ) || ( self.friendlyIcon.material != material ) ) { create_fresh_friendly_icon( material ); } self.friendlyIcon.color = color; if ( !isdefined( non_rotating ) ) self.friendlyIcon SetWaypointEdgeStyle_RotatingIcon(); } CreateFriendlyHudIcon_Normal() { self rebuild_friendly_icon( level.coop_icon_green, "coop_player_location" ); } CreateFriendlyHudIcon_Downed() { self rebuild_friendly_icon( level.coop_icon_downed, "hint_health", true ); } FriendlyHudIcon_BlinkWhenFire() { self endon( "death" ); while ( 1 ) { self waittill( "weapon_fired" ); other_player = get_other_player( self ); other_player thread FriendlyHudIcon_FlashIcon( level.coop_icon_shoot, "coop_player_location_fire" ); } } FriendlyHudIcon_BlinkWhenDamaged() { self endon( "death" ); while ( 1 ) { self waittill( "damage" ); other_player = get_other_player( self ); other_player thread FriendlyHudIcon_FlashIcon( level.coop_icon_damage, "coop_player_location" ); } } FriendlyHudIcon_FlashIcon( color, material ) { if ( isdefined( self.noFriendlyHudIcon ) ) return; self endon( "death" ); self notify( "flash_color_thread" ); self endon( "flash_color_thread" ); other_player = get_other_player( self ); if ( other_player ent_flag( "coop_downed" ) ) return; self rebuild_friendly_icon( color, material ); wait .5; self rebuild_friendly_icon( level.coop_icon_green, "coop_player_location" ); } player_setup_icon() { if ( !flag( "coop_game" ) ) return; level endon( "coop_game" ); self CreateFriendlyHudIcon_Normal(); self thread FriendlyHudIcon_BlinkWhenFire(); self thread FriendlyHudIcon_BlinkWhenDamaged(); if ( isdefined( self.noFriendlyHudIcon ) ) return; while ( 1 ) { flag_wait( "coop_show_constant_icon" ); self.friendlyIcon.alpha = 1; flag_waitopen( "coop_show_constant_icon" ); self.friendlyIcon.alpha = 0; } } player_coop_create_use_target() { level.revive_ent = spawn( "script_model", self.origin + ( 0, 0, 28 ) ); // offset can't be higher than prone height of 30 // level.revive_ent setModel( "defaultvehicle" ); level.revive_ent setModel( "tag_origin" ); level.revive_ent linkTo( self, "tag_origin" ); level.revive_ent makeUsable(); level.revive_ent setHintString( &"SCRIPT_COOP_REVIVE" ); // LANG_ENGLISH Hold ^3[{+usereload}]^7 to revive" } player_coop_destroy_use_target() { foreach ( player in level.players ) player.reviving_buddy = false; if ( isdefined( level.revive_ent ) ) level.revive_ent Delete(); } player_coop_downed() { self endon( "death" ); self player_coop_set_down_attributes(); player_coop_check_alldowned(); if ( flag( "coop_alldowned" ) ) self player_coop_kill(); self player_coop_create_use_target(); //put up icon self thread player_coop_downed_dialogue(); self thread player_coop_downed_hud(); self thread player_coop_downed_icon(); self thread player_coop_enlist_savior(); self add_wait( ::flag_wait, "coop_alldowned" ); self add_wait( ::ent_flag_waitopen, "coop_downed" ); self add_wait( ::waittill_msg, "coop_bled_out" ); do_wait_any(); //take down icon waittillframeend; self notify( "end_func_player_coop_downed_icon" ); if ( flag( "coop_alldowned" ) || self ent_flag( "coop_downed" ) ) self player_coop_kill(); self player_coop_set_original_attributes(); } player_coop_downed_dialogue() { self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); other_player = get_other_player( self ); time = other_player.coop.bleedout_time_default; //time_fifth = time * 0.2; initialWait = 1; wait initialWait; self notify( "so_downed" ); self delaythread( 0.05, ::player_coop_downed_nag_button ); } get_coop_downed_hud_color( current_time, total_time, doBlinks ) { // only one player should see the blinking if( !IsDefined( doBlinks ) ) { doBlinks = true; } // maybe we have to deliver the blink state? if( doBlinks && self coop_downed_hud_should_blink() ) { ASSERT( IsDefined( self.blinkState ) ); if( self.blinkState == 1 ) { return level.coop_icon_white; } } // if we're not blinking, return the base color if ( current_time < ( total_time * level.coop_bleedout_stage3_multiplier ) ) { return level.coop_icon_red; } if ( current_time < ( total_time * level.coop_bleedout_stage2_multiplier ) ) { return level.coop_icon_orange; } return level.coop_icon_downed; } coop_downed_hud_should_blink() { otherplayer = get_other_player( self ); if( otherplayer player_coop_is_reviving() ) { return false; } // have we ever pressed the nag button? if( IsDefined( self.lastReviveNagButtonPressTime ) ) { // did we press the button recently? if( ( GetTime() - self.lastReviveNagButtonPressTime ) < ( level.coop_icon_blinktime * 1000 ) ) { return true; } } return false; } // this toggles the blink state so we don't have to track increment time in the get_coop_downed_hud_color() function player_downed_hud_toggle_blinkstate() { self notify( "player_downed_hud_blinkstate" ); self endon( "player_downed_hud_blinkstate" ); self endon( "death" ); self endon( "revived" ); self.blinkState = 1; while( 1 ) { wait( level.coop_icon_blinkcrement ); if( self.blinkState == 1 ) { self.blinkState = 0; } else { self.blinkState = 1; } } } player_coop_downed_nag_button() { self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); self NotifyOnPlayerCommand( "nag", "weapnext" ); while( 1 ) { if( !self can_show_nag_prompt() ) { wait( 0.05 ); continue; } if( self nag_should_draw_hud() ) { self thread nag_prompt_show(); self thread nag_prompt_cancel(); } msg = self waittill_any_timeout( level.coop_revive_nag_hud_refreshtime, "nag", "nag_cancel" ); if( msg == "nag" ) { self.lastReviveNagButtonPressTime = GetTime(); self thread player_downed_hud_toggle_blinkstate(); self thread maps\_specialops_battlechatter::play_revive_nag(); } wait( 0.05 ); } } nag_should_draw_hud() { waitTime = level.coop_revive_nag_hud_refreshtime * 1000; if( !IsDefined( self.lastReviveNagButtonPressTime ) ) { return true; } else if( GetTime() - self.lastReviveNagButtonPressTime < waitTime ) { return false; } return true; } nag_prompt_show() { fadeTime = 0.05; loc = &"SPECIAL_OPS_REVIVE_NAG_HINT"; hud = self get_nag_hud(); hud.alpha = 0; hud SetText( loc ); hud FadeOverTime( fadeTime ); hud.alpha = 1; self waittill_disable_nag(); hud FadeOverTime( fadeTime ); hud.alpha = 0; hud delaycall( ( fadeTime + 0.05 ), ::Destroy ); } waittill_disable_nag() { level endon( "special_op_terminated" ); self waittill_any( "nag", "nag_cancel", "death" ); } get_nag_hud() { hudelem = NewClientHudElem( self ); hudelem.x = 0; hudelem.y = 50; hudelem.alignX = "center"; hudelem.alignY = "middle"; hudelem.horzAlign = "center"; hudelem.vertAlign = "middle"; hudelem.fontScale = 1; hudelem.color = ( 1.0, 1.0, 1.0 ); hudelem.font = "hudsmall"; hudelem.glowColor = ( 0.3, 0.6, 0.3 ); hudelem.glowAlpha = 0; hudelem.foreground = 1; hudelem.hidewheninmenu = true; hudelem.hidewhendead = true; return hudelem; } nag_prompt_cancel() { self endon( "nag" ); while( self can_show_nag_prompt() ) { wait( 0.05 ); } self notify( "nag_cancel" ); } can_show_nag_prompt() { if ( isdefined( level.hide_nag_prompt ) && level.hide_nag_prompt ) { return false; } otherplayer = get_other_player( self ); if( otherplayer player_coop_is_reviving() ) { return false; } if( !self maps\_specialops_battlechatter::can_say_current_nag_event_type() ) { return false; } return true; } player_coop_downed_hud() { self endon( "end_func_player_coop_downed_icon" ); self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); foreach ( player in level.players ) { player.revive_text = player createClientFontString( "hudsmall", 1.0 ); player.revive_text setPoint( "CENTER", undefined, 0, level.revive_hud_base_offset ); player.revive_text thread maps\_specialops::so_hud_pulse_create(); player.revive_timer = player createClientTimer( "hudsmall", 1.2 ); player.revive_timer setPoint( "CENTER", undefined, 0, level.revive_hud_base_offset + level.revive_bar_base_offset ); player.revive_timer thread maps\_specialops::so_hud_pulse_create(); } self thread player_coop_downed_hud_destroy(); foreach ( player in level.players ) { if ( player == self ) player.revive_text settext( &"SCRIPT_COOP_BLEEDING_OUT" ); else player.revive_text settext( &"SCRIPT_COOP_BLEEDING_OUT_PARTNER" ); player.revive_timer setTimer( self.coop.bleedout_time_default - 1 ); } self thread player_coop_countdown_timer( self.coop.bleedout_time_default ); time = self.coop.bleedout_time_default; foreach ( player in level.players ) { player.revive_text.color = self.revive_text.color; player.revive_timer.color = self.revive_text.color; } // give player a chance to get his timer set waittillframeend; while ( time ) { foreach ( player in level.players ) { previous_color = player.revive_text.color; new_color = get_coop_downed_hud_color( self.coop.bleedout_time, self.coop.bleedout_time_default, false ); player.revive_text.color = new_color; player.revive_timer.color = new_color; if ( distance( new_color, previous_color ) > 0.001 ) { if ( distance( new_color, level.coop_icon_red ) <= 0.001 ) { player.revive_text.pulse_loop = true; player.revive_timer.pulse_loop = true; } player.revive_text thread maps\_specialops::so_hud_pulse_create(); player.revive_timer thread maps\_specialops::so_hud_pulse_create(); } } wait 1.0; time -= 1.0; } } player_coop_downed_hud_destroy() { self thread player_coop_downed_hud_destroy_mission_end(); self waittill_any( "end_func_player_coop_downed_icon", "death" ); foreach ( player in level.players ) { if ( isdefined( player.revive_text ) ) player.revive_text destroy(); if ( isdefined( player.revive_timer ) ) player.revive_timer destroy(); } } player_coop_downed_hud_destroy_mission_end() { level waittill( "special_op_terminated" ); foreach ( player in level.players ) { if ( isdefined( player.revive_text ) ) player.revive_text destroy(); if ( isdefined( player.revive_timer ) ) player.revive_timer destroy(); } if ( isdefined( self.friendlyIcon ) ) self.friendlyIcon Destroy(); other_player = get_other_player( self ); if ( isdefined( other_player.friendlyIcon ) ) other_player.friendlyIcon Destroy(); } player_coop_countdown_timer( time ) { self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); self.coop.bleedout_time = time; while ( self.coop.bleedout_time > 0 ) { if ( self ent_flag( "coop_pause_bleedout_timer" ) ) { foreach ( player in level.players ) player.revive_timer.alpha = 0; self ent_flag_waitopen( "coop_pause_bleedout_timer" ); //need this check because was setting a time that wasn't greater than 0 which would give an error if ( self.coop.bleedout_time >= 1 ) { foreach ( player in level.players ) player.revive_timer settimer( self.coop.bleedout_time - 1 ); } } else { foreach ( player in level.players ) player.revive_timer.alpha = 1; } wait .05; self.coop.bleedout_time -= .05; } self.coop.bleedout_time = 0; maps\_specialops::so_force_deadquote( "@DEADQUOTE_SO_BLED_OUT", "ui_bled_out" ); thread maps\_specialops::so_dialog_mission_failed_bleedout(); self notify( "coop_bled_out" ); } player_coop_downed_icon() { self endon( "end_func_player_coop_downed_icon" ); self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); // self thread player_coop_downed_icon_timer(); //give player a chance to get his timer set waittillframeend; other_player = get_other_player( self ); other_player CreateFriendlyHudIcon_Downed(); while ( self.coop.bleedout_time > 0 ) { self ent_flag_waitopen( "coop_pause_bleedout_timer" ); other_player rebuild_friendly_icon( get_coop_downed_hud_color( self.coop.bleedout_time, self.coop.bleedout_time_default ), "hint_health", true ); wait 0.05; } } /* player_coop_downed_icon_timer() { self endon( "end_func_player_coop_downed_icon" ); self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); //give player a chance to get his timer set waittillframeend; other_player = get_other_player( self ); while ( self.coop.bleedout_time > 0 ) { self ent_flag_waitopen( "coop_pause_bleedout_timer" ); origin = self.origin + ( 0, 0, 80 ); _size = .25 + ( distance( self.origin, other_player.origin ) * .0015 ); if ( self.model != "" ) { origin = self gettagorigin( "tag_origin" ); offset = vector_multiply( anglestoright( self gettagangles( "tag_origin" ) ), 5 ); origin += offset; } string = convert_to_time_string( self.coop.bleedout_time ); color = self get_coop_downed_hud_color( self.coop.bleedout_time, self.coop.bleedout_time_default ); print3d( origin + ( 0, 0, 35 + ( _size * 12 ) ), string, color, .75, _size ); wait .05; } } */ player_coop_enlist_savior() { savior = get_other_player( self ); savior thread player_coop_revive_buddy(); } player_coop_freeze_players( frozen ) { assert( isdefined( self ) ); assert( isdefined( frozen ) ); downed_buddy = get_other_player( self ); assert( isdefined( downed_buddy ) ); if ( frozen ) { self freezecontrols( true ); self disableweapons(); self disableweaponswitch(); downed_buddy freezecontrols( true ); downed_buddy disableweapons(); } else { self freezecontrols( false ); self enableweapons(); self enableweaponswitch(); downed_buddy freezecontrols( false ); if ( !is_player_down_and_out( downed_buddy ) ) downed_buddy enableweapons(); } } player_coop_revive_buddy() { self endon( "death" ); self endon( "revived" ); level endon( "special_op_terminated" ); downed_buddy = get_other_player( self ); buttonTime = 0; for ( ;; ) { level.revive_ent waittill( "trigger", player ); // wait 0.05; if ( player != self ) continue; player.reviving_buddy = true; if ( player_coop_is_reviving() ) { self player_coop_freeze_players( true ); // reset the other player's death protection if he initiates revive, so you can't infinitely revive each other level.coop_last_player_downed_time = 0; // Gives ability to reload by tapping support. wait 0.1; if ( !player_coop_is_reviving() ) { player_coop_revive_buddy_cleanup( downed_buddy ); continue; } level.bars = []; level.bars[ "p1" ] = createClientProgressBar( level.player, level.revive_hud_base_offset + level.revive_bar_base_offset ); level.bars[ "p2" ] = createClientProgressBar( level.player2, level.revive_hud_base_offset + level.revive_bar_base_offset ); foreach ( player in level.players ) { if ( player == downed_buddy ) player.revive_text settext( &"SCRIPT_COOP_REVIVING" ); else player.revive_text settext( &"SCRIPT_COOP_REVIVING_PARTNER" ); } speak_first = randomfloat( 1 ) > 0.33; if ( speak_first ) self notify( "so_reviving" ); buttonTime = 0; totalTime = 1.5; while ( player_coop_is_reviving() ) { downed_buddy ent_flag_set( "coop_pause_bleedout_timer" ); foreach ( bar in level.bars ) bar updateBar( buttonTime / totalTime ); wait( 0.05 ); buttonTime += 0.05; if ( buttonTime > totalTime ) { player_coop_revive_buddy_cleanup( downed_buddy ); //if we get to here - we double tapped downed_buddy player_coop_revive_self(); if ( !speak_first ) self notify( "so_revived" ); return; } } player_coop_revive_buddy_cleanup( downed_buddy ); } } } player_coop_is_reviving() { if ( !self UseButtonPressed() ) { return false; } // Leaving this here, but noting that this causes an SRE, so if we need this sort of logic we'll need to do it a different way. // Also, level.default_use_radius is an invalid number to use, need to use the current value of dvar player_useradius /* if ( DistanceSquared( self.origin, level.revive_ent.origin ) > level.default_use_radius * level.default_use_radius ) { return false; }*/ return self.reviving_buddy; } player_coop_check_mission_ended() { level waittill( "special_op_terminated" ); player_coop_destroy_use_target(); revive_hud_cleanup_bars(); } player_coop_revive_buddy_cleanup( downed_buddy ) { level notify( "revive_bars_killed" ); revive_hud_cleanup_bars(); foreach ( player in level.players ) { if ( player == downed_buddy ) player.revive_text settext( &"SCRIPT_COOP_BLEEDING_OUT" ); else player.revive_text settext( &"SCRIPT_COOP_BLEEDING_OUT_PARTNER" ); } if ( isdefined( downed_buddy ) && isalive( downed_buddy ) ) { downed_buddy ent_flag_clear( "coop_pause_bleedout_timer" ); } if ( isdefined( self ) && isalive( self ) ) { self.reviving_buddy = false; self player_coop_freeze_players( false ); } } revive_hud_cleanup_bars() { if ( isdefined( level.bars ) ) { foreach ( bar in level.bars ) { if ( isdefined( bar ) ) { bar notify( "destroying" ); bar destroyElem(); } } level.bars = undefined; } } player_coop_revive_self() { self ent_flag_clear( "coop_downed" ); self notify( "revived" ); player_coop_destroy_use_target(); self thread player_dying_effect_remove(); // so other player loses health bonus from being only mobile guy thread maps\_gameskill::resetSkill(); } player_coop_proc_ended() { self endon( "death" ); flag_waitopen( "coop_revive" ); self ent_flag_clear( "coop_proc_running" ); self EnableDeathShield( false ); } player_coop_set_down_attributes() { self endon( "death" ); // Use radius increased when someone is down... more like MP distance level.default_use_radius = getdvarint( "player_useradius" ); setsaveddvar( "player_useradius", 128 ); self.coop_downed = true; self.ignoreRandomBulletDamage = true; self EnableInvulnerability(); self ent_flag_set( "coop_downed" ); self.health = 2; self.maxhealth = self.original_maxhealth; self.ignoreme = true; self DisableUsability(); self DisableWeaponSwitch(); self disableoffhandweapons(); self DisableWeapons(); self thread player_coop_kill_by_vehicle(); self thread player_coop_set_down_part1(); } player_coop_kill_by_vehicle() { self endon( "revived" ); self endon( "death" ); level endon( "special_op_terminated" ); if ( flag( "special_op_terminated" ) ) { return; } if ( !IsAlive( self ) ) { return; } while ( 1 ) { vehicles = Vehicle_GetArray(); foreach ( vehicle in vehicles ) { speed = vehicle Vehicle_GetSpeed(); if ( abs( speed ) == 0 ) { continue; } if ( self IsTouching( vehicle ) ) { vehicle maps\_specialops::so_crush_player( self, "MOD_CRUSH" ); return; } } wait( 0.05 ); } } player_coop_set_original_attributes() { // Use radius decreased to default when someone is revived. setsaveddvar( "player_useradius", level.default_use_radius ); level.default_use_radius = undefined; self.ignoreRandomBulletDamage = false; self ent_flag_clear( "coop_downed" ); self.down_part2_proc_ran = undefined; // This is done like this because when a guy goes down, he forces the *other* // person to turn on the health icon. Since only one guy can be down at a time, // we can trust that we only need to reset on the other player. // self CreateFriendlyHudIcon_Normal(); other_player = get_other_player( self ); other_player delaythread( 0.1, ::CreateFriendlyHudIcon_Normal ); self player_coop_getup(); self.health = self.maxhealth; self.ignoreme = false; self setstance( "stand" ); self EnableUsability(); self enableoffhandweapons(); self EnableWeaponSwitch(); // Don't enable weapons when placing a sentry. if ( !isdefined( self.placingSentry ) ) { self EnableWeapons(); } self.coop_downed = undefined; wait 1.0; self DisableInvulnerability(); } // Could possibly be a useful utility function, but only useful here right now. check_for_pistol() { AssertEx( IsPlayer( self ), "check_for_pistol() was called on a non-player." ); weapon_list = self GetWeaponsListPrimaries(); foreach ( weapon in weapon_list ) { // Need to account for Akimbo weapons? if ( WeaponClass( weapon ) == "pistol" ) return weapon; } return undefined; } remove_pistol_if_extra() { AssertEx( IsPlayer( self ), "remove_pistol_if_extra() was called on a non-player." ); if ( isdefined( self.forced_pistol ) ) { self takeweapon( self.forced_pistol ); self.forced_pistol = undefined; } if ( player_can_restore_weapon( self.preincap_weapon ) ) { self SwitchToWeapon( self.preincap_weapon ); } else { primary_weapons = self GetWeaponsListPrimaries(); assert( primary_weapons.size > 0 ); self SwitchToWeapon( primary_weapons[0] ); } self.preincap_weapon = undefined; } player_can_restore_weapon( weapon ) { if ( !isdefined( weapon ) ) return false; if ( weapon == "none" ) return false; if ( !self HasWeapon( weapon ) ) return false; return true; } player_coop_force_switch_to_pistol() { self.preincap_weapon = self GetCurrentWeapon(); weapon_pistol = self check_for_pistol(); if ( !isdefined( weapon_pistol ) ) { weapon_pistol = "Beretta"; if ( isdefined( level.coop_incap_weapon ) ) weapon_pistol = level.coop_incap_weapon; self.forced_pistol = weapon_pistol; self giveWeapon( weapon_pistol ); } self SwitchToWeapon( weapon_pistol ); // Don't enable weapons when placing a sentry. if ( !isdefined( self.placingSentry ) ) { self EnableWeapons(); } } player_coop_set_down_part1() { self endon( "revived" ); self.laststand = true; wait .3; self player_coop_force_switch_to_pistol(); wait .25; self DisableInvulnerability(); self thread player_coop_down_draw_attention(); self waittill( "damage" ); self thread player_coop_set_down_part2(); } player_coop_set_down_part2() { self.down_part2_proc_ran = true; self disableweapons(); self thread player_dying_effect(); self.ignoreme = true; self.ignoreRandomBulletDamage = true; self EnableInvulnerability(); } player_dying_effect() { self endon( "death" ); self endon( "revived" ); //allow this thread to only be run once if ( !ent_flag_exist( "coop_dying_effect" ) ) ent_flag_init( "coop_dying_effect" ); else if ( ent_flag( "coop_dying_effect" ) ) return; ent_flag_set( "coop_dying_effect" ); for ( ;; ) { self shellshock( "default", 60 ); wait ( 60 ); } } player_dying_effect_remove() { if ( ent_flag_exist( "coop_dying_effect" ) ) ent_flag_clear( "coop_dying_effect" ); self stopShellShock(); } player_coop_down_draw_attention() { self endon( "death" ); self endon( "revived" ); self endon( "damage" ); notifyoncommand( "draw_attention", "+attack" ); self waittill_notify_or_timeout( "draw_attention", 4 ); self.ignoreme = false; self.ignoreRandomBulletDamage = false; } player_coop_getup() { self endon( "death" ); self disableweapons(); self remove_pistol_if_extra (); self.laststand = false; self.achieve_downed_kills = undefined; wait .3; //self player_recallweapons(); } player_coop_kill() { self ent_flag_set( "coop_is_dead" ); self thread player_dying_effect_remove(); if ( flag( "coop_fail_when_all_dead" ) ) flag_wait( "coop_alldowned" ); self EnableDeathShield( false ); self DisableInvulnerability(); self EnableHealthShield( false ); self.laststand = false; self.achieve_downed_kills = undefined; waittillframeend; self kill(); } player_coop_check_alldowned() { foreach ( player in level.players ) { downed = player ent_flag( "coop_downed" ); if ( !downed ) return; } flag_set( "coop_alldowned" ); }