1 #using scripts\codescripts\struct;
3 #using scripts\shared\math_shared;
4 #using scripts\shared\statemachine_shared;
5 #using scripts\shared\system_shared;
6 #using scripts\shared\util_shared;
7 #using scripts\shared\vehicle_shared;
8 #using scripts\shared\vehicle_ai_shared;
9 #using scripts\shared\vehicle_death_shared;
11 #insert scripts\shared\shared.gsh;
12 #insert scripts\shared\statemachine.gsh;
14 #insert scripts\shared\ai\utility.gsh;
16 #define PROTOTYPE_SCOUT_HP_MOD 1
17 #define SCOUT_DEFAULT_RADIUS_FOR_DEFEND_ROLE 64
18 #define SCOUT_DEFAULT_RADIUS_FOR_GUARD_ROLE 64
19 #define SCOUT_DEFAULT_RADIUS_FOR_LOITER_ROLE 64
20 #define SCOUT_TRACK_DISTANCE 256 // distance that the scout tries to stay from the player while tracking it
21 #define SCOUT_DEFEND_HEIGHT 300
22 #define SCOUT_LOITER_HEIGHT 300
23 #define SCOUT_PATROL_HEIGHT 300
24 #define SCOUT_TRACK_HEIGHT 128
25 #define SCOUT_TRACK_TETHER 512
26 #define SCOUT_BASE_SPEED_MODIFIER 0.33
28 #precache( "fx", "_t6/destructibles/fx_quadrotor_crash01" );
30 #namespace scout_drone;
38 level._effect[
"quadrotor_crash" ] =
"_t6/destructibles/fx_quadrotor_crash01";
43 self.health =
self.healthdefault;
47 self EnableAimAssist();
48 self SetHoverParams( 25.0, 120.0, 80 );
49 self SetNearGoalNotifyDist( 40 );
51 self.flyheight = GetDvarFloat(
"g_quadrotorFlyHeight" );
54 self.fovcosinebusy = 0.574;
56 self.vehAirCraftCollisionEnabled =
true;
58 self.original_vehicle_type =
self.vehicletype;
66 self.goalpos =
self.origin;
73 function defend( s_centerpoint, n_radius )
75 Assert(
false,
"defend is not implemented for scout" );
80 Assert(
false,
"guard is not implemented for scout" );
85 Assert(
false,
"loiter is not implemented for scout" );
114 self.patrol_path = patrol_path_start_node;
121 self SetSpeed( RandomFloatRange( baseSpeed - randomHalfRange, baseSpeed + randomHalfRange ) );
123 /# println(
"^1WARNING: No patrol path defined, taking the nearest one" ); #/
126 while ( !isdefined(
self.patrol_path ) )
128 searchRadius = searchRadius * 2;
129 nodes = GetNodesInRadius(
self.origin, searchRadius, 0, searchRadius,
"Path", 1 );
131 if ( nodes.size > 0 )
133 self.patrol_path = nodes[ 0 ];
141 self endon(
"change_state" );
142 self endon(
"death" );
147 if ( isdefined(
self.patrol_path ) )
149 nd_current =
self.patrol_path;
150 nd_first = nd_current;
153 if ( isdefined( nd_current.script_height ) )
155 v_height_offset = nd_current.script_height;
158 self SetVehGoalPos( nd_current.origin + ( 0, 0, v_height_offset ), 0, 2 );
160 self ClearVehGoalPos();
163 nd_detour_entry = undefined;
164 b_currently_on_detour =
false;
166 while( isdefined( nd_current.target ) )
170 if ( nd_current == nd_first )
172 a_explored_sidepaths = [];
176 if ( isdefined( nd_detour_entry ) && ( nd_current == nd_detour_entry ) )
178 nd_detour_entry = undefined;
179 b_currently_on_detour =
false;
183 nd_previous = nd_current;
186 a_nodes = GetNodeArray( nd_current.target,
"targetname" );
189 for( i = 0; i < a_nodes.size; i++ )
193 if ( isinarray( a_explored_sidepaths, node ) )
195 ArrayRemoveValue( a_nodes, node );
201 nd_current =
RANDOM( a_nodes );
203 if ( isdefined( nd_current.script_string ) )
206 if ( nd_current.script_string ==
"detour" )
208 ArrayInsert( a_explored_sidepaths, nd_current, 0 );
209 nd_detour_entry = nd_previous;
210 b_currently_on_detour =
true;
213 else if ( nd_current.script_string ==
"poi" )
215 ArrayInsert( a_explored_sidepaths, nd_current, 0 );
216 nd_detour_entry = nd_previous;
217 b_currently_on_detour =
true;
235 if ( isdefined( nd_current.script_height ) )
237 v_height_offset = nd_current.script_height;
239 self SetVehGoalPos( nd_current.origin + ( 0, 0, v_height_offset ), 0, 2 );
241 self ClearVehGoalPos();
242 self SetVehGoalPos(
self.origin, 0, 2 );
244 if ( isdefined( nd_current.script_string ) && ( ( nd_current.script_string ==
"nostop" ) || ( nd_current.script_string ==
"detour" ) ) )
253 self ClearLookAtEnt();
277 self endon(
"change_state" );
278 self endon(
"death" );
282 if ( IsDefined(
self.alertSource ) )
284 self ClearLookAtEnt();
286 goalpos =
self.alertSource;
287 goalpos =
self GetClosestPointOnNavVolume( goalpos, 128 );
289 self.debugGoal = goalpos;
291 if ( IsDefined( goalpos ) &&
self SetVehGoalPos( goalpos,
true, 2 ) )
314 if ( !isdefined(
self.enemy ) )
317 /# println(
"^1Error: Scout drone trying to enter combat state without an enemy as target."); #/
320 self.lockOnTarget =
self.enemy;
323 self SetVehGoalPos( goalpos,
true, 2 );
334 self endon(
"change_state" );
335 self endon(
"death" );
338 lastHasTargetTime = GetTime();
342 if ( isAlive(
self.lockOnTarget ) )
346 self ClearLookAtEnt();
350 if (
self SetVehGoalPos( goalpos,
true, 2 ) )
361 self SetLookAtEnt(
self.lockOnTarget );
364 lastHasTargetTime = GetTime();
366 else if ( isAlive(
self.enemy ) )
368 self.lockOnTarget =
self.enemy;
372 if ( GetTime() - lastHasTargetTime > 4000 )
385 if( health_pct < .25 )
387 return level._effect[
"quadrotor_damage04" ];
389 else if( health_pct < .5 )
391 return level._effect[
"quadrotor_damage03" ];
393 else if( health_pct < .75 )
395 return level._effect[
"quadrotor_damage02" ];
397 else if( health_pct < 0.9 )
399 return level._effect[
"quadrotor_damage01" ];
405 function scout_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
407 if (
self.health > 0 && iDamage > 1 )
409 health_percent = (
self.health - iDamage ) /
self.healthdefault;
415 self notify (
"awareness_level_increase" );
417 self.lockOnTarget = eAttacker;
426 if ( !isdefined(
self.goalpos ) )
428 self.goalpos =
self.origin;
431 origin =
self.goalpos;
435 best_point = undefined;
438 foreach( point
in points )
440 score = RandomFloat( 100 );
442 pointAboveNavMesh = point;
443 if ( IsDefined( pointAboveNavMesh ) )
445 score = score + 100 - Abs( pointAboveNavMesh[2] - point[2] ) * 0.1;
448 if ( score > best_score )
455 if ( isdefined( best_point ) )
457 origin = best_point + ( 0, 0,
self.flyheight + RandomFloatRange( -30, 40 ) );