#include common_scripts\utility; #include maps\_utility_code; /* ============= ///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; visionSetNaked( visionset, transition_time ); } /* ============= ///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 )" "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 ) { self endon("death"); while( !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 ) { self endon("death"); for( ;; ) { 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 ) { self endon("death"); start_time = gettime(); for( ;; ) { if( self.ent_flag[ flagname ] ) break; if( gettime() >= start_time + timer * 1000 ) break; self ent_wait_for_flag_or_time_elapses( flagname, timer ); } } ent_flag_waitopen( msg ) { self endon("death"); while( self.ent_flag[ msg ] ) self waittill( msg ); } ent_flag_assert( msg ) { assertEx( !self ent_flag( msg ), "Flag " + msg + " set too soon on entity at position " + self.origin ); } /* ============= ///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 ) ) assertEx( !isDefined( self.ent_flag[ message ] ), "Attempt to reinitialize existing message: " + message + " on entity at position " + self.origin ); self.ent_flag[ message ] = false; /# self.ent_flags_lock[ message ] = 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 ) { 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 at position " + self.origin ); 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 at position " + self.origin ); 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 ); } } 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( isalive( self ), "Attempt to check a flag on entity that is not alive or removed" ); 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, on entity at position " + self.origin ); if( !self.ent_flag[ message ] ) return false; return true; } ent_flag_init_ai_standards() { message_array = []; message_array[ message_array.size ] = "goal"; message_array[ message_array.size ] = "damage"; for( i = 0; i < message_array.size; i++) { self ent_flag_init( message_array[ i ] ); self thread ent_flag_wait_ai_standards( message_array[ i ] ); } } ent_flag_wait_ai_standards( message ) { /* only runs the first time on the message, so for example if it's waiting on goal, it will only set the goal to true the first time. It also doesn't call ent_set_flag() because that would notify the message possibly twice in the same frame, or worse in the next frame. */ self endon("death"); self waittill( message ); self.ent_flag[ message ] = true; } /* ============= ///ScriptDocBegin "Name: flag_wait_either( , )" "Summary: Waits until either of the the specified flags are set." "Module: Flag" "CallOn: " "MandatoryArg: : name of one flag to wait on" "MandatoryArg: : name of the other flag to wait on" "Example: flag_wait( "hq_cleared", "hq_destroyed" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_wait_either( flag1, flag2 ) { for( ;; ) { if( flag( flag1 ) ) return; if( flag( flag2 ) ) return; level waittill_either( flag1, flag2 ); } } /* ============= ///ScriptDocBegin "Name: flag_wait_any( , , , )" "Summary: Waits until any of the the specified flags are set." "Module: Flag" "CallOn: " "MandatoryArg: : name of a flag to wait on" "MandatoryArg: : name of a flag to wait on" "OptionalArg: : name of a flag to wait on" "OptionalArg: : name of a flag to wait on" "Example: flag_wait_any( "hq_cleared", "hq_destroyed", "hq_overrun", "hq_skipped" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_wait_any( flag1, flag2, flag3, flag4 ) { array = []; if( isdefined( flag4 ) ) { array[ array.size ] = flag1; array[ array.size ] = flag2; array[ array.size ] = flag3; array[ array.size ] = flag4; } else if( isdefined( flag3 ) ) { array[ array.size ] = flag1; array[ array.size ] = flag2; array[ array.size ] = flag3; } else if( isdefined( flag2 ) ) { flag_wait_either( flag1, flag2 ); return; } else { assertmsg( "flag_wait_any() needs at least 2 flags passed to it" ); return; } for( ;; ) { for(i=0; i , , , )" "Summary: Waits until all of the the specified flags are set." "Module: Flag" "CallOn: " "MandatoryArg: : name of a flag to wait on" "MandatoryArg: : name of a flag to wait on" "OptionalArg: : name of a flag to wait on" "OptionalArg: : name of a flag to wait on" "Example: flag_wait_any( "hq_cleared", "hq_destroyed", "hq_overrun", "hq_skipped" );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_wait_all( flag1, flag2, flag3, flag4 ) { if( isdefined( flag1 ) ) flag_wait( flag1 ); if( isdefined( flag2 ) ) flag_wait( flag2 ); if( isdefined( flag3 ) ) flag_wait( flag3 ); if( isdefined( flag4 ) ) flag_wait( flag4 ); } /* ============= ///ScriptDocBegin "Name: flag_wait_or_timeout( , )" "Summary: Waits until either the flag gets set or the timer elapses." "Module: Flag" "CallOn: " "MandatoryArg: : Amount of time to wait before continuing regardless of flag." "Example: flag_wait_or_timeout( "time_to_go", 3 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_wait_or_timeout( flagname, timer ) { start_time = gettime(); for( ;; ) { if( level.flag[ flagname ] ) break; if( gettime() >= start_time + timer * 1000 ) break; wait_for_flag_or_time_elapses( flagname, timer ); } } /* ============= ///ScriptDocBegin "Name: flag_waitopen_or_timeout( , )" "Summary: Waits until either the flag gets cleared or the timer elapses." "Module: Flag" "CallOn: " "MandatoryArg: : Amount of time to wait before continuing regardless of flag." "Example: flag_waitopen_or_timeout( "time_to_go", 3 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ flag_waitopen_or_timeout( flagname, timer ) { start_time = gettime(); for( ;; ) { if( !level.flag[ flagname ] ) break; if( gettime() >= start_time + timer * 1000 ) break; wait_for_flag_or_time_elapses( flagname, timer ); } } 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; } flag_assert( msg ) { assertEx( !flag( msg ), "Flag " + msg + " set too soon!" ); } /* ============= ///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 ); } 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; if( !isAlive( level.player ) ) return; flag_set( "game_saving" ); imagename = "levelshots / autosave / autosave_" + level.script + "end"; saveGame( "levelend", &"AUTOSAVE_AUTOSAVE", imagename, true ); // does not print "Checkpoint Reached" flag_clear( "game_saving" ); } /* ============= ///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 ); } autosave_by_name_thread( name, timeout ) { 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 ); 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 ); } error( message ) { println( "^c * ERROR * ", message ); wait 0.05; /# if( getDebugDvar( "debug" ) != "1" ) assertMsg( "This is a forced error - attach the log file" ); #/ } /* ============= ///ScriptDocBegin "Name: array_levelthread( , , , , )" "Summary: Threads the < process > function for every entity in the < entities > array. The level calls the function and each entity of the array is passed as the first parameter to the process." "Module: Array" "CallOn: " "MandatoryArg: : array of entities to thread the process" "MandatoryArg: : pointer to a script function" "OptionalArg: : parameter 1 to pass to the process" "OptionalArg: : parameter 2 to pass to the process" "OptionalArg: : parameter 3 to pass to the process" "Example: array_levelthread( getentarray( "palm", "targetname" ), ::palmTrees );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ array_levelthread( array, process, var1, var2, var3 ) { keys = getArrayKeys( array ); if( isdefined( var3 ) ) { for( i = 0 ; i < keys.size ; i ++ ) thread [[ process ]]( array[ keys[ i ] ], var1, var2, var3 ); return; } if( isdefined( var2 ) ) { for( i = 0 ; i < keys.size ; i ++ ) thread [[ process ]]( array[ keys[ i ] ], var1, var2 ); return; } if( isdefined( var1 ) ) { for( i = 0 ; i < keys.size ; i ++ ) thread [[ process ]]( array[ keys[ i ] ], var1 ); return; } for( i = 0 ; i < keys.size ; i ++ ) thread [[ process ]]( array[ keys[ i ] ] ); } /* ============= ///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." "Example: debug_message( "I am the enemy", enemy.origin, 3.0 );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ debug_message( message, origin, duration ) { 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; } } /* ============= ///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(); } /* ============= ///ScriptDocBegin "Name: add_to_array( , )" "Summary: Adds < ent > to < array > and returns the new array." "Module: Array" "CallOn: " "MandatoryArg: : The array to add < ent > to." "MandatoryArg: : The entity to be added." "Example: nodes = add_to_array( nodes, new_node );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ add_to_array( array, ent ) { if( !isdefined( ent ) ) return array; if( !isdefined( array ) ) array[ 0 ] = ent; else array[ array.size ] = ent; return array; } 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, dist ) { return compareSizes( org, array, dist, ::closerFunc ); } /* ============= ///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: 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, dist ) { return compareSizes( org, array, dist, ::fartherFunc ); } compareSizesFx( org, array, dist, compareFunc ) { if( !array.size ) return undefined; if( isdefined( dist ) ) { struct = undefined; keys = getArrayKeys( array ); for( i = 0; i < keys.size; i ++ ) { newdist = distance( array[ keys[ i ] ].v[ "origin" ], org ); if( [[ compareFunc ]]( newDist, dist ) ) continue; dist = newdist; struct = array[ keys[ i ] ]; } return struct; } keys = getArrayKeys( array ); struct = array[ keys[ 0 ] ]; dist = distance( struct.v[ "origin" ], org ); for( i = 1; i < keys.size; i ++ ) { newdist = distance( array[ keys[ i ] ].v[ "origin" ], org ); if( [[ compareFunc ]]( newDist, dist ) ) continue; dist = newdist; struct = array[ keys[ i ] ]; } return struct; } compareSizes( org, array, dist, compareFunc ) { if( !array.size ) return undefined; if( isdefined( dist ) ) { ent = undefined; keys = getArrayKeys( array ); for( i = 0; i < keys.size; i ++ ) { newdist = distance( array[ keys[ i ] ].origin, org ); if( [[ compareFunc ]]( newDist, dist ) ) continue; dist = newdist; ent = array[ keys[ i ] ]; } return ent; } keys = getArrayKeys( array ); ent = array[ keys[ 0 ] ]; dist = distance( ent.origin, org ); for( i = 1; i < keys.size; i ++ ) { newdist = distance( array[ keys[ i ] ].origin, org ); if( [[ compareFunc ]]( newDist, dist ) ) continue; dist = newdist; ent = array[ keys[ i ] ]; } return ent; } /* ============= ///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_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_outisde_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; } get_highest_dot( start, end, array ) { if( !array.size ) return; ent = undefined; angles = vectorToAngles( end - start ); dotforward = anglesToForward( angles ); dot = -1; for( i = 0;i < array.size;i ++ ) { angles = vectorToAngles( array[ i ].origin - start ); forward = anglesToForward( angles ); newdot = vectordot( dotforward, forward ); if( newdot < dot ) continue; dot = newdot; ent = array[ i ]; } 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; for( i = 0;i < array.size;i ++ ) { newdist = distance( array[ i ].origin, org ); if( newdist >= dist ) continue; dist = newdist; index = i; } return index; } 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_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 ) { if( isdefined( team ) ) ents = getaiarray( team ); else ents = getaiarray(); if( ents.size == 0 ) return undefined; return getClosest( org, ents ); } /* ============= ///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" "Example: allies_sort = get_array_of_closest( originFC1.origin, allies );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ get_array_of_closest( org, array, excluders, max, maxdist ) { // 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 = []; maxdists2rd = undefined; if( isdefined( maxdist ) ) maxdists2rd = maxdist * maxdist; // return the array, reordered from closest to farthest dist = []; index = []; for( i = 0;i < array.size;i ++ ) { excluded = false; for( p = 0;p < excluders.size;p ++ ) { if( array[ i ] != excluders[ p ] ) continue; excluded = true; break; } if( excluded ) continue; length = distancesquared( org, array[ i ].origin ); if( isdefined( maxdists2rd ) && maxdists2rd < length ) continue; dist[ dist.size ] = length; index[ index.size ] = i; } for( ;; ) { change = false; for( i = 0;i < dist.size - 1;i ++ ) { if( dist[ i ] <= dist[ i + 1 ] ) continue; change = true; temp = dist[ i ]; dist[ i ] = dist[ i + 1 ]; dist[ i + 1 ] = temp; temp = index[ i ]; index[ i ] = index[ i + 1 ]; index[ i + 1 ] = temp; } if( !change ) break; } newArray = []; if( max > dist.size ) max = dist.size; for( i = 0;i < max;i ++ ) newArray[ i ] = array[ index[ i ] ]; return newArray; } 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: 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 ( self.health > self.mbs_oldhealth ) { // the designer may have intentionally set the guys health lower, so don't overwrite it. self.health = self.mbs_oldhealth; } self.a.nextStandingHitDying = self.mbs_anim_nextStandingHitDying; self.attackerAccuracy = 1; self.mbs_oldhealth = undefined; self.mbs_anim_nextStandingHitDying = undefined; self.magic_bullet_shield = undefined; 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; 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." ); } /* ============= ///ScriptDocBegin "Name: magic_bullet_shield( ,