1 #using scripts\codescripts\struct;
3 #using scripts\shared\math_shared;
4 #using scripts\shared\statemachine_shared;
5 #using scripts\shared\clientfield_shared;
6 #using scripts\shared\system_shared;
7 #using scripts\shared\array_shared;
8 #using scripts\shared\util_shared;
10 #using scripts\shared\vehicle_shared;
11 #using scripts\shared\vehicle_death_shared;
12 #using scripts\shared\vehicle_ai_shared;
14 #using scripts\shared\ai\systems\blackboard;
15 #using scripts\shared\ai\blackboard_vehicle;
16 #using scripts\shared\animation_shared;
17 #using scripts\shared\ai\systems\gib;
18 #using scripts\shared\ai\zombie_utility;
20 #insert scripts\shared\shared.gsh;
21 #insert scripts\shared\statemachine.gsh;
22 #insert scripts\shared\version.gsh;
23 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
24 #insert scripts\shared\ai\utility.gsh;
25 #insert scripts\shared\ai\systems\gib.gsh;
27 #define DRAGON_FOV_ANGLE 60
29 #define DRAGON_MOVE_DIST_HEIGHT 90
31 #define DRAGON_FOLLOW_DIST 80
33 #define DRAGON_MELEE_DIST 400
39 #using_animtree( "generic" );
48 self useanimtree( #animtree );
52 self.health =
self.healthdefault;
56 if ( isdefined(
self.scriptbundlesettings ) )
61 assert( isdefined(
self.settings ) );
64 self SetNearGoalNotifyDist(
self.radius * 1.5 );
65 self SetHoverParams(
self.radius,
self.settings.defaultMoveSpeed * 2,
self.radius );
66 self SetSpeed(
self.settings.defaultMoveSpeed );
73 self.fovcosinebusy = 0;
75 self.vehAirCraftCollisionEnabled =
false;
78 self.goalRadius = 9999999;
79 self.goalHeight = 512;
80 self SetGoal(
self.origin,
false,
self.goalRadius,
self.goalHeight );
81 self.delete_on_death =
true;
88 if( IsDefined( level.vehicle_initializer_cb ) )
90 [[level.vehicle_initializer_cb]]( self );
103 if ( SessionModeIsZombiesGame() )
115 SetDvar(
"debug_dragon_threat_selection", 0 );
122 self.startTime = GetTime();
128 if( !IsDefined( target ) )
133 if( !IsAlive( target ) )
148 if( target IsNoTarget() )
153 if(
IS_TRUE( target._dragon_ignoreme ) )
173 if( DistanceSquared(
self.owner.origin, target.origin ) >
SQR(
self.settings.guardradius ) )
178 if (
self VehCanSee( target ) )
183 if ( IsActor( target ) && target CanSee(
self.owner ) )
188 if ( IsVehicle( target ) && target VehCanSee(
self.owner ) )
199 dragon_enemies = GetAITeamArray(
"axis" );
201 distSqr =
SQR( 10000 );
202 best_enemy = undefined;
203 foreach( enemy
in dragon_enemies )
205 newDistSqr = Distance2DSquared( enemy.origin,
self.owner.origin );
210 newDistSqr = Max( Distance2D( enemy.origin,
self.owner.origin ) - 700, 0 );
211 newDistSqr =
SQR( newDistSqr );
215 newDistSqr = Max( Distance2D( enemy.origin,
self.owner.origin ) - 500, 0 );
216 newDistSqr =
SQR( newDistSqr );
218 else if ( enemy ===
self.dragonEnemy )
220 newDistSqr = Max( Distance2D( enemy.origin,
self.owner.origin ) - 300, 0 );
221 newDistSqr =
SQR( newDistSqr );
224 if ( newDistSqr < distSqr )
226 distSqr = newDistSqr;
238 self endon(
"death" );
243 if( !IsDefined(
self.owner ) )
257 if( GetDvarInt(
"debug_dragon_threat_selection", 0 ) )
259 if( IsDefined(
self.dragonEnemy ) )
261 line(
self.origin,
self.dragonEnemy.origin, ( 1, 0, 0 ), 1.0,
false, 5 );
269 if( !isDefined( target ) )
271 self.dragonEnemy = undefined;
275 self.dragonEnemy = target;
287 self endon(
"change_state" );
288 self endon(
"death" );
290 closest_distSqr =
SQR( 10000 );
292 foreach( powerup
in level.active_powerups )
294 powerup.navVolumeOrigin =
self GetClosestPointOnNavVolume( powerup.origin, 100 );
295 if ( !isdefined( powerup.navVolumeOrigin ) )
300 distSqr = DistanceSquared( powerup.origin,
self.origin );
301 if ( distSqr < closest_distSqr )
303 closest_distSqr = distSqr;
308 if ( isdefined( closest ) && distSqr <
SQR( 2000 ) )
310 self SetVehGoalPos( closest.navVolumeOrigin,
true,
true );
316 if ( isdefined( closest ) )
318 trace = BulletTrace(
self.origin, closest.origin,
false,
self );
319 if(
trace[
"fraction"] == 1 )
321 self SetVehGoalPos( closest.origin,
true,
false );
331 if ( level.whelp_no_power_up_pickup ===
true )
336 if ( isdefined(
self.dragonEnemy ) )
341 if ( level.active_powerups.size < 1 )
354 self endon(
"change_state" );
355 self endon(
"death" );
357 idealDistToOwner = 300;
359 self ASMRequestSubstate(
"locomotion@movement" );
361 while ( !isdefined(
self.owner ) )
370 self SetSpeed(
self.settings.defaultMoveSpeed );
371 self ASMRequestSubstate(
"locomotion@movement" );
373 if ( IsDefined(
self.owner ) && Distance2DSquared(
self.origin,
self.owner.origin ) <
SQR( idealDistToOwner ) && IsPointInNavVolume(
self.origin,
"navvolume_small" ) )
375 if ( !isdefined(
self.current_pathto_pos ) )
377 self.current_pathto_pos =
self GetClosestPointOnNavVolume(
self.origin, 100 );
380 self SetVehGoalPos(
self.current_pathto_pos,
true,
false );
385 if( IsDefined(
self.owner ) )
389 sightTarget = undefined;
390 if ( isdefined(
self.dragonEnemy ) )
392 sightTarget =
self.dragonEnemy GetEye();
393 PositionQuery_Filter_Sight( queryResult, sightTarget, (0,0,0),
self, 4 );
396 if(
IS_TRUE( queryResult.centerOnNav ) )
398 ownerOrigin =
self.owner.origin;
399 ownerForward = AnglesToForward(
self.owner.angles );
402 best_point = undefined;
403 best_score = -999999;
405 foreach ( point
in queryResult.data )
407 distSqr = Distance2DSquared( point.origin, ownerOrigin );
408 if ( distSqr >
SQR( idealDistToOwner ) )
410 ADD_POINT_SCORE( point,
"distToOwner", -Sqrt( distSqr ) * 2 );
415 if ( BulletTracePassed( point.origin, sightTarget,
false,
self ) )
417 ADD_POINT_SCORE( point,
"visibility", 400 );
421 vecToOwner = point.origin - ownerOrigin;
422 dirToOwner = VectorNormalize(
FLAT_ORIGIN( vecToOwner ) );
423 if ( VectorDot( ownerForward, dirToOwner ) > 0.34 )
425 if ( Abs( vecToOwner[2] ) < 100 )
427 ADD_POINT_SCORE( point,
"frontOfPlayer", 300 );
429 else if ( Abs( vecToOwner[2] ) < 200 )
431 ADD_POINT_SCORE( point,
"frontOfPlayer", 100 );
435 if ( point.score > best_score )
437 best_score = point.score;
444 if ( isdefined( best_point ) )
447 if (
IS_TRUE( GetDvarInt(
"hkai_debugPositionQuery") ) )
449 recordLine(
self.origin, best_point.origin, (0.3,1,0) );
450 recordLine(
self.origin,
self.owner.origin, (1,0,0.4) );
454 if ( DistanceSquared(
self.origin, best_point.origin ) >
SQR( 50 ) )
456 self.current_pathto_pos = best_point.origin;
458 self SetVehGoalPos(
self.current_pathto_pos,
true,
true );
479 self endon(
"change_state" );
480 self endon(
"death" );
493 if ( !IsDefined(
self.dragonEnemy ) )
498 self SetLookAtEnt(
self.dragonEnemy );
500 if ( !
self VehCanSee(
self.dragonEnemy ) )
505 if ( Distance2DSquared(
self.dragonEnemy.origin,
self.owner.origin ) >
SQR(
self.settings.guardradius ) )
510 eyeOffset = (
self.dragonEnemy GetEye() -
self.dragonEnemy.origin ) * 0.6;
512 if ( !BulletTracePassed(
self.origin,
self.dragonEnemy GetEye() - eyeOffset,
false,
self,
self.dragonEnemy ) )
514 self.dragonEnemy = undefined;
518 aimOffset =
self.dragonEnemy GetVelocity() * 0.3 - eyeOffset;
519 self SetTurretTargetEnt(
self.dragonEnemy, aimOffset );
523 if ( isdefined(
self.dragonEnemy ) )
525 self FireWeapon( 0,
self.dragonEnemy, (0,0,0),
self );
543 while ( queryResult.data.size < 1 )
545 queryResult = PositionQuery_Source_Navigation(
self.origin, 0, 100 * multiplier,
DRAGON_MOVE_DIST_HEIGHT * multiplier,
self.radius * multiplier,
self );
549 if ( queryResult.data.size && !queryResult.centerOnNav )
551 best_point = undefined;
554 foreach ( point
in queryResult.data )
556 point.score = Abs( point.origin[2] - queryResult.origin[2] );
558 if ( point.score < best_score )
560 best_score = point.score;
565 if( IsDefined( best_point ) )
568 self SetNearGoalNotifyDist( 2 );
572 self.current_pathto_pos = point.origin;
574 foundpath =
self SetVehGoalPos(
self.current_pathto_pos,
true,
false );
580 self SetNearGoalNotifyDist(
self.radius );
590 function dragon_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
592 if(
self.dragon_recall_death !==
true )
605 self endon (
"death" );
607 attacker = params.inflictor;
608 if( !isdefined( attacker ) )
610 attacker = params.attacker;
613 if( attacker !==
self && ( !isdefined(
self.owner ) || (
self.owner !== attacker ) ) && ( IsAI( attacker) || IsPlayer( attacker ) ) )
615 self.damage_on_death =
false;
619 attacker = params.inflictor;
620 if( !isdefined( attacker ) )
622 attacker = params.attacker;