mirror of
https://github.com/JezuzLizard/Recompilable-gscs-for-BO2-zombies-and-multiplayer.git
synced 2025-06-10 10:47:58 -05:00
689 lines
14 KiB
Plaintext
689 lines
14 KiB
Plaintext
#include maps/mp/killstreaks/_airsupport;
|
|
#include maps/mp/killstreaks/_helicopter;
|
|
#include maps/mp/gametypes/_weapon_utils;
|
|
#include common_scripts/utility;
|
|
#include maps/mp/_utility;
|
|
|
|
init()
|
|
{
|
|
precacherumble( "stinger_lock_rumble" );
|
|
game[ "locking_on_sound" ] = "uin_alert_lockon_start";
|
|
game[ "locked_on_sound" ] = "uin_alert_lockon";
|
|
precachestring( &"MP_CANNOT_LOCKON_TO_TARGET" );
|
|
thread onplayerconnect();
|
|
level.fx_flare = loadfx( "vehicle/vexplosion/fx_heli_chaff" );
|
|
/#
|
|
setdvar( "scr_freelock", "0" );
|
|
#/
|
|
}
|
|
|
|
onplayerconnect()
|
|
{
|
|
for ( ;; )
|
|
{
|
|
level waittill( "connecting", player );
|
|
player thread onplayerspawned();
|
|
}
|
|
}
|
|
|
|
onplayerspawned()
|
|
{
|
|
self endon( "disconnect" );
|
|
for ( ;; )
|
|
{
|
|
self waittill( "spawned_player" );
|
|
self clearirtarget();
|
|
thread stingertoggleloop();
|
|
self thread stingerfirednotify();
|
|
}
|
|
}
|
|
|
|
clearirtarget()
|
|
{
|
|
self notify( "stinger_irt_cleartarget" );
|
|
self notify( "stop_lockon_sound" );
|
|
self notify( "stop_locked_sound" );
|
|
self.stingerlocksound = undefined;
|
|
self stoprumble( "stinger_lock_rumble" );
|
|
self.stingerlockstarttime = 0;
|
|
self.stingerlockstarted = 0;
|
|
self.stingerlockfinalized = 0;
|
|
if ( isDefined( self.stingertarget ) )
|
|
{
|
|
lockingon( self.stingertarget, 0 );
|
|
lockedon( self.stingertarget, 0 );
|
|
}
|
|
self.stingertarget = undefined;
|
|
self weaponlockfree();
|
|
self weaponlocktargettooclose( 0 );
|
|
self weaponlocknoclearance( 0 );
|
|
self stoplocalsound( game[ "locking_on_sound" ] );
|
|
self stoplocalsound( game[ "locked_on_sound" ] );
|
|
self destroylockoncanceledmessage();
|
|
}
|
|
|
|
stingerfirednotify()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
self waittill( "missile_fire", missile, weap );
|
|
if ( maps/mp/gametypes/_weapon_utils::isguidedrocketlauncherweapon( weap ) )
|
|
{
|
|
if ( isDefined( self.stingertarget ) && self.stingerlockfinalized )
|
|
{
|
|
self.stingertarget notify( "stinger_fired_at_me" );
|
|
}
|
|
level notify( "missile_fired" );
|
|
self notify( "stinger_fired" );
|
|
}
|
|
}
|
|
}
|
|
|
|
stingertoggleloop()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "death" );
|
|
for ( ;; )
|
|
{
|
|
self waittill( "weapon_change", weapon );
|
|
while ( maps/mp/gametypes/_weapon_utils::isguidedrocketlauncherweapon( weapon ) )
|
|
{
|
|
abort = 0;
|
|
while ( !self playerstingerads() )
|
|
{
|
|
wait 0,05;
|
|
if ( !maps/mp/gametypes/_weapon_utils::isguidedrocketlauncherweapon( self getcurrentweapon() ) )
|
|
{
|
|
abort = 1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
if ( abort )
|
|
{
|
|
break;
|
|
}
|
|
else self thread stingerirtloop();
|
|
while ( self playerstingerads() )
|
|
{
|
|
wait 0,05;
|
|
}
|
|
self notify( "stinger_IRT_off" );
|
|
self clearirtarget();
|
|
weapon = self getcurrentweapon();
|
|
}
|
|
}
|
|
}
|
|
|
|
stingerirtloop()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "death" );
|
|
self endon( "stinger_IRT_off" );
|
|
locklength = self getlockonspeed();
|
|
for ( ;; )
|
|
{
|
|
wait 0,05;
|
|
if ( self.stingerlockfinalized )
|
|
{
|
|
passed = softsighttest();
|
|
if ( !passed )
|
|
{
|
|
continue;
|
|
}
|
|
else if ( !isstillvalidtarget( self.stingertarget ) )
|
|
{
|
|
self clearirtarget();
|
|
continue;
|
|
}
|
|
else if ( !self.stingertarget.locked_on )
|
|
{
|
|
self.stingertarget notify( "missile_lock" );
|
|
}
|
|
lockingon( self.stingertarget, 0 );
|
|
lockedon( self.stingertarget, 1 );
|
|
thread looplocallocksound( game[ "locked_on_sound" ], 0,75 );
|
|
continue;
|
|
}
|
|
else if ( self.stingerlockstarted )
|
|
{
|
|
if ( !isstillvalidtarget( self.stingertarget ) )
|
|
{
|
|
self clearirtarget();
|
|
continue;
|
|
}
|
|
else lockingon( self.stingertarget, 1 );
|
|
lockedon( self.stingertarget, 0 );
|
|
passed = softsighttest();
|
|
if ( !passed )
|
|
{
|
|
continue;
|
|
}
|
|
else timepassed = getTime() - self.stingerlockstarttime;
|
|
if ( timepassed < locklength )
|
|
{
|
|
continue;
|
|
}
|
|
else /#
|
|
assert( isDefined( self.stingertarget ) );
|
|
#/
|
|
self notify( "stop_lockon_sound" );
|
|
self.stingerlockfinalized = 1;
|
|
self weaponlockfinalize( self.stingertarget );
|
|
continue;
|
|
}
|
|
else besttarget = self getbeststingertarget();
|
|
if ( !isDefined( besttarget ) )
|
|
{
|
|
self destroylockoncanceledmessage();
|
|
continue;
|
|
}
|
|
else if ( !self locksighttest( besttarget ) )
|
|
{
|
|
self destroylockoncanceledmessage();
|
|
continue;
|
|
}
|
|
else if ( self locksighttest( besttarget ) && isDefined( besttarget.lockondelay ) && besttarget.lockondelay )
|
|
{
|
|
self displaylockoncanceledmessage();
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
self destroylockoncanceledmessage();
|
|
initlockfield( besttarget );
|
|
self.stingertarget = besttarget;
|
|
self.stingerlockstarttime = getTime();
|
|
self.stingerlockstarted = 1;
|
|
self.stingerlostsightlinetime = 0;
|
|
self thread looplocalseeksound( game[ "locking_on_sound" ], 0,6 );
|
|
}
|
|
}
|
|
}
|
|
|
|
destroylockoncanceledmessage()
|
|
{
|
|
if ( isDefined( self.lockoncanceledmessage ) )
|
|
{
|
|
self.lockoncanceledmessage destroy();
|
|
}
|
|
}
|
|
|
|
displaylockoncanceledmessage()
|
|
{
|
|
if ( isDefined( self.lockoncanceledmessage ) )
|
|
{
|
|
return;
|
|
}
|
|
self.lockoncanceledmessage = newclienthudelem( self );
|
|
self.lockoncanceledmessage.fontscale = 1,25;
|
|
self.lockoncanceledmessage.x = 0;
|
|
self.lockoncanceledmessage.y = 50;
|
|
self.lockoncanceledmessage.alignx = "center";
|
|
self.lockoncanceledmessage.aligny = "top";
|
|
self.lockoncanceledmessage.horzalign = "center";
|
|
self.lockoncanceledmessage.vertalign = "top";
|
|
self.lockoncanceledmessage.foreground = 1;
|
|
self.lockoncanceledmessage.hidewhendead = 0;
|
|
self.lockoncanceledmessage.hidewheninmenu = 1;
|
|
self.lockoncanceledmessage.archived = 0;
|
|
self.lockoncanceledmessage.alpha = 1;
|
|
self.lockoncanceledmessage settext( &"MP_CANNOT_LOCKON_TO_TARGET" );
|
|
}
|
|
|
|
getbeststingertarget()
|
|
{
|
|
targetsall = target_getarray();
|
|
targetsvalid = [];
|
|
idx = 0;
|
|
while ( idx < targetsall.size )
|
|
{
|
|
/#
|
|
if ( getDvar( "scr_freelock" ) == "1" )
|
|
{
|
|
if ( self insidestingerreticlenolock( targetsall[ idx ] ) )
|
|
{
|
|
targetsvalid[ targetsvalid.size ] = targetsall[ idx ];
|
|
}
|
|
idx++;
|
|
continue;
|
|
#/
|
|
}
|
|
else if ( level.teambased )
|
|
{
|
|
if ( isDefined( targetsall[ idx ].team ) && targetsall[ idx ].team != self.team )
|
|
{
|
|
if ( self insidestingerreticlenolock( targetsall[ idx ] ) )
|
|
{
|
|
targetsvalid[ targetsvalid.size ] = targetsall[ idx ];
|
|
}
|
|
}
|
|
idx++;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if ( self insidestingerreticlenolock( targetsall[ idx ] ) )
|
|
{
|
|
if ( isDefined( targetsall[ idx ].owner ) && self != targetsall[ idx ].owner )
|
|
{
|
|
targetsvalid[ targetsvalid.size ] = targetsall[ idx ];
|
|
}
|
|
}
|
|
}
|
|
idx++;
|
|
}
|
|
if ( targetsvalid.size == 0 )
|
|
{
|
|
return undefined;
|
|
}
|
|
chosenent = targetsvalid[ 0 ];
|
|
if ( targetsvalid.size > 1 )
|
|
{
|
|
}
|
|
return chosenent;
|
|
}
|
|
|
|
insidestingerreticlenolock( target )
|
|
{
|
|
radius = self getlockonradius();
|
|
return target_isincircle( target, self, 65, radius );
|
|
}
|
|
|
|
insidestingerreticlelocked( target )
|
|
{
|
|
radius = self getlockonradius();
|
|
return target_isincircle( target, self, 65, radius );
|
|
}
|
|
|
|
isstillvalidtarget( ent )
|
|
{
|
|
if ( !isDefined( ent ) )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( !target_istarget( ent ) )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( !insidestingerreticlelocked( ent ) )
|
|
{
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
playerstingerads()
|
|
{
|
|
return self playerads() == 1;
|
|
}
|
|
|
|
looplocalseeksound( alias, interval )
|
|
{
|
|
self endon( "stop_lockon_sound" );
|
|
self endon( "disconnect" );
|
|
self endon( "death" );
|
|
for ( ;; )
|
|
{
|
|
self playlocalsound( alias );
|
|
self playrumbleonentity( "stinger_lock_rumble" );
|
|
wait ( interval / 2 );
|
|
}
|
|
}
|
|
|
|
looplocallocksound( alias, interval )
|
|
{
|
|
self endon( "stop_locked_sound" );
|
|
self endon( "disconnect" );
|
|
self endon( "death" );
|
|
if ( isDefined( self.stingerlocksound ) )
|
|
{
|
|
return;
|
|
}
|
|
self.stingerlocksound = 1;
|
|
for ( ;; )
|
|
{
|
|
self playlocalsound( alias );
|
|
self playrumbleonentity( "stinger_lock_rumble" );
|
|
wait ( interval / 6 );
|
|
self playlocalsound( alias );
|
|
self playrumbleonentity( "stinger_lock_rumble" );
|
|
wait ( interval / 6 );
|
|
self playlocalsound( alias );
|
|
self playrumbleonentity( "stinger_lock_rumble" );
|
|
wait ( interval / 6 );
|
|
self stoprumble( "stinger_lock_rumble" );
|
|
}
|
|
self.stingerlocksound = undefined;
|
|
}
|
|
|
|
locksighttest( target )
|
|
{
|
|
eyepos = self geteye();
|
|
if ( !isDefined( target ) )
|
|
{
|
|
return 0;
|
|
}
|
|
passed = bullettracepassed( eyepos, target.origin, 0, target );
|
|
if ( passed )
|
|
{
|
|
return 1;
|
|
}
|
|
front = target getpointinbounds( 1, 0, 0 );
|
|
passed = bullettracepassed( eyepos, front, 0, target );
|
|
if ( passed )
|
|
{
|
|
return 1;
|
|
}
|
|
back = target getpointinbounds( -1, 0, 0 );
|
|
passed = bullettracepassed( eyepos, back, 0, target );
|
|
if ( passed )
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
softsighttest()
|
|
{
|
|
lost_sight_limit = 500;
|
|
if ( self locksighttest( self.stingertarget ) )
|
|
{
|
|
self.stingerlostsightlinetime = 0;
|
|
return 1;
|
|
}
|
|
if ( self.stingerlostsightlinetime == 0 )
|
|
{
|
|
self.stingerlostsightlinetime = getTime();
|
|
}
|
|
timepassed = getTime() - self.stingerlostsightlinetime;
|
|
if ( timepassed >= lost_sight_limit )
|
|
{
|
|
self clearirtarget();
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
initlockfield( target )
|
|
{
|
|
if ( isDefined( target.locking_on ) )
|
|
{
|
|
return;
|
|
}
|
|
target.locking_on = 0;
|
|
target.locked_on = 0;
|
|
}
|
|
|
|
lockingon( target, lock )
|
|
{
|
|
/#
|
|
assert( isDefined( target.locking_on ) );
|
|
#/
|
|
clientnum = self getentitynumber();
|
|
if ( lock )
|
|
{
|
|
target notify( "locking on" );
|
|
target.locking_on |= 1 << clientnum;
|
|
self thread watchclearlockingon( target, clientnum );
|
|
}
|
|
else
|
|
{
|
|
self notify( "locking_on_cleared" );
|
|
target.locking_on &= 1 << clientnum;
|
|
}
|
|
}
|
|
|
|
watchclearlockingon( target, clientnum )
|
|
{
|
|
target endon( "death" );
|
|
self endon( "locking_on_cleared" );
|
|
self waittill_any( "death", "disconnect" );
|
|
target.locking_on &= 1 << clientnum;
|
|
}
|
|
|
|
lockedon( target, lock )
|
|
{
|
|
/#
|
|
assert( isDefined( target.locked_on ) );
|
|
#/
|
|
clientnum = self getentitynumber();
|
|
if ( lock )
|
|
{
|
|
target.locked_on |= 1 << clientnum;
|
|
self thread watchclearlockedon( target, clientnum );
|
|
}
|
|
else
|
|
{
|
|
self notify( "locked_on_cleared" );
|
|
target.locked_on &= 1 << clientnum;
|
|
}
|
|
}
|
|
|
|
watchclearlockedon( target, clientnum )
|
|
{
|
|
self endon( "locked_on_cleared" );
|
|
self waittill_any( "death", "disconnect" );
|
|
if ( isDefined( target ) )
|
|
{
|
|
target.locked_on &= 1 << clientnum;
|
|
}
|
|
}
|
|
|
|
missiletarget_lockonmonitor( player, endon1, endon2 )
|
|
{
|
|
self endon( "death" );
|
|
if ( isDefined( endon1 ) )
|
|
{
|
|
self endon( endon1 );
|
|
}
|
|
if ( isDefined( endon2 ) )
|
|
{
|
|
self endon( endon2 );
|
|
}
|
|
for ( ;; )
|
|
{
|
|
if ( target_istarget( self ) )
|
|
{
|
|
}
|
|
wait 0,1;
|
|
}
|
|
}
|
|
|
|
_incomingmissile( missile )
|
|
{
|
|
if ( !isDefined( self.incoming_missile ) )
|
|
{
|
|
self.incoming_missile = 0;
|
|
}
|
|
self.incoming_missile++;
|
|
self thread _incomingmissiletracker( missile );
|
|
}
|
|
|
|
_incomingmissiletracker( missile )
|
|
{
|
|
self endon( "death" );
|
|
missile waittill( "death" );
|
|
self.incoming_missile--;
|
|
|
|
/#
|
|
assert( self.incoming_missile >= 0 );
|
|
#/
|
|
}
|
|
|
|
missiletarget_ismissileincoming()
|
|
{
|
|
if ( !isDefined( self.incoming_missile ) )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( self.incoming_missile )
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
missiletarget_handleincomingmissile( responsefunc, endon1, endon2 )
|
|
{
|
|
level endon( "game_ended" );
|
|
self endon( "death" );
|
|
if ( isDefined( endon1 ) )
|
|
{
|
|
self endon( endon1 );
|
|
}
|
|
if ( isDefined( endon2 ) )
|
|
{
|
|
self endon( endon2 );
|
|
}
|
|
for ( ;; )
|
|
{
|
|
self waittill( "stinger_fired_at_me", missile, weap, attacker );
|
|
_incomingmissile( missile );
|
|
if ( isDefined( responsefunc ) )
|
|
{
|
|
[[ responsefunc ]]( missile, attacker, weap, endon1, endon2 );
|
|
}
|
|
}
|
|
}
|
|
|
|
missiletarget_proximitydetonateincomingmissile( endon1, endon2 )
|
|
{
|
|
missiletarget_handleincomingmissile( ::missiletarget_proximitydetonate, endon1, endon2 );
|
|
}
|
|
|
|
_missiledetonate( attacker, weapon )
|
|
{
|
|
self endon( "death" );
|
|
radiusdamage( self.origin, 500, 600, 600, attacker, undefined, weapon );
|
|
wait 0,05;
|
|
self detonate();
|
|
wait 0,05;
|
|
self delete();
|
|
}
|
|
|
|
missiletarget_proximitydetonate( missile, attacker, weapon, endon1, endon2 )
|
|
{
|
|
level endon( "game_ended" );
|
|
missile endon( "death" );
|
|
if ( isDefined( endon1 ) )
|
|
{
|
|
self endon( endon1 );
|
|
}
|
|
if ( isDefined( endon2 ) )
|
|
{
|
|
self endon( endon2 );
|
|
}
|
|
mindist = distance( missile.origin, self.origin );
|
|
lastcenter = self.origin;
|
|
missile missile_settarget( self );
|
|
for ( ;; )
|
|
{
|
|
if ( !isDefined( self ) )
|
|
{
|
|
center = lastcenter;
|
|
}
|
|
else
|
|
{
|
|
center = self.origin;
|
|
}
|
|
lastcenter = center;
|
|
curdist = distance( missile.origin, center );
|
|
if ( curdist < 3500 && isDefined( self.numflares ) && self.numflares > 0 )
|
|
{
|
|
self.numflares--;
|
|
|
|
self thread missiletarget_playflarefx();
|
|
self maps/mp/killstreaks/_helicopter::trackassists( attacker, 0, 1 );
|
|
newtarget = self missiletarget_deployflares( missile.origin, missile.angles );
|
|
missile missile_settarget( newtarget );
|
|
missiletarget = newtarget;
|
|
return;
|
|
}
|
|
if ( curdist < mindist )
|
|
{
|
|
mindist = curdist;
|
|
}
|
|
if ( curdist > mindist )
|
|
{
|
|
if ( curdist > 500 )
|
|
{
|
|
return;
|
|
}
|
|
missile thread _missiledetonate( attacker, weapon );
|
|
}
|
|
wait 0,05;
|
|
}
|
|
}
|
|
|
|
missiletarget_playflarefx()
|
|
{
|
|
if ( !isDefined( self ) )
|
|
{
|
|
return;
|
|
}
|
|
flare_fx = level.fx_flare;
|
|
if ( isDefined( self.fx_flare ) )
|
|
{
|
|
flare_fx = self.fx_flare;
|
|
}
|
|
if ( isDefined( self.flare_ent ) )
|
|
{
|
|
playfxontag( flare_fx, self.flare_ent, "tag_origin" );
|
|
}
|
|
else
|
|
{
|
|
playfxontag( flare_fx, self, "tag_origin" );
|
|
}
|
|
if ( isDefined( self.owner ) )
|
|
{
|
|
self playsoundtoplayer( "veh_huey_chaff_drop_plr", self.owner );
|
|
}
|
|
self playsound( "veh_huey_chaff_explo_npc" );
|
|
}
|
|
|
|
missiletarget_deployflares( origin, angles )
|
|
{
|
|
vec_toforward = anglesToForward( self.angles );
|
|
vec_toright = anglesToRight( self.angles );
|
|
vec_tomissileforward = anglesToForward( angles );
|
|
delta = self.origin - origin;
|
|
dot = vectordot( vec_tomissileforward, vec_toright );
|
|
sign = 1;
|
|
if ( dot > 0 )
|
|
{
|
|
sign = -1;
|
|
}
|
|
flare_dir = vectornormalize( vectorScale( vec_toforward, -0,5 ) + vectorScale( vec_toright, sign ) );
|
|
velocity = vectorScale( flare_dir, randomintrange( 200, 400 ) );
|
|
velocity = ( velocity[ 0 ], velocity[ 1 ], velocity[ 2 ] - randomintrange( 10, 100 ) );
|
|
flareorigin = self.origin;
|
|
flareorigin += vectorScale( flare_dir, randomintrange( 500, 700 ) );
|
|
flareorigin += vectorScale( ( 1, 0, 0 ), 500 );
|
|
if ( isDefined( self.flareoffset ) )
|
|
{
|
|
flareorigin += self.flareoffset;
|
|
}
|
|
flareobject = spawn( "script_origin", flareorigin );
|
|
flareobject.angles = self.angles;
|
|
flareobject setmodel( "tag_origin" );
|
|
flareobject movegravity( velocity, 5 );
|
|
flareobject thread deleteaftertime( 5 );
|
|
self thread debug_tracker( flareobject );
|
|
return flareobject;
|
|
}
|
|
|
|
debug_tracker( target )
|
|
{
|
|
target endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
maps/mp/killstreaks/_airsupport::debug_sphere( target.origin, 10, ( 1, 0, 0 ), 1, 1 );
|
|
wait 0,05;
|
|
}
|
|
}
|