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\audio_shared;
13 #using scripts\shared\clientfield_shared;
15 #using scripts\shared\ai\systems\blackboard;
16 #using scripts\shared\ai\blackboard_vehicle;
18 #insert scripts\shared\version.gsh;
19 #insert scripts\shared\shared.gsh;
20 #insert scripts\shared\statemachine.gsh;
21 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
23 #insert scripts\shared\ai\utility.gsh;
27 #define SPIDER_MOVE_DIST_MAX 300
28 #define SPIDER_MOVE_DIST_MIN 80
30 #using_animtree( "generic" );
38 SetDvar(
"debug_spider_noswitch", 0 );
44 return GetDvarInt(
"debug_spider_noswitch", 0 ) === 1;
50 self.fovcosinebusy = 0;
51 self.delete_on_death =
true;
52 self.health =
self.healthdefault;
54 self UseAnimTree( #animtree );
58 assert( isdefined(
self.scriptbundlesettings ) );
61 self EnableAimAssist();
63 self SetDrawInfrared(
true );
68 self SetNearGoalNotifyDist( 40 );
69 self.goalRadius = 999999;
70 self.goalHeight = 999999;
71 self SetGoal(
self.origin,
false,
self.goalRadius,
self.goalHeight );
73 self SetOnTargetAngle( 3 );
80 if( IsDefined( level.vehicle_initializer_cb ) )
82 [[level.vehicle_initializer_cb]]( self );
85 self ASMRequestSubstate(
"locomotion@movement" );
116 self endon(
"death" );
118 self ASMRequestSubstate(
"death@stationary" );
131 self endon(
"change_state" );
132 self endon(
"death" );
134 self ASMRequestSubstate(
"locomotion@aggressive" );
142 if(
self.goalforced )
148 selfDistToTarget = Distance2D(
self.origin, enemy.origin );
150 goodDist = 0.5 * (
self.settings.engagementDistMin +
self.settings.engagementDistMax );
153 closeDist = 1.2 * goodDist;
154 farDist = 3 * goodDist;
156 queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
158 preferedDistAwayFromOrigin = 300;
165 PositionQuery_Filter_DistanceToGoal( queryResult,
self );
167 PositionQuery_Filter_InClaimedLocation( queryResult,
self );
170 if ( isdefined(
self.avoidEntities ) && isdefined(
self.avoidEntitiesDistance ) )
176 best_point = undefined;
177 best_score = -999999;
179 foreach ( point
in queryResult.data )
182 ADD_POINT_SCORE( point,
"distToOrigin", MapFloat( 0, preferedDistAwayFromOrigin, 0, 300, point.distToOrigin2D ) );
184 if( point.inClaimedLocation )
186 ADD_POINT_SCORE( point,
"inClaimedLocation", -500 );
189 ADD_POINT_SCORE( point,
"random", randomFloatRange( 0, randomness ) );
191 ADD_POINT_SCORE( point,
"engagementDist", -point.distAwayFromEngagementArea );
193 if ( point.score > best_score )
195 best_score = point.score;
202 /#
self.debug_ai_move_to_points_considered = queryResult.data; #/
204 if( !isdefined( best_point ) )
210 if (
IS_TRUE( GetDvarInt(
"hkai_debugPositionQuery") ) )
212 recordLine(
self.origin, best_point.origin, (0.3,1,0) );
213 recordLine(
self.origin, enemy.origin, (1,0,0.4) );
217 return best_point.origin;
222 self endon(
"change_state" );
223 self endon(
"death" );
225 self.pathfailcount = 0;
226 self.foundpath =
true;
228 if ( params.playTransition ===
true )
231 self ASMRequestSubstate(
"exit@aggressive" );
241 self SetSpeed(
self.settings.defaultMoveSpeed );
242 self ASMRequestSubstate(
"locomotion@movement" );
244 self.dont_move = undefined;
248 if ( !IsDefined(
self.enemy ) )
254 else if (
self.dont_move ===
true )
260 if ( IsDefined(
self.can_reach_enemy ) )
262 if ( !
self [[
self.can_reach_enemy ]]() )
269 if ( !
self VehSeenRecently(
self.enemy, 5 ) )
278 if ( IsDefined(
self.current_pathto_pos ) )
280 if (
self SetVehGoalPos(
self.current_pathto_pos,
false,
true ) )
292 self endon(
"change_state" );
293 self endon(
"death" );
297 if ( !IsDefined(
self.enemy ) )
303 state_params = SpawnStruct();
304 state_params.playTransition =
true;
308 foreach( player
in level.players )
310 self GetPerfectInfo( player,
false );
311 if ( player.b_is_designated_target ===
true &&
self.enemy.b_is_designated_target !==
true )
313 self GetPerfectInfo( player,
true );
314 self SetPersonalThreatBias( player, 100000, 2.0 );
321 if (
self vehCanSee(
self.enemy ) )
323 self SetLookAtEnt(
self.enemy );
324 self SetTurretTargetEnt(
self.enemy );
327 if ( Distance2DSquared(
self.origin,
self.enemy.origin ) <
SQR(
self.settings.engagementDistMax * 1.5 ) &&
vehicle_ai::IsCooldownReady(
"rocket" ) &&
self VehCanSee(
self.enemy ) )
340 self notify(
"near_goal" );
342 self.dont_move =
true;
344 self SetLookAtEnt( enemy );
345 self SetTurretTargetEnt( enemy );
346 self SetVehGoalPos( enemy.origin,
false,
false );
348 targetAngleDiff = 30;
349 v_to_enemy =
FLAT_ORIGIN( (enemy.origin -
self.origin) );
350 goalAngles = VectortoAngles( v_to_enemy );
351 angleDiff = AbsAngleClamp180(
self.angles[1] - goalAngles[1] );
352 angleAdjustingStart = GetTime();
355 angleDiff = AbsAngleClamp180(
self.angles[1] - goalAngles[1] );
361 if ( angleDiff <= targetAngleDiff )
363 self ASMRequestSubstate(
"fire@stationary" );
366 if ( timedout !==
true )
375 self ASMRequestSubstate(
"locomotion@movement" );
376 self.dont_move = undefined;
381 self.switch_to_melee =
true;
398 if ( !isdefined(
self.enemy ) )
404 ( Distance2DSquared(
self.origin,
self.enemy.origin ) <
SQR(
self.settings.meleedist ) && Abs(
self.origin[2] -
self.enemy.origin[2] ) <
self.settings.meleedist ) )
418 self endon(
"change_state" );
419 self endon(
"death" );
421 if ( params.playTransition ===
true )
424 self ASMRequestSubstate(
"enter@aggressive" );
434 self.pathfailcount = 0;
435 self.switch_to_melee = undefined;
437 self SetSpeed(
self.settings.defaultMoveSpeed * 1.5 );
439 self ASMRequestSubstate(
"locomotion@aggressive" );
441 self.dont_move = undefined;
447 foreach( player
in level.players )
449 self GetPerfectInfo( player,
true );
450 if ( player.b_is_designated_target ===
true )
452 self SetPersonalThreatBias( player, 100000, 3.0 );
456 if ( !IsDefined(
self.enemy ) )
462 else if (
self.dont_move ===
true )
468 if ( IsDefined(
self.can_reach_enemy ) )
470 if ( !
self [[
self.can_reach_enemy ]]() )
477 self.foundpath =
false;
481 if ( isdefined( targetPos ) )
484 if( DistanceSquared(
self.origin, targetPos ) >
SQR( 1000 ) &&
self IsPosInClaimedLocation( targetPos ) )
486 queryResult = PositionQuery_Source_Navigation( targetPos, 0,
self.settings.max_move_dist,
self.settings.max_move_dist,
self.radius,
self );
488 PositionQuery_Filter_InClaimedLocation( queryResult,
self.enemy );
490 best_point = undefined;
491 best_score = -999999;
492 foreach ( point
in queryResult.data )
494 ADD_POINT_SCORE( point,
"distToOrigin", MapFloat( 0, 200, 0, -200, Distance( point.origin, queryResult.origin ) ) );
495 ADD_POINT_SCORE( point,
"heightToOrigin", MapFloat( 50, 200, 0, -200, Abs( point.origin[2] - queryResult.origin[2] ) ) );
497 if( point.inClaimedLocation ===
true )
499 ADD_POINT_SCORE( point,
"inClaimedLocation", -500 );
502 if ( point.score > best_score )
504 best_score = point.score;
511 if( isdefined( best_point ) )
513 targetPos = best_point.origin;
517 self SetVehGoalPos( targetPos,
false,
true );
520 if (
self.foundpath )
522 self.current_pathto_pos = targetPos;
525 self.pathfailcount = 0;
531 if ( !
self.foundpath )
533 self.pathfailcount++;
535 if (
self.pathfailcount > 2 )
537 if( IsDefined(
self.enemy ) )
540 self SetPersonalThreatBias(
self.enemy, -2000, 5.0 );
547 queryResult = PositionQuery_Source_Navigation(
self.origin, 0,
self.settings.max_move_dist,
self.settings.max_move_dist,
self.radius,
self );
549 if( queryResult.data.size )
551 point = queryResult.data[ randomint( queryResult.data.size ) ];
553 self SetVehGoalPos( point.origin,
false,
false );
554 self.current_pathto_pos = undefined;
557 self notify(
"near_goal" );
567 self endon(
"change_state" );
568 self endon(
"death" );
572 state_params = SpawnStruct();
573 state_params.playTransition =
true;
575 if ( !IsDefined(
self.enemy ) )
584 if (
self vehCanSee(
self.enemy ) )
586 self SetLookAtEnt(
self.enemy );
587 self SetTurretTargetEnt(
self.enemy );
590 if ( Distance2DSquared(
self.origin,
self.enemy.origin ) <
SQR(
self.settings.meleereach ) &&
self VehCanSee(
self.enemy ) )
592 if ( BulletTracePassed(
self.origin + (0,0,10),
self.enemy.origin + (0,0,20),
false,
self,
self.enemy,
false,
true ) )
605 self notify(
"near_goal" );
607 self.dont_move =
true;
608 self ASMRequestSubstate(
"melee@stationary" );
611 if ( timedout !==
true )
613 if ( isalive( enemy ) && Distance2DSquared(
self.origin, enemy.origin ) <
SQR(
self.settings.meleereach * 1.2 ) )
615 enemy DoDamage(
self.settings.meleedamage,
self.origin,
self,
self );
621 self ASMRequestSubstate(
"locomotion@aggressive" );
622 self.dont_move = undefined;
634 if (
self.pathfailcount > 4 )
644 if ( IsAlive(
self.enemy ) && Distance2DSquared(
self.origin,
self.enemy.origin ) >
SQR(
self.settings.meleedist * 4 ) )
649 if ( !isdefined(
self.enemy ) )
660 self endon(
"change_state" );
661 self endon(
"death" );
662 self notify(
"end_prevent_stuck" );
663 self endon(
"end_prevent_stuck" );
668 previous_origin = undefined;
673 if ( isdefined( previous_origin ) && DistanceSquared( previous_origin,
self.origin ) <
SQR( 0.1 ) && !
IS_TRUE( level.bzm_worldPaused ) )
679 previous_origin =
self.origin;
685 self.pathfailcount = 10;
695 if(
self.goalforced )
700 if( isdefined(
self.settings.all_knowing ) )
702 if( isdefined(
self.enemy ) )
704 target_pos =
self.enemy.origin;
714 if( isdefined( target_pos ) )
716 target_pos_onnavmesh = GetClosestPointOnNavMesh( target_pos,
self.settings.detonation_distance * 1.5,
self.radius,
NMMF_ALL & ~
NMMF_NOVEHICLE );
720 if( !isdefined( target_pos_onnavmesh ) )
722 if( isdefined(
self.enemy ) )
724 self SetPersonalThreatBias(
self.enemy, -2000, 5.0 );
727 if ( isdefined(
self.current_pathto_pos ) && DistanceSquared(
self.origin,
self.current_pathto_pos ) >
SQR(
self.settings.meleereach ) )
729 return self.current_pathto_pos;
736 else if ( isdefined(
self.enemy ) )
738 if ( DistanceSquared( target_pos, target_pos_onnavmesh ) >
SQR(
self.settings.detonation_distance * 0.9 ) )
740 self SetPersonalThreatBias(
self.enemy, -2000, 5.0 );
744 if( isdefined( enemy ) && IsPlayer( enemy ) )
746 enemy_vel_offset = enemy GetVelocity() * 0.5;
748 enemy_look_dir_offset = AnglesToForward( enemy.angles );
749 if( distance2dSquared(
self.origin, enemy.origin ) >
SQR( 500 ) )
751 enemy_look_dir_offset *= 110;
755 enemy_look_dir_offset *= 35;
758 offset = enemy_vel_offset + enemy_look_dir_offset;
761 if( TracePassedOnNavMesh( target_pos_onnavmesh, target_pos + offset ) )
763 target_pos += offset;
767 target_pos = target_pos_onnavmesh;
772 target_pos = target_pos_onnavmesh;
780 self endon(
"death" );
781 self endon(
"change_state" );
782 self endon(
"near_goal" );
783 self endon(
"reached_end_node" );
786 self notify(
"clear_interrupt_threads" );
787 self endon(
"clear_interrupt_threads" );
793 if( isdefined(
self.current_pathto_pos ) )
795 if( distance2dSquared(
self.current_pathto_pos,
self.goalpos ) >
SQR(
self.goalRadius ) )
799 self notify(
"near_goal" );
803 if ( isdefined( targetPos ) )
806 if( DistanceSquared(
self.origin, targetPos ) >
SQR( 1000 ) )
808 repath_range =
self.settings.repath_range * 2;
813 repath_range =
self.settings.repath_range;
816 if( distance2dSquared(
self.current_pathto_pos, targetPos ) >
SQR( repath_range ) )
818 self notify(
"near_goal" );
822 if( isdefined(
self.enemy ) && IsPlayer(
self.enemy ) )
824 forward = AnglesToForward(
self.enemy GetPlayerAngles() );
825 dir_to_raps =
self.origin -
self.enemy.origin;
827 speedToUse =
self.settings.defaultMoveSpeed * 2;
828 if( VectorDot( forward, dir_to_raps ) > 0 )
830 self SetSpeed( speedToUse );
834 self SetSpeed( speedToUse * 0.75 );
839 speedToUse =
self.settings.defaultMoveSpeed * 2;
840 self SetSpeed( speedToUse );
854 self endon(
"death" );
855 self endon(
"change_state" );
856 self notify(
"end_nudge_collision" );
857 self endon(
"end_nudge_collision" );
861 self waittill(
"veh_collision", velocity, normal );
862 ang_vel =
self GetAngularVelocity() * 0.8;
863 self SetAngularVelocity( ang_vel );
866 if ( IsAlive(
self ) && VectorDot( normal, (0,0,1) ) < 0.5 )
868 self SetVehVelocity(
self.velocity + normal * 400 );
876 foreach( player
in level.players )
880 self GetPerfectInfo( player,
true );
886 function spider_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
888 if ( IsAlive( eAttacker ) && eAttacker.team ===
self.team )