#include common_scripts\utility; #include maps\_utility; #include maps\_anim; #include maps\_stealth_utility; /************************************************************************************************************/ /* SYSTEM UTILITIES */ /************************************************************************************************************/ //called by _stealth_accuracy_friendly //called by _stealth_behavior_enemy //called by _stealth_behavior_friendly //called by _stealth_color_friendly ai_message_handler_spotted( function, plugin_override ) { self endon( "death" ); assertex( isdefined( plugin_override ), "plugin_override required, modify plugin script -z" ); plugin_override = plugin_override + "spotted"; self notify( plugin_override ); self endon( plugin_override ); switch( self.team ) { case "allies": while ( 1 ) { self ent_flag_wait( "_stealth_enabled" ); self flag_wait( "_stealth_spotted" ); if ( !self ent_flag( "_stealth_enabled" ) ) continue; self thread [[ function ]](); self flag_waitopen( "_stealth_spotted" ); } break; case "axis": case "team3": while ( 1 ) { self ent_flag_wait( "_stealth_enabled" ); self stealth_group_spotted_flag_wait(); if ( !self ent_flag( "_stealth_enabled" ) ) continue; self thread [[ function ]](); self stealth_group_spotted_flag_waitopen(); } break; } } //called by _stealth_accuracy_friendly //called by _stealth_behavior_enemy //called by _stealth_behavior_friendly //called by _stealth_color_friendly ai_message_handler_hidden( function, plugin_override ) { self endon( "death" ); assertex( isdefined( plugin_override ), "plugin_override required, modify plugin script -z" ); plugin_override = plugin_override + "hidden"; self notify( plugin_override ); self endon( plugin_override ); switch( self.team ) { case "allies": while ( 1 ) { self ent_flag_wait( "_stealth_enabled" ); self flag_waitopen( "_stealth_spotted" ); if ( !self ent_flag( "_stealth_enabled" ) ) continue; self thread [[ function ]](); self flag_wait( "_stealth_spotted" ); } break; case "axis": case "team3": while ( 1 ) { self ent_flag_wait( "_stealth_enabled" ); self stealth_group_spotted_flag_waitopen(); if ( !self ent_flag( "_stealth_enabled" ) ) continue; self thread [[ function ]](); self stealth_group_spotted_flag_wait(); } break; } } /* ============= ///ScriptDocBegin "Name: ai_create_behavior_function( , , )" "Summary: sets up a behavior function that an AI using the stealth system will call in a specific situation, by putting an entry in the AI's ._stealth.behavior.ai_functions array." "Module: Entity" "MandatoryArg: : the general category, for example, 'threat', 'animation', or 'event' (among others)." "MandatoryArg: : the specific subcategory, for example, 'heard_scream' or 'reset' (among others)." "MandatoryArg: : the function to run when the stealth script looks for this behavior function." "Example: ai_create_behavior_function( "threat", "reset", ::cliffhanger_enemy_alert_level_reset );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ai_create_behavior_function( name, key, function ) { self._stealth.behavior.ai_functions[ name ][ key ] = function; } // used internally by the stealth system ai_get_behavior_function( name, key ) { return self._stealth.behavior.ai_functions[ name ][ key ]; } /* ============= ///ScriptDocBegin "Name: ai_set_goback_override_function( )" "Summary: sets up an "event" behavior function that an AI using the stealth system will call in a specific situation, by putting an entry in the AI's ._stealth.behavior.ai_functions[ "event" ] array. This function will be called between the AI forgetting about the threat, and the AI heading back to where he was patrolling previously." "Module: Entity" "MandatoryArg: : the function to run when the AI forgets about an event, before he heads back to his previous patrol spot." "Example: ai_create_event_goback_override_function( ::cliffhanger_enemy_alert_level_reset );" "SPMP: singleplayer" ///ScriptDocEnd ============= */ ai_set_goback_override_function( function ) { self._stealth.behavior.goback_startFunc = function; } stealth_event_validate( key ) { if ( key == "heard_scream" || key == "doFlashBanged" || key == "explode" ) { return true; } ASSERTMSG( "valid values for stealth events are 'heard_scream', 'doFlashBanged', and 'explode'. you tried: " + key ); return false; } stealth_debug_print( msg ) { /# if ( !flag( "_stealth_enabled" ) ) return; type = undefined; name = undefined; if ( isdefined( self.script_noteworthy ) ) { type = "Script_noteworthy"; name = self.script_noteworthy; } else if ( isdefined( self.targetname ) ) { type = "Targetname"; name = self.targetname; } actor = "Actor -> ID: " + self.unique_id + " Export: " + self.export; if ( isdefined( type ) ) { actor += " " + type + ": " + name; } txt = "STEALTH DEBUG PRINT: " + actor + "\n " + msg; println( txt ); if ( getdvarint( "stealth_debug_prints" ) == 1 ) self thread debug_message_ai( msg ); #/ } enemy_event_debug_print( type ) { setDvarIfUninitialized( "stealth_debug_prints", "0" ); if ( !isdefined( getdvar( "stealth_debug_prints" ) ) ) setdvar( "stealth_debug_prints", "0" ); if ( getdvarint( "stealth_debug_prints" ) != 1 ) return; /# self endon( "death" ); self waittill( type, subtype ); if ( isdefined( subtype ) ) self stealth_debug_print( "Received an event: " + type + " " + subtype ); else self stealth_debug_print( "Received an event: " + type ); #/ } stealth_flag_debug_print( _flag ) { /# while ( 1 ) { flag_wait( _flag ); { if ( getdvarint( "stealth_debug_prints" ) == 1 ) iprintlnbold( _flag ); else println( _flag ); } flag_waitopen( _flag ); { if ( getdvarint( "stealth_debug_prints" ) == 1 ) iprintlnbold( "back to normal: " + _flag ); else println( "back to normal: " + _flag ); } } #/ } group_flag_init( _flag ) { assertex( issentient( self ), "an AI must call this function" ); if ( isdefined( self.script_stealthgroup ) ) self.script_stealthgroup = string( self.script_stealthgroup ); else self.script_stealthgroup = "default"; name = self group_get_flagname( _flag ); if ( !flag_exist( name ) ) { flag_init( name ); if ( !isdefined( level._stealth.group.flags[ _flag ] ) ) level._stealth.group.flags[ _flag ] = []; size = level._stealth.group.flags[ _flag ].size; level._stealth.group.flags[ _flag ][ size ] = name; } } group_add_to_global_list() { assertex( issentient( self ), "an AI must call this function" ); if ( !isdefined( level._stealth.group.groups[ self.script_stealthgroup ] ) ) { level._stealth.group.groups[ self.script_stealthgroup ] = []; level._stealth.group notify( self.script_stealthgroup ); } size = level._stealth.group.groups[ self.script_stealthgroup ].size; level._stealth.group.groups[ self.script_stealthgroup ][ size ] = self; } group_get_flagname( _flag ) { assertex( issentient( self ), "an AI must call this function" ); return group_get_flagname_from_group( _flag, self.script_stealthgroup ); } group_get_flagname_from_group( _flag, group ) { name = _flag + "-Group:" + group; return name; } group_flag_set( _flag ) { assertex( issentient( self ), "an AI must call this function" ); name = self group_get_flagname( _flag ); flag_set( name ); flag_set( _flag ); } group_return_groups_with_flag_set( _flag ) { return_value = []; array = level._stealth.group.groups; foreach ( key, value in array ) { name = group_get_flagname_from_group( _flag, key ); if ( flag( name ) ) return_value[ return_value.size ] = key; } return return_value; } group_return_ai_with_flag_set( _flag ) { return_value = []; array = level._stealth.group.groups; foreach ( key, value in array ) { name = group_get_flagname_from_group( _flag, key ); if ( flag( name ) ) { ai = group_get_ai_in_group( key ); return_value = array_merge( return_value, ai ); } } return return_value; } group_flag_clear( _flag, group ) { name = group_get_flagname_from_group( _flag, group ); flag_clear( name ); array = level._stealth.group.flags[ _flag ]; clear = true; foreach ( key, value in array ) { if ( flag( value ) ) return; } flag_clear( _flag ); } group_get_ai_in_group( group_name ) { level._stealth.group.groups[ group_name ] = array_removeDead( level._stealth.group.groups[ group_name ] ); return level._stealth.group.groups[ group_name ]; } group_wait_group_spawned( group_name ) { if ( !isdefined( level._stealth.group.groups[ group_name ] ) ) level._stealth.group waittill( group_name ); } /************************************************************************************************************/ /* BEHAVIOR UTILITIES */ /************************************************************************************************************/ ai_stealth_pause_handler() { self endon( "death" ); self endon( "pain_death" ); while ( 1 ) { self ent_flag_waitopen( "_stealth_enabled" ); spotted_func = self._stealth.behavior.ai_functions[ "state" ][ "spotted" ]; switch( self.team ) { case "allies": self [[ spotted_func ]](); break; case "axis": case "team3": self [[ spotted_func ]]( true ); break; } self ent_flag_wait( "_stealth_enabled" ); hidden_func = self._stealth.behavior.ai_functions[ "state" ][ "hidden" ]; self [[ hidden_func ]](); } } enemy_go_back() { self notify( "going_back" ); self endon( "death" ); self notify( "stop_loop" ); if( IsDefined( self._stealth.behavior.goback_startFunc ) ) { self [[ self._stealth.behavior.goback_startFunc ]](); } spot = self._stealth.behavior.last_spot; if ( isdefined( spot ) && self.type != "dog" && !isdefined( self.customMoveTransition ) ) self.customMoveTransition = maps\_patrol::patrol_resume_move_start_func; // stop before moving if ( isdefined( self.customMoveTransition ) && isdefined( self.pathGoalPos ) ) { self setgoalpos( self.origin ); wait 0.05; } if ( isdefined( self.script_patroller ) ) { if ( isdefined( self.last_patrol_goal ) ) { self.target = self.last_patrol_goal.targetname; } //these guys on the ridge in cliffhanger get alerted and jump down a one way traverse. this gives them a pathable patrol path to go back to. if ( isdefined( self.stealth_first_alert_new_patrol_path ) ) { self.target = self.stealth_first_alert_new_patrol_path.targetname; self.stealth_first_alert_new_patrol_path = undefined; } self thread maps\_patrol::patrol(); } else if ( isalive( self.patrol_master ) ) { self thread maps\_patrol::pet_patrol(); self set_dog_walk_anim(); self.script_growl = undefined; } else if ( isdefined( spot ) ) { if ( self.type != "dog" ) self set_generic_run_anim( "_stealth_patrol_cqb", true ); else { self set_dog_walk_anim(); self.script_growl = undefined; } self.disablearrivals = true; self.disableexits = true; self setgoalpos( spot ); self.goalradius = 40; } //make sure the AI has been given a new goal before clearing this flag waittillframeend; self ent_flag_clear( "_stealth_override_goalpos" ); if ( isdefined( spot ) ) self thread enemy_go_back_clear_lastspot( spot ); } enemy_go_back_clear_lastspot( origin ) { self endon( "death" ); self endon( "_stealth_enemy_alert_level_change" ); self waittill_true_goal( origin ); self._stealth.behavior.last_spot = undefined; } // caches result of search enemy_get_nearby_pathnodes( origin, radius, min_radius ) { if ( !isdefined( min_radius ) ) min_radius = 0; if ( isdefined( level._stealth.node_search.nodes_array ) && distanceSquared( origin, level._stealth.node_search.origin ) < 64 * 64 && radius == level._stealth.node_search.radius && min_radius == level._stealth.node_search.min_radius ) return level._stealth.node_search.nodes_array; level._stealth.node_search.origin = origin; level._stealth.node_search.radius = radius; level._stealth.node_search.min_radius = min_radius; level._stealth.node_search.nodes_array = getNodesInRadius( origin, radius, min_radius, 512, "Path" ); return level._stealth.node_search.nodes_array; } // this is called by some functions like finding a corpse or // hearing an explosion that go into alert - but dont want to put into alert // state because alert state shares it's behavior with a guy simply // thinkgin he saw something twice enemy_reaction_state_alert() { self.fovcosine = .01;// 90 degrees to either side...180 cone...default view cone self.ignoreall = false; self.dieQuietly = false; self clear_run_anim(); self.fixednode = false; } enemy_alert_level_forget( enemy, delay ) { self endon( "death" ); enemy endon( "death" ); if ( !isdefined( delay ) ) delay = 60; //after 60 seconds - forget about it wait delay; if ( isdefined( enemy._stealth.logic.spotted_list[ self.unique_id ] ) && enemy._stealth.logic.spotted_list[ self.unique_id ] > 0 ) enemy._stealth.logic.spotted_list[ self.unique_id ] -- ; } enemy_stop_current_behavior() { if ( !self ent_flag( "_stealth_behavior_reaction_anim" ) ) { self anim_stopanimscripted(); self notify( "stop_animmode" ); self notify( "stop_loop" ); } if ( isdefined( self.script_patroller ) ) { if ( isdefined( self.last_patrol_goal ) ) self.last_patrol_goal.patrol_claimed = undefined; self notify( "release_node" ); self notify( "end_patrol" ); } self notify( "stop_first_frame" ); self clear_run_anim(); self clear_generic_idle_anim(); } enemy_find_original_goal() { //if we already have an original goal - stick to it if ( isdefined( self._stealth.behavior.last_spot ) ) return; if ( isdefined( self.last_set_goalnode ) ) self._stealth.behavior.last_spot = self.last_set_goalnode.origin; else if ( isdefined( self.last_set_goalent ) ) self._stealth.behavior.last_spot = self.last_set_goalent.origin; else if ( isdefined( self.last_set_goalpos ) ) self._stealth.behavior.last_spot = self.last_set_goalpos; else self._stealth.behavior.last_spot = self.origin; } enemy_set_original_goal( origin ) { self._stealth.behavior.last_spot = origin; } enemy_runto_and_lookaround( node, position ) { self notify( "enemy_runto_and_lookaround" ); self endon( "enemy_runto_and_lookaround" ); self endon( "death" ); self endon( "_stealth_enemy_alert_level_change" ); if ( self.type != "dog" ) self endon( "_stealth_saw_corpse" ); spotted_flag = self group_get_flagname( "_stealth_spotted" ); level endon( spotted_flag ); //this is for guys who are already DOING this, and need to do it again self notify( "stop_loop" ); self ent_flag_set( "_stealth_override_goalpos" ); if ( isdefined( node ) ) { self setgoalnode( node ); } else { assertex( isdefined( position ), "no node or position defined" ); self setgoalpos( position ); } self.goalradius = 64; self waittill( "goal" ); if ( self.type != "dog" ) self set_generic_idle_anim( "_stealth_look_around" ); } enemy_find_free_pathnode_near( origin, radius, min_radius ) { array = enemy_get_nearby_pathnodes( origin, radius, min_radius ); if ( !isdefined( array ) || array.size == 0 ) return; node = array[ randomInt( array.size ) ]; array = array_remove( array, node ); while ( isdefined( node.owner ) ) { if ( array.size == 0 ) return; node = array[ randomInt( array.size ) ]; array = array_remove( array, node ); } level._stealth.node_search.nodes_array = array; return node; } /************************************************************************************************************/ /* ANNOUCEMENTS */ /************************************************************************************************************/ enemy_announce_wtf() { if ( self.type == "dog" ) return; if ( !( self enemy_announce_snd( "wtf" ) ) ) return; alias = "stealth_" + self.npcID + "_anexplosion"; self playsound( alias ); } // Who's there? enemy_announce_huh() { if ( self.type == "dog" ) return; if ( !( self enemy_announce_snd( "huh" ) ) ) return; alias = "stealth_" + self.npcID + "_huh"; self playsound( alias ); } // Didn't find anything, going back to patrol enemy_announce_hmph() { if ( self.type == "dog" ) return; if ( !( self enemy_announce_snd( "hmph" ) ) ) return; alias = "stealth_" + self.npcID + "_hmph"; self playsound( alias ); } enemy_announce_attack() { self endon( "death" ); self endon( "pain_death" );// don't actually want to be able to still call out to buddies - it kinda sucks to take him down and still lose if ( self.type == "dog" ) return; if ( !( self enemy_announce_snd( "spotted" ) ) ) return; self playsound( "RU_" + self.npcID + "_stealth_alert" ); } enemy_announce_spotted( pos ) { self endon( "death" ); self endon( "pain_death" );// don't actually want to be able to still call out to buddies - it kinda sucks to take him down and still lose // this makes sure that if we're not spotted because we killed // this guy before he could set the flag - we dont' bring // everyone over for no reason. self stealth_group_spotted_flag_wait(); if ( self.type == "dog" ) return; if ( self enemy_announce_snd( "spotted" ) ) { self thread enemy_announce_spotted_bring_group( pos ); alias = "RU_" + self.npcID + "_stealth_alert"; self playsound( alias ); } if ( self enemy_announce_snd( "acknowledge" ) ) self thread enemy_announce_spotted_acknowledge( self.origin ); } enemy_announce_spotted_acknowledge( spotterPos ) { wait 1.5; if ( isdefined( self.npcID ) ) num = self.npcID; else num = randomint( 3 ); alias = "RU_" + num + "_stealth_alert_r"; play_sound_in_space( alias, spotterPos ); } enemy_announce_spotted_bring_group( pos ) { group = group_get_ai_in_group( self.script_stealthgroup ); foreach ( key, ai in group ) { if ( ai == self ) continue; if ( isdefined( ai.enemy ) || isdefined( ai.favoriteenemy ) ) continue; ai notify( "heard_scream", pos ); } } enemy_announce_corpse() { self endon( "death" ); if ( isdefined( self.found_corpse_wait ) ) wait( self.found_corpse_wait ); if ( !( self enemy_announce_snd( "corpse" ) ) ) return; if ( self.type == "dog" ) { self ent_flag_waitopen( "_stealth_behavior_reaction_anim_in_progress" ); self notify( "event_awareness", "howl" ); return; } alias = "stealth_" + self.npcID + "_deadbody"; self playsound( alias ); } /************************************************************************************************************/ /* ANNOUCEMENT UTILITIES */ /************************************************************************************************************/ enemy_announce_snd( type ) { if ( type == "spotted" ) { if ( level._stealth.behavior.sound[ type ][ self.script_stealthgroup ] ) return false; level._stealth.behavior.sound[ type ][ self.script_stealthgroup ] = true; } else { if ( level._stealth.behavior.sound[ type ] ) return false; level._stealth.behavior.sound[ type ] = true; self thread enemy_announce_snd_reset( type ); } return true; } enemy_announce_snd_reset( type ) { wait level._stealth.behavior.sound_reset_time; level._stealth.behavior.sound[ type ] = false; } /************************************************************************************************************/ /* ANIMATION SYSTEM */ /************************************************************************************************************/ enemy_animation_wrapper( type ) { self endon( "death" ); self endon( "pain_death" ); // ALWAYS RUN THIS UNLESS YOU'RE SURE YOU KNOW WHAT YOU"RE DOING if ( self enemy_animation_pre_anim( type ) ) return; self enemy_animation_do_anim( type ); // ALWAYS RUN THIS UNLESS YOU'RE SURE YOU KNOW WHAT YOU"RE DOING self enemy_animation_post_anim( type ); } enemy_animation_do_anim( type ) { if ( isdefined( self._stealth.behavior.event.custom_animation ) ) { self enemy_animation_custom( type ); return; } // do default behavior function = self._stealth.behavior.ai_functions[ "animation" ][ type ]; self [[ function ]]( type ); } enemy_animation_custom( type ) { node = self._stealth.behavior.event.custom_animation.node; anime = self._stealth.behavior.event.custom_animation.anime; tag = self._stealth.behavior.event.custom_animation.tag; ender = self._stealth.behavior.event.custom_animation.ender; self ent_flag_set( "_stealth_behavior_reaction_anim" ); // wouldn't normally do this - but since this is specific to stealth script // i figured it would be ok to set allowdeath. self.allowdeath = true; // cut the loop node notify( ender ); if ( isdefined( self.anim_props ) ) { self.anim_props_animated = true; node thread anim_single( self.anim_props, anime ); } if ( type != "doFlashBanged" ) { // this is the reaction if ( isdefined( tag ) || isdefined( self.has_delta ) ) node anim_generic( self, anime, tag ); else node anim_generic_custom_animmode( self, "gravity", anime ); } // once you the the reaction once - you dont wanna ever do it again...especially not off this node self ai_clear_custom_animation_reaction(); } enemy_animation_pre_anim( type ) { self notify( "enemy_awareness_reaction", type ); // this means that something really bad happened...a first reaction // to the player being spotted or something equally bad like a bullet // whizby if ( self ent_flag( "_stealth_behavior_first_reaction" ) || self ent_flag( "_stealth_behavior_reaction_anim_in_progress" ) ) return true; // this function doesn't stop behavior if _stealth_behavior_reaction_anim // is set - because stoping behavior means ending current animations // and since reacting is an animation - we want to set the flag // AFTER we've stopped the current ones self enemy_stop_current_behavior(); if ( issubstr( type, "warning" ) ) type = "warning"; switch( type ) { case "explode": case "heard_corpse": case "saw_corpse": case "found_corpse": // all the cases above this dont break - so they all will do the same thing when they get to this line self ent_flag_set( "_stealth_behavior_reaction_anim" ); break; case "reset": case "warning": // all the cases above this dont break - so they all will do the same thing when they get to this line // which is absolutely nothing break; default: if ( !self ent_flag_exist( "_stealth_behavior_asleep" ) || !self ent_flag( "_stealth_behavior_asleep" ) || self stealth_group_spotted_flag() ) { self ent_flag_set( "_stealth_behavior_first_reaction" ); self thread enemy_animation_pre_anim_dog_special_first_condition(); } self ent_flag_set( "_stealth_behavior_reaction_anim" ); break; } self ent_flag_set( "_stealth_behavior_reaction_anim_in_progress" ); return false; } enemy_animation_pre_anim_dog_special_first_condition() { spotted_flag = self group_get_flagname( "_stealth_spotted" ); self endon( "death" ); flag_wait_or_timeout( spotted_flag, 3 ); if ( flag( spotted_flag ) ) self ent_flag_set( "_stealth_behavior_first_reaction" ); } enemy_animation_post_anim( type ) { switch( type ) { default: self ent_flag_clear( "_stealth_behavior_reaction_anim" ); break; } self ent_flag_clear( "_stealth_behavior_reaction_anim_in_progress" ); } /************************************************************************************************************/ /* ANIMATION UTILITIES */ /************************************************************************************************************/ ai_clear_custom_animation_reaction() { self._stealth.behavior.event.custom_animation = undefined; self.newEnemyReactionDistSq = squared( 512 ); } ai_clear_custom_animation_reaction_and_idle( waitanimend ) { // could have been cleared by something else if ( !isdefined( self._stealth.behavior.event.custom_animation ) ) return; self._stealth.behavior.event.custom_animation.node notify( "stop_loop" ); if ( !isdefined( waitanimend ) || waitanimend == false ) self stopanimscripted(); self ai_clear_custom_animation_reaction(); } ai_set_custom_animation_reaction( node, anime, tag, ender ) { self._stealth.behavior.event.custom_animation = spawnstruct(); self._stealth.behavior.event.custom_animation.node = node; self._stealth.behavior.event.custom_animation.anime = anime; self._stealth.behavior.event.custom_animation.tag = tag; self._stealth.behavior.event.custom_animation.ender = ender; self thread ai_animate_props_on_death( node, anime, tag, ender ); self.newEnemyReactionDistSq = 0; } ai_animate_props_on_death( node, anime, tag, ender ) { wait .1; if ( !isdefined( self.anim_props ) ) return; prop = self.anim_props; self waittill( "death" ); if ( isdefined( self.anim_props_animated ) ) return; node thread anim_single( prop, anime ); } /************************************************************************************************************/ /* EVENT AWARENESS */ /************************************************************************************************************/ event_awareness_main( dialogue_array, ender_array ) { level notify( "event_awareness_handler" ); level endon( "event_awareness_handler" ); level endon( "default_event_awareness_enders" ); event_awareness_enders( ender_array ); add_wait( ::waittill_msg, "event_awareness_handler" ); add_wait( ::waittill_msg, "default_event_awareness_enders" ); add_func( ::flag_clear, "_stealth_event" ); thread do_wait_any(); while ( 1 ) { flag_wait( "_stealth_enabled" ); flag_wait( "_stealth_event" ); if ( !flag( "_stealth_enabled" ) ) continue; wait 2; event_awareness_dialogue_wrapper( dialogue_array ); flag_waitopen( "_stealth_event" ); } } event_awareness_dialogue_wrapper( array ) { wait randomfloatrange( .5, 1 ); if ( !isdefined( array ) ) return; string = random( array ); level thread function_stack( ::radio_dialogue, string ); } event_awareness_enders( ender_array ) { level endon( "default_event_awareness_enders" ); level endon( "event_awareness_handler" ); if ( isdefined( ender_array ) ) { foreach ( string in ender_array ) { if ( flag_exist( string ) && flag( string ) ) level notify( "default_event_awareness_enders" ); } //don't want to put into the same loop as above because we dont //want to add_wait and then kill this function without every calling //do_wait...cause that would cause some nasty bugs foreach ( string in ender_array ) add_wait( ::waittill_msg, string ); } add_wait( ::flag_wait, "_stealth_spotted" ); add_wait( ::waittill_msg, "end_event_awareness_handler" ); add_wait( ::waittill_msg, "event_awareness_handler" ); add_func( ::send_notify, "default_event_awareness_enders" ); thread do_wait_any(); } /************************************************************************************************************/ /* GLOBAL SCRIPT CALL BACKS */ /************************************************************************************************************/ _autosave_stealthcheck() { if( !stealth_is_everything_normal() ) return false; if ( flag( "_stealth_player_nade" ) ) return false; if ( flag_exist( "_radiation_poisoning" ) ) { if ( flag( "_radiation_poisoning" ) ) return false; } vehicles = getentarray( "destructible", "classname" ); foreach ( vehicle in vehicles ) { if ( isDefined( vehicle.healthDrain ) ) return false; } return true; } _patrol_endon_spotted_flag() { flag1 = self stealth_get_group_spotted_flag(); flag2 = self stealth_get_group_corpse_flag(); add_wait( ::flag_wait, flag1 ); add_wait( ::flag_wait, flag2 ); self add_abort( ::waittill_msg, "death" ); self add_func( ::send_notify, "end_patrol" ); thread do_wait_any(); } _spawner_stealth_default() { self thread stealth_default(); }