#include common_scripts\utility; #include animscripts\utility; #include maps\_utility_code; /* ============= ///ScriptDocBegin "Name: is_coop()" "Summary: returns true if co-op is in use" "Module: Utility" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_coop() { if ( IsSplitScreen() || ( GetDvar( "coop" ) == "1" ) ) { AssertEx( IsDefined( level._player2 ), "In co-op mode but level.player2 is undefined. IsSplitScreen=" + IsSplitScreen() + " coop dvar=" + GetDvar( "coop" ) ); return true; } return false; } /* ============= ///ScriptDocBegin "Name: is_coop_online()" "Summary: Returns true if co-op is in use and the game is online." "Module: Utility" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_coop_online() { if ( issplitscreen() ) return false; if ( !is_coop() ) return false; return true; } /* ============= ///ScriptDocBegin "Name: is_lunar_level()" "Summary: Returns true if the level is a lunar level." "Module: Utility" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_lunar_level() { return IsDefined( level.lunar_level ); } /* ============= ///ScriptDocBegin "Name: set_as_lunar_level()" "Summary: Sets the level as a lunar level." "Module: Utility" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_as_lunar_level() { level.lunar_level = true; } /* ============= ///ScriptDocBegin "Name: is_player_down( )" "Summary: Returns true if a co-op player is in last stand mode." "Module: Entity" "CallOn: A player" "MandatoryArg: : The player you want to check." "Example: return is_player_down( level.player );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_player_down( player ) { assertex( isdefined( player ) && isplayer( player ), "player_coop_is_down() requires a valid player to test." ); if ( !is_coop() ) return false; if ( !isdefined( player.laststand ) ) return false; return player.laststand; } /* ============= ///ScriptDocBegin "Name: is_player_down_and_out( )" "Summary: Returns true if a co-op player is in last stand mode AND been knocked into "out" mode... where they have no weapon." "Module: Entity" "CallOn: A player" "MandatoryArg: : " "Example: return is_player_down_and_out( leve.player );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_player_down_and_out( player ) { assertex( isdefined( player ) && isplayer( player ), "player_coop_is_down_and_out() requires a valid player to test." ); if ( !is_coop() ) return false; if ( !isdefined( player.down_part2_proc_ran ) ) return false; return player.down_part2_proc_ran; } /* ============= ///ScriptDocBegin "Name: clear_custom_eog_summary()" "Summary: Clears all dvars for custom end-of-game summary for special ops" "Module: Utility" "SPMP: singleplayer" ///ScriptDocEnd ============= */ clear_custom_eog_summary() { for ( i = 1; i < 7; i++ ) { SetDvar( "ui_eog_r" + i + "c1_player1", "" ); SetDvar( "ui_eog_r" + i + "c1_player2", "" ); } for ( i = 1; i < 7; i++ ) { SetDvar( "ui_eog_r" + i + "c2_player1", "" ); SetDvar( "ui_eog_r" + i + "c2_player2", "" ); } SetDvar( "ui_eog_success_heading_player1", "" ); SetDvar( "ui_eog_success_heading_player2", "" ); } /* ============= ///ScriptDocBegin "Name: set_custom_eog_summary( , , )" "Summary: Called on player to set custom end-of-game summary for special ops" "Module: Utility" "MandatoryArg: : Row number to set the data in. Currently row is between 1 to 6." "MandatoryArg: : Column number to set the data in. Currently column is between 1 to 2." "MandatoryArg: : Data to be set in string." "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_custom_eog_summary( row, col, data ) { AssertEx( IsDefined( self ) && IsPlayer( self ), "set_custom_eog_summary() Must be called on a Player entity!" ); AssertEx( IsDefined( level._eog_summary_callback ), "Setting custom eog display data when callback function is not set. level.ego_summary_callback function pointer is undefined." ); level._custom_eog_summary = true; r = Int( row ); c = Int( col ); AssertEx( r >= 1 && r <= 6, "Row: " + r + " is out of bound, row = 1->6." ); AssertEx( c >= 1 && c <= 2, "Column: " + c + " is out of bound, column = 1->2." ); eog_dvar = ""; if ( level._players.size > 1 ) { if ( self == level._player ) eog_dvar = "ui_eog_r" + r + "c" + c + "_player1"; else if ( self == level._player2 ) eog_dvar = "ui_eog_r" + r + "c" + c + "_player2"; else AssertEx( true, "set_custom_eog_summary() Must be called on a Player entity!" ); } else { eog_dvar = "ui_eog_r" + r + "c" + c + "_player1"; } SetDvar( eog_dvar, data ); } /* ============= ///ScriptDocBegin "Name: add_custom_eog_summary_line( , , )" "Summary: Compressed way to add a line to the eog summary. By default will add itself in the order it was added." "Module: Utility" "CallOn: A player" "MandatoryArg: : The title message to display in the left column." "MandatoryArg: : The value to display in the right column." "OptionalArg: : Optional value to override the line the summary is going to display on." "Example: add_custom_eog_summary_line( "@SPECIAL_OP_KILLS", player.kill_count );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ add_custom_eog_summary_line( eog_title, eog_value, eog_line_override ) { assertex( isdefined( eog_title ), "so_add_eog_summary_line() requires a valid eog_title." ); assertex( isdefined( eog_value ), "so_add_eog_summary_line() requires a valid eog_title." ); assertex( isdefined( self ) && isplayer( self ), "so_add_eog_summary_line() must be called on a player." ); if ( !isdefined( self.eog_line ) ) self.eog_line = 0; eog_line = undefined; if ( isdefined( eog_line_override ) ) { eog_line = eog_line_override; } else { self.eog_line++; eog_line = self.eog_line; } self set_custom_eog_summary( eog_line, 1, eog_title ); self set_custom_eog_summary( eog_line, 2, eog_value ); } /* ============= ///ScriptDocBegin "Name: add_custom_eog_summary_line_blank( )" "Summary: Simple function that auto-advances the line that the EOG summary is drawing on. Useful to clearly show what the EOG summary is doing." "Module: Utility" "Example: add_custom_eog_summary_line_blank();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ add_custom_eog_summary_line_blank() { if ( !isdefined( self.eog_line ) ) self.eog_line = 0; self.eog_line++; } /* ============= ///ScriptDocBegin "Name: set_eog_success_heading( )" "Summary: Sets mission sucess custom heading end-of-game summary for special ops" "Module: Utility" "MandatoryArg: : Title to be set in string." "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_eog_success_heading( title ) { AssertEx( IsDefined( self ) && IsPlayer( self ), "set_custom_eog_summary() Must be called on a Player entity!" ); AssertEx( IsDefined( level._eog_summary_callback ), "Setting custom eog display data when callback function is not set. level.ego_summary_callback function pointer is undefined." ); level._custom_eog_summary = true; eog_dvar = ""; if ( level._players.size > 1 ) { if ( self == level._player ) eog_dvar = "ui_eog_success_heading_player1"; else if ( self == level._player2 ) eog_dvar = "ui_eog_success_heading_player2"; else AssertEx( true, "set_eog_success_heading() Must be called on a Player entity!" ); } else { eog_dvar = "ui_eog_success_heading_player1"; } SetDvar( eog_dvar, title ); } /* ============= ///ScriptDocBegin "Name: is_specialop()" "Summary: returns true if map is in Special Op mode." "Module: Utility" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_specialop() { return GetDvar( "specialops" ) == "1"; } /* ============= ///ScriptDocBegin "Name: convert_to_time_string( , )" "Summary: Takes a number and returns a string in Minutes:Seconds format." "Module: Utility" "MandatoryArg: : The number you want to convert." "MandatoryArg: : Option to add an additional .0 to the end of the timer." "Example: time_string = convert_to_time_string( time_value );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ convert_to_time_string( timer, show_tenths ) { string = ""; if ( timer < 0 ) string += "-"; timer_clipped = timer * 100; timer_clipped = int( timer_clipped ); timer_clipped = abs( timer_clipped ); minutes = timer_clipped / 6000; minutes = int( minutes ); string += minutes; seconds = timer_clipped / 100; seconds = int( seconds ); seconds -= minutes * 60; if ( seconds < 10 ) string += ":0" + seconds; else string += ":" + seconds; if ( IsDefined( show_tenths ) && show_tenths ) { tenths = timer_clipped; tenths -= minutes * 6000; tenths -= seconds * 100; tenths = int( tenths ); if ( tenths < 10 ) string += ".0" + tenths; else string += "." + tenths; } return string; } /* ============= ///ScriptDocBegin "Name: set_vision_set( , )" "Summary: Sets the vision set over time" "Module: Utility" "MandatoryArg: : Visionset file to use" "OptionalArg: : Time to transition to the new vision set. Defaults to 1 second." "Example: set_vision_set( "blackout_darkness", 0.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_vision_set( visionset, transition_time ) { if ( init_vision_set( visionset ) ) { return; } if ( !isdefined( transition_time ) ) { transition_time = 1; } //iprintlnbold( visionset ); VisionSetNaked( visionset, transition_time ); SetDvar( "vision_set_current", visionset ); } /* ============= ///ScriptDocBegin "Name: set_sun_vision_set( , , , , , )" "Summary: Sets the sun vision set over time" "Module: Utility" "MandatoryArg: : Visionset file to use" "OptionalArg: : Time to transition to the new vision set. Defaults to 1 second." "OptionalArg: : Sun effect intensity. Zero for off" "OptionalArg: : Inner angle" "OptionalArg: : Outer angle" "OptionalArg: : Reference direction for the sun." "Example: set_sun_vision_set( "blackout_darkness", 0.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_sun_vision_set( visionset, transition_time, intensity, inner_fov, outer_fov, sun_direction ) { if ( init_vision_set( visionset ) ) return; if ( !isdefined( transition_time ) ) transition_time = 1; if ( IsDefined( sun_direction ) ) { VisionSetSun( visionset, transition_time, intensity, inner_fov, outer_fov, sun_direction ); } else if ( IsDefined( outer_fov ) ) { VisionSetSun( visionset, transition_time, intensity, inner_fov, outer_fov ); } else if ( IsDefined( inner_fov ) ) { VisionSetSun( visionset, transition_time, intensity, inner_fov ); } else if ( IsDefined( intensity ) ) { VisionSetSun( visionset, transition_time, intensity ); } else if ( IsDefined( transition_time ) ) { VisionSetSun( visionset, transition_time ); } else { VisionSetSun( visionset ); } } /* ============= ///ScriptDocBegin "Name: set_vision_set_player( , )" "Summary: Sets the vision set over time for a specific player in coop" "Module: Utility" "MandatoryArg: : Visionset file to use" "OptionalArg: : Time to transition to the new vision set. Defaults to 1 second." "Example: level.player2 set_vision_set_player( "blackout_darkness", 0.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_vision_set_player( visionset, transition_time ) { if ( init_vision_set( visionset ) ) return; Assert( IsDefined( self ) ); Assert( level != self ); if ( !isdefined( transition_time ) ) transition_time = 1; self VisionSetNakedForPlayer( visionset, transition_time ); } /* ============= ///ScriptDocBegin "Name: set_sun_vision_set_player( , , , , , )" "Summary: Sets the sun vision set over time for a specific player in coop" "Module: Utility" "MandatoryArg: : Visionset file to use" "OptionalArg: : Time to transition to the new vision set. Defaults to 1 second." "OptionalArg: : Sun effect intensity. Zero for off" "OptionalArg: : Sun/View inner angle" "OptionalArg: : Sun/View outer angle" "OptionalArg: : Reference direction for the sun." "Example: level.player2 set_sun_vision_set_player( "blackout_darkness", 0.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_sun_vision_set_player( visionset, transition_time, intensity, inner_fov, outer_fov, sun_dir ) { if ( init_vision_set( visionset ) ) return; Assert( IsDefined( self ) ); Assert( level != self ); if ( !isdefined( transition_time ) ) transition_time = 1; self VisionSetSunForPlayer( visionset, transition_time, intensity, inner_fov, outer_fov, sun_dir ); } /* ============= ///ScriptDocBegin "Name: set_nvg_vision( , )" "Summary: Sets the night vision set over time" "Module: Utility" "MandatoryArg: : Visionset file to use" "OptionalArg: : Time to transition to the new vision set. Defaults to 1 second." "Example: set_nvg_vision( "blackout_darkness", 0.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_nvg_vision( visionset, transition_time ) { // init_vision_set( visionset ); if ( !isdefined( transition_time ) ) transition_time = 1; VisionSetNight( visionset, transition_time ); } /* ============= ///ScriptDocBegin "Name: sun_light_fade( , , )" "Summary: Fade to a given sunlight RGB value over the specified time" "Module: Utility" "MandatoryArg: : Starting RGB values (use whatever the current sun is set to)" "MandatoryArg: : Target RGB values the sun colors should change to" "MandatoryArg: : Time in seconds for the fade to occur" "Example: thread sun_light_fade( (.5,.8,.75), (3.5,3.5,3.5), 2 )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ sun_light_fade( startSunColor, endSunColor, fTime ) { fTime = Int( fTime * 20 ); // determine difference btwn starting and target sun RGBs increment = []; for ( i = 0; i < 3; i++ ) increment[ i ] = ( startSunColor[ i ] - endSunColor[ i ] ) / fTime; // change gradually to new sun color over time newSunColor = []; for ( i = 0; i < fTime; i++ ) { wait( 0.05 ); for ( j = 0; j < 3; j++ ) newSunColor[ j ] = startSunColor[ j ] - ( increment[ j ] * i ); SetSunLight( newSunColor[ 0 ], newSunColor[ 1 ], newSunColor[ 2 ] ); } //set sunlight to new target values to account for rounding off decimal places SetSunLight( endSunColor[ 0 ], endSunColor[ 1 ], endSunColor[ 2 ] ); } /* ============= ///ScriptDocBegin "Name: ent_flag_wait( )" "Summary: Waits until the specified flag is set on self. Even handles some default flags for ai such as 'goal' and 'damage'" "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to wait on" "Example: enemy ent_flag_wait( "goal" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_wait( msg ) { AssertEx( ( !IsSentient( self ) && IsDefined( self ) ) || IsAlive( self ), "Attempt to check a flag on entity that is not alive or removed" ); while ( IsDefined( self ) && !self.ent_flag[ msg ] ) self waittill( msg ); } /* ============= ///ScriptDocBegin "Name: ent_flag_wait_either( , )" "Summary: Waits until either of the the specified flags are set on self. Even handles some default flags for ai such as 'goal' and 'damage'" "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of one flag to wait on" "MandatoryArg: : name of the other flag to wait on" "Example: enemy ent_flag_wait( "goal", "damage" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_wait_either( flag1, flag2 ) { AssertEx( ( !IsSentient( self ) && IsDefined( self ) ) || IsAlive( self ), "Attempt to check a flag on entity that is not alive or removed" ); while ( IsDefined( self ) ) { if ( ent_flag( flag1 ) ) return; if ( ent_flag( flag2 ) ) return; self waittill_either( flag1, flag2 ); } } /* ============= ///ScriptDocBegin "Name: ent_flag_wait_or_timeout( , )" "Summary: Waits until either the flag gets set on self or the timer elapses. Even handles some default flags for ai such as 'goal' and 'damage'" "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : Amount of time to wait before continuing regardless of flag." "Example: ent_flag_wait_or_timeout( "time_to_go", 3 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_wait_or_timeout( flagname, timer ) { AssertEx( ( !IsSentient( self ) && IsDefined( self ) ) || IsAlive( self ), "Attempt to check a flag on entity that is not alive or removed" ); start_time = GetTime(); while ( IsDefined( self ) ) { if ( self.ent_flag[ flagname ] ) break; if ( GetTime() >= start_time + timer * 1000 ) break; self ent_wait_for_flag_or_time_elapses( flagname, timer ); } } /* ============= ///ScriptDocBegin "Name: ent_flag_waitopen( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_waitopen( msg ) { AssertEx( ( !IsSentient( self ) && IsDefined( self ) ) || IsAlive( self ), "Attempt to check a flag on entity that is not alive or removed" ); while ( IsDefined( self ) && self.ent_flag[ msg ] ) self waittill( msg ); } ent_flag_assert( msg ) { AssertEx( !self ent_flag( msg ), "Flag " + msg + " set too soon on entity" ); } /* ============= ///ScriptDocBegin "Name: ent_flag_waitopen_either( , )" "Summary: Waits until either of the the specified flags are open on self. Even handles some default flags for ai such as 'goal' and 'damage'" "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of one flag to waitopen on" "MandatoryArg: : name of the other flag to waitopen on" "Example: enemy ent_flag_waitopen_either( "goal", "damage" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_waitopen_either( flag1, flag2 ) { AssertEx( ( !IsSentient( self ) && IsDefined( self ) ) || IsAlive( self ), "Attempt to check a flag on entity that is not alive or removed" ); while ( IsDefined( self ) ) { if ( !ent_flag( flag1 ) ) return; if ( !ent_flag( flag2 ) ) return; self waittill_either( flag1, flag2 ); } } /* ============= ///ScriptDocBegin "Name: ent_flag_init( )" "Summary: Initialize a flag to be used. All flags must be initialized before using ent_flag_set or ent_flag_wait. Some flags for ai are set by default such as 'goal', 'death', and 'damage'" "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to create" "Example: enemy ent_flag_init( "hq_cleared" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_init( message ) { if ( !isDefined( self.ent_flag ) ) { self.ent_flag = []; self.ent_flags_lock = []; } /# if ( IsDefined( level._first_frame ) && level._first_frame == -1 ) AssertEx( !isDefined( self.ent_flag[ message ] ), "Attempt to reinitialize existing message: " + message + " on entity." ); #/ self.ent_flag[ message ] = false; /# self.ent_flags_lock[ message ] = false; #/ } /* ============= ///ScriptDocBegin "Name: ent_flag_exist( )" "Summary: checks to see if a flag exists" "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to check" "Example: if( enemy ent_flag_exist( "hq_cleared" ) );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_exist( message ) { if ( IsDefined( self.ent_flag ) && IsDefined( self.ent_flag[ message ] ) ) return true; return false; } /* ============= ///ScriptDocBegin "Name: ent_flag_set_delayed( , )" "Summary: Sets the specified flag after waiting the delay time on self, all scripts using ent_flag_wait on self will now continue." "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to set" "MandatoryArg: : time to wait before setting the flag" "Example: entity flag_set_delayed( "hq_cleared", 2.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_set_delayed( message, delay ) { self endon( "death" ); wait( delay ); self ent_flag_set( message ); } /* ============= ///ScriptDocBegin "Name: ent_flag_set( )" "Summary: Sets the specified flag on self, all scripts using ent_flag_wait on self will now continue." "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to set" "Example: enemy ent_flag_set( "hq_cleared" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_set( message ) { /# AssertEx( IsDefined( self ), "Attempt to set a flag on entity that is not defined" ); AssertEx( IsDefined( self.ent_flag[ message ] ), "Attempt to set a flag before calling flag_init: " + message + " on entity." ); Assert( self.ent_flag[ message ] == self.ent_flags_lock[ message ] ); self.ent_flags_lock[ message ] = true; #/ self.ent_flag[ message ] = true; self notify( message ); } /* ============= ///ScriptDocBegin "Name: ent_flag_clear( )" "Summary: Clears the specified flag on self." "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to clear" "Example: enemy ent_flag_clear( "hq_cleared" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_clear( message ) { /# AssertEx( IsDefined( self ), "Attempt to clear a flag on entity that is not defined" ); AssertEx( IsDefined( self.ent_flag[ message ] ), "Attempt to set a flag before calling flag_init: " + message + " on entity." ); Assert( self.ent_flag[ message ] == self.ent_flags_lock[ message ] ); self.ent_flags_lock[ message ] = false; #/ //do this check so we don't unneccessarily send a notify if ( self.ent_flag[ message ] ) { self.ent_flag[ message ] = false; self notify( message ); } } /* ============= ///ScriptDocBegin "Name: ent_flag_clear_delayed( , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag_clear_delayed( message, delay ) { wait( delay ); self ent_flag_clear( message ); } /* ============= ///ScriptDocBegin "Name: ent_flag( )" "Summary: Checks if the flag is set on self. Returns true or false." "Module: Flag" "CallOn: Any entity (script_origin, script_struct, ai, script_model, script_brushmodel, player)" "MandatoryArg: : name of the flag to check" "Example: enemy ent_flag( "death" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ent_flag( message ) { AssertEx( IsDefined( message ), "Tried to check flag but the flag was not defined." ); AssertEx( IsDefined( self.ent_flag[ message ] ), "Tried to check flag " + message + " but the flag was not initialized." ); return self.ent_flag[ message ]; } /* ============= ///ScriptDocBegin "Name: get_closest_to_player_view( , , )" "Summary: Returns array member closest to player's view" "Module: " "CallOn: Variable" "MandatoryArg: : The array of items to test against" "OptionalArg: : Player to test against. If undefined defaults to level.player" "OptionalArg: : Check from the player's eye point. If undefined uses the player's origin." "Example: enemy get_closest_to_player_view( enemies, level.player2, true );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_to_player_view( array, player, use_eye, min_dot ) { if ( !array.size ) return; if ( !isdefined( player ) ) player = level._player; if ( !isdefined( min_dot ) ) min_dot = -1; player_origin = player.origin; if ( IsDefined( use_eye ) && use_eye ) player_origin = player GetEye(); ent = undefined; player_angles = player GetPlayerAngles(); player_forward = AnglesToForward( player_angles ); dot = -1; foreach ( array_item in array ) { angles = VectorToAngles( array_item.origin - player_origin ); forward = AnglesToForward( angles ); newdot = VectorDot( player_forward, forward ); if ( newdot < dot ) continue; if ( newdot < min_dot ) continue; dot = newdot; ent = array_item; } return ent; } /* ============= ///ScriptDocBegin "Name: get_closest_index_to_player_view( , , )" "Summary: Returns array index of item closest to player's view" "Module: " "CallOn: Variable" "MandatoryArg: : The array of items to test against" "OptionalArg: : Player to test against. If undefined defaults to level.player" "OptionalArg: : Check from the player's eye point. If undefined uses the player's origin." "OptionalArg: : If true, will return the index within the array rather than the actual array element." "Example: enemy get_closest_index_to_player_view( enemies, level.player2, true );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_index_to_player_view( array, player, use_eye ) { if ( !array.size ) return; if ( !isdefined( player ) ) player = level._player; player_origin = player.origin; if ( IsDefined( use_eye ) && use_eye ) player_origin = player GetEye(); index = undefined; player_angles = player GetPlayerAngles(); player_forward = AnglesToForward( player_angles ); dot = -1; for ( i = 0; i < array.size; i++ ) { angles = VectorToAngles( array[ i ].origin - player_origin ); forward = AnglesToForward( angles ); newdot = VectorDot( player_forward, forward ); if ( newdot < dot ) continue; dot = newdot; index = i; } return index; } flag_trigger_init( message, trigger, continuous ) { flag_init( message ); if ( !isDefined( continuous ) ) continuous = false; Assert( IsSubStr( trigger.classname, "trigger" ) ); trigger thread _flag_wait_trigger( message, continuous ); return trigger; } flag_triggers_init( message, triggers, all ) { flag_init( message ); if ( !isDefined( all ) ) all = false; for ( index = 0; index < triggers.size; index++ ) { Assert( IsSubStr( triggers[ index ].classname, "trigger" ) ); triggers[ index ] thread _flag_wait_trigger( message, false ); } return triggers; } /* ============= ///ScriptDocBegin "Name: flag_set_delayed( , )" "Summary: Sets the specified flag after waiting the delay time, all scripts using flag_wait will now continue." "Module: Flag" "CallOn: " "MandatoryArg: : name of the flag to set" "MandatoryArg: : time to wait before setting the flag" "Example: flag_set_delayed( "hq_cleared", 2.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_set_delayed( message, delay ) { wait( delay ); flag_set( message ); } /* ============= ///ScriptDocBegin "Name: flag_clear_delayed( , )" "Summary: Clears the specified flag after waiting the delay time, all scripts using flag_waitopen will now continue." "Module: Flag" "CallOn: " "MandatoryArg: : name of the flag to clear" "MandatoryArg: : time to wait before clearing the flag" "Example: flag_clear_delayed( "hq_cleared", 2.5 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_clear_delayed( message, delay ) { wait( delay ); flag_clear( message ); } _flag_wait_trigger( message, continuous ) { self endon( "death" ); for ( ;; ) { self waittill( "trigger", other ); flag_set( message ); if ( !continuous ) return; while ( other IsTouching( self ) ) wait( 0.05 ); flag_clear( message ); } } level_end_save() { if ( arcadeMode() ) return; if ( level._MissionFailed ) return; if ( flag( "game_saving" ) ) return; for ( i = 0; i < level._players.size; i++ ) { player = level._players[ i ]; if ( !isAlive( player ) ) return; } flag_set( "game_saving" ); imagename = "levelshots / autosave / autosave_" + level._script + "end"; // string not found for AUTOSAVE_AUTOSAVE SaveGame( "levelend", &"AUTOSAVE_AUTOSAVE", imagename, true );// does not print "Checkpoint Reached" flag_clear( "game_saving" ); } /* ============= ///ScriptDocBegin "Name: add_extra_autosave_check( , , )" "Summary: Adds an extra autosave check that must pass for an autosave to happen" "Module: Utility" "CallOn: An entity" "MandatoryArg: : identify the index, of this autosave check ( so you can overwrite it )" "MandatoryArg: : function should return true for the check to pass" "MandatoryArg: : this is what will print to the console when this check fails" "Example: add_extra_autosave_check( "boat_check_trailing" , ::autosave_boat_check_trailing , "trailing too far behind the enemy boat." );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ add_extra_autosave_check( name, func, msg ) { level._extra_autosave_checks[ name ] = []; level._extra_autosave_checks[ name ][ "func" ] = func; level._extra_autosave_checks[ name ][ "msg" ] = msg; } /* ============= ///ScriptDocBegin "Name: remove_extra_autosave_check( )" "Summary: removes the extra autosave game condtions added by add_extra_autosave_check" "Module: Utility" "CallOn: An entity" "MandatoryArg: : Name" "Example: add_extra_autosave_check( "boat_check_trailing" ); " "SPMP: singleplayer" ///ScriptDocEnd ============= */ remove_extra_autosave_check( name ) { level._extra_autosave_checks[ name ] = undefined; } /* ============= ///ScriptDocBegin "Name: autosave_stealth()" "Summary: autosave the game if it's 'safe' to do so in a stealth level, internally threaded and handles any 'dangerous' situations that we wouldn't want to save at during stealth gameplay" "Module: Autosave" "CallOn: " "Example: autosave_stealth();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ autosave_stealth() { thread autosave_by_name_thread( "autosave_stealth", 8, true ); } /* ============= ///ScriptDocBegin "Name: autosave_tactical()" "Summary: autosave the game if it's 'safe' during tactical gameplay...meaning don't autosave if the player has any current enemies or has thrown a grenade. ( internally threaded )" "Module: Autosave" "CallOn: " "Example: autosave_tactical();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ autosave_tactical() { autosave_tactical_setup(); thread autosave_tactical_proc(); } /* ============= ///ScriptDocBegin "Name: autosave_by_name( )" "Summary: autosave the game with the specified save name" "Module: Autosave" "CallOn: " "MandatoryArg: : name of the save file to create" "Example: thread autosave_by_name( "building2_cleared" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ autosave_by_name( name ) { thread autosave_by_name_thread( name ); } /* ============= ///ScriptDocBegin "Name: autosave_by_name_silent( )" "Summary: autosave the game with the specified save name without printing a checkpoint msg" "Module: Autosave" "CallOn: " "MandatoryArg: : name of the save file to create" "Example: thread autosave_by_name_silent( "building2_cleared" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ autosave_by_name_silent( name ) { thread autosave_by_name_thread( name, undefined, undefined, true ); } autosave_by_name_thread( name, timeout, doStealthChecks, suppress_hint ) { if ( !isDefined( level._curAutoSave ) ) level._curAutoSave = 1; // nate - sorry auto style guide makes this ugly.. fixing it is complicated and this doesn't hurt things imageName = "levelshots / autosave / autosave_" + level._script + level._curAutoSave; result = level maps\_autosave::tryAutoSave( level._curAutoSave, "autosave", imagename, timeout, doStealthChecks, suppress_hint ); if ( IsDefined( result ) && result ) level._curAutoSave++; } /* ============= ///ScriptDocBegin "Name: autosave_or_timeout( , )" "Summary: Autosaves with the specified name but times out if the time elapses" "Module: Autosave" "MandatoryArg: : The name" "MandatoryArg: : The timeout" "Example: autosave_or_timeout( "thename", 3.5 )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ autosave_or_timeout( name, timeout ) { thread autosave_by_name_thread( name, timeout ); } /* ============= ///ScriptDocBegin "Name: debug_message( , , , )" "Summary: Prints 3d debug text at the specified location for a duration of time." "Module: Debug" "MandatoryArg: : String to print" "MandatoryArg: : Location of string ( x, y, z )" "OptionalArg: : Time to keep the string on screen. Defaults to 5 seconds." "OptionalArg: : Overrides any origin value so that message can print on a moving entity" "Example: debug_message( "I am the enemy", enemy.origin, 3.0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ debug_message( message, origin, duration, entity ) { if ( !isDefined( duration ) ) duration = 5; if ( IsDefined( entity ) ) { entity endon( "death" ); origin = entity.origin; } for ( time = 0; time < ( duration * 20 ); time++ ) { if ( !isdefined( entity ) ) Print3d( ( origin + ( 0, 0, 45 ) ), message, ( 0.48, 9.4, 0.76 ), 0.85 ); else Print3d( entity.origin, message, ( 0.48, 9.4, 0.76 ), 0.85 ); wait 0.05; } } /* ============= ///ScriptDocBegin "Name: debug_message_ai( , )" "Summary: Prints 3d debug text at the ai's origin and follows the ai that passed the function." "Module: Debug" "CallOn: An AI" "MandatoryArg: : String to print" "OptionalArg: : Time to keep the string on screen. Defaults to 5 seconds." "Example: debug_message_ai( "I am the enemy", 3.0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ debug_message_ai( message, duration ) { self notify( "debug_message_ai" ); self endon( "debug_message_ai" ); self endon( "death" ); if ( !isDefined( duration ) ) duration = 5; for ( time = 0; time < ( duration * 20 ); time++ ) { Print3d( ( self.origin + ( 0, 0, 45 ) ), message, ( 0.48, 9.4, 0.76 ), 0.85 ); wait 0.05; } } /* ============= ///ScriptDocBegin "Name: debug_message_clear( , , , )" "Summary: Prints 3d debug text at the specified location for a duration of time, but can be cleared before the normal time has passed if a notify occurs." "Module: Debug" "MandatoryArg: : String to print" "MandatoryArg: : Location of string ( x, y, z )" "OptionalArg: : Time to keep the string on screen. Defaults to 5 seconds." "OptionalArg: : Level notify string that will make this text go away before the time expires." "Example: debug_message( "I am the enemy", enemy.origin, 3.0, "enemy died" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ debug_message_clear( message, origin, duration, extraEndon ) { if ( IsDefined( extraEndon ) ) { level notify( message + extraEndon ); level endon( message + extraEndon ); } else { level notify( message ); level endon( message ); } if ( !isDefined( duration ) ) duration = 5; for ( time = 0; time < ( duration * 20 ); time++ ) { Print3d( ( origin + ( 0, 0, 45 ) ), message, ( 0.48, 9.4, 0.76 ), 0.85 ); wait 0.05; } } chain_off( chain ) { trigs = GetEntArray( "trigger_friendlychain", "classname" ); for ( i = 0; i < trigs.size; i++ ) if ( ( IsDefined( trigs[ i ].script_chain ) ) && ( trigs[ i ].script_chain == chain ) ) { if ( IsDefined( trigs[ i ].oldorigin ) ) trigs[ i ].origin = trigs[ i ].oldorigin; else trigs[ i ].oldorigin = trigs[ i ].origin; trigs[ i ].origin = trigs[ i ].origin + ( 0, 0, -5000 ); } } chain_on( chain ) { trigs = GetEntArray( "trigger_friendlychain", "classname" ); for ( i = 0; i < trigs.size; i++ ) if ( ( IsDefined( trigs[ i ].script_chain ) ) && ( trigs[ i ].script_chain == chain ) ) { if ( IsDefined( trigs[ i ].oldorigin ) ) trigs[ i ].origin = trigs[ i ].oldorigin; } } precache( model ) { ent = Spawn( "script_model", ( 0, 0, 0 ) ); ent.origin = level._player GetOrigin(); ent SetModel( model ); ent Delete(); } closerFunc( dist1, dist2 ) { return dist1 >= dist2; } fartherFunc( dist1, dist2 ) { return dist1 <= dist2; } /* ============= ///ScriptDocBegin "Name: getClosest( , , )" "Summary: Returns the closest entity in < array > to location < org > " "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of entities to check distance on" "OptionalArg: : Minimum distance to check" "Example: friendly = getClosest( level.player.origin, allies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ getClosest( org, array, maxdist ) { if ( !IsDefined( maxdist ) ) maxdist = 500000; // twice the size of the grid ent = undefined; foreach ( item in array ) { newdist = Distance( item.origin, org ); if ( newdist >= maxdist ) continue; maxdist = newdist; ent = item; } return ent; } /* ============= ///ScriptDocBegin "Name: getFarthest( , , )" "Summary: Returns the farthest entity in < array > to location < org > " "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be farthest from." "MandatoryArg: : Array of entities to check distance on" "OptionalArg: : Maximum distance to check" "Example: target = getFarthest( level.player.origin, targets );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ getFarthest( org, array, maxdist ) { if ( !IsDefined( maxdist ) ) maxdist = 500000; // twice the size of the grid dist = 0; ent = undefined; foreach ( item in array ) { newdist = Distance( item.origin, org ); if ( newdist <= dist || newdist >= maxdist ) continue; dist = newdist; ent = item; } return ent; } /* ============= ///ScriptDocBegin "Name: getClosestFx( , , )" "Summary: Returns the closest fx struct created by createfx in < fxarray > to location < org > " "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of createfx structs to check distance on. These are obtained with getfxarraybyID( )" "OptionalArg: : Minimum distance to check" "Example: fxstruct = getClosestFx( hallway_tv, fxarray );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ getClosestFx( org, fxarray, dist ) { return compareSizesFx( org, fxarray, dist, ::closerFunc ); } /* ============= ///ScriptDocBegin "Name: get_closest_point( , , )" "Summary: Returns the closest point from array < points > from location < origin > " "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of points to check distance on" "OptionalArg: : Maximum distance to check" "Example: target = getFarthest( level.player.origin, targets );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_point( origin, points, maxDist ) { Assert( points.size ); closestPoint = points[ 0 ]; dist = Distance( origin, closestPoint ); for ( index = 0; index < points.size; index++ ) { testDist = Distance( origin, points[ index ] ); if ( testDist >= dist ) continue; dist = testDist; closestPoint = points[ index ]; } if ( !isDefined( maxDist ) || dist <= maxDist ) return closestPoint; return undefined; } /* ============= ///ScriptDocBegin "Name: get_farthest_ent( , )" "Summary: Returns the farthest entity in from location < origin > " "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be farthest from." "MandatoryArg: : Array of entities to choose from" "Example: dude = get_farthest_ent( level.player.origin, aFriendlies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_farthest_ent( org, array ) { if ( array.size < 1 ) return; dist = Distance( array[ 0 ] GetOrigin(), org ); ent = array[ 0 ]; for ( i = 0; i < array.size; i++ ) { newdist = Distance( array[ i ] GetOrigin(), org ); if ( newdist < dist ) continue; dist = newdist; ent = array[ i ]; } return ent; } /* ============= ///ScriptDocBegin "Name: get_within_range( , , )" "Summary: Returns all elements from the array that are within DIST range to ORG." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of entities to check distance on" "OptionalArg: : Maximum distance to check" "Example: close_ai = get_within_range( level.player.origin, ai, 500 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_within_range( org, array, dist ) { guys = []; for ( i = 0; i < array.size; i++ ) { if ( Distance( array[ i ].origin, org ) <= dist ) guys[ guys.size ] = array[ i ]; } return guys; } /* ============= ///ScriptDocBegin "Name: get_outside_range( , , )" "Summary: Returns all elements from the array that are outside DIST range to ORG." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of entities to check distance on" "OptionalArg: : Maximum distance to check" "Example: close_ai = get_outside_range( level.player.origin, ai, 500 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_outside_range( org, array, dist ) { guys = []; for ( i = 0; i < array.size; i++ ) { if ( Distance( array[ i ].origin, org ) > dist ) guys[ guys.size ] = array[ i ]; } return guys; } /* ============= ///ScriptDocBegin "Name: get_closest_living( , , )" "Summary: Returns the closest living entity from the array from the origin" "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of entities to check distance on" "OptionalArg: : Maximum distance to check" "Example: kicker = get_closest_living( node.origin, ai );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_living( org, array, dist ) { if ( !isdefined( dist ) ) dist = 9999999; if ( array.size < 1 ) return; ent = undefined; for ( i = 0; i < array.size; i++ ) { if ( !isalive( array[ i ] ) ) continue; newdist = Distance( array[ i ].origin, org ); if ( newdist >= dist ) continue; dist = newdist; ent = array[ i ]; } return ent; } /* ============= ///ScriptDocBegin "Name: get_highest_dot( , , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_highest_dot( start, end, array ) { if ( !array.size ) return; ent = undefined; angles = VectorToAngles( end - start ); dotforward = AnglesToForward( angles ); dot = -1; foreach ( member in array ) { angles = VectorToAngles( member.origin - start ); forward = AnglesToForward( angles ); newdot = VectorDot( dotforward, forward ); if ( newdot < dot ) continue; dot = newdot; ent = member; } return ent; } /* ============= ///ScriptDocBegin "Name: get_closest_index( , , )" "Summary: same as getClosest but returns the closest entity's array index instead of the actual entity." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of entities to check distance on." "OptionalArg: : Maximum distance to check" "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_index( org, array, dist ) { if ( !isdefined( dist ) ) dist = 9999999; if ( array.size < 1 ) return; index = undefined; foreach ( i, ent in array ) { newdist = Distance( ent.origin, org ); if ( newdist >= dist ) continue; dist = newdist; index = i; } return index; } /* ============= ///ScriptDocBegin "Name: get_closest_exclude( , , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_exclude( org, ents, excluders ) { if ( !isdefined( ents ) ) return undefined; range = 0; if ( IsDefined( excluders ) && excluders.size ) { exclude = []; for ( i = 0; i < ents.size; i++ ) exclude[ i ] = false; for ( i = 0; i < ents.size; i++ ) for ( p = 0; p < excluders.size; p++ ) if ( ents[ i ] == excluders[ p ] ) exclude[ i ] = true; found_unexcluded = false; for ( i = 0; i < ents.size; i++ ) if ( ( !exclude[ i ] ) && ( IsDefined( ents[ i ] ) ) ) { found_unexcluded = true; range = Distance( org, ents[ i ].origin ); ent = i; i = ents.size + 1; } if ( !found_unexcluded ) return( undefined ); } else { for ( i = 0; i < ents.size; i++ ) if ( IsDefined( ents[ i ] ) ) { range = Distance( org, ents[ 0 ].origin ); ent = i; i = ents.size + 1; } } ent = undefined; for ( i = 0; i < ents.size; i++ ) if ( IsDefined( ents[ i ] ) ) { exclude = false; if ( IsDefined( excluders ) ) { for ( p = 0; p < excluders.size; p++ ) if ( ents[ i ] == excluders[ p ] ) exclude = true; } if ( !exclude ) { newrange = Distance( org, ents[ i ].origin ); if ( newrange <= range ) { range = newrange; ent = i; } } } if ( IsDefined( ent ) ) return ents[ ent ]; else return undefined; } /* ============= ///ScriptDocBegin "Name: get_closest_player( )" "Summary: Returns the closest coop player to the specified origin." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "Example: player = get_closest_player( tank.origin );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_player( org ) { if ( level._players.size == 1 ) return level._player; player = getClosest( org, level._players ); return player; } /* ============= ///ScriptDocBegin "Name: get_closest_player_healthy( )" "Summary: Returns the closest coop player that is not bleeding out (.coop_downed) to the specified origin." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "Example: player = get_closest_player_healthy( tank.origin );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_player_healthy( org ) { if ( level._players.size == 1 ) return level._player; healthyPlayers = []; foreach ( player in level._players ) { if ( player ent_flag( "coop_downed" ) ) continue; // Checking player.coop_downed is unreliable due to it being set in more than _coop.gsc (see dog_combat.gsc). // We need to go through everything and make the use of player.coop_downed and // ent_flag( "coop_downed" ) consistent and not maintain both. /* if ( IsDefined( player.coop_downed ) && ( player.coop_downed ) ) continue;*/ healthyPlayers[ healthyPlayers.size ] = player; } /# assertex( healthyPlayers.size > 0, "get_closest_player_healthy() was unable to find a healthy player. This should never be possible." ); #/ player = getClosest( org, healthyPlayers ); return player; } /* ============= ///ScriptDocBegin "Name: get_closest_ai( , )" "Summary: Returns the closest AI of the specified team to the specified origin." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Team to use. Can be "allies", "axis", or "both"." "Example: friendly = get_closest_ai( level.player.origin, "allies" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_ai( org, team, excluders ) { if ( IsDefined( team ) ) ents = GetAIArray( team ); else ents = GetAIArray(); if ( ents.size == 0 ) return undefined; if ( IsDefined( excluders ) ) { Assert( excluders.size > 0 ); ents = array_remove_array( ents, excluders ); } return getClosest( org, ents ); } /* ============= ///ScriptDocBegin "Name: get_array_of_farthest( , , , , , )" "Summary: Returns an array of all the entities in < array > sorted in order of farthest to closest." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be farthest from." "MandatoryArg: : Array of entities to check distance on." "OptionalArg: : Array of entities to exclude from the check." "OptionalArg: : Max size of the array to return" "OptionalArg: : Max distance from the origin to return acceptable entities" "OptionalArg: : Min distance from the origin to return acceptable entities" "Example: allies_sort = get_array_of_closest( originFC1.origin, allies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_array_of_farthest( org, array, excluders, max, maxdist, mindist ) { aArray = get_array_of_closest( org, array, excluders, max, maxdist, mindist ); aArray = array_reverse( aArray ); return aArray; } /* ============= ///ScriptDocBegin "Name: get_array_of_closest( , , , , , )" "Summary: Returns an array of all the entities in < array > sorted in order of closest to farthest." "Module: Distance" "CallOn: " "MandatoryArg: : Origin to be closest to." "MandatoryArg: : Array of entities to check distance on." "OptionalArg: : Array of entities to exclude from the check." "OptionalArg: : Max size of the array to return" "OptionalArg: : Max distance from the origin to return acceptable entities" "OptionalArg: : Min distance from the origin to return acceptable entities" "Example: allies_sort = get_array_of_closest( originFC1.origin, allies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_array_of_closest( org, array, excluders, max, maxdist, mindist ) { // pass an array of entities to this function and it will return them in the order of closest // to the origin you pass, you can also set max to limit how many ents get returned if ( !isdefined( max ) ) max = array.size; if ( !isdefined( excluders ) ) excluders = []; maxdist2rd = undefined; if ( IsDefined( maxdist ) ) maxdist2rd = maxdist * maxdist; mindist2rd = 0; if ( IsDefined( mindist ) ) mindist2rd = mindist * mindist; // optimize the common case of a simple sort if ( excluders.size == 0 && max >= array.size && mindist2rd == 0 && !isdefined( maxdist2rd ) ) return SortByDistance( array, org ); newArray = []; foreach ( ent in array ) { excluded = false; foreach ( excluder in excluders ) { if ( ent == excluder ) { excluded = true; break; } } if ( excluded ) continue; dist2rd = DistanceSquared( org, ent.origin ); if ( IsDefined( maxdist2rd ) && dist2rd > maxdist2rd ) continue; if ( dist2rd < mindist2rd ) continue; newArray[ newArray.size ] = ent; } newArray = SortByDistance( newArray, org ); if ( max >= newArray.size ) return newArray; finalArray = []; for ( i = 0; i < max; i++ ) finalArray[ i ] = newArray[ i ]; return finalArray; } /* ============= ///ScriptDocBegin "Name: get_closest_ai_exclude( , , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_closest_ai_exclude( org, team, excluders ) { if ( IsDefined( team ) ) ents = GetAIArray( team ); else ents = GetAIArray(); if ( ents.size == 0 ) return undefined; return get_closest_exclude( org, ents, excluders ); } /* ============= ///ScriptDocBegin "Name: can_see_origin( , )" "Summary: Checks to see if the specified point is within the player's view." "Module: Sentient" "CallOn: An AI or player" "MandatoryArg: : Origin you wish to see whether the player or AI can see." "OptionalArg: : Set to determine whether the sight trace should check against characters." "Example: level.player can_see_origin( entity.origin, true );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ can_see_origin( origin, test_characters ) { AssertEx( IsDefined( origin ), "can_see_origin() requires a valid origin to be passed in." ); AssertEx( IsPlayer( self ) || IsAI( self ), "can_see_origin() can only be called on a player or AI." ); if ( !isdefined( test_characters ) ) test_characters = true; // if not in FOV, return false if ( !self point_in_fov( origin ) ) { return false; } // if in FOV but sight trace fails, return false if ( !SightTracePassed( self GetEye(), origin, test_characters, self ) ) { return false; } // if in FOV with successful trace, return true return true; } /* ============= ///ScriptDocBegin "Name: point_in_fov( )" "Summary: Checks to see if the point is within a standard player view FOV." "Module: Entity" "CallOn: An entity" "MandatoryArg: : The point to check if it is within view." "Example: level.player point_in_fov( weapon_respawn.origin );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ point_in_fov( origin ) { forward = AnglesToForward( self.angles ); normalVec = VectorNormalize( origin - self.origin ); dot = VectorDot( forward, normalVec ); return dot > 0.766;// fov = 80 } /* ============= ///ScriptDocBegin "Name: stop_magic_bullet_shield()" "Summary: Stops magic bullet shield on an AI, setting his health back to a normal value and making him vulnerable to death." "Module: AI" "CallOn: AI" "Example: friendly stop_magic_bullet_shield();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ stop_magic_bullet_shield() { self notify( "stop_magic_bullet_shield" ); AssertEx( IsDefined( self.magic_bullet_shield ) && self.magic_bullet_shield, "Tried to stop magic bullet shield on a guy without magic bulletshield" ); if ( !IsAI( self ) ) { if ( IsDefined( self.pre_mbs_health ) ) { self.health = self.pre_mbs_health; self.pre_mbs_health = undefined; } } if ( IsSentient( self ) )// Sentient only { if ( IsDefined( self.pre_mbs_attackeraccuracy ) ) { self.attackeraccuracy = self.pre_mbs_attackeraccuracy; self.pre_mbs_attackeraccuracy = undefined; } } self.magic_bullet_shield = undefined; self.damageShield = false; self notify( "internal_stop_magic_bullet_shield" ); } // For future projects we should distinguish between "death" and "deletion" // Since we currently do not, bulletshield has to be turned off before deleting characters, or you will get the 2nd assert below magic_bullet_death_detection() { /# self endon( "internal_stop_magic_bullet_shield" ); export = self.export; entnum = self GetEntNum(); self waittill( "death" ); if ( IsDefined( self ) ) AssertEx( 0, "Magic bullet shield guy with export " + export + " died some how." ); else AssertEx( 0, "Magic bullet shield guy with export " + export + " died, most likely deleted from spawning guys." ); export = export;// extra line so you can get this info in the debugger without a breakpoint. #/ } /* ============= ///ScriptDocBegin "Name: magic_bullet_shield( )" "Summary: Makes an AI invulnerable to death. When he gets shot, he is ignored by enemies for < time > seconds and his health is regenerated." "Module: AI" "CallOn: AI" "OptionalArg: : Set this to make the AI not script error on death, like if you want the guy to be deletable." "Example: friendly thread magic_bullet_shield();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ magic_bullet_shield( no_death_detection ) { if ( IsAI( self ) )// AI only { AssertEx( IsAlive( self ), "Tried to do magic_bullet_shield on a dead or undefined guy." ); AssertEx( !self.delayedDeath, "Tried to do magic_bullet_shield on a guy about to die." ); AssertEx( !isDefined( self.Melee ), "Trying to turn on magic_bullet_shield while melee in progress (might be about to die)." ); } else { self.pre_mbs_health = self.health; self.health = 100000; } self endon( "internal_stop_magic_bullet_shield" ); AssertEx( !isdefined( self.magic_bullet_shield ), "Can't call magic bullet shield on a character twice. Use make_hero and remove_heroes_from_array so that you don't end up with shielded guys in your logic." ); if ( IsSentient( self ) )// Sentient only { self.pre_mbs_attackeraccuracy = self.attackeraccuracy; self.attackeraccuracy = 0.1; } /# if ( !isdefined( no_death_detection ) ) thread magic_bullet_death_detection(); else AssertEx( no_death_detection, "no_death_detection must be undefined or true" ); #/ self.magic_bullet_shield = true; self.damageShield = true; } /* ============= ///ScriptDocBegin "Name: disable_long_death( )" "Summary: Disables long death on Self" "Module: Utility" "CallOn: An enemy AI" "Example: level.zakhaev disable_long_death(0" "SPMP: singleplayer" ///ScriptDocEnd ============= */ disable_long_death() { AssertEx( IsAlive( self ), "Tried to disable long death on a non living thing" ); self.a.disableLongDeath = true; } /* ============= ///ScriptDocBegin "Name: enable_long_death( )" "Summary: Enables long death on Self" "Module: Utility" "CallOn: An enemy AI" "Example: level.zakhaev enable_long_death(0" "SPMP: singleplayer" ///ScriptDocEnd ============= */ enable_long_death() { AssertEx( IsAlive( self ), "Tried to enable long death on a non living thing" ); self.a.disableLongDeath = false; } /* ============= ///ScriptDocBegin "Name: enable_blood_pool( )" "Summary: enables blood pools on AI deaths( on by default )" "Module: AI" "CallOn: An AI" "Example: ai enable_blood_pool()" "SPMP: singleplayer" ///ScriptDocEnd ============= */ enable_blood_pool() { self.skipBloodPool = undefined; } /* ============= ///ScriptDocBegin "Name: disable_blood_pool( )" "Summary: disables blood pools on AI deaths( on by default )" "Module: AI" "CallOn: An AI" "Example: ai disable_blood_pool()" "SPMP: singleplayer" ///ScriptDocEnd ============= */ disable_blood_pool() { self.skipBloodPool = true; } /* ============= ///ScriptDocBegin "Name: deletable_magic_bullet_shield()" "Summary: A version of magic bullet shield that does not error if the AI dies. Useful for guys that can be deleted but you want them to have aspects of MBS." "Module: AI" "CallOn: AI" "Example: friendly thread magic_bullet_shield();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ deletable_magic_bullet_shield() { magic_bullet_shield( true ); } /* ============= ///ScriptDocBegin "Name: get_ignoreme( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_ignoreme() { return self.ignoreme; } /* ============= ///ScriptDocBegin "Name: set_ignoreme( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_ignoreme( val ) { AssertEx( IsSentient( self ), "Non ai tried to set ignoreme" ); self.ignoreme = val; } /* ============= ///ScriptDocBegin "Name: set_ignoreall( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_ignoreall( val ) { AssertEx( IsSentient( self ), "Non ai tried to set ignoraell" ); self.ignoreall = val; } /* ============= ///ScriptDocBegin "Name: set_favoriteenemy( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_favoriteenemy( enemy ) { self.favoriteenemy = enemy; } /* ============= ///ScriptDocBegin "Name: get_pacifist( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_pacifist() { return self.pacifist; } /* ============= ///ScriptDocBegin "Name: set_pacifist( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_pacifist( val ) { AssertEx( IsSentient( self ), "Non ai tried to set pacifist" ); self.pacifist = val; } ignore_me_timer( time ) { self notify( "new_ignore_me_timer" ); self endon( "new_ignore_me_timer" ); self endon( "death" ); if ( !isdefined( self.ignore_me_timer_prev_value ) ) self.ignore_me_timer_prev_value = self.ignoreme; ai = GetAIArray( "bad_guys" ); foreach ( guy in ai ) { if ( !isalive( guy.enemy ) ) continue; if ( guy.enemy != self ) continue; guy ClearEnemy(); } self.ignoreme = true; wait( time ); self.ignoreme = self.ignore_me_timer_prev_value; self.ignore_me_timer_prev_value = undefined; } /* ============= ///ScriptDocBegin "Name: array_randomize( )" "Summary: Randomizes the array and returns the new array." "Module: Array" "CallOn: " "MandatoryArg: : Array to be randomized." "Example: roof_nodes = array_randomize( roof_nodes );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_randomize( array ) { for ( i = 0; i < array.size; i++ ) { j = RandomInt( array.size ); temp = array[ i ]; array[ i ] = array[ j ]; array[ j ] = temp; } return array; } /* ============= ///ScriptDocBegin "Name: create_random_no_repeat_struct( )" "Summary: Creates a script struct with all of the information needed to have a non-repeating array." "Module: Array" "CallOn: " "MandatoryArg: : Array of values to be used in the random. It will re-randomize when all elements have been used." "Example: roof_nodes_struct = create_random_no_repeat_struct( roof_nodes );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ create_random_no_repeat_struct( seed_array ) { random_struct = SpawnStruct(); random_struct.seed_array = array_randomize( seed_array ); random_struct.index = 0; return random_struct; } /* ============= ///ScriptDocBegin "Name: get_random_no_repeat_element( )" "Summary: Gets a random element" "Module: Array" "CallOn: " "MandatoryArg: : A structure created using create_random_no_repeat_struct() containing randomization information." "Example: roof_node = get_random_no_repeat_element( level.roof_nodes_struct );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_random_no_repeat_element( random_struct ) { //validate the struct contents. Assert( IsDefined( random_struct.index ) && IsDefined( random_struct.seed_array ) && random_struct.index < random_struct.seed_array.size ); random_struct.index++; //ran out the array, re-randomize and turn over the index. if ( random_struct.index >= random_struct.seed_array.size ) { last = random_struct.seed_array[ random_struct.seed_array.size - 1 ]; random_struct.seed_array = array_randomize( random_struct.seed_array ); random_struct.index = 0; //Prevent the same element appearing twice. Do a swap if needed. if ( random_struct.seed_array[ 0 ] == last ) { swap_index = randomintrange( 1, random_struct.seed_array.size - 1 ); random_struct.seed_array[ 0 ] = random_struct.seed_array[ swap_index ]; random_struct.seed_array[ swap_index ] = last; } } return random_struct.seed_array[ random_struct.index ]; } /* ============= ///ScriptDocBegin "Name: array_reverse( )" "Summary: Reverses the order of the array and returns the new array." "Module: Array" "CallOn: " "MandatoryArg: : Array to be reversed." "Example: patrol_nodes = array_reverse( patrol_nodes );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_reverse( array ) { array2 = []; for ( i = array.size - 1; i >= 0; i-- ) array2[ array2.size ] = array[ i ]; return array2; } /* ============= ///ScriptDocBegin "Name: delete_exploder( )" "Summary: deletes an exploder and its brushes forever." "Module: Level" "CallOn: Level" "MandatoryArg: : number of the exploder that you want to delete" "Example: delete_exploder( 3 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ delete_exploder( num ) { num += ""; prof_begin( "delete_exploder" ); for ( i = 0; i < level._createFXent.size; i++ ) { ent = level._createFXent[ i ]; if ( !isdefined( ent ) ) continue; if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != num ) continue; if ( IsDefined( ent.model ) ) ent.model Delete(); } //ends trigger threads. level notify( "killexplodertridgers" + num ); prof_end( "delete_exploder" ); } delete_exploder_nx( num ) { num += ""; prof_begin( "delete_exploder_nx" ); for ( i = 0; i < level._createFXent.size; i++ ) { ent = level._createFXent[ i ]; if ( !isdefined( ent ) ) continue; if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != num ) continue; if ( IsDefined( ent.model ) ) ent.model Delete(); // this is probably how we delete an FX entity if ( isdefined( ent.looper ) ) { ent.looper delete(); } ent notify( "stop_loop" ); } prof_end( "delete_exploder_nx" ); } /* ============= ///ScriptDocBegin "Name: hide_exploder_models( )" "Summary: Hides the models for an exploder." "Module: Level" "CallOn: Level" "MandatoryArg: : number of the exploder that you want to hide" "Example: hide_exploder_models( 3 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ hide_exploder_models( num ) { num += ""; prof_begin( "hide_exploder" ); for ( i = 0; i < level._createFXent.size; i++ ) { ent = level._createFXent[ i ]; if ( !isdefined( ent ) ) continue; if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != num ) continue; if ( IsDefined( ent.model ) ) ent.model Hide(); } prof_end( "hide_exploder" ); } /* ============= ///ScriptDocBegin "Name: show_exploder_models( )" "Summary: shows the models for an exploder." "Module: Level" "CallOn: Level" "MandatoryArg: : number of the exploder that you want to hide" "Example: show_exploder_models( 3 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ show_exploder_models( num ) { num += ""; prof_begin( "hide_exploder" ); for ( i = 0; i < level._createFXent.size; i++ ) { ent = level._createFXent[ i ]; if ( !isdefined( ent ) ) continue; if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != num ) continue; if ( IsDefined( ent.model ) ) { //pre exploded geo. don't worry about deleted exploder geo.. if ( ! exploder_model_starts_hidden( ent.model ) && ! exploder_model_is_damaged_model( ent.model ) && !exploder_model_is_chunk( ent.model ) ) { ent.model Show(); } //exploded geo and should be shown if ( IsDefined( ent.brush_shown ) ) ent.model Show(); } } prof_end( "hide_exploder" ); } exploder_model_is_damaged_model( ent ) { return( IsDefined( ent.targetname ) ) && ( ent.targetname == "exploder" ); } exploder_model_starts_hidden( ent ) { return( ent.model == "fx" ) && ( ( !isdefined( ent.targetname ) ) || ( ent.targetname != "exploderchunk" ) ); } exploder_model_is_chunk( ent ) { return( IsDefined( ent.targetname ) ) && ( ent.targetname == "exploderchunk" ); } /* ============= ///ScriptDocBegin "Name: stop_exploder( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ stop_exploder( num ) { num += ""; for ( i = 0; i < level._createFXent.size; i++ ) { ent = level._createFXent[ i ]; if ( !isdefined( ent ) ) continue; if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != num ) continue; if ( !isdefined( ent.looper ) ) continue; ent.looper Delete(); } } stop_exploder_nx( num, kill_all_elements ) { num += ""; for ( i = 0; i < level._createFXent.size; i++ ) { ent = level._createFXent[ i ]; if ( !isdefined( ent ) ) continue; if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != num ) continue; if ( !isdefined( ent.looper ) ) continue; if ( isdefined( kill_all_elements ) ) { print( "kill " + num + " immediately\n" ); ent.looper Delete( kill_all_elements ); } else { ent.looper Delete(); } } } /* ============= ///ScriptDocBegin "Name: get_exploder_array( )" "Summary: Return an array of exploders" "Module: Utility" "MandatoryArg: : Exploder num/name" "Example: exploders = get_exploder_array( "boom" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_exploder_array( msg ) { msg += ""; array = []; foreach ( ent in level._createFXent ) { if ( ent.v[ "type" ] != "exploder" ) continue; // make the exploder actually removed the array instead? if ( !isdefined( ent.v[ "exploder" ] ) ) continue; if ( ent.v[ "exploder" ] + "" != msg ) continue; array[ array.size ] = ent; } return array; } flood_spawn( spawners ) { maps\_spawner::flood_spawner_scripted( spawners ); } /* ============= ///ScriptDocBegin "Name: set_ambient( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_ambient( track ) { maps\_ambient::activateAmbient( track ); } /* ============= ///ScriptDocBegin "Name: force_crawling_death( , , , )" "Summary: Force an AI to crawl" "Module: Utility" "CallOn: An AI" "MandatoryArg: : The angle to crawl" "MandatoryArg: : How many times to crawl" "OptionalArg: : Sets self.a.custom_crawling_death_array" "OptionalArg: : Sets self.nofallanim" "Example: self force_crawling_death( self.angles[ 1 ], 2, level.scr_anim[ "crawl_death_1" ], 1 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ force_crawling_death( angle, num_crawls, array, nofallanim ) { if ( !isdefined( num_crawls ) ) num_crawls = 4; self thread force_crawling_death_proc( angle, num_crawls, array, nofallanim ); } #using_animtree( "generic_human" ); override_crawl_death_anims() { if ( IsDefined( self.a.custom_crawling_death_array ) ) { self.a.array[ "crawl" ] = self.a.custom_crawling_death_array[ "crawl" ]; self.a.array[ "death" ] = self.a.custom_crawling_death_array[ "death" ]; self.a.crawl_fx_rate = self.a.custom_crawling_death_array[ "blood_fx_rate" ]; if( isdefined( self.a.custom_crawling_death_array[ "blood_fx" ] ) ) self.a.crawl_fx = self.a.custom_crawling_death_array[ "blood_fx" ]; } self.a.array[ "stand_2_crawl" ] = []; self.a.array[ "stand_2_crawl" ][ 0 ] = %dying_stand_2_crawl_v3; if ( IsDefined( self.nofallanim ) ) self.a.pose = "prone"; self OrientMode( "face angle", self.a.force_crawl_angle ); self.a.force_crawl_angle = undefined; } force_crawling_death_proc( angle, num_crawls, array, nofallanim ) { self.forceLongDeath = true; self.a.force_num_crawls = num_crawls; self.noragdoll = true; self.nofallanim = nofallanim; self.a.custom_crawling_death_array = array; self.crawlingPainAnimOverrideFunc = ::override_crawl_death_anims; self.maxhealth = 100000; self.health = 100000; self enable_long_death(); if ( !isdefined( nofallanim ) || nofallanim == false ) self.a.force_crawl_angle = angle + 181.02; else { self.a.force_crawl_angle = angle; self thread animscripts\shared::noteTrackPoseCrawl(); } } get_friendly_chain_node( chainstring ) { chain = undefined; trigger = GetEntArray( "trigger_friendlychain", "classname" ); for ( i = 0; i < trigger.size; i++ ) { if ( ( IsDefined( trigger[ i ].script_chain ) ) && ( trigger[ i ].script_chain == chainstring ) ) { chain = trigger[ i ]; break; } } if ( !isdefined( chain ) ) { /# error( "Tried to get chain " + chainstring + " which does not exist with script_chain on a trigger." ); #/ return undefined; } node = GetNode( chain.target, "targetname" ); return node; } shock_ondeath() { Assert( IsPlayer( self ) ); PreCacheShellShock( "default" ); self waittill( "death" ); if ( IsDefined( self.specialDeath ) ) return; if ( GetDvar( "r_texturebits" ) == "16" ) return; self ShellShock( "default", 5 ); self playsound ( "shellshock_loop_front" ); deathnode = spawn("sound_emitter", ( 10, 10, 10)); deathnode PlaySound( "shellshock_loop_back" ); } /* ============= ///ScriptDocBegin "Name: delete_on_death_wait_sound( , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ delete_on_death_wait_sound( ent, sounddone ) { ent endon( "death" ); self waittill( "death" ); if ( IsDefined( ent ) ) { if ( ent IsWaitingOnSound() ) ent waittill( sounddone ); ent Delete(); } } is_dead_sentient() { return IsSentient( self ) && !isalive( self ); } /* ============= ///ScriptDocBegin "Name: play_sound_on_tag( , , )" "Summary: Play the specified sound alias on a tag of an entity" "Module: Sound" "CallOn: An entity" "MandatoryArg: : Sound alias to play" "OptionalArg: : Tag on the entity to play sound on. If no tag is specified the entities origin will be used." "OptionalArg: : The sound will be cut short if the entity dies. Defaults to false." "OptionalArg: : Optional notify string on sound done." "Example: vehicle thread play_sound_on_tag( "horn_honk", "tag_engine" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_sound_on_tag( alias, tag, ends_on_death, op_notify_string, radio_dialog ) { if ( is_dead_sentient() ) return; org = Spawn( "sound_emitter", ( 0, 0, 0 ) ); org endon( "death" ); thread delete_on_death_wait_sound( org, "sounddone" ); if ( IsDefined( tag ) ) org LinkTo( self, tag, ( 0, 0, 0 ), ( 0, 0, 0 ) ); else { org.origin = self.origin; org.angles = self.angles; org LinkTo( self ); } /# if ( IsDefined( level._player_radio_emitter ) && ( self == level._player_radio_emitter ) ) PrintLn( "**dialog alias playing radio: " + alias ); #/ org PlaySound( alias, "sounddone" ); if ( IsDefined( ends_on_death ) ) { AssertEx( ends_on_death, "ends_on_death must be true or undefined" ); if ( !isdefined( wait_for_sounddone_or_death( org ) ) ) org StopSounds(); // don't call StopSounds (redundantly) when the sound stopped since this can cut off sounds in SO for the non host wait( 0.05 );// stopsounds doesnt work if the org is deleted same frame } else { org waittill( "sounddone" ); } if ( IsDefined( op_notify_string ) ) self notify( op_notify_string ); org Delete(); } /* ///ScriptDocBegin "Name: play_sound_on_ent( , )" "Summary: Play the specified sound alias on an entity" "Module: Sound" "CallOn: An entity" "MandatoryArg: : Sound alias to play" "OptionalArg: : The sound will be cut short if the entity dies. Defaults to false." "Example: vehicle thread play_sound_on_ent( "horn_honk", "tag_engine" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_sound_on_ent( alias, ends_on_death ) { if ( is_dead_sentient() ) return; thread delete_on_death_wait_sound( self, "sounddone" ); self PlaySound( alias, "sounddone", true ); if ( IsDefined( ends_on_death ) ) { AssertEx( ends_on_death, "ends_on_death must be true or undefined" ); if ( !isdefined( wait_for_sounddone_or_death( self ) ) ) self StopSounds(); // don't call StopSounds (redundantly) when the sound stopped since this can cut off sounds in SO for the non host } } /* ============= ///ScriptDocBegin "Name: play_stoppable_sound_on_entity( , )" "Summary: Play the specified sound alias on an entity" "Module: Sound" "CallOn: An entity" "MandatoryArg: : Sound alias to play" "OptionalArg: : The sound will be cut short if the entity dies. Defaults to false." "Example: guy play_stoppable_sound_on_entity ( "gun_fire_sfx", true );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_stoppable_sound_on_entity( alias, ends_on_death ) { if ( is_dead_sentient() ) return; self PlaySound( alias, "sounddone" ); if ( IsDefined( ends_on_death ) ) { AssertEx( ends_on_death, "ends_on_death must be true or undefined" ); if ( !isdefined( wait_for_sounddone_or_death( self ) ) ) self StopSounds(); } else { self waittill( "sounddone" ); } } /* ============= ///ScriptDocBegin "Name: play_sound_on_tag_endon_death( , )" "Summary: Play the specified sound alias on a tag of an entity but gets cut short if the entity dies" "Module: Sound" "CallOn: An entity" "MandatoryArg: : Sound alias to play" "OptionalArg: : Tag on the entity to play sound on. If no tag is specified the entities origin will be used." "Example: vehicle thread play_sound_on_tag_endon_death( "horn_honk", "tag_engine" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_sound_on_tag_endon_death( alias, tag ) { play_sound_on_tag( alias, tag, true ); } /* ============= ///ScriptDocBegin "Name: play_sound_on_entity( , )" "Summary: Play the specified sound alias on an entity at it's origin" "Module: Sound" "CallOn: An entity" "MandatoryArg: : Sound alias to play" "OptionalArg: : Optional notify string on sound done." "Example: level.player play_sound_on_entity( "breathing_better" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_sound_on_entity( alias, op_notify_string ) { AssertEx( !isSpawner( self ), "Spawner tried to play a sound" ); play_sound_on_tag( alias, undefined, undefined, op_notify_string ); } /* ============= ///ScriptDocBegin "Name: play_loop_sound_on_tag( , , bStopSoundOnDeath )" "Summary: Play the specified looping sound alias on a tag of an entity" "Module: Sound" "CallOn: An entity" "MandatoryArg: : Sound alias to loop" "OptionalArg: : Tag on the entity to play sound on. If no tag is specified the entities origin will be used." "OptionalArg: : Defaults to true. If true, will stop the looping sound when self dies" "Example: vehicle thread play_loop_sound_on_tag( "engine_belt_run", "tag_engine" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_loop_sound_on_tag( alias, tag, bStopSoundOnDeath ) { org = Spawn( "sound_emitter", ( 0, 0, 0 ) ); org endon( "death" ); if ( !isdefined( bStopSoundOnDeath ) ) bStopSoundOnDeath = true; if ( bStopSoundOnDeath ) thread delete_on_death( org ); if ( IsDefined( tag ) ) org LinkTo( self, tag, ( 0, 0, 0 ), ( 0, 0, 0 ) ); else { org.origin = self.origin; org.angles = self.angles; org LinkTo( self ); } // org endon( "death" ); org PlayLoopSound( alias ); // PrintLn( "playing loop sound ", alias, " on entity at origin ", self.origin, " at ORIGIN ", org.origin ); self waittill( "stop sound" + alias ); org StopLoopSound( alias ); org Delete(); } /* ============= ///ScriptDocBegin "Name: play_flux_sound( sound_prefix, distance, time )" "Summary: Play the specified sound with movement towards player" "Module: Sound" "CallOn: An entity" "MandatoryArg: sound_prefix : Sound prefix - which is appended with _l and _r in script" "MandatoryArg: distance : distance sound should move, in inches" "MandatoryArg: time : time sound takes to move, in seconds" "Example: vehicle thread play_flux_sound( "vehicle_explo_sfx, 100 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ play_flux_sound( sound_prefix, distance, time ) { soundorg_l = Spawn( "sound_emitter", ( self.origin ) ); soundorg_r = Spawn( "sound_emitter", ( self.origin ) ); left_dest = (level._player.origin + ( distance, (60 + distance), 0) ); right_dest = (level._player.origin + ( distance, (distance - 60), 0) ); soundorg_l playsound( sound_prefix + "_l" ); soundorg_r playsound( sound_prefix + "_r" ); soundorg_l MoveTo( left_dest, time ); soundorg_r MoveTo( right_dest, time ); wait time + 2; soundorg_l Delete(); soundorg_r Delete(); } save_friendlies() { ai = GetAIArray( "allies" ); game_characters = 0; for ( i = 0; i < ai.size; i++ ) { if ( IsDefined( ai[ i ].script_friendname ) ) continue; // attachsize = // PrintLn( "attachSize = ", self GetAttachSize() ); game[ "character" + game_characters ] = ai[ i ] codescripts\character::save(); game_characters++; } game[ "total characters" ] = game_characters; } /* ============= ///ScriptDocBegin "Name: spawn_failed( )" "Summary: Checks to see if the spawned AI spawned correctly or had errors. Also waits until all spawn initialization is complete. Returns true or false." "Module: AI" "CallOn: " "MandatoryArg: : The actor that just spawned" "Example: spawn_failed( level.price );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ spawn_failed( spawn ) { if ( !isalive( spawn ) ) return true; if ( !isdefined( spawn.finished_spawning ) ) spawn waittill( "finished spawning" ); if ( IsAlive( spawn ) ) return false; return true; } spawn_setcharacter( data ) { codescripts\character::precache( data ); self waittill( "spawned", spawn ); if ( maps\_utility::spawn_failed( spawn ) ) return; PrintLn( "Size is ", data[ "attach" ].size ); spawn codescripts\character::new(); spawn codescripts\character::load( data ); } key_hint_print( message, binding ) { // Note that this will insert only the first bound key for the action IPrintLnBold( message, binding[ "key1" ] ); } view_tag( tag ) { self endon( "death" ); for ( ;; ) { maps\_debug::drawTag( tag ); wait( 0.05 ); } } /* ============= ///ScriptDocBegin "Name: assign_animtree( )" "Summary: Assigns the level.scr_animtree for the given animname to self." "Module: _Anim" "OptionalArg: : You can optionally assign the animname for self at this juncture." "Example: model = assign_animtree( "whatever" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ assign_animtree( animname ) { if ( IsDefined( animname ) ) self.animname = animname; AssertEx( IsDefined( level._scr_animtree[ self.animname ] ), "There is no level.scr_animtree for animname " + self.animname ); self UseAnimTree( level._scr_animtree[ self.animname ] ); } /* ============= ///ScriptDocBegin "Name: assign_model( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ assign_model() { AssertEx( IsDefined( level._scr_model[ self.animname ] ), "There is no level.scr_model for animname " + self.animname ); if ( IsArray( level._scr_model[ self.animname ] ) ) { randIndex = RandomInt( level._scr_model[ self.animname ].size ); self SetModel( level._scr_model[ self.animname ][ randIndex ] ); } else self SetModel( level._scr_model[ self.animname ] ); } /* ============= ///ScriptDocBegin "Name: spawn_anim_model( , )" "Summary: Spawns a script model and gives it the animtree and model associated with that animname" "Module: _Anim" "MandatoryArg: : Name of the animname from this map_anim.gsc." "OptionalArg: : Optional origin." "Example: model = spawn_anim_model( "player_rappel" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ spawn_anim_model( animname, origin ) { if ( !isdefined( origin ) ) origin = ( 0, 0, 0 ); model = Spawn( "script_model", origin ); model.animname = animname; model assign_animtree(); model assign_model(); return model; } /* ============= ///ScriptDocBegin "Name: trigger_wait( , )" "Summary: Waits until a trigger with the specified key / value is triggered" "Module: Trigger" "CallOn: " "MandatoryArg: : Name of the key on this trigger" "MandatoryArg: : Key on the trigger to use, example: "targetname" or "script_noteworthy"" "Example: trigger_wait( "player_in_building1", "targetname" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ trigger_wait( strName, strKey ) { eTrigger = GetEnt( strName, strKey ); if ( !isdefined( eTrigger ) ) { AssertMsg( "trigger not found: " + strName + " key: " + strKey ); return; } eTrigger waittill( "trigger", eOther ); level notify( strName, eOther ); return eOther; } /* ============= ///ScriptDocBegin "Name: trigger_wait_targetname( )" "Summary: Waits until a trigger with the specified key / value is triggered" "Module: Trigger" "CallOn: " "MandatoryArg: : targetname key to waitfor" "Example: trigger_wait_targetname( "player_in_building1" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ trigger_wait_targetname( strName ) { eTrigger = GetEnt( strName, "targetname" ); if ( !isdefined( eTrigger ) ) { AssertMsg( "trigger not found: " + strName + " targetname " ); return; } eTrigger waittill( "trigger", eOther ); level notify( strName, eOther ); return eOther; } /* ============= ///ScriptDocBegin "Name: set_flag_on_dead( , )" "Summary: the function will set the flag after the actors from have spawned and then died " "Module: AI" "CallOn: " "MandatoryArg: : the array of spawners" "MandatoryArg: : the flag to set" "Example: set_flag_on_dead( spawners, "base_guys_dead" )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_flag_on_dead( spawners, strFlag ) { thread set_flag_on_func_wait_proc( spawners, strFlag, ::waittill_dead, "set_flag_on_dead" ); } /* ============= ///ScriptDocBegin "Name: set_flag_on_dead_or_dying( , )" "Summary: the function will set the flag after the actors from have spawned and then are dead or dying ( long death )." "Module: AI" "CallOn: " "MandatoryArg: : the array of spawners" "MandatoryArg: : the flag to set" "Example: set_flag_on_dead_or_dying( spawners, "base_guys_dead" )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_flag_on_dead_or_dying( spawners, strFlag ) { thread set_flag_on_func_wait_proc( spawners, strFlag, ::waittill_dead_or_dying, "set_flag_on_dead_or_dying" ); } /* ============= ///ScriptDocBegin "Name: set_flag_on_spawned( , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_flag_on_spawned( spawners, strFlag ) { thread set_flag_on_func_wait_proc( spawners, strFlag, ::empty_func, "set_flag_on_spawned" ); } empty_func( var ) { return; } set_flag_on_spawned_ai_proc( system, internal_flag ) { self waittill( "spawned", guy ); if ( maps\_utility::spawn_failed( guy ) ) return; system.ai[ system.ai.size ] = guy; self ent_flag_set( internal_flag ); } set_flag_on_func_wait_proc( spawners, strFlag, waitfunc, internal_flag ) { system = SpawnStruct(); system.ai = []; AssertEx( spawners.size, "spawners is empty" ); foreach ( key, spawn in spawners ) spawn ent_flag_init( internal_flag ); array_thread( spawners, ::set_flag_on_spawned_ai_proc, system, internal_flag ); foreach ( key, spawn in spawners ) spawn ent_flag_wait( internal_flag ); [[ waitfunc ]]( system.ai ); flag_set( strFlag ); } /* ============= ///ScriptDocBegin "Name: set_flag_on_trigger( , )" "Summary: Calls flag_set to set the specified flag when the trigger is triggered" "Module: Trigger" "CallOn: " "MandatoryArg: : trigger entity to use" "MandatoryArg: : name of the flag to set" "Example: set_flag_on_trigger( trig, "player_is_outside" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_flag_on_trigger( eTrigger, strFlag ) { if ( !flag( strFlag ) ) { eTrigger waittill( "trigger", eOther ); flag_set( strFlag ); return eOther; } } /* ============= ///ScriptDocBegin "Name: set_flag_on_targetname_trigger( )" "Summary: Sets the specified flag when a trigger with targetname < flag > is triggered." "Module: Trigger" "CallOn: " "MandatoryArg: : name of the flag to set, and also the targetname of the trigger to use" "Example: set_flag_on_targetname_trigger( "player_is_outside" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_flag_on_targetname_trigger( msg ) { Assert( IsDefined( level._flag[ msg ] ) ); if ( flag( msg ) ) return; trigger = GetEnt( msg, "targetname" ); trigger waittill( "trigger" ); flag_set( msg ); } /* ============= ///ScriptDocBegin "Name: is_in_array( , )" "Summary: Returns true if < eFindee > is an entity in array < aeCollection > . False if it is not. " "Module: Array" "CallOn: " "MandatoryArg: : array of entities to search through" "MandatoryArg: : entity to check if it's in the array" "Example: qBool = is_in_array( eTargets, vehicle1 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ is_in_array( aeCollection, eFindee ) { for ( i = 0; i < aeCollection.size; i++ ) { if ( aeCollection[ i ] == eFindee ) return( true ); } return( false ); } /* ============= ///ScriptDocBegin "Name: waittill_dead( , , )" "Summary: Waits until all the AI in array < guys > are dead." "Module: AI" "CallOn: " "MandatoryArg: : Array of actors to wait until dead" "OptionalArg: : Number of guys that must die for this function to continue" "OptionalArg: : Number of seconds before this function times out and continues" "Example: waittill_dead( GetAIArray( "axis" ) );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ waittill_dead( guys, num, timeoutLength ) { // verify the living - ness of the ai /# allAlive = true; foreach ( member in guys ) { if ( IsAlive( member ) ) continue; allAlive = false; break; } AssertEx( allAlive, "Waittill_Dead was called with dead or removed AI in the array, meaning it will never pass." ); if ( !allAlive ) { newArray = []; foreach ( member in guys ) { if ( IsAlive( member ) ) newArray[ newArray.size ] = member; } guys = newArray; } #/ ent = SpawnStruct(); if ( IsDefined( timeoutLength ) ) { ent endon( "thread_timed_out" ); ent thread waittill_dead_timeout( timeoutLength ); } ent.count = guys.size; if ( IsDefined( num ) && num < ent.count ) ent.count = num; array_thread( guys, ::waittill_dead_thread, ent ); while ( ent.count > 0 ) ent waittill( "waittill_dead guy died" ); } /* ============= ///ScriptDocBegin "Name: waittill_dead_or_dying( , , )" "Summary: Similar to waittill_dead(). Waits until all the AI in array < guys > are dead OR dying (long deaths)." "Module: AI" "CallOn: " "MandatoryArg: : Array of actors to wait until dead or dying" "OptionalArg: : Number of guys that must die or be dying for this function to continue" "OptionalArg: : Number of seconds before this function times out and continues" "Example: waittill_dead_or_dying( GetAIArray( "axis" ) );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ waittill_dead_or_dying( guys, num, timeoutLength ) { // verify the living - ness and healthy - ness of the ai newArray = []; foreach ( member in guys ) { if ( IsAlive( member ) && !member.ignoreForFixedNodeSafeCheck ) newArray[ newArray.size ] = member; } guys = newArray; ent = SpawnStruct(); if ( IsDefined( timeoutLength ) ) { ent endon( "thread_timed_out" ); ent thread waittill_dead_timeout( timeoutLength ); } ent.count = guys.size; // optional override on count if ( IsDefined( num ) && num < ent.count ) ent.count = num; array_thread( guys, ::waittill_dead_or_dying_thread, ent ); while ( ent.count > 0 ) ent waittill( "waittill_dead_guy_dead_or_dying" ); } waittill_dead_thread( ent ) { self waittill( "death" ); ent.count--; ent notify( "waittill_dead guy died" ); } waittill_dead_or_dying_thread( ent ) { self waittill_either( "death", "pain_death" ); ent.count--; ent notify( "waittill_dead_guy_dead_or_dying" ); } waittill_dead_timeout( timeoutLength ) { wait( timeoutLength ); self notify( "thread_timed_out" ); } waittill_aigroupcleared( aigroup ) { while ( level._ai_group[ aigroup ].spawnercount || level._ai_group[ aigroup ].aicount ) wait( 0.25 ); } waittill_alive_aigroupcleared( aigroup ) { while ( level._ai_group[ aigroup ].aicount ) wait( 0.25 ); } waittill_aigroupcount( aigroup, count ) { while ( level._ai_group[ aigroup ].spawnercount + level._ai_group[ aigroup ].aicount > count ) wait( 0.25 ); } waittill_aigroupsentientcount( aigroup, count ) { while ( level._ai_group[ aigroup ].aicount > count ) wait( 0.25 ); } get_ai_group_count( aigroup ) { return( level._ai_group[ aigroup ].spawnercount + level._ai_group[ aigroup ].aicount ); } get_ai_group_sentient_count( aigroup ) { return( level._ai_group[ aigroup ].aicount ); } get_ai_group_ai( aigroup ) { aiSet = []; for ( index = 0; index < level._ai_group[ aigroup ].ai.size; index++ ) { if ( !isAlive( level._ai_group[ aigroup ].ai[ index ] ) ) continue; aiSet[ aiSet.size ] = level._ai_group[ aigroup ].ai[ index ]; } return( aiSet ); } get_ai_group_ai_including_dying( aigroup ) { aiSet = []; for ( index = 0; index < level._ai_group[ aigroup ].ai.size; index++ ) { if ( !isDefined( level._ai_group[ aigroup ].ai[ index ] ) ) continue; aiSet[ aiSet.size ] = level._ai_group[ aigroup ].ai[ index ]; } return( aiSet ); } get_ai_group_ai_dying( aigroup ) { aiSet = []; for ( index = 0; index < level._ai_group[ aigroup ].ai.size; index++ ) { if ( !isDefined( level._ai_group[ aigroup ].ai[ index ] ) || IsAlive( level._ai_group[ aigroup ].ai[ index ] ) ) continue; aiSet[ aiSet.size ] = level._ai_group[ aigroup ].ai[ index ]; } return( aiSet ); } /* ============= ///ScriptDocBegin "Name: waittill_notetrack_or_damage( )" "Summary: Waits until the entity hits a certain notetrack or is damaged or killed" "Module: AI" "CallOn: An AI" "MandatoryArg: : the notetrack to wait for" "Example: self waittill_notetrack_or_damage( "bodyfall large" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ waittill_notetrack_or_damage( notetrack ) { self endon( "damage" ); self endon( "death" ); self waittillmatch( "single anim", notetrack ); } /* ============= ///ScriptDocBegin "Name: get_living_ai( , )" "Summary: Returns single spawned ai in the level of and . Error if used on more than one ai with same name and type " "Module: AI" "CallOn: " "MandatoryArg: : the value of the targetname or script_noteworthy of the ai" "MandatoryArg: : valid types are targetname and script_noteworthy" "Example: patroller = get_living_ai( "patrol", "script_noteworthy" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_living_ai( name, type ) { array = get_living_ai_array( name, type ); if ( array.size > 1 ) { AssertMsg( "get_living_ai used for more than one living ai of type " + type + " called " + name + "." ); return undefined; } return array[ 0 ]; } /* ============= ///ScriptDocBegin "Name: get_living_ai_array( , )" "Summary: Returns array of spawned ai in the level of and " "Module: AI" "CallOn: " "MandatoryArg: : the value of the targetname or script_noteworthy of the ai" "MandatoryArg: : valid types are targetname and script_noteworthy" "Example: patrollers = get_living_ai_array( "patrol", "script_noteworthy" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_living_ai_array( name, type ) { ai = GetAISpeciesArray( "all", "all" ); array = []; foreach ( actor in ai ) { if ( !isalive( actor ) ) continue; switch( type ) { case "targetname":{ if ( IsDefined( actor.targetname ) && actor.targetname == name ) array[ array.size ] = actor; }break; case "script_noteworthy":{ if ( IsDefined( actor.script_noteworthy ) && actor.script_noteworthy == name ) array[ array.size ] = actor; }break; } } return array; } /* ============= ///ScriptDocBegin "Name: get_vehicle( , )" "Summary: Returns the vehicle spawned from the SHIFT-V radient menu of and " "Module: Vehicle" "CallOn: " "MandatoryArg: : the value of the targetname or script_noteworthy of the vehicle" "MandatoryArg: : valid types are targetname and script_noteworthy" "Example: patrollers = get_vehicle( "heli_1", "script_noteworthy" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_vehicle( name, type ) { Assert( IsDefined( name ) ); Assert( IsDefined( type ) ); array = get_vehicle_array( name, type ); if ( !array.size ) return undefined; AssertEx( array.size == 1, "tried to get_vehicle() on vehicles with key-pair: " + name + "," + type ); return array[ 0 ]; } /* ============= ///ScriptDocBegin "Name: get_vehicle_array( , )" "Summary: Returns the vehicles spawned from the SHIFT-V radient menu of and " "Module: Vehicle" "CallOn: " "MandatoryArg: : the value of the targetname or script_noteworthy of the vehicle" "MandatoryArg: : valid types are targetname and script_noteworthy" "Example: helis = get_vehicle_array( "tower_helis", "script_noteworthy" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_vehicle_array( name, type ) { array = GetEntArray( name, type ); vehicle = []; merge_array = []; foreach ( object in array ) { if ( object.code_classname != "script_vehicle" ) continue; merge_array[ 0 ] = object; //since vehicles lose their targetname return the last vehicle spawned from the spawner. if ( IsSpawner( object ) ) { if ( IsDefined( object.last_spawned_vehicle ) ) { merge_array[ 0 ] = object.last_spawned_vehicle; vehicle = array_merge( vehicle, merge_array );// least tricky way for me to do this. } continue; } vehicle = array_merge( vehicle, merge_array );// least tricky way for me to do this. } return vehicle; } /* ============= ///ScriptDocBegin "Name: get_living_aispecies( , , )" "Summary: Returns single spawned ai in the level of and . Error if used on more than one ai with same name and type " "Module: AI" "CallOn: " "MandatoryArg: : the value of the targetname or script_noteworthy of the ai" "MandatoryArg: : valid types are targetname and script_noteworthy" "OptionalArg: : the breadof spieces, if none is given, defaults to 'all' " "Example: patroller = get_living_aispecies( "patrol", "script_noteworthy", "dog" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_living_aispecies( name, type, breed ) { array = get_living_ai_array( name, type, breed ); if ( array.size > 1 ) { AssertMsg( "get_living_aispecies used for more than one living ai of type " + type + " called " + name + "." ); return undefined; } return array[ 0 ]; } /* ============= ///ScriptDocBegin "Name: get_living_aispecies_array( , , )" "Summary: Returns array of spawned ai of any speices in the level of , , and " "Module: AI" "CallOn: " "MandatoryArg: : the value of the targetname or script_noteworthy of the ai" "MandatoryArg: : valid types are targetname and script_noteworthy" "OptionalArg: : the breadof spieces, if none is given, defaults to 'all' " "Example: patrollers = get_living_aispecies_array( "patrol", "script_noteworthy", "dog" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_living_aispecies_array( name, type, breed ) { if ( !isdefined( breed ) ) breed = "all"; ai = GetAISpeciesArray( "allies", breed ); ai = array_combine( ai, GetAISpeciesArray( "axis", breed ) ); array = []; for ( i = 0; i < ai.size; i++ ) { switch( type ) { case "targetname":{ if ( IsDefined( ai[ i ].targetname ) && ai[ i ].targetname == name ) array[ array.size ] = ai[ i ]; }break; case "script_noteworthy":{ if ( IsDefined( ai[ i ].script_noteworthy ) && ai[ i ].script_noteworthy == name ) array[ array.size ] = ai[ i ]; }break; } } return array; } // Creates an event based on this message if none exists, and sets it to true after the delay. gather_delay_proc( msg, delay ) { if ( IsDefined( level._gather_delay[ msg ] ) ) { if ( level._gather_delay[ msg ] ) { wait( 0.05 ); if ( IsAlive( self ) ) self notify( "gather_delay_finished" + msg + delay ); return; } level waittill( msg ); if ( IsAlive( self ) ) self notify( "gather_delay_finished" + msg + delay ); return; } level._gather_delay[ msg ] = false; wait( delay ); level._gather_delay[ msg ] = true; level notify( msg ); if ( IsAlive( self ) ) self notify( "gather_delay_finished" + msg + delay ); } gather_delay( msg, delay ) { thread gather_delay_proc( msg, delay ); self waittill( "gather_delay_finished" + msg + delay ); } set_environment( env ) { animscripts\utility::setEnv( env ); } death_waiter( notifyString ) { self waittill( "death" ); level notify( notifyString ); } getchar( num ) { if ( num == 0 ) return "0"; if ( num == 1 ) return "1"; if ( num == 2 ) return "2"; if ( num == 3 ) return "3"; if ( num == 4 ) return "4"; if ( num == 5 ) return "5"; if ( num == 6 ) return "6"; if ( num == 7 ) return "7"; if ( num == 8 ) return "8"; if ( num == 9 ) return "9"; } /* ============= ///ScriptDocBegin "Name: player_god_on()" "Summary: Puts the player in god mode. Player takes damage but will never die." "Module: Player" "CallOn: " "Example: thread player_god_on();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ player_god_on() { thread player_god_on_thread(); } player_god_on_thread() { self endon( "godoff" ); self.oldhealth = self.health; for ( ;; ) { self waittill( "damage" ); self.health = 10000; } } /* ============= ///ScriptDocBegin "Name: player_god_off()" "Summary: Remove god mode from player. Player will be vulnerable to death again." "Module: Player" "CallOn: " "Example: thread player_god_off();" "SPMP: singleplayer" ///ScriptDocEnd ============= */ player_god_off() { self notify( "godoff" ); Assert( IsDefined( self.oldhealth ) ); self.health = self.oldhealth; } getlinks_array( array, linkMap )// don't pass stuff through as an array of struct.linkname[] but only linkMap[] { ents = []; for ( j = 0; j < array.size; j++ ) { node = array[ j ]; script_linkname = node.script_linkname; if ( !isdefined( script_linkname ) ) continue; if ( !isdefined( linkMap[ script_linkname ] ) ) continue; ents[ ents.size ] = node; } return ents; } // Adds only things that are new to the array. // Requires the arrays to be of node with script_linkname defined. /* ============= ///ScriptDocBegin "Name: array_merge_links( , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_merge_links( array1, array2 ) { if ( !array1.size ) return array2; if ( !array2.size ) return array1; linkMap = []; for ( i = 0; i < array1.size; i++ ) { node = array1[ i ]; linkMap[ node.script_linkName ] = true; } for ( i = 0; i < array2.size; i++ ) { node = array2[ i ]; if ( IsDefined( linkMap[ node.script_linkName ] ) ) continue; linkMap[ node.script_linkName ] = true; array1[ array1.size ] = node; } return array1; } /* ============= ///ScriptDocBegin "Name: array_merge( , )" "Summary: Combines the two arrays and returns the resulting array. Adds only things that are new to the array, no duplicates." "Module: Array" "CallOn: " "MandatoryArg: : first array" "MandatoryArg: : second array" "Example: combinedArray = array_merge( array1, array2 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_merge( array1, array2 )// adds only things that are new to the array { if ( array1.size == 0 ) return array2; if ( array2.size == 0 ) return array1; newarray = array1; foreach ( array2_ent in array2 ) { foundmatch = false; foreach ( array1_ent in array1 ) { if ( array1_ent == array2_ent ) { foundmatch = true; break; } } if ( foundmatch ) continue; else newarray[ newarray.size ] = array2_ent; } return newarray; } /* ============= ///ScriptDocBegin "Name: array_exclude( , )" "Summary: Returns an array excluding all members of < arrayExclude > " "Module: Array" "CallOn: " "MandatoryArg: : Array containing all items" "MandatoryArg: : Arary containing all items to remove" "Example: newArray = array_exclude( array1, array2 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_exclude( array, arrayExclude )// returns "array" minus all members of arrayExclude { newarray = array; for ( i = 0; i < arrayExclude.size; i++ ) { if ( is_in_array( array, arrayExclude[ i ] ) ) newarray = array_remove( newarray, arrayExclude[ i ] ); } return newarray; } /* ============= ///ScriptDocBegin "Name: array_compare( , )" "Summary: checks whether 2 arrays are equal. Returns true if they are, false if they are not" "Module: Array" "CallOn: " "MandatoryArg: : the first array to compare " "MandatoryArg: : the second array to compare " "Example: if( array_compare( array1, array2 ) )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_compare( array1, array2 ) { if ( array1.size != array2.size ) return false; foreach ( key, member in array1 ) { if ( !isdefined( array2[ key ] ) ) return false; member2 = array2[ key ]; if ( member2 != member ) return false; } return true; } /* ============= ///ScriptDocBegin "Name: array_contains( , )" "Summary: Checks whether an item is in the array or not." "Module: Array" "CallOn: " "MandatoryArg: : The array to search." "MandatoryArg: : The item to see if it exists in the array" "Example: if( arrray_contains( array, important_item ) )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_contains( array, compare ) { if ( array.size <= 0 ) return false; foreach ( member in array ) { if ( member == compare ) return true; } return false; } /* ============= ///ScriptDocBegin "Name: getLinkedVehicleNodes()" "Summary: Returns an array of vehicle nodes that SELF is linked to" "Module: Utility" "CallOn: An entity that links to vehicle nodes" "Example: spawners = heli get_linked_ents()" "SPMP: both" ///ScriptDocEnd ============= */ getLinkedVehicleNodes() { array = []; if ( IsDefined( self.script_linkTo ) ) { linknames = get_links(); foreach ( name in linknames ) { entities = GetVehicleNodeArray( name, "script_linkname" ); array = array_combine( array, entities ); } } return array; } /* ============= ///ScriptDocBegin "Name: draw_line( , , , , )" "Summary: Draws a line from < org1 > to < org2 > in the specified color forever" "Module: Debug" "CallOn: " "MandatoryArg: : starting origin for the line" "MandatoryArg: : ending origin for the line" "MandatoryArg: : red color value( 0 to 1 )" "MandatoryArg: : green color value( 0 to 1 )" "MandatoryArg: : blue color value( 0 to 1 )" "Example: thread draw_line( level.player.origin, vehicle.origin, 1, 0, 0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_line( org1, org2, r, g, b ) { while ( 1 ) { Line( org1, org2, ( r, g, b ), 1 ); wait .05; } } /* ============= ///ScriptDocBegin "Name: draw_line_to_ent_for_time( , , , , , )" "Summary: Draws a line from < org1 > to < ent > origin in the specified color for the specified duration. Updates to the entities origin each frame." "Module: Debug" "CallOn: " "MandatoryArg: : starting origin for the line" "MandatoryArg: : entity to draw line to" "MandatoryArg: : red color value( 0 to 1 )" "MandatoryArg: : green color value( 0 to 1 )" "MandatoryArg: : blue color value( 0 to 1 )" "MandatoryArg: : time in seconds the line should last" "Example: thread draw_line_to_ent_for_time( level.player.origin, vehicle, 1, 0, 0, 10.0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_line_to_ent_for_time( org1, ent, r, g, b, timer ) { timer = GetTime() + ( timer * 1000 ); while ( GetTime() < timer ) { Line( org1, ent.origin, ( r, g, b ), 1 ); wait .05; if ( !isdefined( ent ) || !isdefined( ent.origin ) ) return; } } /* ============= ///ScriptDocBegin "Name: draw_line_from_ent_for_time( , , , , , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_line_from_ent_for_time( ent, org, r, g, b, timer ) { draw_line_to_ent_for_time( org, ent, r, g, b, timer ); } /* ============= ///ScriptDocBegin "Name: draw_line_from_ent_to_ent_for_time( , , , , , )" "Summary: Draws a line from one entity origin to another entity origin in the specified color for the specified duration. Updates to the entities origin each frame." "Module: Debug" "CallOn: " "MandatoryArg: : entity to draw line from" "MandatoryArg: : entity to draw line to" "MandatoryArg: : red color value( 0 to 1 )" "MandatoryArg: : green color value( 0 to 1 )" "MandatoryArg: : blue color value( 0 to 1 )" "MandatoryArg: : time in seconds the line should last" "Example: thread draw_line_from_ent_to_ent_for_time( level.player, vehicle, 1, 0, 0, 10.0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_line_from_ent_to_ent_for_time( ent1, ent2, r, g, b, timer ) { ent1 endon( "death" ); ent2 endon( "death" ); timer = GetTime() + ( timer * 1000 ); while ( GetTime() < timer ) { Line( ent1.origin, ent2.origin, ( r, g, b ), 1 ); wait .05; } } /* ============= ///ScriptDocBegin "Name: draw_line_from_ent_to_ent_until_notify( , , , , , , )" "Summary: Draws a line from one entity origin to another entity origin in the specified color until < notifyEnt > is notified < notifyString > . Updates to the entities origin each frame." "Module: Debug" "CallOn: " "MandatoryArg: : entity to draw line from" "MandatoryArg: : entity to draw line to" "MandatoryArg: : red color value( 0 to 1 )" "MandatoryArg: : green color value( 0 to 1 )" "MandatoryArg: : blue color value( 0 to 1 )" "MandatoryArg: : entity that waits for the notify" "MandatoryArg: : notify string that will make the line stop being drawn" "Example: thread draw_line_from_ent_to_ent_until_notify( level.player, guy, 1, 0, 0, guy, "anim_on_tag_done" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_line_from_ent_to_ent_until_notify( ent1, ent2, r, g, b, notifyEnt, notifyString ) { Assert( IsDefined( notifyEnt ) ); Assert( IsDefined( notifyString ) ); ent1 endon( "death" ); ent2 endon( "death" ); notifyEnt endon( notifyString ); while ( 1 ) { Line( ent1.origin, ent2.origin, ( r, g, b ), 0.05 ); wait .05; } } /* ============= ///ScriptDocBegin "Name: draw_line_until_notify( , , , , , , )" "Summary: Draws a line from < org1 > to < org2 > in the specified color until < notifyEnt > is notified < notifyString > " "Module: Debug" "CallOn: " "MandatoryArg: : starting origin for the line" "MandatoryArg: : ending origin for the line" "MandatoryArg: : red color value( 0 to 1 )" "MandatoryArg: : green color value( 0 to 1 )" "MandatoryArg: : blue color value( 0 to 1 )" "MandatoryArg: : entity that waits for the notify" "MandatoryArg: : notify string that will make the line stop being drawn" "Example: thread draw_line_until_notify( self.origin, targetLoc, 1, 0, 0, self, "stop_drawing_line" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_line_until_notify( org1, org2, r, g, b, notifyEnt, notifyString ) { Assert( IsDefined( notifyEnt ) ); Assert( IsDefined( notifyString ) ); notifyEnt endon( notifyString ); while ( 1 ) { draw_line_for_time( org1, org2, r, g, b, 0.05 ); } } /* ============= ///ScriptDocBegin "Name: draw_circle_until_notify(
, , , , , , )" "Summary: Draws a circle at < center > with < radius > in the specified color until < notifyEnt > is notified < notifyString > " "Module: Debug" "CallOn: " "MandatoryArg:
: origin center of the circle" "MandatoryArg: : radius of the circle to draw" "MandatoryArg: : red color value( 0 to 1 )" "MandatoryArg: : green color value( 0 to 1 )" "MandatoryArg: : blue color value( 0 to 1 )" "MandatoryArg: : entity that waits for the notify" "MandatoryArg: : notify string that will make the line stop being drawn" "Example: thread draw_circle_until_notify( self.origin, self.radius, 1, 0, 0, self, "stop_drawing_circle" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ draw_circle_until_notify( center, radius, r, g, b, notifyEnt, notifyString ) { circle_sides = 16; angleFrac = 360 / circle_sides; // Z circle circlepoints = []; for ( i = 0; i < circle_sides; i++ ) { angle = ( angleFrac * i ); xAdd = Cos( angle ) * radius; yAdd = Sin( angle ) * radius; x = center[ 0 ] + xAdd; y = center[ 1 ] + yAdd; z = center[ 2 ]; circlepoints[ circlepoints.size ] = ( x, y, z ); } thread draw_circle_lines_until_notify( circlepoints, r, g, b, notifyEnt, notifyString ); /* // X circle circlepoints = []; for ( i = 0 ; i < circle_sides ; i++ ) { angle = ( angleFrac * i ); xAdd = Cos( angle ) * radius; yAdd = Sin( angle ) * radius; x = center[ 0 ]; y = center[ 1 ] + xAdd; z = center[ 2 ] + yAdd; circlepoints[ circlepoints.size ] = ( x, y, z ); } thread debug_circle_drawlines( circlepoints, 5.0, ( 1, 0, 0 ), center ); // Y circle circlepoints = []; for ( i = 0 ; i < circle_sides ; i++ ) { angle = ( angleFrac * i ); xAdd = Cos( angle ) * radius; yAdd = Sin( angle ) * radius; x = center[ 0 ] + yAdd; y = center[ 1 ]; z = center[ 2 ] + xAdd; circlepoints[ circlepoints.size ] = ( x, y, z ); } thread debug_circle_drawlines( circlepoints, 5.0, ( 1, 0, 0 ), center ); */ } draw_circle_lines_until_notify( circlepoints, r, g, b, notifyEnt, notifyString ) { for ( i = 0; i < circlepoints.size; i++ ) { start = circlepoints[ i ]; if ( i + 1 >= circlepoints.size ) end = circlepoints[ 0 ]; else end = circlepoints[ i + 1 ]; thread draw_line_until_notify( start, end, r, g, b, notifyEnt, notifyString ); } } clear_enemy_passthrough() { self notify( "enemy" ); self ClearEnemy(); } /* ============= ///ScriptDocBegin "Name: battlechatter_off( )" "Summary: Disable battlechatter for the specified team" "Module: Battlechatter" "CallOn: " "MandatoryArg: : team to disable battlechatter on" "Example: battlechatter_off( "allies" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ battlechatter_off( team ) { level notify( "battlechatter_off_thread" ); animscripts\battlechatter::bcs_setup_chatter_toggle_array(); if ( IsDefined( team ) ) { set_battlechatter_variable( team, false ); soldiers = GetAIArray( team ); } else { foreach ( team in anim.teams ) { set_battlechatter_variable( team, false ); } soldiers = GetAIArray(); } if ( !isDefined( anim.chatInitialized ) || !anim.chatInitialized ) return; for ( index = 0; index < soldiers.size; index++ ) soldiers[ index ].battlechatter = false; for ( index = 0; index < soldiers.size; index++ ) { soldier = soldiers[ index ]; if ( !isalive( soldier ) ) continue; if ( !soldier.chatInitialized ) continue; if ( !soldier.isSpeaking ) continue; soldier wait_until_done_speaking(); } speakDiff = GetTime() - anim.lastTeamSpeakTime[ "allies" ]; if ( speakDiff < 1500 ) wait( speakDiff / 1000 ); if ( IsDefined( team ) ) level notify( team + " done speaking" ); else level notify( "done speaking" ); } /* ============= ///ScriptDocBegin "Name: battlechatter_on( )" "Summary: Enable battlechatter for the specified team" "Module: Battlechatter" "CallOn: " "MandatoryArg: : team to enable battlechatter on" "Example: battlechatter_on( "allies" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ battlechatter_on( team ) { thread battlechatter_on_thread( team ); } battlechatter_on_thread( team ) { level endon( "battlechatter_off_thread" ); animscripts\battlechatter::bcs_setup_chatter_toggle_array(); while ( !IsDefined( anim.chatInitialized ) ) { wait( 0.05 ); } flag_set( "battlechatter_on_thread_waiting" ); // buffer time wait( 1.5 ); flag_clear( "battlechatter_on_thread_waiting" ); if ( IsDefined( team ) ) { set_battlechatter_variable( team, true ); soldiers = GetAIArray( team ); } else { foreach ( team in anim.teams ) { set_battlechatter_variable( team, true ); } soldiers = GetAIArray(); } for ( index = 0; index < soldiers.size; index++ ) soldiers[ index ] set_battlechatter( true ); } /* ============= ///ScriptDocBegin "Name: set_battlechatter( )" "Summary: Turns an AI's battlechatter on/off. Will be overridden if a spawner's .script_bcdialog is set to 0." "Module: Battlechatter" "CallOn: An AI" "MandatoryArg: : True/false, describes whether battlechatter should be on or off for this AI" "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_battlechatter( state ) { if ( !anim.chatInitialized ) return; if ( self.type == "dog" ) return; if ( state ) { if ( IsDefined( self.script_bcdialog ) && !self.script_bcdialog ) self.battlechatter = false; else self.battlechatter = true; } else { self.battlechatter = false; if ( IsDefined( self.isSpeaking ) && self.isSpeaking ) self waittill( "done speaking" ); } } /* ============= ///ScriptDocBegin "Name: flavorbursts_on( )" "Summary: Gives all the AIs on a team the ability to play flavor burst transmissions. (Only US allies can use FBTs.) Note: if the battlechatter system is not working, the flavorbursts will not work even if the AIs have this set on them." "Module: Battlechatter" "CallOn: " "OptionalArg: : which team? Usually, only allies have flavorbursts." "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ flavorbursts_on( team ) { thread set_flavorbursts_team_state( true, team ); } /* ============= ///ScriptDocBegin "Name: flavorbursts_off( )" "Summary: Removes the ability to play flavor burst transmissions from all AIs on a team. (Only US allies can use FBTs.)" "Module: Battlechatter" "CallOn: " "OptionalArg: : which team? Usually, only allies have flavorbursts." "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ flavorbursts_off( team ) { thread set_flavorbursts_team_state( false, team ); } set_flavorbursts_team_state( state, team ) { if ( !IsDefined( team ) ) { team = "allies"; } if ( !anim.chatInitialized ) { return; } // buffer time wait( 1.5 ); level._flavorbursts[ team ] = state; guys = []; guys = GetAIArray( team ); array_thread( guys, ::set_flavorbursts, state ); } /* ============= ///ScriptDocBegin "Name: set_flavorbursts( )" "Summary: Turns battlechatter flavor burst transmissions for an AI on or off" "Module: Entity" "CallOn: An AI" "MandatoryArg: " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_flavorbursts( state ) { self.flavorbursts = state; } /* ============= ///ScriptDocBegin "Name: friendlyfire_warnings_off()" "Summary: Disables player-originated friendly fire warnings for all allied AI." "Module: Entity" "SPMP: singleplayer" ///ScriptDocEnd ============= */ friendlyfire_warnings_off() { ais = GetAiArray( "allies" ); foreach( guy in ais ) { if( IsAlive( guy ) ) { guy set_friendlyfire_warnings( false ); } } level._friendlyfire_warnings = false; } /* ============= ///ScriptDocBegin "Name: friendlyfire_warnings_on()" "Summary: Enables player-originated friendly fire warnings for all allied AI." "Module: Entity" "SPMP: singleplayer" ///ScriptDocEnd ============= */ friendlyfire_warnings_on() { ais = GetAiArray( "allies" ); foreach( guy in ais ) { if( IsAlive( guy ) ) { guy set_friendlyfire_warnings( true ); } } level._friendlyfire_warnings = true; } /* ============= ///ScriptDocBegin "Name: set_friendlyfire_warnings( )" "Summary: Turns player-originated friendly fire warnings for an AI on or off" "Module: Entity" "CallOn: An AI" "MandatoryArg: " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_friendlyfire_warnings( state ) { if( state ) { self.friendlyfire_warnings_disable = undefined; } else { self.friendlyfire_warnings_disable = true; } } // // This is for scripted sequence guys that the LD has setup to not // get interrupted in route. // set_friendly_chain_wrapper( node ) { level._player SetFriendlyChain( node ); level notify( "newFriendlyChain", node.script_noteworthy ); } // Newvillers objective management /* level.currentObjective = "obj1";// disables non obj1 friendly chains if you're using newvillers style friendlychains objEvent = get_obj_event( "center_house" );// a trigger with targetname objective_event and a script_deathchain value objEvent waittill_objectiveEvent();// this waits until the AI with the event's script_deathchain are dead, then waits for trigger from the player. If it targets a friendly chain then it'll make the friendlies go to the chain. */ get_obj_origin( msg ) { objOrigins = GetEntArray( "objective", "targetname" ); for ( i = 0; i < objOrigins.size; i++ ) { if ( objOrigins[ i ].script_noteworthy == msg ) return objOrigins[ i ].origin; } } get_obj_event( msg ) { objEvents = GetEntArray( "objective_event", "targetname" ); for ( i = 0; i < objEvents.size; i++ ) { if ( objEvents[ i ].script_noteworthy == msg ) return objEvents[ i ]; } } waittill_objective_event() { waittill_objective_event_proc( true ); } waittill_objective_event_notrigger() { waittill_objective_event_proc( false ); } obj_set_chain_and_enemies() { objChain = GetNode( self.target, "targetname" ); objEnemies = GetEntArray( self.target, "targetname" ); flood_and_secure_scripted( objEnemies ); // array_thread(, ::flood_begin ); level notify( "new_friendly_trigger" ); level._player set_friendly_chain_wrapper( objChain ); } flood_begin() { self notify( "flood_begin" ); } flood_and_secure_scripted( spawners, instantRespawn ) { /* The "scripted" version acts as if it had been player triggered. Spawns AI that run to a spot then get a big goal radius. They stop spawning when auto delete kicks in, then start again when they are retriggered or the player gets close. trigger targetname flood_and_secure ai spawn and run to goal with small goalradius then get large goalradius spawner starts with a notify from any flood_and_secure trigger that triggers it spawner stops when an AI from it is deleted to make space for a new AI or when count is depleted spawners with count of 1 only make 1 guy. Spawners with count of more than 1 only deplete in count when the player kills the AI. spawner can target another spawner. When first spawner's ai dies from death( not deletion ), second spawner activates. */ if ( !isdefined( instantRespawn ) ) instantRespawn = false; if ( !isdefined( level._spawnerWave ) ) level._spawnerWave = []; array_thread( spawners, maps\_spawner::flood_and_secure_spawner, instantRespawn ); for ( i = 0; i < spawners.size; i++ ) { spawners[ i ].playerTriggered = true; spawners[ i ] notify( "flood_begin" ); } } debugorigin() { // self endon( "killanimscript" ); self notify( "Debug origin" ); self endon( "Debug origin" ); self endon( "death" ); for ( ;; ) { forward = AnglesToForward( self.angles ); forwardFar = vector_multiply( forward, 30 ); forwardClose = vector_multiply( forward, 20 ); right = AnglesToRight( self.angles ); left = vector_multiply( right, -10 ); right = vector_multiply( right, 10 ); Line( self.origin, self.origin + forwardFar, ( 0.9, 0.7, 0.6 ), 0.9 ); Line( self.origin + forwardFar, self.origin + forwardClose + right, ( 0.9, 0.7, 0.6 ), 0.9 ); Line( self.origin + forwardFar, self.origin + forwardClose + left, ( 0.9, 0.7, 0.6 ), 0.9 ); wait( 0.05 ); } } /* ============= ///ScriptDocBegin "Name: get_linked_structs()" "Summary: Returns an array of entities that SELF is linked to" "Module: Utility" "CallOn: An entity that links to other entities" "Example: spawners = heli get_linked_structs()" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_linked_structs() { array = []; if ( IsDefined( self.script_linkTo ) ) { linknames = get_links(); for ( i = 0; i < linknames.size; i++ ) { ent = getstruct( linknames[ i ], "script_linkname" ); if ( IsDefined( ent ) ) { array[ array.size ] = ent; } } } return array; } /* ============= ///ScriptDocBegin "Name: get_last_ent_in_chain( )" "Summary: Get the last entity/node/vehiclenode in a chain of targeted entities" "Module: Entity" "CallOn: Any entity that targets a chain of linked nodes, vehiclenodes or other entities like script_origin" "MandatoryArg: : needs to be specified as 'vehiclenode', 'pathnode', 'ent' or 'struct'" "Example: eLastNode = eVehicle get_last_ent_in_chain( "vehiclenode" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_last_ent_in_chain( sEntityType ) { ePathpoint = self; while ( IsDefined( ePathpoint.target ) ) { wait( 0.05 ); if ( IsDefined( ePathpoint.target ) ) { switch( sEntityType ) { case "vehiclenode": ePathpoint = GetVehicleNode( ePathpoint.target, "targetname" ); break; case "pathnode": ePathpoint = GetNode( ePathpoint.target, "targetname" ); break; case "ent": ePathpoint = GetEnt( ePathpoint.target, "targetname" ); break; case "struct": ePathpoint = getstruct( ePathpoint.target, "targetname" ); break; default: AssertMsg( "sEntityType needs to be 'vehiclenode', 'pathnode', 'ent' or 'struct'" ); } } else break; } ePathend = ePathpoint; return ePathend; } player_seek( timeout ) { goalent = Spawn( "script_origin", level._player.origin ); goalent LinkTo( level._player ); if ( IsDefined( timeout ) ) self thread timeout( timeout ); self SetGoalEntity( goalent ); if ( !isdefined( self.oldgoalradius ) ) self.oldgoalradius = self.goalradius; self.goalradius = 300; self waittill_any( "goal", "timeout" ); if ( IsDefined( self.oldgoalradius ) ) { self.goalradius = self.oldgoalradius; self.oldgoalradius = undefined; } goalent Delete(); } timeout( timeout ) { self endon( "death" ); wait( timeout ); self notify( "timeout" ); } /* ============= ///ScriptDocBegin "Name: set_forcegoal( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ set_forcegoal() { if ( IsDefined( self.set_forcedgoal ) ) return; self.oldfightdist = self.pathenemyfightdist; self.oldmaxdist = self.pathenemylookahead; self.oldmaxsight = self.maxsightdistsqrd; self.pathenemyfightdist = 8; self.pathenemylookahead = 8; self.maxsightdistsqrd = 1; self.set_forcedgoal = true; } /* ============= ///ScriptDocBegin "Name: unset_forcegoal( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ unset_forcegoal() { if ( !isdefined( self.set_forcedgoal ) ) return; self.pathenemyfightdist = self.oldfightdist; self.pathenemylookahead = self.oldmaxdist; self.maxsightdistsqrd = self.oldmaxsight; self.set_forcedgoal = undefined; } /* ============= ///ScriptDocBegin "Name: array_add( , )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_add( array, ent ) { array[ array.size ] = ent; return array; } /* ============= ///ScriptDocBegin "Name: array_removeDead_keepkeys( )" "Summary: Remove dead from an array but keep keys intact" "Module: Utility" "CallOn: An array" "MandatoryArg: : The array " "Example: array = array_removeDead_keepkeys( );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_removeDead_keepkeys( array ) { newArray = []; keys = GetArrayKeys( array ); for ( i = 0; i < keys.size; i++ ) { key = keys[ i ]; if ( !isalive( array[ key ] ) ) continue; newArray[ key ] = array[ key ]; } return newArray; } /* ============= ///ScriptDocBegin "Name: array_removeDead( )" "Summary: Returns a new array of < array > minus the dead entities" "Module: Array" "CallOn: " "MandatoryArg: : The array to search for dead entities in." "Example: friendlies = array_removeDead( friendlies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_removeDead( array ) { newArray = []; foreach ( member in array ) { if ( !isalive( member ) ) continue; newArray[ newArray.size ] = member; } return newArray; } /* ============= ///ScriptDocBegin "Name: array_removeDead_or_dying( )" "Summary: Returns a new array of < array > minus the dead or dying ai" "Module: Array" "CallOn: " "MandatoryArg: : The array to search for dead ai in." "Example: friendlies = array_removeDead_or_dying( friendlies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_removeDead_or_dying( array ) { newArray = []; foreach ( member in array ) { if ( !isalive( member ) ) continue; if ( member doingLongDeath() ) continue; newArray[ newArray.size ] = member; } return newArray; } /* ============= ///ScriptDocBegin "Name: array_insert( , , )" "Summary: Returns a new array of < array > plus < object > at the specified index" "Module: Array" "CallOn: " "MandatoryArg: : The array to add to." "MandatoryArg: : The entity to add" "MandatoryArg: : The index position < object > should be added to." "Example: ai = array_insert( ai, spawned, 0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_insert( array, object, index ) { if ( index == array.size ) { temp = array; temp[ temp.size ] = object; return temp; } temp = []; offset = 0; for ( i = 0; i < array.size; i++ ) { if ( i == index ) { temp[ i ] = object; offset = 1; } temp[ i + offset ] = array[ i ]; } return temp; } /* ============= ///ScriptDocBegin "Name: array_remove_nokeys( , )" "Summary: array_remove used on non keyed arrays doesn't flip the array " "Module: Utility" "CallOn: Level" "MandatoryArg: : array to remove from" "MandatoryArg: : thing to remove from the array" "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_remove_nokeys( ents, remover ) { newents = []; for ( i = 0; i < ents.size; i++ ) if ( ents[ i ] != remover ) newents[ newents.size ] = ents[ i ]; return newents; } /* ============= ///ScriptDocBegin "Name: array_remove_index( , )" "Summary: Removes the element in the array with this index, resulting array order is intact." "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_remove_index( array, index ) { for ( i = 0; i < array.size - 1; i++ ) { if ( i == index ) { array[ i ] = array[ i + 1 ]; index++; } } array[ array.size - 1 ] = undefined; return array; } /* ============= ///ScriptDocBegin "Name: array_notify( , )" "Summary: notify this array of entities with " "Module: Array" "CallOn: array of entities" "MandatoryArg: : " "MandatoryArg: : " "Example: array_notify( enemies, "time_to_dance" )" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_notify( ents, notifier, match ) { foreach ( key, value in ents ) value notify( notifier, match ); } // fancy quicker struct array handling, assumes array elements are objects with which an index can be asigned to( IE: can't do 5.struct_array_index ) // also have to be sure that objects can't be a part of another structarray setup as the index position is asigned to the object struct_arrayspawn() { struct = SpawnStruct(); struct.array = []; struct.lastindex = 0; return struct; } /* structarray_add( struct, object ) { struct.array[ struct.lastindex ] = SpawnStruct(); struct.array[ struct.lastindex ].object = object; struct.array[ struct.lastindex ].struct_array_index = struct.lastindex; struct.lastindex ++ ; } */ structarray_add( struct, object ) { Assert( !isdefined( object.struct_array_index ) );// can't have elements of two structarrays on these. can add that later if it's needed struct.array[ struct.lastindex ] = object; object.struct_array_index = struct.lastindex; struct.lastindex++; } /* ============= ///ScriptDocBegin "Name: structarray_remove( , : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ structarray_remove( struct, object ) { structarray_swaptolast( struct, object ); struct.array[ struct.lastindex - 1 ] = undefined; struct.lastindex--; } structarray_remove_index( struct, index ) { // overwrite the index to remove with the last in the array struct.array[ index ] = struct.array[ struct.lastindex - 1 ]; struct.array[ index ].struct_array_index = index; // remove the last from the array since it's now at position 'index' struct.array[ struct.lastindex - 1 ] = undefined; struct.lastindex = struct.array.size; } structarray_remove_undefined( struct ) { // remove undefined ents from array newArray = []; foreach( object in struct.array ) { if ( !isdefined( object ) ) continue; newArray[ newArray.size ] = object; } struct.array = newArray; // reassign all the index vars foreach( i, object in struct.array ) { object.struct_array_index = i; } struct.lastindex = struct.array.size; } structarray_swaptolast( struct, object ) { struct structarray_swap( struct.array[ struct.lastindex - 1 ], object ); } structarray_shuffle( struct, shuffle ) { for ( i = 0; i < shuffle; i++ ) struct structarray_swap( struct.array[ i ], struct.array[ RandomInt( struct.lastindex ) ] ); } // starts this ambient track set_ambient_alias( ambient, alias ) { // change the meaning of this ambience so that the ambience can change over the course of the level level._ambient_modifier[ ambient ] = alias; // if the ambient being aliased is the current ambience then restart it so it gets the new track if ( level._ambient == ambient ) maps\_ambient::activateAmbient( ambient ); } /* ============= ///ScriptDocBegin "Name: get_use_key( )" "Summary: " "Module: Entity" "CallOn: An entity" "MandatoryArg: : " "OptionalArg: : " "Example: " "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_use_key() { if ( level._console ) return " + usereload"; else return " + activate"; } doom() { // send somebody far away then delete them self Teleport( ( 0, 0, -15000 ) ); self Kill( ( 0, 0, 0 ) ); } /* ============= ///ScriptDocBegin "Name: custom_battlechatter( )" "Summary: Call this on an AI to get him to use the battlechatter system to say a specific kind of phrase. AIs who have battlechatter turned off won't be able to say the phrase. Returns false if it couldn't do the custom battlechatter for some reason (will output to console or assert with errors, depending on severity)." "Module: Battlechatter" "CallOn: An AI" "MandatoryArg: : the string ID for the phrase that the AI will try to say. Legit phrases are: "order_move_combat", "order_move_noncombat", "order_action_coverme", "inform_reloading"" "Example: level.sarge custom_battlechatter( "move_combat" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ custom_battlechatter( phrase ) { return self animscripts\battlechatter_ai::custom_battlechatter_internal( phrase ); } /* ============= ///ScriptDocBegin "Name: get_stop_watch(