2024-12-11 11:28:08 +01:00

1729 lines
44 KiB
Plaintext

#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
UAV_REMOTE_FLY_TIME = 60;
UAV_REMOTE_AIM_ASSIST_RANGE = 200;
UAV_REMOTE_MAX_PAST_RANGE = 200;
UAV_REMOTE_MIN_HELI_PROXIMITY = 150;
UAV_REMOTE_MAX_HELI_PROXIMITY = 300;
UAV_REMOTE_PAST_RANGE_COUNTDOWN = 6;
UAV_REMOTE_HELI_RANGE_COUNTDOWN = 3;
UAV_REMOTE_COLLISION_RADIUS = 18;
UAV_REMOTE_Z_OFFSET = -9;
init()
{
level.RemoteUAV_fx["hit"] = loadfx("fx/impacts/large_metal_painted_hit");
level.RemoteUAV_fx["smoke"] = loadfx( "fx/smoke/remote_heli_damage_smoke_runner" );
level.RemoteUAV_fx["explode"] = loadfx( "fx/explosions/bouncing_betty_explosion" );
level.RemoteUAV_fx["missile_explode"] = loadfx( "fx/explosions/stinger_explosion" );
level.RemoteUAV_dialog["launch"][0] = "ac130_plt_yeahcleared";
level.RemoteUAV_dialog["launch"][1] = "ac130_plt_rollinin";
level.RemoteUAV_dialog["launch"][2] = "ac130_plt_scanrange";
level.RemoteUAV_dialog["out_of_range"][0] = "ac130_plt_cleanup";
level.RemoteUAV_dialog["out_of_range"][1] = "ac130_plt_targetreset";
level.RemoteUAV_dialog["track"][0] = "ac130_fco_moreenemy";
level.RemoteUAV_dialog["track"][1] = "ac130_fco_getthatguy";
level.RemoteUAV_dialog["track"][2] = "ac130_fco_guymovin";
level.RemoteUAV_dialog["track"][3] = "ac130_fco_getperson";
level.RemoteUAV_dialog["track"][4] = "ac130_fco_guyrunnin";
level.RemoteUAV_dialog["track"][5] = "ac130_fco_gotarunner";
level.RemoteUAV_dialog["track"][6] = "ac130_fco_backonthose";
level.RemoteUAV_dialog["track"][7] = "ac130_fco_gonnagethim";
level.RemoteUAV_dialog["track"][8] = "ac130_fco_personnelthere";
level.RemoteUAV_dialog["track"][9] = "ac130_fco_rightthere";
level.RemoteUAV_dialog["track"][10] = "ac130_fco_tracking";
level.RemoteUAV_dialog["tag"][0] = "ac130_fco_nice";
level.RemoteUAV_dialog["tag"][1] = "ac130_fco_yougothim";
level.RemoteUAV_dialog["tag"][2] = "ac130_fco_yougothim2";
level.RemoteUAV_dialog["tag"][3] = "ac130_fco_okyougothim";
level.RemoteUAV_dialog["assist"][0] = "ac130_fco_goodkill";
level.RemoteUAV_dialog["assist"][1] = "ac130_fco_thatsahit";
level.RemoteUAV_dialog["assist"][2] = "ac130_fco_directhit";
level.RemoteUAV_dialog["assist"][3] = "ac130_fco_rightontarget";
level.RemoteUAV_lastDialogTime = 0;
level.RemoteUAV_noDeployZones = GetEntArray( "no_vehicles", "targetname" );
level.killstreakFuncs["remote_uav"] = ::useRemoteUAV;
level.remote_uav = [];
/#
SetDevDvarIfUninitialized( "scr_remoteUAVFlyTime", 60 );
#/
}
useRemoteUAV( lifeId, streakName )
{
return tryUseRemoteUAV( lifeId, "remote_uav" );
}
exceededMaxRemoteUAVs( team )
{
if ( level.gameType == "dm" )
{
if ( isDefined( level.remote_uav[team] ) || isDefined( level.remote_uav[level.otherTeam[team]] ) )
return true;
else
return false;
}
else
{
if ( isDefined( level.remote_uav[team] ) )
return true;
else
return false;
}
}
tryUseRemoteUAV( lifeId, streakName )
{
self _disableUsability();
if ( self isUsingRemote() || self isUsingTurret() || isDefined( level.nukeIncoming ) )
{
self _enableUsability();
return false;
}
numIncomingVehicles = 1;
if ( exceededMaxRemoteUAVs( self.team ) || level.littleBirds.size >= 4 )
{
self iPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
self _enableUsability();
return false;
}
else if( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + numIncomingVehicles >= maxVehiclesAllowed() )
{
self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_VEHICLES" );
self _enableUsability();
return false;
}
// ui vars
self setPlayerData( "reconDroneState", "staticAlpha", 0 );
self setPlayerData( "reconDroneState", "incomingMissile", false );
// increment the faux vehicle count before we spawn the vehicle so no other vehicles try to spawn
incrementFauxVehicleCount();
result = self giveCarryRemoteUAV( lifeId, streakName );
if ( result )
{
self maps\mp\_matchdata::logKillstreakEvent( streakName, self.origin );
self thread teamPlayerCardSplash( "used_remote_uav", self );
}
else
{
// decrement the faux vehicle count since this failed to spawn
decrementFauxVehicleCount();
}
self.isCarrying = false;
return ( result );
}
giveCarryRemoteUAV( lifeId, streakName )
{
// create carry object
carryRemoteUAV = createCarryRemoteUAV( streakName, self );
// get rid of clicker and give hand model
self takeWeapon( "killstreak_uav_mp" );
self _giveWeapon( "killstreak_remote_uav_mp" );
self SwitchToWeaponImmediate( "killstreak_remote_uav_mp" );
// give carry object and wait for placement (blocking loop)
self setCarryingRemoteUAV( carryRemoteUAV );
// we're back, what happened?
if ( isAlive( self ) && isDefined( carryRemoteUAV ) )
{
// if it placed, start the killstreak at that location
origin = carryRemoteUAV.origin;
angles = self.angles;
carryRemoteUAV.soundEnt delete();
carryRemoteUAV delete();
result = self startRemoteUAV( lifeId, streakName, origin, angles );
}
else
{
// cancelled placement or died
result = false;
if ( isAlive( self ) )
{
// get rid of hand model
self takeWeapon( "killstreak_remote_uav_mp" );
// give back the clicker to be able to active killstreak again
self _giveWeapon( "killstreak_uav_mp" );
}
}
return result;
}
// Carry Remote UAV
createCarryRemoteUAV( streakName, owner )
{
pos = owner.origin + ( anglesToForward( owner.angles ) * 4 ) + ( anglesToUp( owner.angles ) * 50 );
carryRemoteUAV = spawnTurret( "misc_turret", pos, "sentry_minigun_mp" );
carryRemoteUAV.origin = pos;
carryRemoteUAV.angles = owner.angles;
carryRemoteUAV.sentryType = "sentry_minigun";
carryRemoteUAV.canBePlaced = true;
carryRemoteUAV setTurretModeChangeWait( true );
carryRemoteUAV setMode( "sentry_offline" );
carryRemoteUAV makeUnusable();
carryRemoteUAV makeTurretInoperable();
carryRemoteUAV.owner = owner;
carryRemoteUAV SetSentryOwner( carryRemoteUAV.owner );
carryRemoteUAV.scale = 3;
carryRemoteUAV.inHeliProximity = false;
carryRemoteUAV thread carryRemoteUAV_handleExistence();
carryRemoteUAV.rangeTrigger = GetEnt( "remote_uav_range", "targetname" );
if ( !isDefined( carryRemoteUAV.rangeTrigger ) )
{
heightEnt = GetEnt( "airstrikeheight", "targetname" );
carryRemoteUAV.maxHeight = heightEnt.origin[2];
carryRemoteUAV.maxDistance = 3600;
}
// apparently can't call playLoopSound on a turret?
carryRemoteUAV.soundEnt = spawn( "script_origin", carryRemoteUAV.origin );
carryRemoteUAV.soundEnt.angles = carryRemoteUAV.angles;
carryRemoteUAV.soundEnt.origin = carryRemoteUAV.origin;
carryRemoteUAV.soundEnt linkTo( carryRemoteUAV );
carryRemoteUAV.soundEnt playLoopSound( "recondrone_idle_high" );
return carryRemoteUAV;
}
setCarryingRemoteUAV( carryRemoteUAV )
{
carryRemoteUAV thread carryRemoteUAV_setCarried( self );
self notifyOnPlayerCommand( "place_carryRemoteUAV", "+attack" );
self notifyOnPlayerCommand( "place_carryRemoteUAV", "+attack_akimbo_accessible" ); // support accessibility control scheme
self notifyOnPlayerCommand( "cancel_carryRemoteUAV", "+actionslot 4" );
if( !level.console )
{
self notifyOnPlayerCommand( "cancel_carryRemoteUAV", "+actionslot 5" );
self notifyOnPlayerCommand( "cancel_carryRemoteUAV", "+actionslot 6" );
self notifyOnPlayerCommand( "cancel_carryRemoteUAV", "+actionslot 7" );
}
for ( ;; )
{
result = local_waittill_any_return( "place_carryRemoteUAV", "cancel_carryRemoteUAV", "weapon_switch_started", "force_cancel_placement", "death", "disconnect" );
self forceUseHintOff();
if ( result != "place_carryRemoteUAV" )
{
self carryRemoteUAV_delete( carryRemoteUAV );
break;
}
if ( !carryRemoteUAV.canBePlaced )
{
if ( self.team != "spectator" )
self ForceUseHintOn( &"KILLSTREAKS_REMOTE_UAV_CANNOT_PLACE" );
continue;
}
if( isDefined( level.nukeIncoming ) ||
self isEMPed() ||
exceededMaxRemoteUAVs( self.team ) ||
currentActiveVehicleCount() >= maxVehiclesAllowed() ||
level.fauxVehicleCount >= maxVehiclesAllowed() )
{
if ( isDefined( level.nukeIncoming ) || self isEMPed() )
{
self iPrintLnBold( &"KILLSTREAKS_UNAVAILABLE_FOR_N_WHEN_EMP", level.empTimeRemaining );
}
else
{
self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_VEHICLES" );
}
self carryRemoteUAV_delete( carryRemoteUAV );
break;
}
self.isCarrying = false;
carryRemoteUAV.carriedBy = undefined;
carryRemoteUAV playSound( "sentry_gun_plant" );
carryRemoteUAV notify ( "placed" );
break;
}
}
local_waittill_any_return( string1, string2, string3, string4, string5, string6 )
{
if ( ( !isdefined( string1 ) || string1 != "death" ) &&
( !isdefined( string2 ) || string2 != "death" ) &&
( !isdefined( string3 ) || string3 != "death" ) &&
( !isdefined( string4 ) || string4 != "death" ) &&
( !isdefined( string5 ) || string5 != "death" ) )
self endon( "death" );
ent = spawnstruct();
if ( isdefined( string1 ) )
self thread waittill_string( string1, ent );
if ( isdefined( string2 ) )
self thread waittill_string( string2, ent );
if ( isdefined( string3 ) )
self thread waittill_string( string3, ent );
if ( isdefined( string4 ) )
self thread waittill_string( string4, ent );
if ( isdefined( string5 ) )
self thread waittill_string( string5, ent );
if ( isdefined( string6 ) )
self thread waittill_string( string6, ent );
ent waittill( "returned", msg );
ent notify( "die" );
return msg;
}
carryRemoteUAV_setCarried( carrier )
{
self setCanDamage( false );
self setSentryCarrier( carrier );
self setContents( 0 );
self.carriedBy = carrier;
carrier.isCarrying = true;
carrier thread updateCarryRemoteUAVPlacement( self );
self notify ( "carried" );
}
carryRemoteUAV_delete( carryRemoteUAV )
{
self.isCarrying = false;
if ( isDefined( carryRemoteUAV ) )
{
if ( isDefined( carryRemoteUAV.soundEnt ) )
{
carryRemoteUAV.soundEnt delete();
}
carryRemoteUAV delete();
}
}
isInRemoteNoDeploy()
{
if ( isDefined( level.RemoteUAV_noDeployZones ) && level.RemoteUAV_noDeployZones.size )
{
foreach( zone in level.RemoteUAV_noDeployZones )
{
if ( self isTouching( zone ) )
return true;
}
}
return false;
}
updateCarryRemoteUAVPlacement( carryRemoteUAV )
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
carryRemoteUAV endon ( "placed" );
carryRemoteUAV endon ( "death" );
carryRemoteUAV.canBePlaced = true;
lastCanPlaceCarryRemoteUAV = -1; // force initial update
self _enableUsability();
for( ;; )
{
heightOffset = UAV_REMOTE_COLLISION_RADIUS;
switch( self getStance() )
{
case "stand":
heightOffset = 40;
break;
case "crouch":
heightOffset = 25;
break;
case "prone":
heightOffset = 10;
break;
}
placement = self CanPlayerPlaceTank( 22, 22, 50, heightOffset, 0, 0 );
carryRemoteUAV.origin = placement[ "origin" ] + ( anglesToUp(self.angles) * ( UAV_REMOTE_COLLISION_RADIUS - UAV_REMOTE_Z_OFFSET ) );
carryRemoteUAV.angles = placement[ "angles" ];
carryRemoteUAV.canBePlaced = self isOnGround() && placement[ "result" ] && carryRemoteUAV remoteUAV_in_range() && !carryRemoteUAV isInRemoteNoDeploy();
if ( carryRemoteUAV.canBePlaced != lastCanPlaceCarryRemoteUAV )
{
if ( carryRemoteUAV.canBePlaced )
{
if ( self.team != "spectator" )
self ForceUseHintOn( &"KILLSTREAKS_REMOTE_UAV_PLACE" );
// if they're holding it in launch position just launch now
if ( self attackButtonPressed() )
self notify( "place_carryRemoteUAV" );
}
else
{
if ( self.team != "spectator" )
self ForceUseHintOn( &"KILLSTREAKS_REMOTE_UAV_CANNOT_PLACE" );
}
}
lastCanPlaceCarryRemoteUAV = carryRemoteUAV.canBePlaced;
wait ( 0.05 );
}
}
carryRemoteUAV_handleExistence()
{
level endon ( "game_ended" );
self.owner endon ( "place_carryRemoteUAV" );
self.owner endon ( "cancel_carryRemoteUAV" );
self.owner waittill_any( "death", "disconnect", "joined_team", "joined_spectators" );
if ( isDefined( self ) )
{
if ( isDefined( self.soundEnt ) )
self.soundEnt delete();
self delete();
}
}
// Remote UAV
removeRemoteWeapon()
{
level endon( "game_ended" );
self endon ( "disconnect" );
wait(0.7);
}
startRemoteUAV( lifeId, streakName, origin, angles )
{
self lockPlayerForRemoteUAVLaunch();
self setUsingRemote( streakName );
self _giveWeapon("uav_remote_mp");
self SwitchToWeaponImmediate("uav_remote_mp");
self VisionSetNakedForPlayer( "black_bw", 0.0 );
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak( "remote_uav" );
if ( result != "success" )
{
if ( result != "disconnect" )
{
self notify( "remoteuav_unlock" );
self takeWeapon("uav_remote_mp");
self clearUsingRemote();
}
return false;
}
if( exceededMaxRemoteUAVs( self.team ) ||
currentActiveVehicleCount() >= maxVehiclesAllowed() ||
level.fauxVehicleCount >= maxVehiclesAllowed() )
{
self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_VEHICLES" );
self notify( "remoteuav_unlock" );
self takeWeapon("uav_remote_mp");
self clearUsingRemote();
return false;
}
self notify( "remoteuav_unlock" );
remoteUAV = createRemoteUAV( lifeId, self, streakName, origin, angles );
if ( isDefined( remoteUAV ) )
{
self thread remoteUAV_Ride( lifeId, remoteUAV, streakName );
return true;
}
else
{
self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_VEHICLES" );
self takeWeapon("uav_remote_mp");
self clearUsingRemote();
return false;
}
}
lockPlayerForRemoteUAVLaunch()
{
// lock
lockSpot = spawn( "script_origin", self.origin );
lockSpot hide();
self playerLinkTo( lockSpot );
// wait for unlock
self thread clearPlayerLockFromRemoteUAVLaunch( lockSpot );
}
clearPlayerLockFromRemoteUAVLaunch( lockSpot )
{
level endon( "game_ended" );
msg = self waittill_any_return( "disconnect", "death", "remoteuav_unlock" );
// do unlock stuff
if ( msg != "disconnect" )
self unlink();
lockSpot delete();
}
createRemoteUAV( lifeId, owner, streakName, origin, angles )
{
if ( level.console )
{
remoteUAV = spawnHelicopter( owner, origin, angles, "remote_uav_mp", "vehicle_remote_uav" );
}
else
{
remoteUAV = spawnHelicopter( owner, origin, angles, "remote_uav_mp_pc", "vehicle_remote_uav" );
}
if ( !isDefined( remoteUAV ) )
return undefined;
remoteUAV maps\mp\killstreaks\_helicopter::addToLittleBirdList();
remoteUAV thread maps\mp\killstreaks\_helicopter::removeFromLittleBirdListOnDeath();
//radius and offset should match vehHelicopterBoundsRadius (GDT) and bg_vehicle_sphere_bounds_offset_z.
remoteUAV MakeVehicleSolidCapsule( UAV_REMOTE_COLLISION_RADIUS, UAV_REMOTE_Z_OFFSET, UAV_REMOTE_COLLISION_RADIUS );
remoteUAV.lifeId = lifeId;
remoteUAV.team = owner.team;
remoteUAV.pers["team"] = owner.team;
remoteUAV.owner = owner;
remoteUAV SetOtherEnt(owner);
remoteUAV make_entity_sentient_mp( owner.team );
remoteUAV.maxHealth = 250; // this is the health we'll check
//remoteUAV ThermalDrawEnable();
// scrambler
remoteUAV.scrambler = spawn( "script_model", origin );
remoteUAV.scrambler linkTo( remoteUAV, "tag_origin", (0,0,-160), (0,0,0) );
remoteUAV.scrambler makeScrambler( owner );
remoteUAV.smoking = false;
remoteUAV.inHeliProximity = false;
remoteUAV.heliType = "remote_uav";
remoteUAV.markedPlayers = [];
remoteUAV thread remoteUAV_light_fx();
remoteUAV thread remoteUAV_explode_on_disconnect();
remoteUAV thread remoteUAV_explode_on_changeTeams();
remoteUAV thread remoteUAV_explode_on_death();
remoteUAV thread remoteUAV_clear_marked_on_gameEnded();
remoteUAV thread remoteUAV_leave_on_timeout();
remoteUAV thread remoteUAV_watch_distance();
remoteUAV thread remoteUAV_watchHeliProximity();
remoteUAV thread remoteUAV_handleDamage();
remoteUAV.numFlares = 2;
remoteUAV.hasIncoming = false;
remoteUAV.incomingMissiles = [];
remoteUAV thread remoteUAV_clearIncomingWarning();
remoteUAV thread remoteUAV_handleIncomingStinger();
remoteUAV thread remoteUAV_handleIncomingSAM();
level.remote_uav[remoteUAV.team] = remoteUAV;
return remoteUAV;
}
remoteUAV_ride( lifeId, remoteUAV, streakName )
{
remoteUAV.playerLinked = true;
self.restoreAngles = self.angles;
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( false );
self CameraLinkTo( remoteUAV, "tag_origin" );
self RemoteControlVehicle( remoteUAV );
self thread remoteUAV_playerExit( remoteUAV );
self thread remoteUAV_Track( remoteUAV );
self thread remoteUAV_Fire( remoteUAV );
//self thread remoteUAV_operationRumble( remoteUAV );
self.remote_uav_rideLifeId = lifeId;
self.remoteUAV = remoteUAV;
self thread remoteUAV_delayLaunchDialog( remoteUAV );
self VisionSetNakedForPlayer( "black_bw", 0.0 );
self restoreBaseVisionSet( 1 );
}
remoteUAV_delayLaunchDialog( remoteUAV )
{
level endon( "game_ended" );
self endon ( "disconnect" );
remoteUAV endon ( "death" );
remoteUAV endon ( "end_remote" );
remoteUAV endon ( "end_launch_dialog" );
wait( 3 );
self remoteUAV_dialog( "launch" );
}
remoteUAV_endride( remoteUAV )
{
if ( isDefined( remoteUAV ) )
{
remoteUAV.playerLinked = false;
remoteUAV notify( "end_remote" );
self clearUsingRemote();
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( true );
self CameraUnlink( remoteUAV );
self RemoteControlVehicleOff( remoteUAV );
self ThermalVisionOff();
self setPlayerAngles( self.restoreAngles );
lastWeapon = self getLastWeapon();
if( !self hasWeapon( lastWeapon ) )
{
lastWeapon = self maps\mp\killstreaks\_killstreaks::getFirstPrimaryWeapon();
}
self switchToWeapon( lastWeapon );
self TakeWeapon( "uav_remote_mp" );
self thread remoteUAV_freezeBuffer();
}
self.remoteUAV = undefined;
}
remoteUAV_freezeBuffer()
{
self endon( "disconnect" );
self endon( "death" );
level endon( "game_ended" );
self freezeControlsWrapper( true );
wait( 0.5 );
self freezeControlsWrapper( false );
}
remoteUAV_playerExit( remoteUAV )
{
level endon( "game_ended" );
self endon ( "disconnect" );
remoteUAV endon ( "death" );
remoteUAV endon ( "end_remote" );
// delay exit for transition into remote
wait( 2 );
while( true )
{
timeUsed = 0;
while( self UseButtonPressed() )
{
timeUsed += 0.05;
if( timeUsed > 0.75 )
{
remoteUAV thread remoteUAV_leave();
return;
}
wait( 0.05 );
}
wait( 0.05 );
}
}
remoteUAV_Track( remoteUAV )
{
level endon ( "game_ended" );
self endon ( "disconnect" );
remoteUAV endon ( "death" );
remoteUAV endon ( "end_remote" );
remoteUAV.lastTrackingDialogTime = 0;
self.lockedTarget = undefined;
self weaponLockFree();
// finish transitioning into remote
wait( 1 );
// now loop and track
while( true )
{
// aim assist 'lock on' target for radius check
pos = remoteUAV getTagOrigin( "tag_turret" );
forward = anglesToForward( self getPlayerAngles() );
endpos = pos + forward * 1024;
trace = bulletTrace( pos, endpos, true, remoteUAV );
if ( isDefined( trace["position"] ) )
targetPos = trace["position"];
else
{
targetPos = endpos;
trace["endpos"] = endpos;
}
remoteUAV.trace = trace;
// track all targetable entities, update head icons, check lock-on
lockedPlayer = self remoteUAV_trackEntities( remoteUAV, level.players, targetPos );
lockedTurret = self remoteUAV_trackEntities( remoteUAV, level.turrets, targetPos );
lockedUAV = undefined;
if( level.multiTeamBased )
{
//accumulate a list of all enemy uav models
entityList = [];
foreach ( teamName in level.teamNameList )
{
if ( teamName != self.team )
{
foreach( model in level.uavmodels[teamName] )
{
entityList[entityList.size] = model;
}
}
}
lockedUAV = self remoteUAV_trackEntities( remoteUAV, entityList, targetPos );
}
else if ( level.teamBased )
lockedUAV = self remoteUAV_trackEntities( remoteUAV, level.uavmodels[level.otherTeam[self.team]], targetPos );
else
lockedUAV = self remoteUAV_trackEntities( remoteUAV, level.uavmodels, targetPos );
lockedTarget = undefined;
if ( isDefined( lockedPlayer ) )
lockedTarget = lockedPlayer;
else if ( isDefined( lockedTurret ) )
lockedTarget = lockedTurret;
else if ( isDefined( lockedUAV ) )
lockedTarget = lockedUAV;
if ( isDefined( lockedTarget ) )
{
if ( !isDefined( self.lockedTarget ) || ( isDefined( self.lockedTarget ) && self.lockedTarget != lockedTarget ) )
{
self weaponLockFinalize( lockedTarget );
self.lockedTarget = lockedTarget;
// do vo for players
if ( isDefined( lockedPlayer ) )
{
// cancels the launch dialog delay if we get a target before then
remoteUAV notify( "end_launch_dialog" );
self remoteUAV_dialog( "track" );
}
}
}
else
{
self weaponLockFree();
self.lockedTarget = undefined;
}
wait( 0.05 );
}
}
remoteUAV_trackEntities( remoteUAV, entities, targetPos )
{
level endon( "game_ended" );
lockedTarget = undefined;
foreach ( entity in entities )
{
if ( level.teamBased && ( !isDefined( entity.team ) || entity.team == self.team ) )
continue;
if ( isPlayer( entity ) )
{
if ( !isReallyAlive( entity ) )
continue;
if ( entity == self )
continue;
id = entity.guid;
}
else
id = entity.birthtime;
// offset
if ( isDefined( entity.sentryType ) || isDefined( entity.turretType ) )
{
offset = (0,0,32);
unmarkedShader = "hud_fofbox_hostile_vehicle";
}
else if ( isDefined( entity.uavType ) )
{
offset = (0,0,-52);
unmarkedShader = "hud_fofbox_hostile_vehicle";
}
else
{
offset = (0,0,26);
unmarkedShader = "veh_hud_target_unmarked";
}
// already marked
if ( isDefined( entity.UAVRemoteMarkedBy ) )
{
// marked, but no headicon yet
if ( !isDefined( remoteUAV.markedPlayers[id] ) )
{
remoteUAV.markedPlayers[id] = [];
remoteUAV.markedPlayers[id]["player"] = entity;
remoteUAV.markedPlayers[id]["icon"] = entity maps\mp\_entityheadIcons::setHeadIcon( self, "veh_hud_target_marked", offset, 10, 10, false, 0.05, false, false, false, false );
remoteUAV.markedPlayers[id]["icon"].shader = "veh_hud_target_marked";
if ( !isDefined( entity.sentryType ) || !isDefined( entity.turretType ) )
remoteUAV.markedPlayers[id]["icon"] SetTargetEnt( entity );
}
// headicon hasn't been switched to marked yet
else if ( isDefined( remoteUAV.markedPlayers[id] ) && isDefined( remoteUAV.markedPlayers[id]["icon"] ) && isDefined( remoteUAV.markedPlayers[id]["icon"].shader ) && remoteUAV.markedPlayers[id]["icon"].shader != "veh_hud_target_marked" )
{
remoteUAV.markedPlayers[id]["icon"].shader = "veh_hud_target_marked";
remoteUAV.markedPlayers[id]["icon"] setShader( "veh_hud_target_marked", 10, 10 );
remoteUAV.markedPlayers[id]["icon"] setWaypoint( false, false, false, false );
}
}
// not marked yet
else
{
// exceptions
if ( isPlayer( entity ) )
{
spawnProtected = ( isDefined( entity.spawntime ) && ( getTime() - entity.spawntime )/1000 <= 5 );
hudTargetProtected = entity _hasPerk( "specialty_blindeye" );
carried = false;
leaving = false;
}
else
{
spawnProtected = false;
hudTargetProtected = false;
carried = isDefined( entity.carriedBy );
leaving = ( isDefined( entity.isLeaving ) && entity.isLeaving == true );
}
// no headicon yet
if ( !isDefined( remoteUAV.markedPlayers[id] ) && !spawnProtected && !hudTargetProtected && !carried && !leaving )
{
remoteUAV.markedPlayers[id] = [];
remoteUAV.markedPlayers[id]["player"] = entity;
remoteUAV.markedPlayers[id]["icon"] = entity maps\mp\_entityheadIcons::setHeadIcon( self, unmarkedShader, offset, 10, 10, false, 0.05, false, false, false, false );
remoteUAV.markedPlayers[id]["icon"].shader = unmarkedShader;
if ( !isDefined( entity.sentryType ) || !isDefined( entity.turretType ) )
remoteUAV.markedPlayers[id]["icon"] SetTargetEnt( entity );
}
// lock on? (don't allow aim assist for spawn campers)
if ( ( !isDefined( lockedTarget ) || lockedTarget != entity ) &&
( isDefined( remoteUAV.trace["entity"] ) && remoteUAV.trace["entity"] == entity && !carried && !leaving ) ||
( distance( entity.origin, targetPos ) < UAV_REMOTE_AIM_ASSIST_RANGE * remoteUAV.trace[ "fraction" ] && !spawnProtected && !carried && !leaving ) ||
( !leaving && remoteUAV_canTargetUAV( remoteUAV, entity ) ) )
{
// final check, make sure there is line of sight
trace = bulletTrace( remoteUAV.origin, entity.origin + (0,0,32), true, remoteUAV );
if ( ( isDefined( trace["entity"] ) && trace["entity"] == entity ) || trace["fraction"] == 1 )
{
self playLocalSound( "recondrone_lockon" );
lockedTarget = entity;
}
}
}
}
return lockedTarget;
}
remoteUAV_canTargetUAV( remoteUAV, uav )
{
// lenient targeting for other uavs, just point in the correct direction and ignore range to keep players flying low
if ( isDefined( uav.uavType ) )
{
forward = anglesToForward( self getPlayerAngles() );
toUAV = vectorNormalize( uav.origin - remoteUAV getTagOrigin( "tag_turret" ) );
dot = vectorDot( forward, toUAV );
if ( dot > 0.985 )
return true;
}
return false;
}
remoteUAV_Fire( remoteUAV )
{
self endon ( "disconnect" );
remoteUAV endon ( "death" );
level endon ( "game_ended" );
remoteUAV endon ( "end_remote" );
// transition into remote
wait( 1 );
self notifyOnPlayerCommand( "remoteUAV_tag", "+attack" );
self notifyOnPlayerCommand( "remoteUAV_tag", "+attack_akimbo_accessible" ); // support accessibility control scheme
while ( true )
{
self waittill( "remoteUAV_tag" );
if ( isDefined( self.lockedTarget ) )
{
self playLocalSound( "recondrone_tag" );
// hit FX
self maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "" );
// mark target
self thread remoteUAV_markPlayer( self.lockedTarget );
// feedback
self thread remoteUAV_Rumble( remoteUAV, 3 );
wait( 0.25 );
}
else
{
wait( 0.05 );
}
}
}
remoteUAV_Rumble( remoteUAV, amount )
{
self endon ( "disconnect" );
remoteUAV endon ( "death" );
level endon ( "game_ended" );
remoteUAV endon ( "end_remote" );
remoteUAV notify( "end_rumble" );
remoteUAV endon ( "end_rumble" );
for( i=0; i<amount; i++ )
{
self playRumbleOnEntity( "damage_heavy" );
wait( 0.05 );
}
}
remoteUAV_markPlayer( targetPlayer )
{
level endon( "game_ended" );
// set the target player as marked by RC driver
targetPlayer.UAVRemoteMarkedBy = self;
// hit and notify target player
if ( isPlayer( targetPlayer ) && !targetPlayer isUsingRemote() )
{
targetPlayer playLocalSound( "player_hit_while_ads_hurt" );
targetPlayer thread maps\mp\_flashgrenades::applyFlash(2.0, 1.0);
targetPlayer thread maps\mp\gametypes\_rank::xpEventPopup( "marked_by_remote_uav" );
}
// hack for uav, removed entity on death has no .birthtime
else if ( isDefined( targetPlayer.uavType ) )
{
targetPlayer.birth_time = targetPlayer.birthtime;
}
// turret, notify owner
else if ( isDefined( targetPlayer.owner ) && isAlive( targetPlayer.owner ) )
{
targetPlayer.owner thread maps\mp\gametypes\_rank::xpEventPopup( "turret_marked_by_remote_uav" );
}
// notify operator
self remoteUAV_dialog( "tag" );
self thread maps\mp\gametypes\_rank::xpEventPopup( "remote_uav_marked" );
if ( level.gameType != "dm" )
{
if ( isPlayer( targetPlayer ) )
{
maps\mp\gametypes\_gamescore::givePlayerScore( "kill", self, undefined, true );
self thread maps\mp\gametypes\_rank::giveRankXP( "kill" );
}
}
// put em on the minimap
if ( isPlayer( targetPlayer ) )
targetPlayer setPerk( "specialty_radarblip", true, false );
else
{
if ( isDefined( targetPlayer.uavType ) )
shaderName = "compassping_enemy_uav";
else
shaderName = "compassping_sentry_enemy";
if ( level.teamBased )
{
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( curObjID, "invisible", (0,0,0) );
objective_OnEntity( curObjID, targetPlayer );
objective_state( curObjID, "active" );
objective_team( curObjID, self.team );
objective_icon( curObjID, shaderName );
targetPlayer.remoteUAVMarkedObjID01 = curObjID;
}
else
{
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( curObjID, "invisible", (0,0,0) );
objective_OnEntity( curObjID, targetPlayer );
objective_state( curObjID, "active" );
objective_team( curObjID, level.otherTeam[self.team] );
objective_icon( curObjID, shaderName );
targetPlayer.remoteUAVMarkedObjID02 = curObjID;
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( curObjID, "invisible", (0,0,0) );
objective_OnEntity( curObjID, targetPlayer );
objective_state( curObjID, "active" );
objective_team( curObjID, self.team );
objective_icon( curObjID, shaderName );
targetPlayer.remoteUAVMarkedObjID03 = curObjID;
}
}
// track their existence to remove from marked players list and minimap
targetPlayer thread remoteUAV_unmarkRemovedPlayer( self.remoteUAV );
}
remoteUAV_processTaggedAssist( victim )
{
self remoteUAV_dialog( "assist" );
self thread maps\mp\gametypes\_rank::xpEventPopup( "remote_uav_assist" );
if ( level.gameType != "dm" )
{
self.taggedAssist = true;
if ( isDefined( victim ) )
self thread maps\mp\gametypes\_gamescore::processAssist( victim );
else
{
maps\mp\gametypes\_gamescore::givePlayerScore( "assist", self, undefined, true );
self thread maps\mp\gametypes\_rank::giveRankXP( "assist" );
}
}
}
remoteUAV_unmarkRemovedPlayer( remoteUAV )
{
level endon( "game_ended" );
msg = self waittill_any_return( "death", "disconnect", "carried", "leaving" );
// hack for uavs
if ( msg == "leaving" || !isDefined( self.uavType ) )
self.UAVRemoteMarkedBy = undefined;
if ( isDefined( remoteUAV ) )
{
if ( isPlayer( self ) )
id = self.guid;
else if ( isDefined( self.birthtime ) )
id = self.birthtime;
else
id = self.birth_time; // hack for uav, removed entity on death has no .birthtime
if ( msg == "carried" || msg == "leaving" )
{
remoteUAV.markedPlayers[id]["icon"] destroy();
remoteUAV.markedPlayers[id]["icon"] = undefined;
}
if ( isDefined( id ) && isDefined( remoteUAV.markedPlayers[id] ) )
{
remoteUAV.markedPlayers[id] = undefined;
remoteUAV.markedPlayers = array_removeUndefined( remoteUAV.markedPlayers );
}
}
if ( isPlayer( self ) )
self unsetPerk( "specialty_radarblip", true );
else
{
if( isDefined( self.remoteUAVMarkedObjID01 ) )
_objective_delete( self.remoteUAVMarkedObjID01 );
if( isDefined( self.remoteUAVMarkedObjID02 ) )
_objective_delete( self.remoteUAVMarkedObjID02 );
if( isDefined( self.remoteUAVMarkedObjID03 ) )
_objective_delete( self.remoteUAVMarkedObjID03 );
}
}
remoteUAV_clearMarkedForOwner()
{
foreach( markedPlayer in self.markedPlayers )
{
if ( isDefined( markedPlayer["icon"] ) )
{
markedPlayer["icon"] destroy();
markedPlayer["icon"] = undefined;
}
}
self.markedPlayers = undefined;
}
remoteUAV_operationRumble( remoteUAV )
{
self endon ( "disconnect" );
remoteUAV endon ( "death" );
level endon ( "game_ended" );
remoteUAV endon ( "end_remote" );
while( true )
{
// JDS TODO: make a light, subtle buzzing
self PlayRumbleOnEntity( "damage_light" );
wait( 0.5 );
}
}
remoteUAV_watch_distance()
{
self endon ("death" );
// script distance and airstrike height until in range triggers are created for levels
self.rangeTrigger = GetEnt( "remote_uav_range", "targetname" );
if ( !isDefined( self.rangeTrigger ) )
{
heightEnt = GetEnt( "airstrikeheight", "targetname" );
self.maxHeight = heightEnt.origin[2];
self.maxDistance = 12800;
}
// ent to put headicon on for pointing to inside of map when they go out of range
self.centerRef = Spawn( "script_model", level.mapCenter );
// shouldn't be possible to start out of range, but just in case
inRangePos = self.origin;
self.rangeCountdownActive = false;
// loop
while ( true )
{
if ( !self remoteUAV_in_range() )
{
// increase static with distance from exit point or distance to heli in proximity
staticAlpha = 0;
while ( !self remoteUAV_in_range() )
{
self.owner remoteUAV_dialog( "out_of_range" );
if ( !self.rangeCountdownActive )
{
self.rangeCountdownActive = true;
self thread remoteUAV_rangeCountdown();
}
if ( isDefined( self.heliInProximity ) )
{
dist = distance( self.origin, self.heliInProximity.origin );
staticAlpha = 1 - ( (dist-UAV_REMOTE_MIN_HELI_PROXIMITY) / (UAV_REMOTE_MAX_HELI_PROXIMITY-UAV_REMOTE_MIN_HELI_PROXIMITY) );
}
else
{
dist = distance( self.origin, inRangePos );
staticAlpha = min( 1, dist/UAV_REMOTE_MAX_PAST_RANGE );
}
self.owner setPlayerData( "reconDroneState", "staticAlpha", staticAlpha );
wait ( 0.05 );
}
// end countdown
self notify( "in_range" );
self.rangeCountdownActive = false;
// fade out static
self thread remoteUAV_staticFade( staticAlpha );
}
inRangePos = self.origin;
wait ( 0.05 );
}
}
remoteUAV_in_range()
{
if ( isDefined( self.rangeTrigger ) )
{
if ( !self isTouching( self.rangeTrigger ) && !self.inHeliProximity )
return true;
}
else
{
if ( distance2D( self.origin, level.mapCenter ) < self.maxDistance && self.origin[2] < self.maxHeight && !self.inHeliProximity )
return true;
}
return false;
}
remoteUAV_staticFade( staticAlpha )
{
self endon ( "death" );
while( self remoteUAV_in_range() )
{
staticAlpha -= 0.05;
if ( staticAlpha < 0 )
{
self.owner setPlayerData( "reconDroneState", "staticAlpha", 0 );
break;
}
self.owner setPlayerData( "reconDroneState", "staticAlpha", staticAlpha );
wait( 0.05 );
}
}
remoteUAV_rangeCountdown()
{
self endon( "death" );
self endon( "in_range" );
if ( isDefined( self.heliInProximity ) )
countdown = UAV_REMOTE_HELI_RANGE_COUNTDOWN;
else
countdown = UAV_REMOTE_PAST_RANGE_COUNTDOWN;
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( countdown );
self notify( "death" );
}
remoteUAV_explode_on_disconnect()
{
self endon ( "death" );
self.owner waittill( "disconnect" );
self notify( "death" );
}
remoteUAV_explode_on_changeTeams()
{
self endon ( "death" );
self.owner waittill_any( "joined_team", "joined_spectators" );
self notify( "death" );
}
remoteUAV_clear_marked_on_gameEnded()
{
self endon ( "death" );
level waittill( "game_ended" );
self remoteUAV_clearMarkedForOwner();
}
remoteUAV_leave_on_timeout()
{
self endon ( "death" );
flyTime = 60.0;
/#
flyTime = GetDvarInt( "scr_remoteUAVFlyTime", flyTime );
#/
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( flyTime );
self thread remoteUAV_leave();
}
remoteUAV_leave()
{
level endon( "game_ended" );
self endon( "death" );
// disengage player
self notify( "leaving" );
self.owner remoteUAV_endride( self );
// remove
self notify( "death" );
}
remoteUAV_explode_on_death()
{
level endon( "game_ended" );
self waittill( "death" );
self playSound( "recondrone_destroyed" );
playFX( level.RemoteUAV_fx["explode"], self.origin );
remoteUAV_cleanup();
}
remoteUAV_cleanup()
{
if ( self.playerLinked == true && isDefined( self.owner ) )
self.owner remoteUAV_endride( self );
if ( isDefined( self.scrambler ) )
self.scrambler delete();
if ( isDefined( self.centerRef ) )
self.centerRef delete();
self remoteUAV_clearMarkedForOwner();
stopFXOnTag( level.RemoteUAV_fx["smoke"], self, "tag_origin" );
level.remote_uav[self.team] = undefined;
// decrement the faux vehicle count right before it is deleted this way we know for sure it is gone
decrementFauxVehicleCount();
self delete();
}
remoteUAV_light_fx()
{
playFXOnTag( level.chopper_fx["light"]["belly"], self, "tag_light_nose" );
wait ( 0.05 );
playFXOnTag( level.chopper_fx["light"]["tail"], self, "tag_light_tail1" );
}
remoteUAV_dialog( dialogGroup )
{
if ( dialogGroup == "tag" )
waitTime = 1000;
else
waitTime = 5000;
if ( getTime() - level.RemoteUAV_lastDialogTime < waitTime )
return;
level.RemoteUAV_lastDialogTime = getTime();
randomIndex = randomInt( level.remoteUAV_dialog[ dialogGroup ].size );
soundAlias = level.remoteUAV_dialog[ dialogGroup ][ randomIndex ];
fullSoundAlias = maps\mp\gametypes\_teams::getTeamVoicePrefix( self.team ) + soundAlias;
self playLocalSound( fullSoundAlias );
}
remoteUAV_handleIncomingStinger()
{
level endon ( "game_ended" );
self endon ( "death" );
self endon ( "end_remote" );
while ( true )
{
level waittill ( "stinger_fired", player, missile, lockTarget );
if ( !isDefined( missile ) || !IsDefined( lockTarget ) || (lockTarget != self) )
continue;
// notify owner
self.owner PlayLocalSound( "javelin_clu_lock" );
self.owner setPlayerData( "reconDroneState", "incomingMissile", true );
self.hasIncoming = true;
self.incomingMissiles[self.incomingMissiles.size] = missile;
// track missile
missile.owner = player;
missile thread watchStingerProximity( lockTarget );
}
}
remoteUAV_handleIncomingSAM()
{
level endon ( "game_ended" );
self endon ( "death" );
self endon ( "end_remote" );
while ( true )
{
level waittill ( "sam_fired", player, missileGroup, lockTarget );
if ( !IsDefined( lockTarget ) || ( lockTarget != self ) )
continue;
numIncomming = 0;
foreach ( missile in missileGroup )
{
if ( isDefined( missile ) )
{
self.incomingMissiles[self.incomingMissiles.size] = missile;
missile.owner = player;
numIncomming++;
}
}
if ( numIncomming )
{
// notify owner
self.owner PlayLocalSound( "javelin_clu_lock" );
self.owner setPlayerData( "reconDroneState", "incomingMissile", true );
self.hasIncoming = true;
// track missile
level thread watchSAMProximity( lockTarget, missileGroup );
}
}
}
watchStingerProximity( missileTarget )
{
level endon( "game_ended" );
self endon ( "death" );
self Missile_SetTargetEnt( missileTarget );
lastVecToTarget = vectorNormalize( missileTarget.origin - self.origin );
while( isDefined( missileTarget ) )
{
center = missileTarget GetPointInBounds( 0, 0, 0 );
curDist = distance( self.origin, center );
// flares?
if ( missileTarget.numFlares > 0 && curDist < 4000 )
{
newTarget = missileTarget deployFlares();
self Missile_SetTargetEnt( newTarget );
return;
}
// still on target?
else
{
curVecToTarget = vectorNormalize( missileTarget.origin - self.origin );
if ( vectorDot( curVecToTarget, lastVecToTarget ) < 0 )
{
self playSound( "exp_stinger_armor_destroy" );
playFX( level.RemoteUAV_fx["missile_explode"], self.origin );
if ( isDefined( self.owner ) )
RadiusDamage( self.origin, 400, 1000, 1000, self.owner, "MOD_EXPLOSIVE", "stinger_mp" );
else
RadiusDamage( self.origin, 400, 1000, 1000, undefined, "MOD_EXPLOSIVE", "stinger_mp" );
self hide();
wait ( 0.05 );
self delete();
}
else
lastVecToTarget = curVecToTarget;
}
wait ( 0.05 );
}
}
watchSAMProximity( missileTarget, missileGroup )
{
level endon ( "game_ended" );
missileTarget endon( "death" );
foreach ( missile in missileGroup )
{
if ( isDefined( missile ) )
{
missile Missile_SetTargetEnt( missileTarget );
missile.lastVecToTarget = vectorNormalize( missileTarget.origin - missile.origin );
}
}
while( missileGroup.size && isDefined( missileTarget ) )
{
center = missileTarget GetPointInBounds( 0, 0, 0 );
foreach ( missile in missileGroup )
{
if ( isDefined( missile ) )
{
if ( isDefined( self.markForDetete ) )
{
self delete();
continue;
}
// flares?
if ( missileTarget.numFlares > 0 )
{
distToTarget = distance( missile.origin, center );
if ( distToTarget < 4000 )
{
newTarget = missileTarget deployFlares();
foreach ( missileToRedirect in missileGroup )
if ( IsDefined( missileToRedirect ) )
missileToRedirect Missile_SetTargetEnt( newTarget );
return;
}
}
// still on target?
else
{
curVecToTarget = vectorNormalize( missileTarget.origin - missile.origin );
if ( vectorDot( curVecToTarget, missile.lastVecToTarget ) < 0 )
{
missile playSound( "exp_stinger_armor_destroy" );
playFX( level.RemoteUAV_fx["missile_explode"], missile.origin );
if ( isDefined( missile.owner ) )
RadiusDamage( missile.origin, 400, 1000, 1000, missile.owner, "MOD_EXPLOSIVE", "stinger_mp" );
else
RadiusDamage( missile.origin, 400, 1000, 1000, undefined, "MOD_EXPLOSIVE", "stinger_mp" );
missile hide();
missile.markForDetete = true;
}
else
missile.lastVecToTarget = curVecToTarget;
}
}
}
missileGroup = array_removeUndefined( missileGroup );
wait ( 0.05 );
}
}
deployFlares()
{
// decrement
self.numFlares--;
// player feedback
self.owner thread remoteUAV_Rumble( self, 6 );
self playSound( "WEAP_SHOTGUNATTACH_FIRE_NPC" );
// fx
self thread playFlareFx();
// flare
spawnPos = self.origin + (0,0,-100);
flareObject = spawn( "script_origin", spawnPos );
flareObject.angles = self.angles;
flareObject moveGravity( (0,0,-1), 5.0 );
flareObject thread deleteAfterTime( 5.0 );
return flareObject;
}
playFlareFx()
{
for ( i = 0; i < 5; i++ )
{
if ( !isDefined( self ) )
return;
PlayFXOnTag( level._effect[ "vehicle_flares" ], self, "TAG_FLARE" );
wait ( 0.15 );
}
}
deleteAfterTime( delay )
{
wait ( delay );
self delete();
}
remoteUAV_clearIncomingWarning()
{
level endon ( "game_ended" );
self endon ( "death" );
self endon ( "end_remote" );
while( true )
{
numIncoming = 0;
for ( i=0; i<self.incomingMissiles.size; i++ )
{
if ( isDefined( self.incomingMissiles[i] ) && missile_isIncoming( self.incomingMissiles[i], self ) )
numIncoming++;
}
if ( self.hasIncoming && !numIncoming )
{
self.hasIncoming = false;
self.owner setPlayerData( "reconDroneState", "incomingMissile", false );
}
self.incomingMissiles = array_removeUndefined( self.incomingMissiles );
wait( 0.05 );
}
}
missile_isIncoming( missile, remoteUAV )
{
vecToRemote = vectorNormalize( remoteUAV.origin - missile.origin );
vecToFacing = anglesToForward( missile.angles );
return ( vectorDot( vecToRemote, vecToFacing ) > 0 );
}
remoteUAV_watchHeliProximity()
{
level endon( "game_ended" );
self endon( "death" );
self endon( "end_remote" );
while( true )
{
inHeliProximity = false;
foreach( heli in level.helis )
{
if ( distance( heli.origin, self.origin ) < UAV_REMOTE_MAX_HELI_PROXIMITY )
{
inHeliProximity = true;
self.heliInProximity = heli;
}
}
foreach( littlebird in level.littleBirds )
{
if ( littlebird != self && ( !isDefined(littlebird.heliType) || littlebird.heliType != "remote_uav" ) && distance( littlebird.origin, self.origin ) < UAV_REMOTE_MAX_HELI_PROXIMITY )
{
inHeliProximity = true;
self.heliInProximity = littlebird;
}
}
if ( !self.inHeliProximity && inHeliProximity )
self.inHeliProximity = true;
else if ( self.inHeliProximity && !inHeliProximity )
{
self.inHeliProximity = false;
self.heliInProximity = undefined;
}
wait( 0.05 );
}
}
remoteUAV_handleDamage()
{
self endon( "end_remote" );
self maps\mp\gametypes\_damage::monitorDamage(
self.maxHealth,
"remote_uav",
::handleDeathDamage,
::modifyDamage,
true // isKillstreak
);
}
modifyDamage( attacker, weapon, type, damage )
{
modifiedDamage = damage;
// modifiedDamage = self maps\mp\gametypes\_damage::handleMeleeDamage( weapon, type, modifiedDamage );
modifiedDamage = self maps\mp\gametypes\_damage::handleEmpDamage( weapon, type, modifiedDamage );
modifiedDamage = self maps\mp\gametypes\_damage::handleMissileDamage( weapon, type, modifiedDamage );
modifiedDamage = self maps\mp\gametypes\_damage::handleAPDamage( weapon, type, modifiedDamage, attacker );
// this is super hacky. Should be in an "onDamaged" function
PlayFXOnTagForClients( level.RemoteUAV_fx["hit"], self, "tag_origin", self.owner );
self PlaySound( "recondrone_damaged" );
if( self.smoking == false && self.damageTaken >= self.maxhealth/2 )
{
self.smoking = true;
PlayFxOnTag( level.RemoteUAV_fx["smoke"], self, "tag_origin" );
}
return modifiedDamage;
}
handleDeathDamage( attacker, weapon, type, damage ) // self == trophy
{
// !!! need VO
self maps\mp\gametypes\_damage::onKillstreakKilled( attacker, weapon, type, damage, "destroyed_remote_uav", undefined, "callout_destroyed_remote_uav" );
}