1269 lines
31 KiB
Plaintext
1269 lines
31 KiB
Plaintext
#include maps\_utility;
|
|
#include maps\_anim;
|
|
#include common_scripts\utility;
|
|
#include maps\_stealth_utility;
|
|
#include maps\_stealth_shared_utilities;
|
|
#include maps\cliffhanger_code;
|
|
|
|
|
|
/************************************************************************************************************/
|
|
/* INITIALIZATIONS */
|
|
/************************************************************************************************************/
|
|
|
|
//stealth_price_accuracy_control()
|
|
//{
|
|
// level endon( "price_starts_moving" );
|
|
// self.baseaccuracy = 5000000;
|
|
//
|
|
// flag_wait( "near_camp_entrance" );
|
|
//
|
|
// self.baseaccuracy = .5;
|
|
//
|
|
// flag_wait( "at_hanger_entrance" );
|
|
//
|
|
// self.baseaccuracy = 1;
|
|
//}
|
|
|
|
init_cliffhanger_cold_patrol_anims()
|
|
{
|
|
// make sure we alternate instead of doing a random selection
|
|
if( !IsDefined( level.lastColdPatrolAnimSetAssigned ) )
|
|
{
|
|
level.lastColdPatrolAnimSetAssigned = "none";
|
|
}
|
|
|
|
if( level.lastColdPatrolAnimSetAssigned != "huddle" )
|
|
{
|
|
self.patrol_walk_anim = "patrol_cold_huddle";
|
|
self.patrol_walk_twitch = "patrol_twitch_weights";
|
|
|
|
self.patrol_scriptedanim[ "pause" ][ 0 ] = "patrol_cold_huddle_pause";
|
|
self.patrol_stop[ "pause" ] = "patrol_cold_huddle_stop";
|
|
self.patrol_start[ "pause" ] = "patrol_cold_huddle_start";
|
|
|
|
self.patrol_stop[ "path_end_idle" ] = "patrol_cold_huddle_stop";
|
|
self.patrol_end_idle[ 0 ] = "patrol_cold_huddle_pause";
|
|
|
|
level.lastColdPatrolAnimSetAssigned = "huddle";
|
|
}
|
|
else
|
|
{
|
|
self.patrol_walk_anim = "patrol_cold_crossed";
|
|
self.patrol_walk_twitch = "patrol_twitch_weights";
|
|
|
|
self.patrol_scriptedanim[ "pause" ][ 0 ] = "patrol_cold_crossed_pause";
|
|
self.patrol_stop[ "pause" ] = "patrol_cold_crossed_stop";
|
|
self.patrol_start[ "pause" ] = "patrol_cold_crossed_start";
|
|
|
|
self.patrol_stop[ "path_end_idle" ] = "patrol_cold_crossed_stop";
|
|
self.patrol_end_idle[ 0 ] = "patrol_cold_crossed_pause";
|
|
|
|
level.lastColdPatrolAnimSetAssigned = "crossed";
|
|
}
|
|
}
|
|
|
|
clear_cliffhanger_cold_patrol_anims()
|
|
{
|
|
self.patrol_walk_anim = undefined;
|
|
self.patrol_walk_twitch = undefined;
|
|
|
|
self.patrol_scriptedanim = undefined;
|
|
self.patrol_stop = undefined;
|
|
self.patrol_start = undefined;
|
|
|
|
self.patrol_stop = undefined;
|
|
self.patrol_end_idle = undefined;
|
|
|
|
self maps\_patrol::set_patrol_run_anim_array();
|
|
}
|
|
|
|
set_cliffhanger_alert_cold_patrol_anims()
|
|
{
|
|
self.patrol_walk_anim = "patrol_cold_gunup";
|
|
self.patrol_walk_twitch = "patrol_gunup_twitch_weights";
|
|
}
|
|
|
|
stealth_cliffhanger_clifftop()
|
|
{
|
|
self stealth_plugin_basic();
|
|
|
|
if ( isplayer( self ) )
|
|
return;
|
|
|
|
threat_array[ "warning1" ] = maps\_stealth_threat_enemy::enemy_alert_level_warning2;
|
|
|
|
|
|
switch( self.team )
|
|
{
|
|
case "axis":
|
|
self stealth_plugin_threat();
|
|
self stealth_pre_spotted_function_custom( ::clifftop_prespotted_func );
|
|
self stealth_threat_behavior_custom( threat_array );
|
|
self stealth_enable_seek_player_on_spotted();
|
|
self stealth_plugin_corpse();
|
|
self stealth_plugin_event_all();
|
|
self.baseaccuracy = 1;
|
|
self.fovcosine = .76; // for the 2nd group -z
|
|
self.fovcosinebusy = .1;
|
|
//self thread dialog_price_kill();
|
|
|
|
self init_cliffhanger_cold_patrol_anims();
|
|
break;
|
|
|
|
case "allies":
|
|
//self stealth_plugin_aicolor();
|
|
//self stealth_plugin_accuracy();
|
|
//self stealth_plugin_smart_stance();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
stealth_cliffhanger()
|
|
{
|
|
self stealth_plugin_basic();
|
|
|
|
if( isplayer( self ) )
|
|
{
|
|
self._stealth_move_detection_cap = 0;
|
|
return;
|
|
}
|
|
|
|
switch( self.team )
|
|
{
|
|
case "axis":
|
|
self ent_flag_init( "player_found" );
|
|
self ent_flag_init( "not_first_attack" );
|
|
self thread maps\_stealth_shared_utilities::enemy_event_debug_print( "player_found" );
|
|
self thread maps\_stealth_shared_utilities::enemy_event_debug_print( "not_first_attack" );
|
|
self stealth_plugin_threat();//call first
|
|
|
|
custom_array = [];
|
|
|
|
if ( level.gameskill < 2 )
|
|
{
|
|
custom_array[ "warning1" ] = maps\_stealth_threat_enemy::enemy_alert_level_warning1;
|
|
custom_array[ "warning2" ] = maps\_stealth_threat_enemy::enemy_alert_level_warning2;
|
|
}
|
|
else
|
|
{
|
|
custom_array[ "warning1" ] = maps\_stealth_threat_enemy::enemy_alert_level_warning2;
|
|
}
|
|
self stealth_threat_behavior_custom( custom_array );
|
|
|
|
//goal radius etc for attack
|
|
//overridding this: enemy_alert_level_attack( enemy )
|
|
//modify this to make sure you can see the player
|
|
b_array = [];
|
|
b_array [ "attack" ] = ::cliffhanger_enemy_attack_behavior;
|
|
self stealth_threat_behavior_replace( b_array, undefined );
|
|
|
|
//time till attack once stealth is broken
|
|
//overriding this: enemy_animation_attack( type )
|
|
new_array = [];
|
|
new_array[ "attack" ] = ::cliffhanger_enemy_animation_attack;
|
|
self stealth_threat_behavior_replace( undefined, new_array );
|
|
|
|
//how long till rest of group is notified
|
|
//modify this to wait for ent_flag from attack_behavior
|
|
self stealth_pre_spotted_function_custom( ::cliffhanger_prespotted_func_with_flag_wait );
|
|
|
|
self stealth_enable_seek_player_on_spotted();
|
|
self stealth_plugin_corpse();
|
|
|
|
self stealth_plugin_event_all();
|
|
|
|
self maps\_stealth_shared_utilities::ai_set_goback_override_function( ::cliffhanger_enemy_goback_startfunc );
|
|
|
|
self.grenadeAmmo = 0;
|
|
self.baseaccuracy = 1;
|
|
self.fovcosine = .5; // cos60
|
|
self.fovcosinebusy = .1;
|
|
self thread dialog_player_kill();
|
|
self thread dialog_price_kill();
|
|
self thread dialog_theyre_looking_for_you();
|
|
|
|
self init_cliffhanger_cold_patrol_anims();
|
|
break;
|
|
|
|
case "allies":
|
|
//self stealth_plugin_aicolor();
|
|
//self stealth_plugin_accuracy();
|
|
|
|
//self allowedstances( "crouch" );
|
|
self.grenadeawareness = 0;//dont chase grenades
|
|
self thread stealth_plugin_smart_stance();
|
|
self._stealth.behavior.no_prone = true;
|
|
self._stealth.behavior.wait_resume_path = 4;
|
|
self._stealth_move_detection_cap = 0;
|
|
|
|
array = [];
|
|
array[ "hidden" ] = ::cliffhanger_friendly_state_hidden;
|
|
array[ "spotted" ] = ::cliffhanger_friendly_state_spotted;
|
|
stealth_basic_states_custom( array );
|
|
}
|
|
}
|
|
|
|
cliffhanger_enemy_goback_startfunc()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
self endon( "_stealth_attack" );
|
|
self endon( "restart_attack_behavior" );
|
|
self endon( "_stealth_enemy_alert_level_change" );
|
|
|
|
// report back to base that we didn't find anybody
|
|
if ( self can_report_to_base() )
|
|
{
|
|
level.reportingToBase = true;
|
|
level thread reset_reportingToBase( self );
|
|
|
|
self thread enemy_announce_hmph();
|
|
|
|
self.customMoveTransition = maps\_patrol::patrol_resume_move_start_func;
|
|
}
|
|
else
|
|
{
|
|
self.customMoveTransition = maps\_patrol::turn_180_move_start_func;
|
|
}
|
|
|
|
// set patrol cold walking anims back
|
|
self init_cliffhanger_cold_patrol_anims();
|
|
self maps\_patrol::set_patrol_run_anim_array();
|
|
}
|
|
|
|
|
|
// check to see if an enemy who has given up searching for the player
|
|
// can do the "report back to base" anim
|
|
can_report_to_base()
|
|
{
|
|
// don't do it if someone is already doing it
|
|
if ( IsDefined( level.reportingToBase ) )
|
|
return false;
|
|
|
|
// don't do it if we're not standing
|
|
if ( !IsDefined( self.a.stance ) || self.a.stance != "stand" )
|
|
return false;
|
|
|
|
// don't do it if we don't have enough room in front of us
|
|
delta = GetMoveDelta( level.scr_anim[ "generic" ][ "patrol_radio_in_clear" ], 0, 1 );
|
|
endPoint = self LocalToWorldCoords( delta );
|
|
if ( !self MayMoveToPoint( endPoint ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
reset_reportingToBase( ai )
|
|
{
|
|
time = GetAnimLength( level.scr_anim[ "generic" ][ "patrol_radio_in_clear" ] );
|
|
|
|
wait time;
|
|
|
|
//ai waittill_any( "death", "pain_death", "_stealth_enemy_alert_level_change", "_stealth_attack", "restart_attack_behavior" );
|
|
|
|
level.reportingToBase = undefined;
|
|
}
|
|
|
|
|
|
friendly_init_cliffhanger()
|
|
{
|
|
spawner = level.price_spawner;
|
|
spawner.count = 1;
|
|
level.price = spawner stalingradSpawn();
|
|
spawn_failed( level.price );
|
|
assert( isDefined( level.price ) );
|
|
|
|
//add overrides for bcs and color nodes
|
|
|
|
level.price.ref_node = Spawn( "script_origin", level.price.origin );
|
|
//level.price.fixednode = false;
|
|
level.price.animname = "price";
|
|
|
|
//level.price thread disable_ai_color();
|
|
// level.price stealth_plugin_aicolor();
|
|
// array = [];
|
|
// array[ "hidden" ] = ::do_nothing;
|
|
// array[ "spotted" ] = ::do_nothing;
|
|
// level.price stealth_color_state_custom( array );
|
|
|
|
level.price enable_ai_color();
|
|
level.price.pathRandomPercent = 0;
|
|
|
|
level.price thread magic_bullet_shield();
|
|
//level.price thread price_bullet_sheild(); //disables bullet shield if player is too far
|
|
//level.price thread price_handle_death(); //mission fail if price dies
|
|
level.price make_hero();
|
|
level.price.allowdeath = false;
|
|
level.price thread ShootEnemyWrapper_price();
|
|
|
|
thread battlechatter_off( "allies" );
|
|
|
|
//level.price thread stealth_price_accuracy_control();
|
|
|
|
level.price.baseaccuracy = 5000000;
|
|
|
|
//all stuff from scoutsniper that might be a good idea
|
|
// level.price thread price_death();
|
|
// level.price setthreatbiasgroup( "price" );
|
|
}
|
|
|
|
|
|
|
|
cliffhanger_friendly_state_hidden()
|
|
{
|
|
self thread set_battlechatter( false );
|
|
|
|
self.grenadeammo = 0;
|
|
|
|
self.forceSideArm = undefined;
|
|
//used to be ignore all - but that makes him not aim at enemies when exposed - which isn't good...also
|
|
//after stealth groups were created we want to differentiate between who should be shot at and who shouldn't
|
|
//so we don't all of a sudden alert another stealth group by shooting at them
|
|
//self.dontEverShoot = true;
|
|
self.ignoreme = true;
|
|
//self enable_ai_color();
|
|
}
|
|
|
|
cliffhanger_friendly_state_spotted()
|
|
{
|
|
if( flag( "price_go_to_climb_ridge" ) )
|
|
self.dontEverShoot = true;
|
|
//self thread set_battlechatter( true );
|
|
|
|
self.grenadeammo = 0;
|
|
//used to be ignore all - but that makes him not aim at enemies when exposed - which isn't good...also
|
|
//after stealth groups were created we want to differentiate between who should be shot at and who shouldn't
|
|
//so we don't all of a sudden alert another stealth group by shooting at them
|
|
//self.dontEverShoot = false;//self.ignoreall = false;
|
|
if( !flag( "said_lets_split_up" ) )
|
|
self.ignoreme = false;
|
|
|
|
//self.disablearrivals = true;
|
|
//self.disableexits = true;
|
|
|
|
self pushplayer( false );
|
|
//self disable_cqbwalk();
|
|
|
|
//self thread maps\_stealth_behavior_friendly::friendly_spotted_getup_from_prone();
|
|
//self allowedstances( "prone", "crouch", "stand" );
|
|
//self anim_stopanimscripted();
|
|
|
|
//self disable_ai_color();
|
|
//self setgoalpos( self.origin );
|
|
}
|
|
|
|
check_near_enemy()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "stop_check_near_enemy" );
|
|
self endon( "restart_attack_behavior" );
|
|
|
|
distanceSq = max( self.newEnemyReactionDistSq, squared( self.pathEnemyFightDist ) );
|
|
|
|
waittillframeend;
|
|
|
|
while ( 1 )
|
|
{
|
|
if( !isdefined( self.enemy ) )
|
|
return;
|
|
if( distanceSquared( self.origin, self.enemy.origin ) < distanceSq )
|
|
break;
|
|
wait 0.1;
|
|
}
|
|
|
|
self notify( "near_enemy" );
|
|
}
|
|
|
|
cliffhanger_enemy_attack_behavior_attacked_again()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "_stealth_attack" );
|
|
level endon( "_stealth_spotted" );
|
|
|
|
wait 2;
|
|
|
|
self waittill( "_stealth_bad_event_listener" );
|
|
|
|
self maps\_stealth_shared_utilities::enemy_reaction_state_alert();
|
|
|
|
self ent_flag_set( "not_first_attack" );
|
|
|
|
self notify( "enemy_runto_and_lookaround" );
|
|
self notify( "restart_attack_behavior" );
|
|
|
|
self clear_generic_idle_anim();
|
|
|
|
self thread cliffhanger_enemy_attack_behavior( self.enemy );
|
|
}
|
|
|
|
cliffhanger_enemy_attack_behavior( enemy )
|
|
{
|
|
self endon( "restart_attack_behavior" );
|
|
|
|
self set_cliffhanger_alert_cold_patrol_anims();
|
|
|
|
//que up the yell
|
|
if ( !self ent_flag( "not_first_attack" ) )
|
|
self thread maps\_stealth_shared_utilities::enemy_announce_spotted( self.origin );
|
|
|
|
self endon( "death" );
|
|
|
|
self ent_flag_set( "_stealth_override_goalpos" );
|
|
|
|
self thread cliffhanger_enemy_attack_behavior_attacked_again();
|
|
|
|
if ( !self stealth_group_spotted_flag() )
|
|
{
|
|
self thread cliffhanger_enemy_attack_behavior_looking_for_player();
|
|
|
|
//give the player a chance to hide
|
|
wait_reaction_time();
|
|
|
|
if ( !self ent_flag( "not_first_attack" ) )
|
|
{
|
|
self thread check_near_enemy();
|
|
waittill_notify_or_timeout( "near_enemy", 3 );
|
|
|
|
self notify( "stop_check_near_enemy" );
|
|
}
|
|
|
|
self thread flag_when_you_can_see_the_player( "player_found" );
|
|
self ent_flag_wait( "player_found" );
|
|
}
|
|
|
|
self.dontevershoot = undefined;
|
|
cliffhanger_enemy_attack_behavior_sees_player();
|
|
}
|
|
|
|
wait_reaction_time()
|
|
{
|
|
//200 = 0, 700 = .5
|
|
d = distance( self.origin, ( get_closest_player( self.origin ) ).origin );
|
|
t = ( d - 200)/1000;
|
|
t = clamp( t, 0, 0.5 );
|
|
wait t;
|
|
println( "---------reaction time: " + t );
|
|
}
|
|
|
|
/*
|
|
low sight dist
|
|
self orientmode( "face motion" );
|
|
patrol to here
|
|
reaction time
|
|
wait till "enemy visible" = cansee
|
|
regular combat
|
|
|
|
|
|
*/
|
|
|
|
|
|
cliffhanger_enemy_attack_behavior_looking_for_player()
|
|
{
|
|
self endon( "player_found" );
|
|
self endon( "death" );
|
|
self endon( "_stealth_attack" );
|
|
self endon( "restart_attack_behavior" );
|
|
self endon( "_stealth_enemy_alert_level_change" );
|
|
level endon( "_stealth_spotted" );
|
|
|
|
//dont shoot until you can see him
|
|
self.dontevershoot = true;
|
|
|
|
//cqb halfway to enemy
|
|
self enable_cqbwalk();
|
|
self.disablearrivals = false;
|
|
self.disableexits = false;
|
|
self.goalradius = 64;
|
|
|
|
player = get_closest_player( self.origin );
|
|
|
|
lastknownspot = player.origin;
|
|
distance = distance( lastknownspot, self.origin );
|
|
|
|
self ent_flag_set( "_stealth_override_goalpos" );
|
|
|
|
if ( self cansee( player ) )
|
|
{
|
|
self setgoalpos( lastknownspot );
|
|
}
|
|
else
|
|
{
|
|
searchRadius = 256;
|
|
|
|
nodes = getNodesInRadius( lastknownspot, searchRadius, 0, 512, "Path" );
|
|
|
|
if ( nodes.size )
|
|
{
|
|
node = nodes[ randomint( nodes.size ) ];
|
|
self setgoalpos( node.origin );
|
|
}
|
|
else
|
|
{
|
|
self setgoalpos( lastknownspot );
|
|
}
|
|
}
|
|
|
|
self.goalradius = distance * .5;
|
|
self waittill( "goal" );
|
|
|
|
//switch to a walk
|
|
if ( !flag( "_stealth_spotted" ) && ( !isdefined( self.enemy ) || !self cansee( self.enemy ) ) )
|
|
{
|
|
self set_cliffhanger_search_walk();
|
|
|
|
self thread maps\_stealth_shared_utilities::enemy_runto_and_lookaround( undefined, lastknownspot );
|
|
}
|
|
}
|
|
|
|
set_cliffhanger_search_walk()
|
|
{
|
|
self disable_cqbwalk();
|
|
|
|
self set_generic_run_anim( "patrol_cold_gunup_search", true );
|
|
|
|
self.disablearrivals = true;
|
|
self.disableexits = true;
|
|
}
|
|
|
|
cliffhanger_enemy_attack_behavior_sees_player()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "_stealth_enemy_alert_level_change" );
|
|
|
|
//there is a .5 second delay in enemy_runto_and_lookaround...
|
|
//this notify makes sure that script dies here so that the
|
|
//looping anim doesn't start after we stop current behavior below
|
|
self notify( "enemy_runto_and_lookaround" );
|
|
self maps\_stealth_shared_utilities::enemy_stop_current_behavior();
|
|
|
|
self.dontevershoot = undefined;
|
|
self.aggressivemode = true;//dont linger at cover when you cant see your enemy
|
|
prev_pos = undefined;
|
|
|
|
while( !flag( "script_attack_override" ) )
|
|
{
|
|
player = get_closest_player( self.origin );
|
|
|
|
if ( animscripts\utility::isShotgun( self.weapon ) )
|
|
radius = 250;
|
|
else
|
|
radius = max( 500, player.maxVisibleDist );
|
|
|
|
self.goalradius = radius;
|
|
|
|
last_known_pos = self lastKnownPos( player );
|
|
player_pos = ( player.origin * 0.25 ) + ( last_known_pos * 0.75 );
|
|
|
|
if ( self set_goal_near_pos( player_pos, prev_pos ) )
|
|
prev_pos = player_pos;
|
|
|
|
wait 5;
|
|
}
|
|
}
|
|
|
|
|
|
set_goal_near_pos( pos, prev_pos )
|
|
{
|
|
if ( !isdefined( prev_pos ) || distanceSquared( pos, prev_pos ) > squared( 64 ) )
|
|
{
|
|
searchRadius = 256;
|
|
|
|
nodes = getNodesInRadius( pos, searchRadius, 0 );
|
|
|
|
if ( nodes.size )
|
|
{
|
|
node = nodes[ randomint( nodes.size ) ];
|
|
self setgoalpos( node.origin );
|
|
}
|
|
else
|
|
{
|
|
self setgoalpos( pos );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
flag_when_you_can_see_the_player( flag_name )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "restart_attack_behavior" );
|
|
|
|
while ( 1 )
|
|
{
|
|
player = get_closest_player( self.origin );
|
|
|
|
if ( self cansee( player ) )
|
|
{
|
|
self ent_flag_set( flag_name );
|
|
break;
|
|
}
|
|
wait .1;
|
|
}
|
|
}
|
|
|
|
cliffhanger_enemy_animation_attack( type )
|
|
{
|
|
// no animation, just attack
|
|
self thread maps\_stealth_shared_utilities::enemy_announce_attack();
|
|
}
|
|
|
|
stealth_settings()
|
|
{
|
|
stealth_set_default_stealth_function( "cliffhanger", ::stealth_cliffhanger );
|
|
stealth_set_default_stealth_function( "clifftop", ::stealth_cliffhanger_clifftop );
|
|
|
|
ai_event = [];
|
|
ai_event[ "ai_eventDistNewEnemy" ] = [];
|
|
ai_event[ "ai_eventDistNewEnemy" ][ "spotted" ] = 512;
|
|
ai_event[ "ai_eventDistNewEnemy" ][ "hidden" ] = 256;
|
|
|
|
ai_event[ "ai_eventDistExplosion" ] = [];
|
|
ai_event[ "ai_eventDistExplosion" ][ "spotted" ] = 1500;
|
|
ai_event[ "ai_eventDistExplosion" ][ "hidden" ] = 1500;
|
|
|
|
ai_event[ "ai_eventDistDeath" ] = [];
|
|
ai_event[ "ai_eventDistDeath" ][ "spotted" ] = 512;
|
|
ai_event[ "ai_eventDistDeath" ][ "hidden" ] = 512; // used to be 256
|
|
|
|
ai_event[ "ai_eventDistPain" ] = [];
|
|
ai_event[ "ai_eventDistPain" ][ "spotted" ] = 256;
|
|
ai_event[ "ai_eventDistPain" ][ "hidden" ] = 256; // used to be 256
|
|
|
|
ai_event[ "ai_eventDistBullet" ] = [];
|
|
ai_event[ "ai_eventDistBullet" ][ "spotted" ] = 96;
|
|
ai_event[ "ai_eventDistBullet" ][ "hidden" ] = 96;
|
|
|
|
|
|
stealth_ai_event_dist_custom( ai_event );
|
|
|
|
array = [];
|
|
array[ "player_dist" ] = 1000;
|
|
array[ "sight_dist" ] = 400;
|
|
array[ "detect_dist" ] = 200;
|
|
stealth_corpse_ranges_custom( array );
|
|
}
|
|
|
|
sight_ranges_long()
|
|
{
|
|
ai_event[ "ai_eventDistFootstep" ] = [];
|
|
ai_event[ "ai_eventDistFootstep" ][ "spotted" ] = 300;
|
|
ai_event[ "ai_eventDistFootstep" ][ "hidden" ] = 300;
|
|
|
|
ai_event[ "ai_eventDistFootstepWalk" ] = [];
|
|
ai_event[ "ai_eventDistFootstepWalk" ][ "spotted" ] = 300;
|
|
ai_event[ "ai_eventDistFootstepWalk" ][ "hidden" ] = 300;
|
|
|
|
ai_event[ "ai_eventDistFootstepSprint" ] = [];
|
|
ai_event[ "ai_eventDistFootstepSprint" ][ "spotted" ] = 400;
|
|
ai_event[ "ai_eventDistFootstepSprint" ][ "hidden" ] = 400;
|
|
|
|
stealth_ai_event_dist_custom( ai_event );
|
|
|
|
rangesHidden = [];
|
|
rangesHidden[ "prone" ] = 800;
|
|
rangesHidden[ "crouch" ] = 800;
|
|
rangesHidden[ "stand" ] = 800;
|
|
|
|
rangesSpotted = [];
|
|
rangesSpotted[ "prone" ] = 8192;
|
|
rangesSpotted[ "crouch" ] = 8192;
|
|
rangesSpotted[ "stand" ] = 8192;
|
|
|
|
stealth_detect_ranges_set( rangesHidden, rangesSpotted );
|
|
|
|
stealth_alert_level_duration( 0.5 );
|
|
}
|
|
|
|
sight_ranges_blizzard()
|
|
{
|
|
ai_event[ "ai_eventDistFootstep" ] = [];
|
|
ai_event[ "ai_eventDistFootstep" ][ "spotted" ] = 120;
|
|
ai_event[ "ai_eventDistFootstep" ][ "hidden" ] = 120;
|
|
|
|
ai_event[ "ai_eventDistFootstepWalk" ] = [];
|
|
ai_event[ "ai_eventDistFootstepWalk" ][ "spotted" ] = 60;
|
|
ai_event[ "ai_eventDistFootstepWalk" ][ "hidden" ] = 60;
|
|
|
|
ai_event[ "ai_eventDistFootstepSprint" ] = [];
|
|
ai_event[ "ai_eventDistFootstepSprint" ][ "spotted" ] = 400;
|
|
ai_event[ "ai_eventDistFootstepSprint" ][ "hidden" ] = 400;
|
|
|
|
stealth_ai_event_dist_custom( ai_event );
|
|
|
|
rangesHidden = [];
|
|
rangesHidden[ "prone" ] = 250;
|
|
rangesHidden[ "crouch" ] = 450;
|
|
rangesHidden[ "stand" ] = 500;
|
|
|
|
rangesSpotted = [];
|
|
rangesSpotted[ "prone" ] = 500;
|
|
rangesSpotted[ "crouch" ] = 500;
|
|
rangesSpotted[ "stand" ] = 600;
|
|
|
|
stealth_detect_ranges_set( rangesHidden, rangesSpotted );
|
|
|
|
alert_duration = [];
|
|
alert_duration[0] = 1;
|
|
alert_duration[1] = 1;
|
|
alert_duration[2] = 1;
|
|
alert_duration[3] = 0.75;
|
|
|
|
// easy and normal have 2 alert levels so the above times are effectively doubled
|
|
stealth_alert_level_duration( alert_duration[ level.gameskill ] );
|
|
}
|
|
|
|
clifftop_prespotted_func()
|
|
{
|
|
//thread debug_timer();
|
|
self.battlechatter = false;
|
|
wait 5;
|
|
self.battlechatter = true;
|
|
}
|
|
|
|
|
|
debug_timer()
|
|
{
|
|
time_past = 0;
|
|
while( time_past < 10 )
|
|
{
|
|
wait .05;
|
|
time_past = time_past + .05;
|
|
println( "time past: " + time_past );
|
|
}
|
|
}
|
|
|
|
cliffhanger_prespotted_func_with_flag_wait()
|
|
{
|
|
self.battlechatter = false;
|
|
if( level.gameskill < 3 )
|
|
self ent_flag_wait( "player_found" );
|
|
|
|
if( level.gameskill < 2 )
|
|
wait 3;
|
|
else
|
|
wait .25;
|
|
|
|
self.battlechatter = true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
price_stealth_kills_guy( targetguy2 )
|
|
{
|
|
level.price.fixednode = false;
|
|
level.price disable_ai_color();
|
|
level.price setgoalpos( level.price.origin );
|
|
level.price.goalradius = 8;
|
|
self.dontattackme = undefined;
|
|
level.price.favoriteenemy = self;
|
|
self.health = 1;
|
|
self waittill( "death" );
|
|
|
|
//alert second guy and tell price to kill him
|
|
if( isalive( targetguy2 ) )
|
|
{
|
|
targetguy2.favoriteenemy = level.player;
|
|
wait .2;
|
|
level.price.favoriteenemy = self;
|
|
targetguy2.dontattackme = undefined;
|
|
|
|
targetguy2 waittill( "death" );
|
|
}
|
|
wait .8;
|
|
wait 2;
|
|
level.price.fixednode = true;
|
|
level.price enable_ai_color();
|
|
|
|
//level.price Shoot();
|
|
//aim_spot = self geteye();
|
|
//MagicBullet( level.price.weapon, level.price gettagorigin( "tag_flash" ), aim_spot );
|
|
}
|
|
|
|
wait_for_player_interupt( msg )
|
|
{
|
|
if( flag( msg ) )
|
|
return;
|
|
level endon ( "_stealth_spotted" );
|
|
level endon ( msg );
|
|
level.player waittill( "weapon_fired" );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
start_truck_patrol()
|
|
{
|
|
array_thread( getentarray( "truck_guys", "script_noteworthy" ), ::add_spawn_function, ::base_truck_guys_think );
|
|
|
|
flag_wait( "start_truck_patrol" );
|
|
autosave_stealth();
|
|
|
|
truck_spawner = getent( "truck_patrol", "targetname" );
|
|
truck_spawner.script_badplace = true;
|
|
level.truck_patrol = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "truck_patrol" );
|
|
|
|
level.truck_patrol thread dialog_truck_coming();
|
|
|
|
level.truck_patrol thread play_loop_sound_on_entity( "cliffhanger_truck_music" );
|
|
|
|
level.truck_patrol thread base_truck_think();
|
|
|
|
level.truck_patrol thread truck_headlights();
|
|
|
|
thread dialog_jeep_blown_up();
|
|
level.truck_patrol thread dialog_jeep_stopped();
|
|
|
|
level.truck_patrol waittill( "death" );
|
|
|
|
flag_set( "jeep_blown_up" );
|
|
level.truck_patrol notify( "stop sound" + "cliffhanger_truck_music" );
|
|
}
|
|
|
|
truck_headlights()
|
|
{
|
|
//level.truck_patrol maps\_vehicle::lights_on( "headlights" );
|
|
PlayFXOnTag( level._effect[ "lighthaze_snow_headlights" ], self, "TAG_LIGHT_RIGHT_FRONT" );
|
|
PlayFXOnTag( level._effect[ "lighthaze_snow_headlights" ], self, "TAG_LIGHT_LEFT_FRONT" );
|
|
//level.truck_patrol maps\_vehicle::lights_on( "brakelights" );
|
|
|
|
//taillights
|
|
PlayFXOnTag( level._effect[ "car_taillight_uaz_l" ], self, "TAG_LIGHT_LEFT_TAIL" );
|
|
PlayFXOnTag( level._effect[ "car_taillight_uaz_l" ], self, "TAG_LIGHT_RIGHT_TAIL" );
|
|
|
|
self waittill ( "death" );
|
|
|
|
if( isdefined( self ) )
|
|
delete_truck_headlights();
|
|
}
|
|
|
|
delete_truck_headlights()
|
|
{
|
|
StopFXOnTag( level._effect[ "lighthaze_snow_headlights" ], self, "TAG_LIGHT_RIGHT_FRONT" );
|
|
StopFXOnTag( level._effect[ "lighthaze_snow_headlights" ], self, "TAG_LIGHT_LEFT_FRONT" );
|
|
StopFXOnTag( level._effect[ "car_taillight_uaz_l" ], self, "TAG_LIGHT_LEFT_TAIL" );
|
|
StopFXOnTag( level._effect[ "car_taillight_uaz_l" ], self, "TAG_LIGHT_RIGHT_TAIL" );
|
|
}
|
|
|
|
|
|
base_truck_think()
|
|
{
|
|
self endon( "death" );
|
|
|
|
//level.truck_patrol thread handle_end_of_path();
|
|
//array_thread( level.players, ::base_truck_see, self );
|
|
|
|
|
|
level.truck_patrol thread unload_and_attack_if_stealth_broken_and_close();
|
|
//level.truck_patrol thread break_stealth_if_player_spotted();
|
|
//level.truck_patrol thread break_stealth_if_damage_taken();//handled by wizz bys
|
|
|
|
flag_wait( "truck_guys_alerted" );
|
|
|
|
//self.runtovehicleoverride = ::truck_guy_runtovehicle;
|
|
|
|
//guys = self.attachedguys;
|
|
guys = get_living_ai_array( "truck_guys", "script_noteworthy" );
|
|
|
|
if( guys.size == 0 )
|
|
{
|
|
self Vehicle_SetSpeed( 0, 15 );
|
|
return;
|
|
}
|
|
|
|
screamer = random( guys );
|
|
screamer maps\_stealth_shared_utilities::enemy_announce_wtf();
|
|
|
|
//wait .5;
|
|
self waittill( "safe_to_unload" );
|
|
|
|
self Vehicle_SetSpeed( 0, 15 );
|
|
wait 1;
|
|
self maps\_vehicle::vehicle_unload();
|
|
|
|
flag_set( "jeep_stopped" );
|
|
|
|
|
|
|
|
//self waittill( "unloaded" );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
handle_end_of_path()
|
|
{
|
|
while( 1 )
|
|
{
|
|
self waittillmatch( "noteworthy", "end_of_path" );
|
|
path = getent( self.target, "targetname" );
|
|
self maps\_vehicle::vehicle_paths( path );
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
//break_stealth_if_damage_taken()
|
|
//{
|
|
// self waittill( "damage" );
|
|
//
|
|
// flag_set( "truck_guys_alerted" );
|
|
//}
|
|
|
|
unload_and_attack_if_stealth_broken_and_close()
|
|
{
|
|
self endon( "truck_guys_alerted" );
|
|
|
|
while( 1 )
|
|
{
|
|
flag_wait( "_stealth_spotted" );
|
|
level.player waittill_entity_in_range( self, 800 );
|
|
if( !flag( "_stealth_spotted" ) )
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
flag_set( "truck_guys_alerted" );
|
|
}
|
|
|
|
|
|
|
|
//base_truck_see( truck )
|
|
//{
|
|
// truck endon( "death" );
|
|
// self endon( "death" );
|
|
//
|
|
// while ( 1 )
|
|
// {
|
|
// dist = self.maxVisibleDist * .75;
|
|
// dist = dist * dist;
|
|
//
|
|
// if ( distancesquared( self.origin, truck.origin ) <= dist )
|
|
// break;
|
|
//
|
|
// wait .1;
|
|
// }
|
|
//
|
|
// flag_set( "truck_guys_alerted" );
|
|
//}
|
|
|
|
|
|
|
|
|
|
base_truck_guys_attacked_again()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "_stealth_attack" );
|
|
level endon( "_stealth_spotted" );
|
|
|
|
wait 2;
|
|
|
|
self waittill( "_stealth_bad_event_listener" );
|
|
|
|
self maps\_stealth_shared_utilities::enemy_reaction_state_alert();
|
|
|
|
self ent_flag_set( "not_first_attack" );
|
|
}
|
|
|
|
|
|
base_truck_guys_think()
|
|
{
|
|
self endon( "death" );
|
|
|
|
//if ( flag( "_stealth_spotted" ) || self ent_flag( "_stealth_attack" ) )
|
|
// return;
|
|
|
|
level endon( "_stealth_spotted" );
|
|
self endon( "_stealth_attack" );
|
|
|
|
self ent_flag_init( "jumped_out" );
|
|
self thread truck_guys_think_jumpout();
|
|
|
|
corpse_array = [];
|
|
corpse_array[ "saw" ] = ::truck_guys_reaction_behavior;
|
|
corpse_array[ "found" ] = ::truck_guys_reaction_behavior;
|
|
|
|
alert_array = [];
|
|
alert_array[ "warning1" ] = ::truck_guys_reaction_behavior;
|
|
alert_array[ "warning2" ] = ::truck_guys_reaction_behavior;
|
|
alert_array[ "attack" ] = ::truck_alert_level_attack;
|
|
|
|
awareness_array = [];
|
|
awareness_array[ "explode" ] = ::truck_guys_no_enemy_reaction_behavior;
|
|
awareness_array[ "heard_scream" ] = ::truck_guys_no_enemy_reaction_behavior;
|
|
awareness_array[ "doFlashBanged" ] = ::truck_guys_no_enemy_reaction_behavior;
|
|
|
|
self maps\_stealth_shared_utilities::ai_create_behavior_function( "animation", "wrapper", ::truck_animation_wrapper );
|
|
self stealth_threat_behavior_custom( alert_array );
|
|
self stealth_corpse_behavior_custom( corpse_array );
|
|
foreach ( key, value in awareness_array )
|
|
self maps\_stealth_event_enemy::stealth_event_mod( key, value );
|
|
|
|
self ent_flag_set( "_stealth_behavior_reaction_anim" );
|
|
}
|
|
|
|
truck_guys_base_search_behavior( node )
|
|
{
|
|
self endon( "_stealth_enemy_alert_level_change" );
|
|
level endon( "_stealth_spotted" );
|
|
self endon( "_stealth_attack" );
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
|
|
self thread base_truck_guys_attacked_again();
|
|
|
|
self.disablearrivals = false;
|
|
self.disableexits = false;
|
|
|
|
distance = distance( node.origin, self.origin );
|
|
|
|
self setgoalnode( node );
|
|
self.goalradius = distance * .5;
|
|
|
|
wait 0.05; // because stealth system keeps clearing run anim on every enemy_animation_wrapper
|
|
self set_generic_run_anim( "_stealth_patrol_cqb" );
|
|
self waittill( "goal" );
|
|
|
|
if ( !flag( "_stealth_spotted" ) && ( !isdefined( self.enemy ) || !self cansee( self.enemy ) ) )
|
|
{
|
|
set_cliffhanger_search_walk();
|
|
|
|
self maps\_stealth_shared_utilities::enemy_runto_and_lookaround( node );
|
|
}
|
|
}
|
|
|
|
|
|
truck_guys_think_jumpout()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
|
|
while ( 1 )
|
|
{
|
|
self waittill( "jumpedout" );
|
|
self enemy_set_original_goal( self.origin );
|
|
self.got_off_truck_origin = self.origin;
|
|
self ent_flag_set( "jumped_out" );
|
|
|
|
self waittill( "enteredvehicle" );
|
|
wait .15;
|
|
self ent_flag_clear( "jumped_out" );
|
|
self ent_flag_set( "_stealth_behavior_reaction_anim" );
|
|
}
|
|
}
|
|
|
|
truck_animation_wrapper( type )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
|
|
flag_set( "truck_guys_alerted" );
|
|
|
|
self ent_flag_wait( "jumped_out" );
|
|
|
|
self maps\_stealth_shared_utilities::enemy_animation_wrapper( type );
|
|
}
|
|
|
|
truck_guys_reaction_behavior( type )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
level endon( "_stealth_spotted" );
|
|
self endon( "_stealth_attack" );
|
|
|
|
flag_set( "truck_guys_alerted" );
|
|
|
|
self ent_flag_wait( "jumped_out" );
|
|
|
|
if ( !flag( "truck_guys_alerted" ) )
|
|
return;
|
|
if ( flag_exist( "truck_guys_not_going_back" ) && flag( "truck_guys_not_going_back" ) )
|
|
return;
|
|
|
|
if ( !flag( "_stealth_spotted" ) && !self ent_flag( "_stealth_attack" ) )
|
|
{
|
|
player = get_closest_player( self.origin );
|
|
node = maps\_stealth_shared_utilities::enemy_find_free_pathnode_near( player.origin, 1500, 128 );
|
|
|
|
if ( isdefined( node ) )
|
|
self thread truck_guys_base_search_behavior( node );
|
|
}
|
|
|
|
spotted_flag = self group_get_flagname( "_stealth_spotted" );
|
|
if ( flag( spotted_flag ) )
|
|
self flag_waitopen( spotted_flag );
|
|
else
|
|
self waittill( "normal" );
|
|
}
|
|
|
|
|
|
truck_guys_no_enemy_reaction_behavior( type )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
level endon( "_stealth_spotted" );
|
|
self endon( "_stealth_attack" );
|
|
|
|
flag_set( "truck_guys_alerted" );
|
|
|
|
self ent_flag_wait( "jumped_out" );
|
|
|
|
if ( !flag( "truck_guys_alerted" ) )
|
|
return;
|
|
if ( flag_exist( "truck_guys_not_going_back" ) && flag( "truck_guys_not_going_back" ) )
|
|
return;
|
|
|
|
if ( !flag( "_stealth_spotted" ) && !self ent_flag( "_stealth_attack" ) )
|
|
{
|
|
origin = self._stealth.logic.event.awareness_param[ type ];
|
|
|
|
node = self maps\_stealth_shared_utilities::enemy_find_free_pathnode_near( origin, 300, 40 );
|
|
|
|
self thread maps\_stealth_shared_utilities::enemy_announce_wtf();
|
|
|
|
if ( isdefined( node ) )
|
|
self thread truck_guys_base_search_behavior( node );
|
|
}
|
|
|
|
spotted_flag = self group_get_flagname( "_stealth_spotted" );
|
|
if ( flag( spotted_flag ) )
|
|
self flag_waitopen( spotted_flag );
|
|
else
|
|
self waittill( "normal" );
|
|
}
|
|
|
|
|
|
truck_alert_level_attack( enemy )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "pain_death" );
|
|
|
|
flag_set( "truck_guys_alerted" );
|
|
self ent_flag_wait( "jumped_out" );
|
|
|
|
self cliffhanger_enemy_attack_behavior();
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
spawn_beehive()
|
|
{
|
|
level endon ( "done_with_stealth_camp" );
|
|
|
|
|
|
spawner_triggers = getentarray( "beehive_spawner", "targetname" );
|
|
array_thread( getentarray( "beehive_spawner", "script_noteworthy" ), ::add_spawn_function, ::beehive_enemies );
|
|
|
|
|
|
while( 1 )
|
|
{
|
|
println( " beehive ready" );
|
|
flag_wait( "_stealth_spotted" );
|
|
|
|
wait 1;
|
|
|
|
num = alert_enemies_count();
|
|
hives = 0;
|
|
if ( num <= 3 )
|
|
hives = 2;
|
|
if ( num > 3 )
|
|
hives = 1;
|
|
if ( num > 5 )
|
|
hives = 0;
|
|
if(! is_group77_alert() )
|
|
hives = 0;
|
|
|
|
|
|
|
|
println( " beehives : " + hives );
|
|
//sort from closest to furtherest
|
|
spawner_triggers = get_array_of_closest( getAveragePlayerOrigin(), spawner_triggers );
|
|
|
|
//skip the closest 2
|
|
for( i = 2 ; i < (2 + hives); i++ )
|
|
{
|
|
spawner_triggers[i] notify ( "trigger" );
|
|
}
|
|
|
|
flag_waitopen( "_stealth_spotted" );
|
|
}
|
|
}
|
|
|
|
is_group77_alert()
|
|
{
|
|
alerted_groups = stealth_group_return_groups_with_spotted_flag();
|
|
foreach( group in alerted_groups )
|
|
{
|
|
if( group == "77" )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
alert_enemies_count()
|
|
{
|
|
enemies = getaiarray( "axis" );
|
|
count = 0;
|
|
foreach( guy in enemies )
|
|
{
|
|
if( guy ent_flag_exist( "_stealth_normal" ) )
|
|
if( !guy ent_flag( "_stealth_normal" ) )
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
beehive_enemies()
|
|
{
|
|
self endon( "death" );
|
|
self.baseaccuracy = 1;
|
|
self.aggressivemode = true;
|
|
g_radius = 700;
|
|
if( self.weapon == "m1014" )
|
|
g_radius = 250;
|
|
|
|
while( 1 )
|
|
{
|
|
if ( isdefined( self.enemy ) )
|
|
{
|
|
self.goalradius = g_radius;
|
|
player = get_closest_player( self.origin );
|
|
self setgoalpos( player.origin );
|
|
}
|
|
wait 4;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
MIN_NON_ALERT_TEAMMATE_DIST_SQ = 300 * 300;
|
|
MIN_ALERT_TEAMMATE_DIST_SQ = 1000 * 1000;
|
|
|
|
// price should snipe if AI is not alert or there are no teammates nearby it.
|
|
price_should_snipe_me()
|
|
{
|
|
teammates = getAIArray( self.team );
|
|
foreach( ai in teammates )
|
|
{
|
|
if ( self == ai )
|
|
continue;
|
|
|
|
if ( ai.alertLevel == "alert" )
|
|
checkDistSq = MIN_ALERT_TEAMMATE_DIST_SQ;
|
|
else
|
|
checkDistSq = MIN_NON_ALERT_TEAMMATE_DIST_SQ;
|
|
|
|
if ( distanceSquared( self.origin, ai.origin ) < checkDistSq )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|