#using scripts\codescripts\struct; #using scripts\shared\callbacks_shared; #using scripts\shared\challenges_shared; #using scripts\shared\clientfield_shared; #using scripts\shared\damagefeedback_shared; #using scripts\shared\killstreaks_shared; #using scripts\shared\math_shared; #using scripts\shared\scoreevents_shared; #using scripts\shared\system_shared; #using scripts\shared\tweakables_shared; #using scripts\shared\util_shared; #using scripts\shared\weapons\_heatseekingmissile; #using scripts\shared\weapons\_weaponobjects; #using scripts\mp\gametypes\_globallogic_audio; #using scripts\mp\killstreaks\_airsupport; #using scripts\mp\killstreaks\_killstreak_bundles; #using scripts\mp\killstreaks\_killstreak_detect; #using scripts\mp\killstreaks\_killstreak_hacking; #using scripts\mp\killstreaks\_killstreakrules; #using scripts\mp\killstreaks\_killstreaks; #using scripts\mp\teams\_teams; #using scripts\mp\_util; #precache( "eventstring", "mpl_killstreak_radar" ); #precache( "string", "KILLSTREAK_EARNED_RADAR" ); #precache( "string", "KILLSTREAK_RADAR_INBOUND" ); #precache( "string", "KILLSTREAK_RADAR_NOT_AVAILABLE" ); #precache( "string", "KILLSTREAK_DESTROYED_UAV" ); #precache( "string", "KILLSTREAK_RADAR_HACKED" ); #precache( "fx", "killstreaks/fx_uav_damage_trail" ); #precache( "fx", "killstreaks/fx_uav_lights" ); #precache( "fx", "killstreaks/fx_uav_bunner" ); #namespace uav; function init() { if ( level.teamBased ) { foreach( team in level.teams ) { level.activeUAVs[ team ] = 0; } } else { level.activeUAVs = []; } level.activePlayerUAVs = []; level.spawnedUAVs = []; if ( tweakables::getTweakableValue( "killstreak", "allowradar" ) ) { killstreaks::register( "uav", "uav", "killstreak_uav", "uav_used", &ActivateUAV ); killstreaks::register_strings( "uav", &"KILLSTREAK_EARNED_RADAR", &"KILLSTREAK_RADAR_NOT_AVAILABLE", &"KILLSTREAK_RADAR_INBOUND", undefined, &"KILLSTREAK_RADAR_HACKED" ); killstreaks::register_dialog( "uav", "mpl_killstreak_radar", "uavDialogBundle", "uavPilotDialogBundle", "friendlyUav", "enemyUav", "enemyUavMultiple", "friendlyUavHacked", "enemyUavHacked", "requestUav", "threatUav" ); } level thread UAVTracker(); callback::on_connect( &OnPlayerConnect ); callback::on_spawned( &OnPlayerSpawned ); callback::on_joined_team( &OnPlayerJoinedTeam ); setMatchFlag( "radar_allies", 0 ); setMatchFlag( "radar_axis", 0 ); } function HackedPreFunction( hacker ) { uav = self; uav ResetActiveUAV(); } function ConfigureTeamPost( owner, isHacked ) { uav = self; uav thread teams::WaitUntilTeamChangeSingleTon( owner, "UAV_watch_team_change", &OnTeamChange, owner.entNum, "delete", "death", "leaving" ); if ( isHacked == false ) { uav teams::HideToSameTeam(); } else { uav SetVisibleToAll(); } owner AddActiveUAV(); } function ActivateUAV() { assert( isdefined( level.players ) ); if ( self killstreakrules::isKillstreakAllowed( "uav", self.team ) == false ) { return false; } killstreak_id = self killstreakrules::killstreakStart( "uav", self.team ); if ( killstreak_id == -1 ) { return false; } rotator = level.airsupport_rotator; attach_angle = -90; uav = spawn( "script_model", rotator getTagOrigin( "tag_origin" ) ); if ( !isdefined( level.spawnedUAVs ) ) level.spawnedUAVs = []; else if ( !IsArray( level.spawnedUAVs ) ) level.spawnedUAVs = array( level.spawnedUAVs ); level.spawnedUAVs[level.spawnedUAVs.size]=uav;; uav setModel( "veh_t7_drone_uav_enemy_vista" ); uav.targetname = "uav"; uav killstreaks::configure_team( "uav", killstreak_id, self, undefined, undefined, &ConfigureTeamPost ); uav killstreak_hacking::enable_hacking( "uav", &HackedPreFunction, undefined ); uav clientfield::set( "enemyvehicle", 1 ); killstreak_detect::killstreakTargetSet( uav ); uav SetDrawInfrared( true ); uav.killstreak_id = killstreak_id; uav.leaving = false; uav.health = 99999; uav.maxhealth = ( 700 ); uav.lowhealth = ( ( 700 ) * 0.5 ); uav SetCanDamage( true ); uav thread killstreaks::MonitorDamage( "uav", uav.maxhealth, &DestroyUAV, uav.lowhealth, &OnLowHealth, 0, undefined, true ); uav thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile( "crashing", undefined, true ); uav.rocketDamage = uav.maxhealth + 1; minFlyHeight = int( airsupport::getMinimumFlyHeight() ); zOffset = minFlyHeight + (isdefined(level.uav_z_offset)?level.uav_z_offset:( 2500 )); angle = randomInt( 360 ); radiusOffset = (isdefined(level.uav_rotation_radius)?level.uav_rotation_radius:( 4000 )) + randomInt( (isdefined(level.uav_rotation_random_offset)?level.uav_rotation_random_offset:( 1000 )) ); xOffset = cos( angle ) * radiusOffset; yOffset = sin( angle ) * radiusOffset; angleVector = vectorNormalize( ( xOffset, yOffset, zOffset ) ); angleVector = angleVector * zOffset; uav linkTo( rotator, "tag_origin", angleVector, ( 0, angle + attach_angle, 0 ) ); self AddWeaponStat( GetWeapon( "uav" ), "used", 1 ); uav thread killstreaks::WaitForTimeout( "uav", ( 25000 ), &OnTimeout, "delete", "death", "crashing" ); uav thread killstreaks::WaitForTimecheck( ( ( 25000 ) / 2 ), &OnTimecheck, "delete", "death", "crashing" ); uav thread StartUAVFx(); self killstreaks::play_killstreak_start_dialog( "uav", self.team, killstreak_id ); uav killstreaks::play_pilot_dialog_on_owner( "arrive", "uav", killstreak_id ); uav thread killstreaks::player_killstreak_threat_tracking( "uav" ); return true; } function OnLowHealth( attacker, weapon ) { self.is_damaged = true; params = level.killstreakBundle["uav"]; if( isdefined( params.fxLowHealth ) ) PlayFXOnTag( params.fxLowHealth, self, "tag_origin" ); } function OnTeamChange( entNum, event ) { DestroyUAV( undefined, undefined ); } function DestroyUAV( attacker, weapon ) { attacker = self [[ level.figure_out_attacker ]]( attacker ); if( isdefined( attacker ) && ( !isdefined( self.owner ) || self.owner util::IsEnemyPlayer( attacker ) ) ) { challenges::destroyedAircraft( attacker, weapon, false ); scoreevents::processScoreEvent( "destroyed_uav", attacker, self.owner, weapon ); LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_UAV", attacker.entnum ); attacker challenges::addFlySwatterStat( weapon, self ); } if( !self.leaving ) { self RemoveActiveUAV(); self killstreaks::play_destroyed_dialog_on_owner( "uav", self.killstreak_id ); } self notify( "crashing" ); self playsound ( "evt_helicopter_midair_exp" ); params = level.killstreakBundle["uav"]; if( isdefined( params.ksExplosionFX ) ) PlayFXOnTag( params.ksExplosionFX, self, "tag_origin" ); self StopLoopSound(); self setModel( "tag_origin" ); Target_Remove( self ); self unlink(); wait( 0.5 ); ArrayRemoveValue( level.spawnedUAVs, self ); self notify( "delete" ); self delete(); } function OnPlayerConnect() { self.entNum = self getEntityNumber(); if ( !level.teambased ) { level.activeUAVs[ self.entNum ] = 0; } level.activePlayerUAVs[ self.entNum ] = 0; // needed for UAV-related kill scores } function OnPlayerSpawned() { self endon( "disconnect" ); if( level.teambased == false || level.multiteam == true ) { level notify( "uav_update" ); } } function OnPlayerJoinedTeam() { HideAllUAVsToSameTeam(); } function OnTimeout() { PlayAfterburnerFx(); if( ( isdefined( self.is_damaged ) && self.is_damaged ) ) { PlayFxOnTag( "killstreaks/fx_uav_damage_trail", self, "tag_body" ); } self killstreaks::play_pilot_dialog_on_owner( "timeout", "uav" ); self.leaving = true; self RemoveActiveUAV(); airsupport::Leave( ( 10 ) ); wait( ( 10 ) ); Target_Remove( self ); ArrayRemoveValue( level.spawnedUAVs, self ); self delete(); } function OnTimecheck() { self killstreaks::play_pilot_dialog_on_owner( "timecheck", "uav", self.killstreak_id ); } function StartUAVFx() { self endon( "death" ); wait ( 0.1 ); if( isdefined( self ) ) { PlayFXOnTag( "killstreaks/fx_uav_lights", self, "tag_origin" ); PlayFXOnTag( "killstreaks/fx_uav_bunner", self, "tag_origin" ); self PlayLoopSound ("veh_uav_engine_loop", 1); } } function PlayAfterburnerFx() { self endon( "death" ); wait ( 0.1 ); if( isdefined( self ) ) { PlayFXOnTag( "killstreaks/fx_uav_bunner", self, "tag_origin" ); self StopLoopSound(); team = util::getOtherTeam( self.team ); self playsoundtoteam ( "veh_kls_uav_afterburner" , team ); } } function HasUAV( team_or_entnum ) { return level.activeUAVs[ team_or_entnum ] > 0; } function AddActiveUAV() { if ( level.teamBased ) { assert( isdefined( self.team ) ); level.activeUAVs[self.team]++; } else { assert( isdefined( self.entNum ) ); if ( !isdefined( self.entNum ) ) { self.entNum = self GetEntityNumber(); } level.activeUAVs[ self.entNum ]++; } level.activePlayerUAVs[ self.entNum ]++; level notify ( "uav_update" ); } function RemoveActiveUAV() { uav = self; uav ResetActiveUAV(); uav killstreakrules::killstreakStop( "uav", self.originalteam, self.killstreak_id ); } function ResetActiveUAV() { if ( level.teamBased ) { level.activeUAVs[self.team]--; assert( level.activeUAVs[self.team] >= 0 ); if( level.activeUAVs[self.team] < 0 ) { level.activeUAVs[self.team] = 0; } } else if( isdefined( self.owner ) ) { assert( isdefined( self.owner.entNum ) ); if( !isdefined( self.owner.entNum ) ) { self.owner.entNum = self.owner getEntityNumber(); } level.activeUAVs[self.owner.entNum]--; assert( level.activeUAVs[self.owner.entNum] >= 0 ); if( level.activeUAVs[self.owner.entNum] < 0 ) { level.activeUAVs[self.owner.entNum] = 0; } } if ( isdefined( self.owner ) ) { level.activePlayerUAVs[self.owner.entNum]--; assert( level.activePlayerUAVs[self.owner.entNum] >= 0 ); } level notify ( "uav_update" ); } function UAVTracker() { level endon ( "game_ended" ); while( true ) { level waittill ( "uav_update" ); // intentionally keeping both teambased and non-teambased logic for now // TODO: one "might" be able to change it to teambased only; when trying to do so, watch for knock-on effects if( level.teamBased ) { foreach( team in level.teams ) { activeUAVs = level.activeUAVs[ team ]; activeUAVsAndSatellites = activeUAVs + ( ( isdefined( level.activeSatellites ) ) ? level.activeSatellites[ team ] : 0 ); SetTeamSpyplane( team, int( min( activeUAVs, 2 ) ) ); util::set_team_radar( team, ( activeUAVsAndSatellites > 0 ) ); } } else { for( i = 0; i < level.players.size; i++ ) { player = level.players[ i ]; assert( isdefined( player.entNum ) ); if( !isdefined( player.entNum ) ) { player.entNum = player getEntityNumber(); } activeUAVs = level.activeUAVs[ player.entNum ]; activeUAVsAndSatellites = activeUAVs + ( ( isdefined( level.activeSatellites ) ) ? level.activeSatellites[ player.entnum ] : 0 ); player SetClientUIVisibilityFlag( "radar_client", ( activeUAVsAndSatellites > 0 ) ); player.hasSpyplane = int( min( activeUAVs, 2 ) ); } } } } function HideAllUAVsToSameTeam() { foreach( uav in level.spawnedUAVs ) { if ( isdefined( uav ) ) { uav teams::HideToSameTeam(); } } }