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\array_shared;
7 #using scripts\shared\util_shared;
9 #using scripts\shared\vehicle_shared;
10 #using scripts\shared\vehicle_death_shared;
11 #using scripts\shared\vehicle_ai_shared;
12 #using scripts\shared\clientfield_shared;
14 #insert scripts\shared\shared.gsh;
15 #insert scripts\shared\statemachine.gsh;
16 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
18 #insert scripts\shared\ai\utility.gsh;
19 #insert scripts\shared\version.gsh;
21 #define WASP_MOVE_DIST_MIN 80
22 #define WASP_MOVE_DIST_MAX 500
24 #define WASP_ENEMY_TOO_CLOSE_DIST 250
26 #define WASP_GROUP_RADIUS 140
27 #define WASP_GROUP_SIZE 3
29 #define WASP_GUARD_ACQUIRE_ENEMY_DIST 1000
30 #define WASP_GUARD_LOSE_ENEMY_DIST 1200
31 #define WASP_GUARD_KEEP_ENEMY_DIST 300
33 #define WASP_HOVER_RADIUS 50
35 #define WASP_NEARGOAL_DIST 40
37 #using_animtree( "generic" );
51 self UseAnimTree( #animtree );
53 Target_Set(
self, ( 0, 0, 0 ) );
55 self.health =
self.healthdefault;
59 self EnableAimAssist();
67 self.fovcosinebusy = 0;
69 self.vehAirCraftCollisionEnabled =
true;
71 assert( isdefined(
self.scriptbundlesettings ) );
74 self.goalRadius = 999999;
75 self.goalHeight = 999999;
76 self SetGoal(
self.origin,
false,
self.goalRadius,
self.goalHeight );
80 if ( IsSubStr(
self.vehicleType,
"rocket" ) )
82 self.variant =
"rocket";
91 if( IsDefined( level.vehicle_initializer_cb ) )
93 [[level.vehicle_initializer_cb]]( self );
96 if (
self.variant ===
"rocket" )
98 self.ignoreFireFly =
true;
141 self endon(
"death" );
143 if ( isArray(
self.followers ) )
145 foreach( follower
in self.followers )
147 if ( isdefined( follower ) )
149 follower.leader = undefined;
157 if ( !isdefined( death_type ) && isdefined( params ) )
159 if ( isdefined( params.weapon ) )
161 if ( params.weapon.doannihilate )
163 death_type =
"gibbed";
165 else if ( params.weapon.dogibbing && isdefined( params.attacker ) )
167 dist = Distance(
self.origin, params.attacker.origin );
168 if ( dist < params.weapon.maxgibdistance )
170 gib_chance = 1.0 - ( dist / params.weapon.maxgibdistance );
172 if ( RandomFloatRange( 0.0, 2.0 ) < gib_chance )
174 death_type =
"gibbed";
180 if ( isdefined( params.meansOfDeath ) )
182 meansOfDeath = params.meansOfDeath;
183 if ( meansOfDeath ===
"MOD_EXPLOSIVE" || meansOfDeath ===
"MOD_GRENADE_SPLASH" || meansOfDeath ===
"MOD_PROJECTILE_SPLASH" || meansOfDeath ===
"MOD_PROJECTILE" )
185 death_type =
"gibbed";
191 if ( !isdefined( death_type ) )
193 crash_style = RandomInt( 3 );
194 switch( crash_style )
198 if (
self.hijacked ===
true )
200 params.death_type =
"gibbed";
216 params.death_type = death_type;
226 self endon (
"death" );
227 self endon (
"change_state" );
233 self notify(
"end_nudge_collision" );
236 empdowntime = params.notify_param[0];
237 assert( isdefined( empdowntime ) );
240 wait RandomFloat( 0.2 );
243 ang_vel =
self GetAngularVelocity();
247 ang_vel += ( pitch_vel, yaw_vel, roll_vel );
248 self SetAngularVelocity( ang_vel );
251 if ( IsPointInNavVolume(
self.origin,
"navvolume_small" ) )
253 self.position_before_fall =
self.origin;
257 self SetPhysAcceleration( ( 0, 0, -gravity ) );
259 killonimpact_speed =
self.settings.killonimpact_speed;
260 if(
self.health <= 20 )
262 killonimpact_speed = 1;
265 self fall_and_bounce( killonimpact_speed,
self.settings.killonimpact_time );
267 self notify(
"landed" );
270 self SetVehVelocity( ( 0, 0, 0 ) );
271 self SetPhysAcceleration( ( 0, 0, -gravity * 0.1 ) );
272 self SetAngularVelocity( ( 0, 0, 0 ) );
282 self.abnormal_status.emped =
false;
287 while( bootup_timer > 0 )
298 if ( isdefined(
self.position_before_fall ) )
300 originoffset = (0,0,5);
301 goalpoint =
self GetClosestPointOnNavVolume(
self.origin + originoffset, 50 );
302 if ( isdefined( goalpoint ) && SightTracePassed(
self.origin + originoffset, goalpoint,
false,
self ) )
304 self SetVehGoalPos( goalpoint,
false,
false );
307 if ( isdefined(
self.enemy ) )
309 self SetLookAtEnt(
self.enemy );
313 self.current_pathto_pos =
self.position_before_fall;
314 foundGoal =
self SetVehGoalPos(
self.current_pathto_pos,
true,
true );
317 foundGoal =
self SetVehGoalPos(
self.current_pathto_pos,
true,
true );
327 self SetVehGoalPos(
self.origin,
true,
false );
330 self.position_before_fall = undefined;
341 self endon(
"death" );
342 self endon(
"change_state" );
349 angularVelStablizeParams = ( 0.3, 0.5, 0.2 );
350 anglesStablizeInitialScale = 0.6;
351 anglesStablizeIncrement = 0.2;
353 fallStart = GetTime();
354 while ( bouncedTime < maxBounceTime && LengthSquared(
self.velocity ) >
SQR( 10 ) )
356 self waittill(
"veh_collision", impact_vel, normal );
359 if ( LengthSquared( impact_vel ) >
SQR( killOnImpact_speed ) || (
vehicle_ai::TimeSince( fallStart ) > killOnImpact_time && LengthSquared( impact_vel ) >
SQR( killOnImpact_speed * 0.8 ) ) )
364 else if ( !isdefined(
self.position_before_fall ) )
370 fallStart = GetTime();
374 oldvelocity =
self.velocity;
375 vel_hitDir = -VectorProjection( impact_vel, normal );
376 vel_hitDirUp = VectorProjection( vel_hitDir, (0,0,1) );
378 velscale = min( bounceScale * ( bouncedTime + 1 ), 0.9 );
379 newVelocity = ( oldvelocity - VectorProjection( oldvelocity, vel_hitDir ) ) * ( 1 - velocityLoss );
380 newVelocity += vel_hitDir * velscale;
383 shouldBounce = ( VectorDot( normal, (0,0,1) ) > 0.76 );
388 velocityLengthSqr = LengthSquared( newVelocity );
389 stablizeScale = MapFloat(
SQR( 5 ),
SQR( 60 ), 0.1, 1, velocityLengthSqr );
391 ang_vel =
self GetAngularVelocity();
392 ang_vel *= angularVelStablizeParams * stablizeScale;
393 self SetAngularVelocity( ang_vel );
396 angles =
self.angles;
397 anglesStablizeScale = min( anglesStablizeInitialScale - bouncedTime * anglesStablizeIncrement, 0.1 );
401 surfaceAngles = VectorToAngles( normal );
402 surfaceRoll = surfaceAngles[2];
403 if ( pitch < -maxAngle || pitch > maxAngle )
405 pitch *= anglesStablizeScale;
407 if ( roll < surfaceRoll - maxAngle || roll > surfaceRoll + maxAngle )
409 roll = LerpFloat( surfaceRoll, roll, anglesStablizeScale );
411 self.angles = ( pitch, yaw, roll );
414 self SetVehVelocity( newVelocity );
429 self._guard_points = [];
430 ARRAY_ADD(
self._guard_points, (150, -110, 110) );
431 ARRAY_ADD(
self._guard_points, (150, 110, 110) );
432 ARRAY_ADD(
self._guard_points, (120, -110, 80) );
433 ARRAY_ADD(
self._guard_points, (120, 110, 80) );
434 ARRAY_ADD(
self._guard_points, (180, 0, 140) );
440 self endon (
"death" );
442 if (
self.isdebugdrawing ===
true )
447 self.isdebugdrawing =
true;
450 foreach( point
in self.debugpointsarray )
453 if ( IsPointInNavVolume( point,
"navvolume_small" ) )
458 debugstar( point, 5, color );
467 assert(
self._guard_points.size > 0,
"wasp has no guard points" );
474 foreach( point
in self._guard_points )
476 offset = RotatePoint( point, owner.angles );
477 worldPoint = offset + owner.origin + owner GetVelocity() * 0.5;
480 if ( IsPointInNavVolume( worldPoint,
"navvolume_small" ) )
486 if ( points_array.size < 1 )
488 queryResult = PositionQuery_Source_Navigation( owner.origin + (0,0,50), 25, 200, 100, 1.2 *
self.radius,
self );
489 PositionQuery_Filter_Sight( queryResult, owner.origin + (0,0,10), (0, 0, 0),
self, 3 );
491 foreach( point
in queryResult.data )
493 if ( point.visibility ===
true && BulletTracePassed( owner.origin + (0,0,10), point.origin,
false,
self,
self,
false,
true ) )
505 if (
self.enable_guard !==
true || !isdefined(
self.owner ) )
510 if ( !isdefined(
self.enemy ) || !
self VehSeenRecently(
self.enemy, 3 ) )
522 if ( !IsPointInNavVolume(
self.origin,
"navvolume_small" ) )
532 if (
self.enable_target_laser ===
true )
542 if ( isdefined(
self.owner ) && !isAlive(
self.owner.main_guard ) ||
self.owner.main_guard.owner !==
self.owner )
544 self.owner.main_guard =
self;
550 if ( isdefined(
self.owner ) &&
self.owner.main_guard ===
self )
552 self.owner.main_guard = undefined;
558 if ( SightTracePassed(
self.origin, point,
false,
self ) )
560 if ( BulletTracePassed(
self.origin, point,
false,
self,
self,
false,
true ) )
573 getbackPoint = undefined;
574 foreach( point
in queryResult.data )
577 if ( testresult == 1 )
581 else if ( testresult == 0 )
592 self endon(
"death" );
593 self endon(
"change_state" );
595 self SetHoverParams( 20.0, 40.0, 30.0 );
597 timeNotAtGoal = GetTime();
603 if( isdefined(
self.enemy ) && DistanceSquared(
self.owner.origin,
self.enemy.origin ) <
SQR(
WASP_GUARD_ACQUIRE_ENEMY_DIST ) &&
self VehSeenRecently(
self.enemy, 1 ) && IsPointInNavVolume(
self.origin,
"navvolume_small" ) )
611 if ( !isdefined( owner ) )
617 usePathfinding =
true;
618 onNavVolume = IsPointInNavVolume(
self.origin,
"navvolume_small" );
622 getbackPoint = undefined;
625 pointOnNavVolume =
self GetClosestPointOnNavVolume(
self.origin, 500 );
626 if ( isdefined( pointOnNavVolume ) )
630 getbackPoint = pointOnNavVolume;
635 if ( !isdefined( getbackPoint ) )
637 queryResult = PositionQuery_Source_Navigation(
self.origin, 0, 1500, 200, 80,
self );
642 if ( !isdefined( getbackPoint ) )
644 queryResult = PositionQuery_Source_Navigation(
self.origin, 0, 300, 700, 30,
self );
648 if ( isdefined( getbackPoint ) )
652 self.current_pathto_pos = getbackPoint;
653 usePathfinding =
false;
654 self.vehAirCraftCollisionEnabled =
false;
664 if ( stuckCount == 1 )
666 stuckLocation =
self.origin;
668 else if ( stuckCount > 10 )
671 assert(
false,
"Wasp fall outside of NavVolume at " +
self.origin );
672 v_box_min = ( -
self.radius, -
self.radius, -
self.radius );
673 v_box_max = (
self.radius,
self.radius,
self.radius );
674 Box(
self.origin, v_box_min, v_box_max,
self.angles[1], (1,0,0), 1,
false, 1000000 );
675 if ( isdefined( stuckLocation ) )
677 Line( stuckLocation,
self.origin, (1,0,0), 1,
true, 1000000 );
689 if ( owner.main_guard ===
self )
692 if ( guardPoints.size < 1 )
699 self.vehAirCraftCollisionEnabled =
true;
701 if ( guardPoints.size <= pointIndex )
703 pointIndex = RandomInt( Int( min(
self._guard_points.size, guardPoints.size ) ) );
704 timeNotAtGoal = GetTime();
707 self.current_pathto_pos = guardPoints[pointIndex];
711 main_guard = owner.main_guard;
712 if( isalive( main_guard ) && isdefined( main_guard.current_pathto_pos ) )
714 query_position = main_guard.current_pathto_pos;
715 queryResult = PositionQuery_Source_Navigation( query_position, 20,
WASP_GROUP_RADIUS, 100, 20,
self, 15 );
717 if ( queryResult.data.size > 0 )
719 self.current_pathto_pos = queryResult.data[ queryResult.data.size - 1 ].origin;
725 if ( IsDefined(
self.current_pathto_pos ) )
727 distanceToGoalSq = DistanceSquared(
self.current_pathto_pos,
self.origin );
728 if ( !onNavVolume || distanceToGoalSq >
SQR( 60 ) )
730 if ( distanceToGoalSq >
SQR( 600 ) )
732 self SetSpeed(
self.settings.defaultMoveSpeed * 2 );
734 else if ( distanceToGoalSq <
SQR( 100 ) )
736 self SetSpeed(
self.settings.defaultMoveSpeed * 0.3 );
740 self SetSpeed(
self.settings.defaultMoveSpeed );
743 timeNotAtGoal = GetTime();
749 pointIndex = RandomInt(
self._guard_points.size );
750 timeNotAtGoal = GetTime();
757 if (
self SetVehGoalPos(
self.current_pathto_pos,
true, usePathfinding ) )
759 self playsound (
"veh_wasp_direction" );
761 self ClearLookAtEnt();
762 self notify(
"fire_stop" );
794 if (
self.enable_target_laser ===
true )
799 if ( IsDefined(
self.owner ) && IsDefined(
self.owner.enemy ) )
801 self.favoriteEnemy =
self.owner.enemy;
808 self endon(
"death" );
809 self endon(
"change_state" );
811 isRocketType = (
self.variant ===
"rocket" );
815 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
817 if( DistanceSquared(
self.enemy.origin,
self.origin ) <
SQR( 0.5 * (
self.settings.engagementDistMin +
self.settings.engagementDistMax ) * 3 ) )
819 self SetLookAtEnt(
self.enemy );
830 startAim = GetTime();
836 if ( isdefined(
self.enemy ) &&
self.turretontarget &&
self.noshoot !==
true )
840 for( i = 0; i < 2 && isdefined(
self.enemy ); i++ )
842 self FireWeapon( 0,
self.enemy );
849 self vehicle_ai::fire_for_time( RandomFloatRange(
self.settings.turret_fire_burst_min,
self.settings.turret_fire_burst_max ), 0,
self.enemy );
852 if( isdefined(
self.settings.turret_cooldown_max ) )
854 DEFAULT(
self.settings.turret_cooldown_min, 0 );
855 wait( RandomFloatRange(
self.settings.turret_cooldown_min,
self.settings.turret_cooldown_max ) );
860 if( isdefined(
self.settings.turret_enemy_detect_freq ) )
861 wait
self.settings.turret_enemy_detect_freq;
864 self SetTurretTargetRelativeAngles( (15,0,0), 0 );
869 if( isdefined(
self.enemy ) && IsAI(
self.enemy ) )
871 wait( RandomFloatRange( 4, 7 ) );
875 wait( RandomFloatRange( 3, 5 ) );
880 if( isdefined(
self.enemy ) && IsAI(
self.enemy ) )
882 wait( RandomFloatRange( 2, 2.5 ) );
886 wait( RandomFloatRange( 0.5, 1.5 ) );
900 self endon(
"death" );
901 self endon(
"change_state" );
902 self endon(
"near_goal" );
903 self endon(
"reached_end_node" );
905 old_enemy =
self.enemy;
911 if( isdefined(
self.current_pathto_pos ) )
913 if( distance2dSquared(
self.current_pathto_pos,
self.goalpos ) >
SQR(
self.goalradius ) )
916 self notify(
"near_goal" );
920 if ( isdefined(
self.enemy ) )
922 if (
self.noshoot !==
true &&
self VehCanSee(
self.enemy ) )
924 self SetTurretTargetEnt(
self.enemy );
925 self SetLookAtEnt(
self.enemy );
928 if( !isdefined( old_enemy ) )
930 self notify(
"near_goal" );
932 else if(
self.enemy != old_enemy )
934 self notify(
"near_goal" );
939 self notify(
"near_goal" );
949 self endon(
"change_state" );
950 self endon(
"death" );
959 if( isdefined(
self.current_pathto_pos ) )
961 if( distanceSquared(
self.current_pathto_pos,
self.goalpos ) >
SQR(
self.goalradius ) )
967 if( isdefined(
self.enemy ) )
969 if ( !
self vehCanSee(
self.enemy ) )
972 if( cant_see_count >= 3 )
988 goalHeight =
self.enemy.origin[2] + 0.5 * (
self.settings.engagementHeightMin +
self.settings.engagementHeightMax );
989 distFromPreferredHeight = abs(
self.origin[2] - goalHeight );
990 if ( distFromPreferredHeight > 100 )
995 if( isplayer(
self.enemy ) &&
self.enemy islookingat(
self ) )
999 wait RandomFloatRange( 0.1, 0.5 );
1007 if( isdefined(
self.leader ) && isdefined(
self.leader.current_pathto_pos ) )
1023 if( isdefined(
self.leader ) )
1025 ArrayRemoveValue(
self.leader.followers,
self );
1026 self.leader = undefined;
1033 if( isdefined(
self.no_group ) &&
self.no_group ==
true )
1038 if( isdefined(
self.leader ) )
1043 if( isdefined(
self.followers ) )
1045 self.followers = array::remove_dead(
self.followers,
false );
1046 if(
self.followers.size > 0 )
1052 team_mates = GetAITeamArray(
self.team );
1054 foreach( guy
in team_mates )
1056 if( isdefined( guy.archetype ) && guy.archetype ==
"wasp" )
1058 if( isdefined( guy.leader ) )
1068 if( distanceSquared(
self.origin, guy.origin ) >
SQR( 700 ) )
1073 if( !isdefined( guy.followers ) )
1084 guy.followers[ guy.followers.size ] =
self;
1093 if (
self.always_face_enemy ===
true )
1098 if( distanceToGoalSq <
SQR( 250 ) )
1104 if( isdefined(
self.enemy ) )
1106 to_goal = VectorNormalize(
self.current_pathto_pos -
self.origin );
1107 to_enemy = VectorNormalize(
self.enemy.origin -
self.origin );
1109 dot = VectorDot( to_goal, to_enemy );
1110 if( abs( dot ) > 0.7 )
1116 if( distanceToGoalSq >
SQR( 400 ) )
1118 return RandomInt( 100 ) > 25;
1121 return RandomInt( 100 ) > 50;
1126 self endon(
"change_state" );
1127 self endon(
"death" );
1136 self SetSpeed(
self.settings.defaultMoveSpeed );
1146 if (
self.enable_guard ===
true )
1151 if ( IsDefined(
self.enemy ) )
1153 self SetTurretTargetEnt(
self.enemy );
1154 self SetLookAtEnt(
self.enemy );
1159 if ( !IsDefined(
self.enemy ) )
1161 self ClearLookAtEnt();
1163 AIArray = GetAITeamArray(
"all" );
1164 foreach ( AI
in AIArray )
1166 self GetPerfectInfo( AI );
1169 players = GetPlayers(
"all" );
1170 foreach ( player
in players )
1172 self GetPerfectInfo( player );
1178 usePathfinding =
true;
1179 onNavVolume = IsPointInNavVolume(
self.origin,
"navvolume_small" );
1183 getbackPoint = undefined;
1185 if (
self.aggresive_navvolume_recover ===
true )
1190 pointOnNavVolume =
self GetClosestPointOnNavVolume(
self.origin, 100 );
1191 if ( isdefined( pointOnNavVolume ) )
1193 if ( SightTracePassed(
self.origin, pointOnNavVolume,
false,
self ) )
1195 getbackPoint = pointOnNavVolume;
1199 if ( !isdefined( getbackPoint ) )
1201 queryResult = PositionQuery_Source_Navigation(
self.origin, 0, 200, 100, 2 *
self.radius,
self );
1202 PositionQuery_Filter_Sight( queryResult,
self.origin, (0, 0, 0),
self, 1 );
1203 getbackPoint = undefined;
1204 foreach( point
in queryResult.data )
1206 if ( point.visibility ===
true )
1208 getbackPoint = point.origin;
1214 if ( isdefined( getbackPoint ) )
1216 self.current_pathto_pos = getbackPoint;
1217 usePathfinding =
false;
1222 if ( stuckCount == 1 )
1224 stuckLocation =
self.origin;
1226 else if ( stuckCount > 10 )
1229 assert(
false,
"Wasp fall outside of NavVolume at " +
self.origin );
1230 v_box_min = ( -
self.radius, -
self.radius, -
self.radius );
1231 v_box_max = (
self.radius,
self.radius,
self.radius );
1232 Box(
self.origin, v_box_min, v_box_max,
self.angles[1], (1,0,0), 1,
false, 1000000 );
1233 if ( isdefined( stuckLocation ) )
1235 Line( stuckLocation,
self.origin, (1,0,0), 1,
true, 1000000 );
1246 if(
self.goalforced )
1248 goalpos =
self GetClosestPointOnNavVolume(
self.goalpos, 100 );
1249 if ( isdefined( goalpos ) )
1251 self.current_pathto_pos = goalpos;
1252 usePathfinding =
true;
1256 self.current_pathto_pos =
self.goalpos;
1257 usePathfinding =
false;
1260 else if ( IsDefined(
self.enemy ) )
1263 usePathfinding =
true;
1268 usePathfinding =
true;
1272 if ( IsDefined(
self.current_pathto_pos ) )
1274 distanceToGoalSq = DistanceSquared(
self.current_pathto_pos,
self.origin );
1278 if ( distanceToGoalSq >
SQR( 2000 ) )
1280 self SetSpeed(
self.settings.defaultMoveSpeed * 2 );
1283 if (
self SetVehGoalPos(
self.current_pathto_pos,
true, usePathfinding ) )
1285 if ( IsDefined(
self.enemy ) )
1287 self playsound (
"veh_wasp_direction" );
1291 self playsound (
"veh_wasp_vox" );
1297 self ClearLookAtEnt();
1298 self notify(
"fire_stop" );
1299 self.noshoot =
true;
1303 self.noshoot = undefined;
1313 queryMultiplier = 1;
1315 queryResult = PositionQuery_Source_Navigation(
self.origin,
WASP_MOVE_DIST_MIN,
WASP_MOVE_DIST_MAX * queryMultiplier, 130, 3 *
self.radius * queryMultiplier,
self,
self.radius * queryMultiplier );
1316 PositionQuery_Filter_DistanceToGoal( queryResult,
self );
1319 self.isOnNav = queryResult.centerOnNav;
1321 best_point = undefined;
1322 best_score = -999999;
1324 foreach ( point
in queryResult.data )
1326 randomScore = randomFloatRange( 0, 100 );
1327 distToOriginScore = point.distToOrigin2D * 0.2;
1329 point.score += randomScore + distToOriginScore;
1330 ADD_POINT_SCORE(point,
"distToOrigin", distToOriginScore );
1332 if ( point.score > best_score )
1334 best_score = point.score;
1341 if( !isdefined( best_point ) )
1346 return best_point.origin;
1351 if( !isdefined(
self.enemy ) )
1357 selfDistToTarget = Distance2D(
self.origin,
self.enemy.origin );
1359 goodDist = 0.5 * (
self.settings.engagementDistMin +
self.settings.engagementDistMax );
1361 closeDist = 1.2 * goodDist;
1362 farDist = 3 * goodDist;
1364 queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
1366 preferedHeightRange = 35;
1369 avoid_locations = [];
1373 if( isalive(
self.leader ) && isdefined(
self.leader.current_pathto_pos ) )
1375 query_position =
self.leader.current_pathto_pos;
1377 queryResult = PositionQuery_Source_Navigation( query_position, 0,
WASP_GROUP_RADIUS, 100, 35,
self, 25 );
1390 else if ( isalive(
self.owner ) &&
self.enable_guard ===
true )
1392 ownerorigin =
self GetClosestPointOnNavVolume(
self.owner.origin + (0,0,40), 50 );
1393 if ( isdefined( ownerorigin ) )
1395 queryResult = PositionQuery_Source_Navigation( ownerorigin, 0,
WASP_MOVE_DIST_MAX * min( queryMultiplier, 1.5 ), 130, 3 *
self.radius,
self );
1396 if ( isdefined( queryResult ) && isdefined( queryResult.data ) )
1398 PositionQuery_Filter_Sight( queryResult,
self.owner GetEye(), (0, 0, 0),
self, 5,
self,
"visowner" );
1399 PositionQuery_Filter_Sight( queryResult,
self.enemy GetEye(), (0, 0, 0),
self, 5,
self,
"visenemy" );
1400 foreach ( point
in queryResult.data )
1402 if ( point.visowner ===
true )
1404 ADD_POINT_SCORE( point,
"visowner", 300 );
1407 if ( point.visenemy ===
true )
1409 ADD_POINT_SCORE( point,
"visenemy", 300 );
1417 queryResult = PositionQuery_Source_Navigation(
self.origin, 0,
WASP_MOVE_DIST_MAX * min( queryMultiplier, 2 ), 130, 3 *
self.radius * queryMultiplier,
self, 2.2 *
self.radius * queryMultiplier );
1419 team_mates = GetAITeamArray(
self.team );
1423 foreach( guy
in team_mates )
1425 if( isdefined( guy.archetype ) && guy.archetype ==
"wasp" )
1428 if( isdefined( guy.followers ) && guy.followers.size > 0 && guy !=
self )
1430 if( isdefined( guy.current_pathto_pos ) )
1432 avoid_locations[ avoid_locations.size ] = guy.current_pathto_pos;
1440 if( !isdefined( queryResult ) || !isdefined( queryResult.data ) || queryResult.data.size == 0)
1446 PositionQuery_Filter_DistanceToGoal( queryResult,
self );
1447 PositionQuery_Filter_InClaimedLocation( queryResult,
self );
1453 best_point = undefined;
1454 best_score = -999999;
1456 foreach ( point
in queryResult.data )
1458 ADD_POINT_SCORE( point,
"random", randomFloatRange( 0, randomness ) );
1460 ADD_POINT_SCORE( point,
"engagementDist", -point.distAwayFromEngagementArea );
1461 ADD_POINT_SCORE( point,
"height", -point.distEngagementHeight * 1.4 );
1463 if( point.disttoorigin2d < 120 )
1465 ADD_POINT_SCORE( point,
"tooCloseToSelf", (120 - point.disttoorigin2d) * -1.5 );
1468 foreach( location
in avoid_locations )
1470 if( distanceSquared( point.origin, location ) <
SQR( avoid_radius ) )
1472 ADD_POINT_SCORE( point,
"tooCloseToOthers", -avoid_radius );
1476 if( point.inClaimedLocation )
1478 ADD_POINT_SCORE( point,
"inClaimedLocation", -500 );
1481 if ( point.score > best_score )
1483 best_score = point.score;
1490 if( !isdefined( best_point ) )
1496 if (
IS_TRUE( GetDvarInt(
"hkai_debugPositionQuery") ) )
1498 recordLine(
self.origin, best_point.origin, (0.3,1,0) );
1499 recordLine(
self.origin,
self.enemy.origin, (1,0,0.4) );
1503 return best_point.origin;
1506 function drone_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
1508 iDamage =
vehicle_ai::shared_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );
1515 if ( isdefined( eAttacker ) && isdefined( eAttacker.archetype ) && isdefined( sMeansOfDeath )
1516 && eAttacker.archetype ==
ARCHETYPE_WASP && sMeansOfDeath ==
"MOD_EXPLOSIVE" )
1530 self endon(
"change_state" );
1532 driver =
self GetSeatOccupant( 0 );
1534 if( isPlayer( driver ) )
1539 if( isPlayer( driver ) && isDefined(
self.playerDrivenVersion) )
1548 self endon (
"death" );
1549 self endon (
"change_state" );
1551 driver =
self GetSeatOccupant( 0 );
1553 driver endon(
"disconnect" );
1555 cam_low_type =
self.vehicletype;
1556 cam_high_type =
self.playerDrivenVersion;