1 #using scripts\codescripts\struct;
3 #using scripts\shared\clientfield_shared;
4 #using scripts\shared\hostmigration_shared;
5 #using scripts\shared\killstreaks_shared;
6 #using scripts\shared\util_shared;
7 #using scripts\shared\weapons\_heatseekingmissile;
9 #using scripts\mp\_util;
10 #using scripts\mp\gametypes\_hostmigration;
11 #using scripts\mp\gametypes\_spawning;
12 #using scripts\mp\killstreaks\_airsupport;
13 #using scripts\mp\killstreaks\_helicopter;
14 #using scripts\mp\killstreaks\_killstreak_detect;
15 #using scripts\mp\killstreaks\_killstreak_hacking;
16 #using scripts\mp\killstreaks\_killstreakrules;
17 #using scripts\mp\killstreaks\_killstreaks;
19 #insert scripts\mp\_hacker_tool.gsh;
20 #insert scripts\shared\shared.gsh;
21 #insert scripts\shared\version.gsh;
23 #precache( "string", "MP_CIVILIAN_AIR_TRAFFIC" );
24 #precache( "string", "MP_AIR_SPACE_TOO_CROWDED" );
25 #precache( "string", "KILLSTREAK_EARNED_HELICOPTER_GUARD" );
26 #precache( "string", "KILLSTREAK_HELICOPTER_GUARD_NOT_AVAILABLE" );
27 #precache( "string", "KILLSTREAK_HELICOPTER_GUARD_INBOUND" );
28 #precache( "string", "KILLSTREAK_HELICOPTER_GUARD_HACKED" );
29 #precache( "eventstring", "mpl_killstreak_lbguard_strt" );
30 #precache( "fx", "killstreaks/fx_ed_lights_green" );
31 #precache( "fx", "killstreaks/fx_ed_lights_red" );
32 #namespace helicopter_guard;
38 killstreaks::register_strings(
"helicopter_guard", &
"KILLSTREAK_EARNED_HELICOPTER_GUARD", &
"KILLSTREAK_HELICOPTER_GUARD_NOT_AVAILABLE", &
"KILLSTREAK_HELICOPTER_GUARD_INBOUND", undefined, &
"KILLSTREAK_HELICOPTER_GUARD_HACKED");
39 killstreaks::register_dialog(
"helicopter_guard",
"mpl_killstreak_lbguard_strt",
"kls_littlebird_used",
"",
"kls_littlebird_enemy",
"",
"kls_littlebird_ready");
42 level._effect[
"heli_guard_light"][
"friendly"] =
"killstreaks/fx_ed_lights_green";
43 level._effect[
"heli_guard_light"][
"enemy"] =
"killstreaks/fx_ed_lights_red";
45 level.heliGuardFlyOverNFZ =
false;
46 if ( level.script ==
"mp_hydro" )
48 level.heliGuardFlyOverNFZ =
true;
54 #define PLAYER_HEIGHT_INCREASE (0,0,50)
55 #define HELI_GUARD_FIRE_TIME 0.15
56 #define HELI_GUARD_MIN_SHOTS 10
57 #define HELI_GUARD_MAX_SHOTS 20
58 #define HELI_GUARD_MIN_PAUSE 1.0
59 #define HELI_GUARD_MAX_PAUSE 2.0
60 #define HELI_GUARD_GUNNER 0
61 #define HELI_GUARD_SPINUP 0.2
71 if ( isdefined( level.civilianJetFlyBy ) )
73 self iPrintLnBold( &
"MP_CIVILIAN_AIR_TRAFFIC" );
77 if (
self IsRemoteControlling() )
82 if ( !isdefined( level.heli_paths ) || level.heli_paths.size <= 0 )
84 self iPrintLnBold( &
"MP_UNAVAILABLE_IN_LEVEL" );
89 if ( killstreak_id == -1 )
95 if ( !isdefined( heliGuard ) )
113 hardpointType =
"helicopter_guard";
115 if( isdefined( closestStartNode.angles ) )
116 startAng = closestStartNode.angles;
118 startAng = ( 0, 0, 0);
122 forward = anglesToForward( owner.angles );
123 targetPos = ( owner.origin*(1,1,0) ) + ( (0,0,1)*flyHeight ) + ( forward * -100 );
125 startPos = closestStartNode.origin;
127 heliGuard = spawnHelicopter( owner, startPos, startAng,
"heli_guard_mp",
"veh_t6_drone_overwatch_light" );
128 if ( !isdefined( heliGuard ) )
131 heliGuard.harpointType = hardpointType;
136 Target_Set( heliGuard, (0,0,-50) );
138 heliguard setEnemyModel(
"veh_t6_drone_overwatch_dark");
139 heliGuard.speed = 150;
140 heliGuard.followSpeed = 40;
141 heliGuard setCanDamage(
true );
142 heliGuard SetMaxPitchRoll( 45, 45 );
143 heliGuard SetSpeed( heliGuard.speed, 100, 40 );
144 heliGuard SetYawSpeed( 120, 60 );
145 heliGuard setneargoalnotifydist( 512 );
150 heliGuard.killCount = 0;
151 heliGuard.streakName =
"littlebird_support";
152 heliGuard.heliType =
"littlebird";
153 heliGuard.targettingRadius = 2000;
155 heliGuard.targetPos = targetPos;
156 heliGuard.currentNode = closestNode;
158 heliGuard.attract_strength = 10000;
159 heliGuard.attract_range = 150;
160 heliGuard.attractor = Missile_CreateAttractorEnt( heliGuard, heliGuard.attract_strength, heliGuard.attract_range );
161 heliGuard.health = 999999;
162 heliGuard.maxHealth = level.heli_maxhealth;
163 heliGuard.rocketDamageOneShot = heliGuard.maxhealth + 1;
164 heliGuard.crashType =
"explode";
166 heliGuard.targeting_delay = level.heli_targeting_delay;
167 heliGuard.hasDodged =
false;
168 heliGuard SetDrawInfrared(
true );
176 killstreakTimeout = 60.0;
181 heliGuard.numFlares = 1;
182 heliGuard.flareOffset = (0,0,0);
186 heliGuard.killstreak_id = killstreak_id;
188 level.littlebirdGuard = heliGuard;
195 if ( !(owner isInsideHeightLock()) )
200 maxMeshHeight = littleBird GetHeliHeightLockHeight( owner.origin );
201 return max( maxMeshHeight, owner.origin[2] );
206 level endon(
"game_ended" );
207 littleBird endon(
"death" );
210 littleBird SetLookAtEnt(
self );
215 playerMeshOrigin = (
self.origin[0],
self.origin[1], height);
216 vecToStart = VectorNormalize(littleBird.origin - littleBird.targetPos);
218 target = littleBird.targetPos + vecToStart * dist;
220 while ( isdefined(collide) && dist > 0)
223 target = littleBird.targetPos + vecToStart * dist;
227 littleBird setVehGoalPos( target, 1 );
228 Target_SetTurretAquire( littleBird,
false );
230 littleBird waittill(
"near_goal" );
231 Target_SetTurretAquire( littleBird,
true );
232 littleBird SetVehGoalPos( playerMeshOrigin, 1);
233 littleBird waittill(
"near_goal" );
234 littleBird SetSpeed( littleBird.speed, 80, 30 );
235 littleBird waittill (
"goal" );
247 level endon(
"game_ended" );
248 self endon(
"death" );
249 self endon(
"leaving" );
251 if( !isdefined(
self.owner ) )
257 self SetSpeed(
self.followSpeed, 20, 20 );
260 if( isdefined(
self.owner ) && IsAlive(
self.owner ) )
271 self notify(
"heliGuardSupport_moveToPlayer" );
272 self endon(
"heliGuardSupport_moveToPlayer" );
274 level endon(
"game_ended" );
275 self endon(
"death" );
276 self endon(
"leaving" );
277 self.owner endon(
"death" );
278 self.owner endon(
"disconnect" );
279 self.owner endon(
"joined_team" );
280 self.owner endon(
"joined_spectators" );
284 hoverGoal = (
self.owner.origin[0],
self.owner.origin[1], maxMeshHeight );
287 if ( isdefined( zoneIndex ) && level.heliGuardFlyOverNFZ )
289 self.inTransit =
true;
292 self setVehGoalPos(( hoverGoal[0], hoverGoal[1], noFlyZoneHeight ),
true );
293 self waittill (
"goal" );
297 if ( isdefined( zoneIndex ) )
299 dist = Distance2D(
self.owner.origin, level.noFlyZones[zoneIndex].origin );
301 zoneOrgToPlayer2D =
self.owner.origin - level.noFlyZones[zoneIndex].origin;
302 zoneOrgToPlayer2D *= (1,1,0);
304 zoneOrgToChopper2D =
self.origin - level.noFlyZones[zoneIndex].origin;
305 zoneOrgToChopper2D *= (1,1,0);
307 zoneOrgAtMeshHeight = ( level.noFlyZones[zoneIndex].origin[0], level.noFlyZones[zoneIndex].origin[1], maxMeshHeight );
310 zoneOrgToAdjPos = VectorScale( VectorNormalize( zoneOrgToPlayer2D ), level.noFlyZones[ zoneIndex ].radius + 150.0 );
312 adjacentGoalPos = zoneOrgToAdjPos + level.noFlyZones[zoneIndex].origin;
313 adjacentGoalPos = ( adjacentGoalPos[0], adjacentGoalPos[1], maxMeshHeight );
315 zoneOrgToPerpendicular = ( zoneOrgToAdjPos[1], -zoneOrgToAdjPos[0], 0 );
316 zoneOrgToOppositePerpendicular = ( -zoneOrgToAdjPos[1], zoneOrgToAdjPos[0], 0 );
318 perpendicularGoalPos = zoneOrgToPerpendicular + zoneOrgAtMeshHeight;
319 oppositePerpendicularGoalPos = zoneOrgToOppositePerpendicular + zoneOrgAtMeshHeight;
321 if ( dist < level.noFlyZones[zoneIndex].radius )
323 zoneIndex = undefined;
326 if ( isdefined( zoneIndex ))
328 hoverGoal = perpendicularGoalPos;
332 hoverGoal = adjacentGoalPos;
339 hoverGoal = perpendicularGoalPos;
343 zoneIndex = undefined;
345 if ( isdefined( zoneIndex ))
347 hoverGoal = oppositePerpendicularGoalPos;
350 self.inTransit =
true;
352 self setVehGoalPos(( hoverGoal[0], hoverGoal[1], maxMeshHeight ),
true );
353 self waittill (
"goal" );
359 upperHeight = max(
self.origin[2], height );
361 acquireUpperHeight = (
self.origin[0],
self.origin[1], upperHeight );
362 hoverOverPlayer = (
self.owner.origin[0],
self.owner.origin[1], upperHeight );
363 hoverCorrectHeight = (
self.owner.origin[0],
self.owner.origin[1], height );
365 self.inTransit =
true;
366 self setVehGoalPos( acquireUpperHeight,
true );
367 self waittill (
"goal" );
369 self setVehGoalPos( hoverOverPlayer,
true );
370 self waittill (
"goal" );
372 self setVehGoalPos( hoverCorrectHeight,
true );
373 self waittill (
"goal" );
375 self.inTransit =
false;
384 self notify(
"heliGuardSupport_watchForEarlyLeave" );
385 self endon(
"heliGuardSupport_watchForEarlyLeave" );
386 level endon (
"game_ended" );
387 self endon(
"death" );
388 self endon(
"leaving" );
398 self notify(
"heliGuardSupport_watchOwnerDamage" );
399 self endon(
"heliGuardSupport_watchOwnerDamage" );
400 level endon (
"game_ended" );
401 self endon(
"death" );
402 self endon(
"leaving" );
403 self.owner endon(
"disconnect" );
404 self.owner endon(
"joined_team" );
405 self.owner endon(
"joined_spectators" );
410 self.owner waittill(
"damage",
damage, attacker, direction_vec, point, meansOfDeath, modelName, tagName, partName, weapon, iDFlags );
412 if( isPlayer( attacker ) )
416 self SetLookAtEnt( attacker );
426 level endon (
"game_ended" );
427 self endon(
"death" );
428 self endon(
"leaving" );
429 self.owner endon(
"disconnect" );
430 self.owner endon(
"joined_team" );
431 self.owner endon(
"joined_spectators" );
433 level waittill (
"round_end_finished" );
441 self endon(
"death" );
442 self notify(
"leaving" );
443 level.littlebirdGuard = undefined;
446 self clearturrettarget();
449 self ClearLookAtEnt();
451 targetPos =
self.origin + anglesToForward(
self.angles ) * 1500 + (0,0,flyHeight);
454 while ( isdefined( collide ) && tries > 0 )
456 yaw = RandomInt(360);
457 targetPos =
self.origin + anglesToForward( (
self.angles[0], yaw,
self.angles[2]) ) * 1500 + (0,0,flyHeight);
463 targetPos =
self.origin + (0,0,flyHeight);
465 self SetSpeed(
self.speed, 80 );
466 self SetMaxPitchRoll( 45, 180 );
467 self setVehGoalPos( targetPos );
468 self waittill (
"goal" );
471 targetPos = targetPos + anglesToForward( (0,
self.angles[1],
self.angles[2]) ) * 14000;
472 self setVehGoalPos( targetPos );
473 self waittill (
"goal" );
476 self notify(
"gone" );
482 level.littlebirdGuard = undefined;
484 if (! isdefined(
self) )
487 self SetSpeed( 25, 5 );
488 self thread
lbSpin( RandomIntRange(180, 220) );
490 wait( RandomFloatRange( .5, 1.5 ) );
497 self notify (
"explode" );
504 self endon(
"explode" );
507 playfxontag( level.chopper_fx[
"explode"][
"large"],
self,
"tail_rotor_jnt" );
508 self thread
trail_fx( level.chopper_fx[
"smoke"][
"trail"],
"tail_rotor_jnt",
"stop tail smoke" );
510 self setyawspeed( speed, speed, speed );
511 while ( isdefined(
self ) )
513 self settargetyaw(
self.angles[1]+(speed*0.9) );
521 self notify( stop_notify );
522 self endon( stop_notify );
523 self endon(
"death" );
527 playfxontag(
trail_fx,
self, trail_tag );
539 if( isdefined(
self.marker ) )
540 self.marker
delete();
549 level endon (
"game_ended" );
550 missileTarget endon(
"death" );
552 for( i = 0; i < missileGroup.size; i++ )
554 if( isdefined( missileGroup[ i ] ) && !missileTarget.hasDodged )
556 missileTarget.hasDodged =
true;
558 newTarget =
spawn(
"script_origin", missileTarget.origin );
559 newTarget.angles = missileTarget.angles;
560 newTarget MoveGravity( AnglesToRight( missileGroup[ i ].angles ) * -1000, 0.05 );
563 for( j = 0; j < missileGroup.size; j++ )
565 if( isdefined( missileGroup[ j ] ) )
567 missileGroup[ j ] SetTargetEntity( newTarget );
572 dodgePoint = missileTarget.origin + ( AnglesToRight( missileGroup[ i ].angles ) * 200 );
573 missileTarget SetSpeed( missileTarget.speed, 100, 40 );
574 missileTarget SetVehGoalPos( dodgePoint,
true );
577 missileTarget SetSpeed( missileTarget.followSpeed, 20, 20 );
590 closestNode = undefined;
591 closestDistance = 999999;
593 foreach( path
in level.heli_paths )
595 foreach( loc
in path )
597 nodeDistance = distance( loc.origin, pos );
598 if ( nodeDistance < closestDistance )
601 closestDistance = nodeDistance;
612 closestNode = undefined;
613 closestDistance = 999999;
615 foreach( loc
in level.heli_loop_paths )
617 nodeDistance = distance( loc.origin, pos );
618 if ( nodeDistance < closestDistance )
621 closestDistance = nodeDistance;
631 closestNode = undefined;
632 totalDistance = Distance2D(
self.currentNode.origin, pos );
633 closestDistance = totalDistance;
635 target =
self.currentNode.target;
637 while( isdefined( target ) )
639 nextNode = GetEnt( target,
"targetname" );
641 if ( nextNode ==
self.currentNode )
646 nodeDistance = Distance2D( nextNode.origin, pos );
647 if ( nodeDistance < totalDistance && nodeDistance < closestDistance )
649 closestNode = nextNode;
650 closestDistance = nodeDistance;
653 target = nextNode.target;
664 foreach ( member
in array )
666 if ( member == compare )
682 level.air_start_nodes =
struct::get_array(
"chopper_boss_path_start",
"targetname" );
684 foreach( loc
in level.air_start_nodes )
693 level.air_node_mesh =
struct::get_array(
"so_chopper_boss_path_struct",
"script_noteworthy" );
695 foreach( loc
in level.air_node_mesh )
702 foreach( other_loc
in level.air_node_mesh )
704 if ( loc == other_loc )
708 loc.neighbors[ loc.neighbors.size ] = other_loc;
719 self endon(
"death" );
720 level endon(
"game_ended" );
721 self endon(
"leaving" );
731 self endon(
"death" );
732 self endon(
"leaving" );
733 self endon(
"stop_shooting" );
734 level endon(
"game_ended" );
740 if ( !isdefined(
self.primaryTarget ) )
742 self waittill(
"primary acquired");
745 if ( isdefined(
self.primaryTarget ) )
747 targetEnt =
self.primaryTarget;
750 self SetLookAtEnt( targetEnt );
754 self waittill(
"turret_on_target" );
760 for ( i = 0; i < numShots; i++ )
771 self clearturrettarget();
779 self endon(
"death" );
780 self endon(
"leaving" );
781 self notify(
"heli_guard_target_death_watcher" );
782 self endon(
"heli_guard_target_death_watcher" );
788 self notify(
"stop_shooting" );
789 self.primaryTarget = undefined;
790 self SetLookAtEnt(
self.owner );
792 self clearturrettarget();