IW4-Dump-Files/maps/_stealth_visibility_enemy.gsc

514 lines
14 KiB
Plaintext

#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include maps\_stealth_utility;
#include maps\_stealth_shared_utilities;
stealth_visibility_enemy_main()
{
self enemy_init();
self thread enemy_threat_logic();
}
/************************************************************************************************************/
/* ENEMY LOGIC */
/************************************************************************************************************/
MIN_TIME_TO_LOSE_ENEMY = 20 * 1000;
enemy_threat_logic()
{
self endon( "death" );
self endon( "pain_death" );
while ( 1 )
{
self ent_flag_wait( "_stealth_enabled" );
self waittill( "enemy" );
if ( !self ent_flag( "_stealth_enabled" ) )
continue;
if ( !isalive( self.enemy ) )
continue;
if ( !self stealth_group_spotted_flag() )
{
if ( !self enemy_alert_level_logic( self.enemy ) )
continue;
}
else
{
// if we hit this line it means we're not the first ones to find the enemy
self maps\_stealth_threat_enemy::enemy_alert_level_change( "attack" );
}
self thread enemy_threat_set_spotted();
//wait a minimum of 10 seconds before trying to lose your enemy
wait 10;
// must not have gotten any event from enemy for MIN_TIME_TO_LOSE_ENEMY and must be out of maxVisibleDist
while ( isdefined( self.enemy ) && self ent_flag( "_stealth_enabled" ) )
{
time_past_last_event = gettime() - self lastKnownTime( self.enemy );
if ( MIN_TIME_TO_LOSE_ENEMY > time_past_last_event )
{
wait ( ( MIN_TIME_TO_LOSE_ENEMY - time_past_last_event ) * 0.001 );
continue;
}
if ( distance( self.origin, self.enemy.origin ) > self.enemy.maxVisibleDist )
break;
wait .5;
}
if ( !self ent_flag( "_stealth_enabled" ) )
continue;
//if we ever break out - if means everyone actually managed to hide...unbelievable
if ( isdefined( self.enemy ) )
enemy_alert_level_forget( self.enemy, 0 );
self clearenemy();
self maps\_stealth_threat_enemy::enemy_alert_level_change( "reset" );
}
}
enemy_alert_level_logic_start_attacking( enemy )
{
//the first check means that a gun shot or something equally bad happened
//the second check is to see if you've been spotted already twice before
if ( self ent_flag( "_stealth_bad_event_listener" ) || enemy._stealth.logic.spotted_list[ self.unique_id ] > self._stealth.logic.alert_level.max_warnings )
{
/#
if ( self ent_flag( "_stealth_bad_event_listener" ) )
self stealth_debug_print( "BROKEN STEALTH. Received ent '" + enemy.unique_id + "' as an enemy from code. Attacked because the reason was a bad_event_listener...ie a gunshot or something equally bad" );
else
self stealth_debug_print( "BROKEN STEALTH. Received ent '" + enemy.unique_id + "' as an enemy from code. Attacked because " + enemy.unique_id + " had been spotted more than the max_warning amount of " + self._stealth.logic.alert_level.max_warnings );
#/
self maps\_stealth_threat_enemy::enemy_alert_level_change( "attack" );
return true;
}
return false;
}
enemy_recheck_time = 500;
enemy_alert_level_logic( enemy )
{
// enemy is not stealthy one bit
if ( !isdefined( enemy._stealth ) )
return true;
//add this ai to this spotted list
if ( !isdefined( enemy._stealth.logic.spotted_list[ self.unique_id ] ) )
enemy._stealth.logic.spotted_list[ self.unique_id ] = 0;
while (1)
{
enemy._stealth.logic.spotted_list[ self.unique_id ]++;
if ( enemy_alert_level_logic_start_attacking( enemy ) )
return true;
//this makes the ai look smart by being aware of your presence
number = enemy._stealth.logic.spotted_list[ self.unique_id ];
self maps\_stealth_threat_enemy::enemy_alert_level_change( "warning" + number );
//forget about him after a while
self thread enemy_alert_level_forget( enemy );
//give the player a chance to hide with this
self enemy_alert_level_waittime( enemy );
if ( gettime() - self lastKnownTime( enemy ) > enemy_recheck_time )
{
self clearenemy();
return false;
}
}
}
enemy_threat_set_spotted()
{
self endon( "death" );
self endon( "pain_death" );
enemy = self.enemy;
self.dontEverShoot = undefined;
self [[ self._stealth.logic.pre_spotted_func ]]();
if ( isdefined( enemy ) )
level._stealth.group.spotted_enemy[ self.script_stealthgroup ] = enemy;
self group_flag_set( "_stealth_spotted" );
}
enemy_prespotted_func_default()
{
wait 2.25;// randomfloatrange( 2, 2.5 ); // used to be .25, .5
}
enemy_alert_level_waittime( enemy )
{
//this makes sure that if someone else spots you...then this quits earler
//than the givin amount of time for the player to try and hide again
if ( self stealth_group_corpse_flag() || self ent_flag( "_stealth_bad_event_listener" ) )
return;
timefrac = distance( self.origin, enemy.origin ) * .0005;
waittime = level._stealth.logic.min_alert_level_duration + timefrac;
self stealth_debug_print( "WARNING time = " + waittime );
//iprintlnbold( waittime );
level endon( group_get_flagname( "_stealth_spotted" ) );
self endon( "_stealth_bad_event_listener" );
wait( waittime );
}
/************************************************************************************************************/
/* EVENTS */
/************************************************************************************************************/
enemy_event_listeners_logic( type )
{
self endon( "death" );
while ( 1 )
{
self waittill( type, subtype, param ); // subtype and param for debugging
if ( !self ent_flag( "_stealth_enabled" ) )
continue;
if ( self ent_flag_exist( "_stealth_behavior_asleep" ) && self ent_flag( "_stealth_behavior_asleep" ) )
continue;
self ent_flag_set( "_stealth_bad_event_listener" );
}
}
//this function resets all event listeners after they happen...so that we can detect each one multiple times
enemy_event_listeners_proc()
{
self endon( "death" );
while ( 1 )
{
self ent_flag_wait( "_stealth_bad_event_listener" );
wait .65;
//this time is set so high because apparently the ai can take up to .5 seconds to
//detect you as an enemy after they have received an event listener...
//EDIT: after testing i've noticed that they still miss the event because they
//receive an enemy even after .65 seconds of receiving the event...but it's more
//fun this way actually...to get away with it once in a while.
self ent_flag_clear( "_stealth_bad_event_listener" );
}
}
enemy_event_awareness_notify( type, param )
{
self ent_flag_clear( "_stealth_normal" );
self._stealth.logic.event.awareness_param[ type ] = param;
self notify( "event_awareness", type );
level notify( "event_awareness", type );
}
// for major categories with subtypes (ai_event, awareness_alert_level, awareness_corpse)
enemy_event_category_awareness( type )
{
self endon( "death" );
self endon( "pain_death" );
while ( 1 )
{
self waittill( type, subtype, param );
if ( !self ent_flag( "_stealth_enabled" ) )
continue;
//
// special check for dogs deleted from here, see revision history #15
//
switch( type )
{
case "awareness_alert_level":
break;
case "ai_event":
if ( !isdefined( self._stealth.logic.event.aware_aievents[ subtype ] ) )
continue;
//this makes sure that magic bullets and friendly bullets that don't cause an enemy notify don't cause guys to break out of animations
if( subtype == "bulletwhizby" && ( !isdefined( param.team ) || param.team == self.team ) )
continue;
// fall through
default:
group_flag_set( "_stealth_event" );
level thread enemy_event_handle_clear( self.script_stealthgroup );
break;
}
enemy_event_awareness_notify( subtype, param );
waittillframeend;// wait a frame to make sure stealth_spotted didn't get set this frame
}
}
// for special awareness events
enemy_event_awareness( type )
{
self endon( "death" );
self endon( "pain_death" );
//just to create the key so it exists so other scripts (mainly behavior)
//can reference it and see what awareness options it has
self._stealth.logic.event.awareness_param[ type ] = true;
while ( 1 )
{
self waittill( type, param );
if ( !self ent_flag( "_stealth_enabled" ) )
continue;
group_flag_set( "_stealth_event" );
level thread enemy_event_handle_clear( self.script_stealthgroup );
enemy_event_awareness_notify( type, param );
waittillframeend;// wait a frame to make sure stealth_spotted didn't get set this frame
}
}
enemy_event_handle_clear( name )
{
end_msg = "enemy_event_handle_clear:" + name + " Proc";
wait_msg = "enemy_event_handle_clear:" + name + " Cleared";
level notify( end_msg );
level endon( end_msg );
wait 2;
ai = group_get_ai_in_group( name );
if ( ai.size )
{
level add_wait( ::array_wait, ai, "event_awareness_waitclear_ai" );
level add_endon( end_msg );
level add_func( ::send_notify, wait_msg );
level thread do_wait();
array_thread( ai, ::event_awareness_waitclear_ai, end_msg );
level waittill( wait_msg );
}
group_flag_clear( "_stealth_event", name );
}
event_awareness_waitclear_ai( end_msg )
{
level endon( end_msg );
self event_awareness_waitclear_ai_proc();
self notify( "event_awareness_waitclear_ai" );
}
event_awareness_waitclear_ai_proc()
{
self endon( "death" );
waittillframeend;// make sure these flag's are set;
check1 = false;
if ( isdefined( self.ent_flag[ "_stealth_behavior_first_reaction" ] ) )
check1 = self ent_flag( "_stealth_behavior_first_reaction" );
check2 = false;
if ( isdefined( self.ent_flag[ "_stealth_behavior_reaction_anim" ] ) )
check1 = self ent_flag( "_stealth_behavior_reaction_anim" );
if ( !check1 && !check2 )
return;
self add_wait( ::waittill_msg, "death" );
self add_wait( ::waittill_msg, "going_back" );
do_wait_any();
self endon( "goal" );
allies = array_combine( getaiarray( "allies" ), level.players );
dist = level._stealth.logic.detect_range[ "hidden" ][ "crouch" ];
distsquared = dist * dist;
loop = true;
if ( loop )
{
loop = false;
foreach ( actor in allies )
{
if ( distancesquared( self.origin, actor.origin ) < distsquared )
continue;
loop = true;
}
wait 1;
}
}
enemy_event_declare_to_team( type, name )
{
other = undefined;
team = self.team;
while ( 1 )
{
if ( !isalive( self ) )
return;
self waittill( type, var1, var2 );
if ( isalive( self ) && !self ent_flag( "_stealth_enabled" ) )
continue;
switch( type )
{
case "death":
other = var1;
break;
case "damage":
other = var2;
break;
}
if ( !isdefined( other ) )
continue;
if ( isplayer( other ) || ( isdefined( other.team ) && other.team != team ) )
break;
}
if ( !isdefined( self ) )
{
// in case of deletion
return;
}
ai = getaispeciesarray( "bad_guys", "all" );
check = int( level._stealth.logic.ai_event[ name ][ level._stealth.logic.detection_level ] );
for ( i = 0; i < ai.size; i++ )
{
if ( !isalive( ai[ i ] ) )
continue;
if ( !isdefined( ai[ i ]._stealth ) )
continue;
if ( distance( ai[ i ].origin, self.origin ) > check )
continue;
if ( ai[ i ] ent_flag_exist( "_stealth_behavior_asleep" ) && ai[ i ] ent_flag( "_stealth_behavior_asleep" ) )
continue;
ai[ i ] ent_flag_set( "_stealth_bad_event_listener" );
}
}
/************************************************************************************************************/
/* SETUP */
/************************************************************************************************************/
enemy_init()
{
assertex( !isdefined( self._stealth ), "you called maps\_stealth_logic::enemy_init() twice on the same ai" );
self clearenemy();
self._stealth = spawnstruct();
self._stealth.logic = spawnstruct();
self ent_flag_init( "_stealth_enabled" );
self ent_flag_set( "_stealth_enabled" );
self ent_flag_init( "_stealth_normal" );
self ent_flag_set( "_stealth_normal" );
self ent_flag_init( "_stealth_attack" );
self group_flag_init( "_stealth_spotted" );
self group_flag_init( "_stealth_event" );
self group_flag_init( "_stealth_found_corpse" );
self group_add_to_global_list();
if ( !isdefined( level._stealth.behavior.sound[ "spotted" ][ self.script_stealthgroup ] ) )
level._stealth.behavior.sound[ "spotted" ][ self.script_stealthgroup ] = false;
self._stealth.logic.alert_level = spawnstruct();
self._stealth.logic.alert_level.max_warnings = 0;
self enemy_alert_level_default_pre_spotted_func();
self enemy_event_listeners_init();
}
enemy_event_listeners_init()
{
self ent_flag_init( "_stealth_bad_event_listener" );
self._stealth.logic.event = spawnstruct();
self addAIEventListener( "grenade danger" );
self addAIEventListener( "gunshot" );
self addAIEventListener( "gunshot_teammate" );
self addAIEventListener( "silenced_shot" );
self addAIEventListener( "bulletwhizby" );
self addAIEventListener( "projectile_impact" );
self thread enemy_event_listeners_logic( "ai_event" ); // catch all of the above eventListener events
self thread enemy_event_declare_to_team( "damage", "ai_eventDistPain" );
self thread enemy_event_declare_to_team( "death", "ai_eventDistDeath" );
self thread enemy_event_listeners_proc();
self._stealth.logic.event.awareness_param = [];
//a lot of these overlap with event listeners - because even though the event
//listeners above will cause a spotted state - we still want to know
//why the ai got an enemy and perhaps do specific animations based on that
self._stealth.logic.event.aware_aievents = [];
self._stealth.logic.event.aware_aievents[ "bulletwhizby" ] = true;
self._stealth.logic.event.aware_aievents[ "projectile_impact" ] = true;
self._stealth.logic.event.aware_aievents[ "gunshot_teammate" ] = true;
self._stealth.logic.event.aware_aievents[ "grenade danger" ] = true;
self thread enemy_event_category_awareness( "ai_event" );
self thread enemy_event_category_awareness( "awareness_alert_level" ); // this is actually notified in this script
self thread enemy_event_category_awareness( "awareness_corpse" ); // this is called from corpse
/#
//these are for extra debug prints
self thread enemy_event_debug_print( "awareness_alert_level" );
self thread enemy_event_debug_print( "awareness_corpse" );
self thread enemy_event_debug_print( "ai_event" );
#/
}
enemy_alert_level_set_pre_spotted_func( func )
{
self._stealth.logic.pre_spotted_func = func;
}
enemy_alert_level_default_pre_spotted_func()
{
self._stealth.logic.pre_spotted_func = ::enemy_prespotted_func_default;
}