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\flag_shared;
11 #using scripts\shared\abilities\_ability_power;
13 #insert scripts\shared\shared.gsh;
14 #insert scripts\shared\statemachine.gsh;
16 #insert scripts\shared\ai\utility.gsh;
18 #define DRONE_HUD_MARKED_TARGET "hud_proto_rts_secure_target"
19 #define DRONE_HUD_ELEM_CONSTANT_SIZE true
21 #precache( "material", DRONE_HUD_MARKED_TARGET );
22 #precache( "fx", "_t6/electrical/fx_elec_sp_emp_stun_quadrotor" );
24 #namespace escort_drone;
30 level._effect[
"escort_drone_stun" ] =
"_t6/electrical/fx_elec_sp_emp_stun_quadrotor";
35 assert( IsDefined( player ) );
37 self.n_tetherMax = player._gadgets_player.escortTetherMaxDist;
38 self.n_tetherMin = player._gadgets_player.escortTetherMinDist;
40 self.n_tetherMaxSq =
self.n_tetherMax *
self.n_tetherMax;
41 self.n_tetherMinSq =
self.n_tetherMin *
self.n_tetherMin;
43 self.n_target_time = player._gadgets_player.escortTargetAcquireTime;
44 self.n_burstCountMin = player._gadgets_player.escortBurstCountMin;
45 self.n_burstCountMax = player._gadgets_player.escortBurstCountMax;
46 self.n_burstWaitTime = player._gadgets_player.escortBurstWaitTime;
47 self.n_burstPowerLoss = player._gadgets_player.escortBurstPowerLoss;
49 self.n_BulletPowerLoss = player._gadgets_player.escortBulletPowerLoss;
50 self.n_ExplosionPowerLoss = player._gadgets_player.escortExplosionPowerLoss;
51 self.n_MiscPowerLoss = player._gadgets_player.escortMiscPowerLoss;
54 self EnableAimAssist();
55 self SetHoverParams( 25.0, 120.0, 80 );
56 self SetNearGoalNotifyDist( 30 );
58 self.flyheight = GetDvarFloat(
"g_quadrotorFlyHeight" );
61 self.fovcosinebusy = 0.574;
63 self.vehAirCraftCollisionEnabled =
true;
65 if ( !IsDefined(
self.heightAboveGround ) )
69 self.heightAboveGround = player._gadgets_player.escortHoverHeight;
72 if( !isdefined(
self.goalradius ) )
74 self.goalradius = 300;
77 if( !isdefined(
self.goalpos ) )
79 self.goalpos =
self.origin;
82 self.original_vehicle_type =
self.vehicletype;
94 self HidePart(
"tag_viewmodel" );
99 if ( isdefined(
self.script_startstate ) )
101 if(
self.script_startstate ==
"off" )
125 if( !IsAlive(
self ) )
128 driver =
self GetSeatOccupant( 0 );
129 if( isdefined( driver ) )
146 if( !isdefined(
self.
emped ) )
148 self DisableAimAssist();
159 self EnableAimAssist();
160 self.off = undefined;
166 self.goalpos =
self.origin;
180 self endon(
"death" );
181 self endon(
"change_state" );
185 no_target_delay = 0.05;
191 if ( IsDefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) &&
self.enemy
is_in_combat() )
193 wait(
self.n_target_time );
195 if ( IsDefined(
self.enemy ) && DistanceSquared(
self.enemy.origin,
self.origin ) < max_range * max_range )
197 self SetTurretTargetEnt(
self.enemy );
201 wait (
self.n_burstWaitTime );
205 wait no_target_delay;
212 hud_marked_target = NewHudElem();
214 hud_marked_target.horzAlign =
"right";
215 hud_marked_target.vertAlign =
"middle";
217 hud_marked_target.sort = 2;
219 hud_marked_target.hidewheninmenu =
true;
220 hud_marked_target.immunetodemogamehudsettings =
true;
224 while ( isdefined(
self ) )
226 if ( isdefined(
self.enemy ) )
228 hud_marked_target.alpha = 1;
230 hud_marked_target.x =
self.enemy.origin[0];
231 hud_marked_target.y =
self.enemy.origin[1];
232 hud_marked_target.z =
self.enemy.origin[2] + Z_OFFSET;
240 hud_marked_target.alpha = 0;
246 hud_marked_target Destroy();
251 results = PhysicsTraceEx(
self.origin, position, (-15,-15,-5), (15,15,5),
self );
253 if( results[
"fraction"] == 1 )
263 if( isdefined(
self.enemy ) )
265 if( IsAI(
self.enemy ) )
270 if(
self.enemy.origin[2] + offset > goalpos[2] )
272 goal_z =
self.enemy.origin[2] + offset;
273 if( goal_z > goalpos[2] + 400 )
275 goal_z = goalpos[2] + 400;
277 results = PhysicsTraceEx( goalpos, ( goalpos[0], goalpos[1], goal_z ), (-15,-15,-5), (15,15,5),
self );
279 if( results[
"fraction"] == 1 )
281 goalpos = ( goalpos[0], goalpos[1], goal_z );
291 start = pos + (0,0,
self.flyheight);
292 end = pos + (0,0,-
self.flyheight);
293 trace = BulletTrace( start,
end,
false,
self,
false,
false );
296 pos =
end + (0,0,
self.flyheight);
298 z =
self GetHeliHeightLockHeight( pos );
299 pos = ( pos[0], pos[1], z );
306 self endon(
"death" );
307 self endon(
"change_state" );
317 self endon(
"death" );
318 self endon(
"change_state" );
327 self endon(
"death" );
328 self endon(
"change_state" );
330 assert( IsAlive(
self ) );
332 while ( !isdefined(
self.owner ) )
339 old_goalpos =
self.goalpos;
355 while ( !IsDefined( goalpos ) )
361 self.goalpos = goalpos;
364 if(
self SetVehGoalPos( goalpos,
true, 2 ) )
368 if( isdefined(
self.goal_node ) )
369 self.goal_node.escort_drone_claimed =
true;
371 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
373 if( RandomInt( 100 ) > 50 )
375 self SetLookAtEnt(
self.enemy );
381 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
383 self SetLookAtEnt(
self.enemy );
384 wait RandomFloatRange( 2, 3 );
385 self ClearLookAtEnt();
392 if( isdefined(
self.goal_node ) )
394 self.goal_node.escort_drone_fails =
true;
397 if( goalfailures == 1 )
402 else if( goalfailures == 2 )
405 goalpos =
self.origin;
407 else if( goalfailures == 3 )
410 goalpos =
self.origin;
411 self SetVehGoalPos( goalpos,
true );
412 self waittill(
"near_goal" );
414 else if( goalfailures > 3 )
417 println(
"WARNING: Quadrotor can't find path to goal over 4 times." +
self.origin +
" " + goalpos );
418 line(
self.origin, goalpos, (1,1,1), 1, 100 );
424 old_goalpos = goalpos;
426 offset = ( RandomFloatRange(-50,50), RandomFloatRange(-50,50), RandomFloatRange(50, 150) );
428 goalpos = goalpos + offset;
434 self SetVehGoalPos( goalpos,
true );
437 wait RandomFloatRange( 1, 3 );
439 if( !
self.vehonpath )
441 self SetVehGoalPos( old_goalpos,
true );
452 nodes = GetNodesInRadiusSorted(
self.origin, 200, 0, 500,
"Path" );
454 if( nodes.size == 0 )
456 nodes = GetNodesInRadiusSorted(
self.goalpos, 3000, 0, 2000,
"Path" );
459 foreach( node
in nodes )
461 if( node.type ==
"BAD NODE" )
474 position =
self.origin;
476 if ( IsDefined(
self.owner ) )
478 n_distToPlayerSq = Distance2DSquared(
self.origin,
self.owner.origin );
480 if ( n_distToPlayerSq >=
self.n_tetherMaxSq )
482 forward_vector = anglestoforward(
self.owner.angles ) *
self.n_tetherMin;
483 position =
self.owner.origin + ( forward_vector + (0,0,100) );
487 adjustedgoalpos = position;
489 if( isdefined( adjustedgoalpos ) )
491 position = adjustedgoalpos;
494 position =
self GetClosestPointOnNavVolume( position, 200 );
506 self waittill(
"exit_vehicle", player );
508 player.ignoreme =
false;
509 player DisableInvulnerability();
511 self SetHeliHeightLock(
false );
512 self EnableAimAssist();
513 self.attachedpath = undefined;
515 self.goalpos =
self.origin;
521 driver =
self GetSeatOccupant( 0 );
522 if( isdefined(driver) )
524 self DisableAimAssist();
525 self SetHeliHeightLock(
true );
527 driver.ignoreme =
true;
528 driver EnableInvulnerability();
534 if( isdefined(
self.goal_node ) && isdefined(
self.goal_node.escort_drone_claimed ) )
536 self.goal_node.escort_drone_claimed = undefined;
539 self ClearTargetEntity();
541 self ClearVehGoalPos();
542 self PathVariableOffsetClear();
543 self PathFixedOffsetClear();
544 self ClearLookAtEnt();
549 if( isdefined(
self.damage_fx_ent ) )
551 if(
self.damage_fx_ent.effect == effect )
556 self.damage_fx_ent
delete();
560 ent =
Spawn(
"script_model", ( 0, 0, 0 ) );
561 ent SetModel(
"tag_origin" );
562 ent.origin =
self GetTagOrigin( tag );
563 ent.angles =
self GetTagAngles( tag );
566 ent LinkTo(
self, tag );
568 playfxontag( effect, ent,
"tag_origin" );
569 ent playsound(
"veh_qrdrone_sparks");
572 self.damage_fx_ent = ent;
577 if( isdefined(
self.damage_fx_ent ) )
579 self.damage_fx_ent
delete();
582 if( isdefined(
self.stun_fx ) )
584 self.stun_fx
delete();
590 self endon(
"crash_done" );
591 self endon(
"change_state" );
592 self endon(
"death" );
594 if( isdefined(
self.
emped ) )
597 weapon =
self SeatGetWeapon( 0 );
598 fireTime = weapon.fireTime;
605 while( time < totalFireTime && !isdefined(
self.
emped ) )
618 self endon(
"crash_done" );
619 self endon(
"death" );
623 self waittill(
"veh_predictedcollision", velocity, normal );
624 if( normal[2] >= 0.6 )
626 self notify(
"veh_collision", velocity, normal );
633 self endon(
"change_state" );
634 self endon(
"crash_done" );
635 self endon(
"death" );
639 self waittill(
"veh_collision", velocity, normal );
640 driver =
self GetSeatOccupant( 0 );
641 if( isdefined( driver ) && LengthSquared( velocity ) > 70*70 )
643 Earthquake( 0.25, 0.25, driver.origin, 50 );
644 driver PlayRumbleOnEntity(
"damage_heavy" );
651 self endon(
"change_state" );
652 self endon(
"crash_done" );
653 self endon(
"death" );
655 if( !IsAlive(
self ) )
662 self waittill(
"veh_collision", velocity, normal );
663 ang_vel =
self GetAngularVelocity() * 0.5;
664 self SetAngularVelocity( ang_vel );
667 if( normal[2] < 0.6 || ( IsAlive(
self ) && !isdefined(
self.
emped ) ) )
669 self SetVehVelocity(
self.velocity + normal * 90 );
670 self PlaySound(
"veh_qrdrone_wall" );
671 if( normal[2] < 0.6 )
673 fx_origin =
self.origin - normal * 28;
677 fx_origin =
self.origin - normal * 10;
684 if( isdefined(
self.
emped ) )
686 if( isdefined(
self.bounced ) )
688 self playsound(
"veh_qrdrone_wall" );
689 self SetVehVelocity( (0,0,0) );
690 self SetAngularVelocity( (0,0,0) );
691 if(
self.angles[0] < 0 )
693 if(
self.angles[0] < -15 )
695 self.angles = ( -15,
self.angles[1],
self.angles[2] );
697 else if(
self.angles[0] > -10 )
699 self.angles = ( -10,
self.angles[1],
self.angles[2] );
704 if(
self.angles[0] > 15 )
706 self.angles = ( 15,
self.angles[1],
self.angles[2] );
708 else if(
self.angles[0] < 10 )
710 self.angles = ( 10,
self.angles[1],
self.angles[2] );
714 self.bounced = undefined;
715 self notify(
"landed" );
721 self SetVehVelocity(
self.velocity + normal * 120 );
722 self playsound(
"veh_qrdrone_wall" );
723 if( normal[2] < 0.6 )
725 fx_origin =
self.origin - normal * 28;
729 fx_origin =
self.origin - normal * 10;
737 self playsound(
"veh_qrdrone_explo" );
738 self notify(
"crash_done" );
748 if( !isdefined(
self.off ) )
756 self endon(
"death" );
765 self endon(
"death" );
766 self endon(
"emped" );
767 self endon(
"landed" );
769 while( isdefined(
self.
emped ) )
771 velocity =
self.velocity;
772 self.angles = (
self.angles[0] * 0.85,
self.angles[1],
self.angles[2] * 0.85 );
773 ang_vel =
self GetAngularVelocity() * 0.85;
774 self SetAngularVelocity( ang_vel );
775 self SetVehVelocity( velocity );
782 self endon(
"death" );
783 self notify(
"emped" );
784 self endon(
"emped" );
788 PlaySoundAtPosition(
"veh_qrdrone_emp_down",
self.origin );
791 self SetPhysAcceleration( ( 0, 0, -600 ) );
795 if( !isdefined(
self.stun_fx ) )
797 self.stun_fx =
Spawn(
"script_model",
self.origin );
798 self.stun_fx SetModel(
"tag_origin" );
799 self.stun_fx LinkTo(
self,
"tag_origin", (0,0,0), (0,0,0) );
800 PlayFXOnTag( level._effect[
"escort_drone_stun" ],
self.stun_fx,
"tag_origin" );
803 wait RandomFloatRange( 4, 7 );
805 self.stun_fx
delete();
807 self.emped = undefined;
808 self SetPhysAcceleration( ( 0, 0, 0 ) );
810 self playsound (
"veh_qrdrone_boot_qr");
815 self notify(
"bullet_shield" );
816 self endon(
"bullet_shield" );
818 self.bullet_shield =
true;
820 wait invulnerable_time;
822 if( isdefined(
self ) )
824 self.bullet_shield = undefined;
826 if( isdefined(
self ) &&
self.health < 40 )
833 function EscortDroneCallback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
835 driver =
self GetSeatOccupant( 0 );
837 if( weapon.isEmp && sMeansOfDeath !=
"MOD_IMPACT" )
839 if( !isdefined( driver ) )
841 if( !isdefined(
self.off ) )
850 if (
self.owner.cclass_power.powerRemaining > power_loss )
854 else if (
self.owner.cclass_power.powerRemaining > 0 )
866 switch(sMeansOfDeath)
872 case "MOD_HIT_BY_OBJECT":
874 case "MOD_PROJECTILE":
876 case "MOD_HEAD_SHOT":
878 case "MOD_TRIGGER_HURT":
880 case "MOD_MELEE_WEAPON_BUTT":
881 return self.n_MiscPowerLoss;
884 case "MOD_EXPLOSIVE":
885 case "MOD_PROJECTILE_SPLASH":
887 case "MOD_GRENADE_SPLASH":
888 return self.n_ExplosionPowerLoss;
891 case "MOD_PISTOL_BULLET":
892 case "MOD_RIFLE_BULLET":
894 return self.n_BulletPowerLoss;
901 if ( IsDefined(
self.archetype ) && IsDefined (
self.str_awareness_state ) &&
self.str_awareness_state ==
STATE_COMBAT )