1 #using scripts\codescripts\struct;
3 #using scripts\shared\gameskill_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\statemachine_shared;
6 #using scripts\shared\system_shared;
7 #using scripts\shared\util_shared;
8 #using scripts\shared\vehicle_shared;
9 #using scripts\shared\vehicle_ai_shared;
10 #using scripts\shared\vehicle_death_shared;
11 #using scripts\shared\flag_shared;
13 #insert scripts\shared\shared.gsh;
14 #insert scripts\shared\statemachine.gsh;
16 #insert scripts\shared\ai\utility.gsh;
18 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate01" );
19 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate02" );
20 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate03" );
21 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate04" );
22 #precache( "fx", "_t6/destructibles/fx_quadrotor_crash01" );
23 #precache( "fx", "_t6/destructibles/fx_quadrotor_nudge01" );
24 #precache( "fx", "_t6/electrical/fx_elec_sp_emp_stun_quadrotor" );
37 level._effect[
"quadrotor_damage01" ] =
"_t6/destructibles/fx_quadrotor_damagestate01";
38 level._effect[
"quadrotor_damage02" ] =
"_t6/destructibles/fx_quadrotor_damagestate02";
39 level._effect[
"quadrotor_damage03" ] =
"_t6/destructibles/fx_quadrotor_damagestate03";
40 level._effect[
"quadrotor_damage04" ] =
"_t6/destructibles/fx_quadrotor_damagestate04";
42 level._effect[
"quadrotor_crash" ] =
"_t6/destructibles/fx_quadrotor_crash01";
43 level._effect[
"quadrotor_nudge" ] =
"_t6/destructibles/fx_quadrotor_nudge01";
45 level._effect[
"quadrotor_stun" ] =
"_t6/electrical/fx_elec_sp_emp_stun_quadrotor";
52 self EnableAimAssist();
53 self SetHoverParams( 25.0, 120.0, 80 );
54 self SetNearGoalNotifyDist( 30 );
56 self.flyheight = GetDvarFloat(
"g_quadrotorFlyHeight" );
59 self.fovcosinebusy = 0.574;
61 self.vehAirCraftCollisionEnabled =
true;
63 if ( !IsDefined(
self.heightAboveGround ) )
65 self.heightAboveGround = 100;
68 if( !isdefined(
self.goalradius ) )
70 self.goalradius = 600;
73 if( !isdefined(
self.goalpos ) )
75 self.goalpos =
self.origin;
78 self.original_vehicle_type =
self.vehicletype;
93 self HidePart(
"tag_viewmodel" );
98 if ( isdefined(
self.script_startstate ) )
100 if(
self.script_startstate ==
"off" )
124 if( !IsAlive(
self ) )
127 driver =
self GetSeatOccupant( 0 );
128 if( isdefined( driver ) )
145 self HidePart(
"tag_rotor_fl" );
146 self HidePart(
"tag_rotor_fr" );
147 self HidePart(
"tag_rotor_rl" );
148 self HidePart(
"tag_rotor_rr" );
149 if( !isdefined(
self.
emped ) )
151 self DisableAimAssist();
161 self ShowPart(
"tag_rotor_fl" );
162 self ShowPart(
"tag_rotor_fr" );
163 self ShowPart(
"tag_rotor_rl" );
164 self ShowPart(
"tag_rotor_rr" );
165 self EnableAimAssist();
166 self.off = undefined;
172 self.goalpos =
self.origin;
186 self endon(
"death" );
187 self endon(
"change_state" );
191 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
193 enemy_is_hind =
false;
194 if( isdefined(
self.enemy ) && isdefined(
self.enemy.vehicletype ) )
196 enemy_is_hind =
self.enemy.vehicletype ==
"heli_hind_afghan_rts";
199 if( DistanceSquared(
self.enemy.origin,
self.origin ) < 1280 * 1280 || enemy_is_hind )
201 self SetTurretTargetEnt(
self.enemy );
205 if( isdefined(
self.enemy ) && IsAI(
self.enemy ) )
207 wait( RandomFloatRange( 2, 2.5 ) );
211 wait( RandomFloatRange( 0.5, 1.5 ) );
223 results = PhysicsTraceEx(
self.origin, position, (-15,-15,-5), (15,15,5),
self );
225 if( results[
"fraction"] == 1 )
235 if( isdefined(
self.enemy ) )
237 if( IsAI(
self.enemy ) )
242 if(
self.enemy.origin[2] + offset > goalpos[2] )
244 goal_z =
self.enemy.origin[2] + offset;
245 if( goal_z > goalpos[2] + 400 )
247 goal_z = goalpos[2] + 400;
249 results = PhysicsTraceEx( goalpos, ( goalpos[0], goalpos[1], goal_z ), (-15,-15,-5), (15,15,5),
self );
251 if( results[
"fraction"] == 1 )
253 goalpos = ( goalpos[0], goalpos[1], goal_z );
263 start = pos + (0,0,
self.flyheight);
264 end = pos + (0,0,-
self.flyheight);
265 trace = BulletTrace( start,
end,
false,
self,
false,
false );
268 pos =
end + (0,0,
self.flyheight);
270 z =
self GetHeliHeightLockHeight( pos );
271 pos = ( pos[0], pos[1], z );
278 self endon(
"death" );
279 self endon(
"change_state" );
289 self endon(
"death" );
290 self endon(
"change_state" );
299 self endon(
"death" );
300 self endon(
"change_state" );
302 assert( IsAlive(
self ) );
305 old_goalpos =
self.goalpos;
308 if( !
self.vehonpath )
310 if( isdefined(
self.attachedpath ) )
316 else if( DistanceSquared(
self.origin,
self.goalpos ) < 100*100 && (
self.goalpos[2] > old_goalpos[2] + 10 ||
self.origin[2] + 10 <
self.goalpos[2] ) )
318 self SetVehGoalPos(
self.goalpos,
true );
319 self PathVariableOffset( (0,0,20), 2 );
325 self SetVehGoalPos( goalpos,
true );
330 assert( IsAlive(
self ) );
347 while ( !IsDefined(goalpos) )
352 if ( isdefined( level.ai_quadrotor_goal ) )
354 goalpos = level.ai_quadrotor_goal;
357 adjustedGoal =
self GetClosestPointOnNavVolume( goalpos, searchRadius );
358 if ( isdefined( adjustedGoal ) )
360 goalpos = adjustedGoal;
363 self.goalpos = goalpos;
366 if(
self SetVehGoalPos( goalpos,
true, 2 ) )
370 if( isdefined(
self.goal_node ) )
371 self.goal_node.quadrotor_claimed =
true;
373 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
375 if( RandomInt( 100 ) > 50 )
377 self SetLookAtEnt(
self.enemy );
383 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
385 self SetLookAtEnt(
self.enemy );
386 wait RandomFloatRange( 3, 6 );
387 self ClearLookAtEnt();
390 if( isdefined(
self.goal_node ) )
391 self.goal_node.quadrotor_claimed = undefined;
397 if( isdefined(
self.goal_node ) )
399 self.goal_node.quadrotor_fails =
true;
402 if( goalfailures == 1 )
407 else if( goalfailures == 2 )
410 goalpos =
self.origin;
412 else if( goalfailures == 3 )
415 goalpos =
self.origin;
416 self SetVehGoalPos( goalpos,
true );
417 self waittill(
"near_goal" );
419 else if( goalfailures > 3 )
422 println(
"WARNING: Quadrotor can't find path to goal over 4 times." +
self.origin +
" " + goalpos );
423 line(
self.origin, goalpos, (1,1,1), 1, 100 );
429 old_goalpos = goalpos;
431 offset = ( RandomFloatRange(-50,50), RandomFloatRange(-50,50), RandomFloatRange(50, 150) );
433 goalpos = goalpos + offset;
439 self SetVehGoalPos( goalpos,
true );
442 wait RandomFloatRange( 1, 3 );
444 if( !
self.vehonpath )
446 self SetVehGoalPos( old_goalpos,
true );
457 nodes = GetNodesInRadiusSorted(
self.origin, 200, 0, 500,
"Path" );
459 if( nodes.size == 0 )
461 nodes = GetNodesInRadiusSorted(
self.goalpos, 3000, 0, 2000,
"Path" );
464 foreach( node
in nodes )
466 if( node.type ==
"BAD NODE" )
479 position = undefined;
481 while ( !isdefined( position ) )
484 position =
self GetRandomPointOnNavVolume();
487 goalpos =
self.origin;
499 self waittill(
"exit_vehicle", player );
501 player.ignoreme =
false;
502 player DisableInvulnerability();
506 self ShowPart(
"tag_turret" );
507 self ShowPart(
"body_animate_jnt" );
508 self ShowPart(
"tag_flaps" );
509 self ShowPart(
"tag_ammo_case" );
510 self HidePart(
"tag_viewmodel" );
511 self SetHeliHeightLock(
false );
512 self EnableAimAssist();
513 self SetVehicleType(
self.original_vehicle_type );
514 self.attachedpath = undefined;
516 self.goalpos =
self.origin;
522 driver =
self GetSeatOccupant( 0 );
523 if( isdefined(driver) )
525 self DisableAimAssist();
526 self HidePart(
"tag_turret" );
527 self HidePart(
"body_animate_jnt" );
528 self HidePart(
"tag_flaps" );
529 self HidePart(
"tag_ammo_case" );
530 self ShowPart(
"tag_viewmodel" );
531 self SetHeliHeightLock(
true );
534 driver.ignoreme =
true;
535 driver EnableInvulnerability();
538 self SetVehicleType(
"heli_quadrotor_rts_player" );
540 if( isdefined(
self.vehicle_weapon_override ) )
542 self SetVehWeapon(
self.vehicle_weapon_override );
551 if( isdefined(
self.goal_node ) && isdefined(
self.goal_node.quadrotor_claimed ) )
553 self.goal_node.quadrotor_claimed = undefined;
556 self ClearTargetEntity();
558 self ClearVehGoalPos();
559 self PathVariableOffsetClear();
560 self PathFixedOffsetClear();
561 self ClearLookAtEnt();
566 if( health_pct < .25 )
568 return level._effect[
"quadrotor_damage04" ];
570 else if( health_pct < .5 )
572 return level._effect[
"quadrotor_damage03" ];
574 else if( health_pct < .75 )
576 return level._effect[
"quadrotor_damage02" ];
578 else if( health_pct < 0.9 )
580 return level._effect[
"quadrotor_damage01" ];
588 if( isdefined(
self.damage_fx_ent ) )
590 if(
self.damage_fx_ent.effect == effect )
595 self.damage_fx_ent
delete();
599 ent =
Spawn(
"script_model", ( 0, 0, 0 ) );
600 ent SetModel(
"tag_origin" );
601 ent.origin =
self GetTagOrigin( tag );
602 ent.angles =
self GetTagAngles( tag );
605 ent LinkTo(
self, tag );
607 playfxontag( effect, ent,
"tag_origin" );
608 ent playsound(
"veh_qrdrone_sparks");
611 self.damage_fx_ent = ent;
616 max_health =
self.healthdefault;
617 if( isdefined(
self.health_max ) )
619 max_health =
self.health_max;
623 if( isdefined( effect ) )
629 if( isdefined(
self.damage_fx_ent ) )
631 self.damage_fx_ent
delete();
638 self endon(
"crash_done" );
640 while( isdefined(
self) )
642 self waittill(
"damage",
damage, undefined , dir, point, type );
644 if(
self.health > 0 &&
damage > 1 )
649 if( isdefined(
self.off ) )
654 if( type ==
"MOD_EXPLOSIVE" || type ==
"MOD_GRENADE_SPLASH" || type ==
"MOD_PROJECTILE_SPLASH" )
656 self SetVehVelocity(
self.velocity + VectorNormalize(dir) * 300 );
657 ang_vel =
self GetAngularVelocity();
658 ang_vel += ( RandomFloatRange( -300, 300 ), RandomFloatRange( -300, 300 ), RandomFloatRange( -300, 300 ) );
659 self SetAngularVelocity( ang_vel );
663 ang_vel =
self GetAngularVelocity();
664 yaw_vel = RandomFloatRange( -320, 320 );
671 ang_vel += ( RandomFloatRange( -150, 150 ), yaw_vel, RandomFloatRange( -150, 150 ) );
672 self SetAngularVelocity( ang_vel );
681 if( isdefined(
self.damage_fx_ent ) )
683 self.damage_fx_ent
delete();
686 if( isdefined(
self.stun_fx ) )
688 self.stun_fx
delete();
696 self notify(
"nodeath_thread" );
698 self waittill(
"death", attacker, damageFromUnderneath, weapon, point, dir );
700 self notify(
"nodeath_thread" );
702 if( isdefined(
self.goal_node ) && isdefined(
self.goal_node.quadrotor_claimed ) )
704 self.goal_node.quadrotor_claimed = undefined;
709 if ( isdefined(
self ) )
718 if ( !isdefined(
self ) )
723 self endon(
"death" );
727 self DisableAimAssist();
741 self waittill(
"crash_done" );
753 self playsound(
"veh_qrdrone_sparks");
758 self endon(
"crash_done" );
759 self endon(
"death" );
762 self ClearVehGoalPos();
763 self ClearLookAtEnt();
765 self SetPhysAcceleration( ( 0, 0, -800 ) );
766 self.vehcheckforpredictedcrash =
true;
768 if( !isdefined( hitdir ) )
773 side_dir = VectorCross( hitdir, (0,0,1) );
774 side_dir_mag = RandomFloatRange( -100, 100 );
776 side_dir *= side_dir_mag;
778 self SetVehVelocity(
self.velocity + (0,0,100) + VectorNormalize( side_dir ) );
780 ang_vel =
self GetAngularVelocity();
781 ang_vel = ( ang_vel[0] * 0.3, ang_vel[1], ang_vel[2] * 0.3 );
783 yaw_vel = RandomFloatRange( 0, 210 ) *
math::sign( ang_vel[1] );
786 ang_vel += ( RandomFloatRange( -1, 1 ), yaw_vel, RandomFloatRange( -1, 1 ) );
788 self SetAngularVelocity( ang_vel );
790 self.crash_accel = RandomFloatRange( 75, 110 );
792 if( !isdefined(
self.off ) )
799 self playsound(
"veh_qrdrone_dmg_hit");
802 if( !isdefined(
self.off ) )
809 if( RandomInt( 100 ) < 40 && !isdefined(
self.off ) )
817 self notify(
"crash_done" );
823 dmg_ent =
Spawn(
"script_origin",
self.origin);
824 dmg_ent linkto (
self);
825 dmg_ent PlayLoopSound (
"veh_qrdrone_dmg_loop");
827 dmg_ent stoploopsound(1);
835 self endon(
"crash_done" );
836 self endon(
"change_state" );
837 self endon(
"death" );
839 if( isdefined(
self.
emped ) )
842 weapon =
self SeatGetWeapon( 0 );
843 fireTime = weapon.fireTime;
847 if( weapon.name ==
"quadrotor_turret_explosive" )
849 if( totalFireTime < fireTime * 2 )
850 totalFireTime = fireTime * 2;
858 if( ( isdefined(
self.enemy ) && !IsPlayer(
self.enemy ) && !
IS_TRUE(
self.enemy.isBigDog ) ) ||
859 isdefined(
self.fire_half_blanks ) )
868 while( time < totalFireTime && !isdefined(
self.
emped ) )
870 if( isdefined(
self.enemy ) && isdefined(
self.enemy.attackerAccuracy) &&
self.enemy.attackerAccuracy == 0 )
872 self FireWeapon( 0,
self.enemy );
874 else if( aiFireChance > 1 )
891 self endon(
"crash_done" );
892 self endon(
"death" );
898 self SetVehVelocity(
self.velocity + AnglesToUp(
self.angles ) *
self.crash_accel );
899 self.crash_accel *= 0.98;
906 if( RandomInt( 100 ) > 40 )
908 if(
self.velocity[2] > 150.0 )
910 self.crash_accel *= 0.75;
912 else if(
self.velocity[2] < 40.0 && count < 60 )
914 if( Abs(
self.angles[0] ) > 30 || Abs(
self.angles[2] ) > 30 )
916 self.crash_accel = RandomFloatRange( 160, 200 );
920 self.crash_accel = RandomFloatRange( 85, 120 );
930 self endon(
"crash_done" );
931 self endon(
"death" );
935 self waittill(
"veh_predictedcollision", velocity, normal );
936 if( normal[2] >= 0.6 )
938 self notify(
"veh_collision", velocity, normal );
945 self endon(
"change_state" );
946 self endon(
"crash_done" );
947 self endon(
"death" );
951 self waittill(
"veh_collision", velocity, normal );
952 driver =
self GetSeatOccupant( 0 );
953 if( isdefined( driver ) && LengthSquared( velocity ) > 70*70 )
955 Earthquake( 0.25, 0.25, driver.origin, 50 );
956 driver PlayRumbleOnEntity(
"damage_heavy" );
963 self endon(
"change_state" );
964 self endon(
"crash_done" );
965 self endon(
"death" );
967 if( !IsAlive(
self ) )
974 self waittill(
"veh_collision", velocity, normal );
975 ang_vel =
self GetAngularVelocity() * 0.5;
976 self SetAngularVelocity( ang_vel );
979 if( normal[2] < 0.6 || ( IsAlive(
self ) && !isdefined(
self.
emped ) ) )
981 self SetVehVelocity(
self.velocity + normal * 90 );
982 self PlaySound(
"veh_wasp_wall_imp" );
983 if( normal[2] < 0.6 )
985 fx_origin =
self.origin - normal * 28;
989 fx_origin =
self.origin - normal * 10;
991 PlayFX( level._effect[
"quadrotor_nudge" ], fx_origin, normal );
996 if( isdefined(
self.
emped ) )
998 if( isdefined(
self.bounced ) )
1000 self playsound(
"veh_wasp_wall_imp" );
1001 self SetVehVelocity( (0,0,0) );
1002 self SetAngularVelocity( (0,0,0) );
1003 if(
self.angles[0] < 0 )
1005 if(
self.angles[0] < -15 )
1007 self.angles = ( -15,
self.angles[1],
self.angles[2] );
1009 else if(
self.angles[0] > -10 )
1011 self.angles = ( -10,
self.angles[1],
self.angles[2] );
1016 if(
self.angles[0] > 15 )
1018 self.angles = ( 15,
self.angles[1],
self.angles[2] );
1020 else if(
self.angles[0] < 10 )
1022 self.angles = ( 10,
self.angles[1],
self.angles[2] );
1026 self.bounced = undefined;
1027 self notify(
"landed" );
1032 self.bounced =
true;
1033 self SetVehVelocity(
self.velocity + normal * 120 );
1034 self playsound(
"veh_wasp_wall_imp" );
1035 if( normal[2] < 0.6 )
1037 fx_origin =
self.origin - normal * 28;
1041 fx_origin =
self.origin - normal * 10;
1043 PlayFX( level._effect[
"quadrotor_nudge" ], fx_origin, normal );
1048 CreateDynEntAndLaunch(
self.deathmodel,
self.origin,
self.angles,
self.origin,
self.velocity * 0.01, level._effect[
"quadrotor_crash" ] );
1049 self playsound(
"veh_qrdrone_explo" );
1051 self notify(
"crash_done" );
1059 sound_ent =
Spawn(
"script_origin",
self.origin );
1060 sound_ent PlayLoopSound(
"veh_qrdrone_death_fire_loop" , .1 );
1062 sound_ent StopLoopSound( 1 );
1069 if( isdefined(
self.vehmodelenemy ) )
1071 if( isSubstr( level.script,
"so_rts_" ) )
1076 if( team ==
"axis" )
1078 self SetModel(
self.vehmodelenemy );
1079 self SetVehWeapon( GetWeapon(
"quadrotor_turret_enemy" ) );
1083 self SetModel(
self.vehmodel );
1084 self SetVehWeapon( GetWeapon(
"quadrotor_turret" ) );
1089 if( !isdefined(
self.off ) )
1097 self endon(
"death" );
1107 self endon(
"death" );
1108 self endon(
"exit_vehicle" );
1112 vr = Abs(
self GetSpeed() /
self GetMaxSpeed() );
1116 level.player PlayRumbleOnEntity(
"quadrotor_fly" );
1121 time = RandomFloatRange( 0.1, 0.2 );
1122 Earthquake( RandomFloatRange( 0.1, 0.15 ), time,
self.origin, 200 );
1123 level.player PlayRumbleOnEntity(
"quadrotor_fly" );
1131 self endon(
"death" );
1132 self endon(
"exit_vehicle" );
1134 const max_self_destruct_time = 5;
1136 self_destruct =
false;
1137 self_destruct_time = 0;
1141 if ( !self_destruct )
1143 if ( level.player MeleeButtonPressed() )
1145 self_destruct =
true;
1146 self_destruct_time = max_self_destruct_time;
1154 IPrintLnBold( self_destruct_time );
1158 self_destruct_time -= 1;
1159 if ( self_destruct_time == 0 )
1161 driver =
self GetSeatOccupant( 0 );
1162 if( isdefined(driver) )
1164 driver DisableInvulnerability();
1167 Earthquake( 3, 1,
self.origin, 256 );
1168 RadiusDamage(
self.origin, 1000, 15000, 15000, level.player,
"MOD_EXPLOSIVE" );
1169 self DoDamage(
self.health + 1000,
self.origin );
1179 self endon(
"death" );
1180 self endon(
"emped" );
1181 self endon(
"landed" );
1183 while( isdefined(
self.
emped ) )
1185 velocity =
self.velocity;
1186 self.angles = (
self.angles[0] * 0.85,
self.angles[1],
self.angles[2] * 0.85 );
1187 ang_vel =
self GetAngularVelocity() * 0.85;
1188 self SetAngularVelocity( ang_vel );
1189 self SetVehVelocity( velocity );
1196 self endon(
"death" );
1197 self notify(
"emped" );
1198 self endon(
"emped" );
1202 PlaySoundAtPosition(
"veh_qrdrone_emp_down",
self.origin );
1205 self SetPhysAcceleration( ( 0, 0, -600 ) );
1209 if( !isdefined(
self.stun_fx ) )
1211 self.stun_fx =
Spawn(
"script_model",
self.origin );
1212 self.stun_fx SetModel(
"tag_origin" );
1213 self.stun_fx LinkTo(
self,
"tag_origin", (0,0,0), (0,0,0) );
1214 PlayFXOnTag( level._effect[
"quadrotor_stun" ],
self.stun_fx,
"tag_origin" );
1217 wait RandomFloatRange( 4, 7 );
1219 self.stun_fx
delete();
1221 self.emped = undefined;
1222 self SetPhysAcceleration( ( 0, 0, 0 ) );
1224 self playsound (
"veh_qrdrone_boot_qr");
1229 self notify(
"bullet_shield" );
1230 self endon(
"bullet_shield" );
1232 self.bullet_shield =
true;
1234 wait invulnerable_time;
1236 if( isdefined(
self ) )
1238 self.bullet_shield = undefined;
1240 if( isdefined(
self ) &&
self.health < 40 )
1247 function QuadrotorCallback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
1249 driver =
self GetSeatOccupant( 0 );
1251 if( weapon.isEmp && sMeansOfDeath !=
"MOD_IMPACT" )
1253 if( !isdefined( driver ) )
1255 if( !isdefined(
self.off ) )
1263 if( isdefined( driver ) )
1265 if( sMeansOfDeath ==
"MOD_BULLET" )
1267 if( isdefined(
self.bullet_shield ) )
1273 if( !isdefined(
self.bullet_shield ) )