From fc474f9f1680a70246ec3fd462aeb30ecfce709b Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sun, 20 Sep 2020 23:41:47 -0600 Subject: [PATCH] nuke --- main/server.cfg | 12 + userraw/maps/mp/killstreaks/_emp.gsc | 562 ++++++++++++++++++++++++++ userraw/maps/mp/killstreaks/_nuke.gsc | 457 +++++++++++++++++++++ 3 files changed, 1031 insertions(+) create mode 100644 userraw/maps/mp/killstreaks/_emp.gsc create mode 100644 userraw/maps/mp/killstreaks/_nuke.gsc diff --git a/main/server.cfg b/main/server.cfg index 5f96586..500c73a 100644 --- a/main/server.cfg +++ b/main/server.cfg @@ -467,6 +467,10 @@ set g_playerEjection "1" set g_playerCollision "1" set sv_enableBounces "1" +set perk_scavengerMode "0" +set scr_deleteexplosivesonspawn "1" +set scr_maxPerPlayerExplosives "2" + // CUSTOM @@ -523,3 +527,11 @@ set scr_allowDropWeaponOnDeath "1" set scr_allowClaymoreBounces "1" set scr_extraTeamIcons "1" set scr_deleteNadeOnTeamChange "1" + + +// _nuke +set scr_nukeEndsGame "0" +set scr_nukeKillsAll "0" + +// _emp +set scr_empEffectsAll "0" diff --git a/userraw/maps/mp/killstreaks/_emp.gsc b/userraw/maps/mp/killstreaks/_emp.gsc new file mode 100644 index 0000000..652a133 --- /dev/null +++ b/userraw/maps/mp/killstreaks/_emp.gsc @@ -0,0 +1,562 @@ +#include maps\mp\_utility; +#include common_scripts\utility; + + +init() +{ + level._effect[ "emp_flash" ] = loadfx( "explosions/emp_flash_mp" ); + + level.teamEMPed["allies"] = false; + level.teamEMPed["axis"] = false; + level.empPlayer = undefined; + + if ( level.teamBased ) + level thread EMP_TeamTracker(); + else + level thread EMP_PlayerTracker(); + + level.killstreakFuncs["emp"] = ::EMP_Use; + + setDvarIfUninitialized( "scr_empEffectsAll", true ); + level.empEffectsAll = getDvarInt( "scr_empEffectsAll" ); + + level thread onPlayerConnect(); +} + + + +onPlayerConnect() +{ + for(;;) + { + level waittill("connected", player); + player thread onPlayerSpawned(); + } +} + + +onPlayerSpawned() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "spawned_player" ); + + if ( (level.teamBased && level.teamEMPed[self.team]) || (!level.teamBased && isDefined( level.empPlayer ) && level.empPlayer != self) ) + self setEMPJammed( true ); + } +} + + +EMP_Use( lifeId, delay ) +{ + assert( isDefined( self ) ); + + if ( !isDefined( delay ) ) + delay = 5.0; + + myTeam = self.pers["team"]; + otherTeam = level.otherTeam[myTeam]; + + if ( level.teamBased ) + self thread EMP_JamTeam( otherTeam, 60.0, delay ); + else + self thread EMP_JamPlayers( self, 60.0, delay ); + + self maps\mp\_matchdata::logKillstreakEvent( "emp", self.origin ); + self notify( "used_emp" ); + + return true; +} + + +EMP_JamTeam( teamName, duration, delay ) +{ + level endon ( "game_ended" ); + + assert( teamName == "allies" || teamName == "axis" ); + + //wait ( delay ); + + thread teamPlayerCardSplash( "used_emp", self ); + + level notify ( "EMP_JamTeam" + teamName ); + level endon ( "EMP_JamTeam" + teamName ); + + foreach ( player in level.players ) + { + player playLocalSound( "emp_activate" ); + + if ( player.team != teamName ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOff(); + } + + visionSetNaked( "coup_sunblind", 0.1 ); + thread empEffects(); + + wait ( 0.1 ); + + // resetting the vision set to the same thing won't normally have an effect. + // however, if the client receives the previous visionset change in the same packet as this one, + // this will force them to lerp from the bright one to the normal one. + visionSetNaked( "coup_sunblind", 0 ); + visionSetNaked( getDvar( "mapname" ), 3.0 ); + + level.teamEMPed[teamName] = true; + level notify ( "emp_update" ); + + if(!level.empEffectsAll) + level destroyActiveVehiclesTeam( teamName , self ); + else + level destroyActiveVehicles( self ); + + maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration ); + + level.teamEMPed[teamName] = false; + + foreach ( player in level.players ) + { + if ( player.team != teamName ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOn(); + } + + level notify ( "emp_update" ); +} + +EMP_JamPlayers( owner, duration, delay ) +{ + level notify ( "EMP_JamPlayers" ); + level endon ( "EMP_JamPlayers" ); + + assert( isDefined( owner ) ); + + //wait ( delay ); + + foreach ( player in level.players ) + { + player playLocalSound( "emp_activate" ); + + if ( player == owner ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOff(); + } + + visionSetNaked( "coup_sunblind", 0.1 ); + thread empEffects(); + + wait ( 0.1 ); + + // resetting the vision set to the same thing won't normally have an effect. + // however, if the client receives the previous visionset change in the same packet as this one, + // this will force them to lerp from the bright one to the normal one. + visionSetNaked( "coup_sunblind", 0 ); + visionSetNaked( getDvar( "mapname" ), 3.0 ); + + level notify ( "emp_update" ); + + level.empPlayer = owner; + level.empPlayer thread empPlayerFFADisconnect(); + + if(!level.empEffectsAll) + level destroyActiveVehiclesNotSelf( owner ); + else + level destroyActiveVehicles( owner ); + + level notify ( "emp_update" ); + + maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration ); + + foreach ( player in level.players ) + { + if ( player == owner ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOn(); + } + + level.empPlayer = undefined; + level notify ( "emp_update" ); + level notify ( "emp_ended" ); +} + +empPlayerFFADisconnect() +{ + level endon ( "EMP_JamPlayers" ); + level endon ( "emp_ended" ); + + self waittill( "disconnect" ); + level notify ( "emp_update" ); +} + +empEffects() +{ + foreach( player in level.players ) + { + playerForward = anglestoforward( player.angles ); + playerForward = ( playerForward[0], playerForward[1], 0 ); + playerForward = VectorNormalize( playerForward ); + + empDistance = 20000; + + empEnt = Spawn( "script_model", player.origin + ( 0, 0, 8000 ) + Vector_Multiply( playerForward, empDistance ) ); + empEnt setModel( "tag_origin" ); + empEnt.angles = empEnt.angles + ( 270, 0, 0 ); + empEnt thread empEffect( player ); + } +} + +empEffect( player ) +{ + player endon( "disconnect" ); + + wait( 0.5 ); + PlayFXOnTagForClients( level._effect[ "emp_flash" ], self, "tag_origin", player ); +} + +EMP_TeamTracker() +{ + level endon ( "game_ended" ); + + for ( ;; ) + { + level waittill_either ( "joined_team", "emp_update" ); + + foreach ( player in level.players ) + { + if ( player.team == "spectator" ) + continue; + + player setEMPJammed( level.teamEMPed[player.team] ); + } + } +} + + +EMP_PlayerTracker() +{ + level endon ( "game_ended" ); + + for ( ;; ) + { + level waittill_either ( "joined_team", "emp_update" ); + + foreach ( player in level.players ) + { + if ( player.team == "spectator" ) + continue; + + if ( isDefined( level.empPlayer ) && level.empPlayer != player ) + player setEMPJammed( true ); + else + player setEMPJammed( false ); + } + } +} + +doSilentEMPTeam( teamName, duration, delay, owner ) +{ + level endon ( "game_ended" ); + + assert( teamName == "allies" || teamName == "axis" ); + + //wait ( delay ); + + level notify ( "EMP_JamTeam" + teamName ); + level endon ( "EMP_JamTeam" + teamName ); + + foreach ( player in level.players ) + { + if ( player.team != teamName ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOff(); + } + + level.teamEMPed[teamName] = true; + level notify ( "emp_update" ); + + if(!level.empEffectsAll) + level destroyActiveVehiclesTeam( teamName , owner ); + else + level destroyActiveVehicles( owner ); + + maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration ); + + level.teamEMPed[teamName] = false; + + foreach ( player in level.players ) + { + if ( player.team != teamName ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOn(); + } + + level notify ( "emp_update" ); +} + +doSilentEMPPlayer( owner, duration, delay ) +{ + level notify ( "EMP_JamPlayers" ); + level endon ( "EMP_JamPlayers" ); + + assert( isDefined( owner ) ); + + //wait ( delay ); + + foreach ( player in level.players ) + { + if ( player == owner ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOff(); + } + + level notify ( "emp_update" ); + + level.empPlayer = owner; + level.empPlayer thread empPlayerFFADisconnect(); + + if(!level.empEffectsAll) + level destroyActiveVehiclesNotSelf( owner ); + else + level destroyActiveVehicles( owner ); + + level notify ( "emp_update" ); + + maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration ); + + foreach ( player in level.players ) + { + if ( player == owner ) + continue; + + if ( player _hasPerk( "specialty_localjammer" ) ) + player RadarJamOn(); + } + + level.empPlayer = undefined; + level notify ( "emp_update" ); + level notify ( "emp_ended" ); +} + +destroyActiveVehicles( attacker ) +{ + if ( isDefined( attacker ) ) + { + foreach ( heli in level.helis ) + radiusDamage( heli.origin, 384, 5000, 5000, attacker ); + + foreach ( littleBird in level.littleBird ) + radiusDamage( littleBird.origin, 384, 5000, 5000, attacker ); + + foreach ( turret in level.turrets ) + radiusDamage( turret.origin, 16, 5000, 5000, attacker ); + + foreach ( rocket in level.rockets ) + rocket notify ( "death" ); + + if ( level.teamBased ) + { + foreach ( uav in level.uavModels["allies"] ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + + foreach ( uav in level.uavModels["axis"] ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + } + else + { + foreach ( uav in level.uavModels ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + } + + if ( isDefined( level.ac130player ) ) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000, attacker ); + } + else + { + foreach ( heli in level.helis ) + radiusDamage( heli.origin, 384, 5000, 5000 ); + + foreach ( littleBird in level.littleBird ) + radiusDamage( littleBird.origin, 384, 5000, 5000 ); + + foreach ( turret in level.turrets ) + radiusDamage( turret.origin, 16, 5000, 5000 ); + + foreach ( rocket in level.rockets ) + rocket notify ( "death" ); + + if ( level.teamBased ) + { + foreach ( uav in level.uavModels["allies"] ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + + foreach ( uav in level.uavModels["axis"] ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + } + else + { + foreach ( uav in level.uavModels ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + } + + if ( isDefined( level.ac130player ) ) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000 ); + } +} + +destroyActiveVehiclesNotSelf( attacker ) +{ + if ( isDefined( attacker ) ) + { + foreach ( heli in level.helis ) + if (!isDefined(heli.owner) || heli.owner != attacker) + radiusDamage( heli.origin, 384, 5000, 5000, attacker ); + + foreach ( littleBird in level.littleBird ) + if(!isDefined(littleBird.owner) || littleBird.owner != attacker) + radiusDamage( littleBird.origin, 384, 5000, 5000, attacker ); + + foreach ( turret in level.turrets ) + if(!isDefined(turret.owner) || turret.owner != attacker) + radiusDamage( turret.origin, 16, 5000, 5000, attacker ); + + foreach ( rocket in level.rockets ) + if(!isDefined(rocket.owner) || rocket.owner != attacker) + rocket notify ( "death" ); + + if ( level.teamBased ) + { + foreach ( uav in level.uavModels["allies"] ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + + foreach ( uav in level.uavModels["axis"] ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + } + else + { + foreach ( uav in level.uavModels ) + if(!isDefined(uav.owner) || uav.owner != attacker) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + } + + if ( isDefined( level.ac130player ) ) + if (level.ac130player != attacker) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000, attacker ); + } + else + { + foreach ( heli in level.helis ) + radiusDamage( heli.origin, 384, 5000, 5000 ); + + foreach ( littleBird in level.littleBird ) + radiusDamage( littleBird.origin, 384, 5000, 5000 ); + + foreach ( turret in level.turrets ) + radiusDamage( turret.origin, 16, 5000, 5000 ); + + foreach ( rocket in level.rockets ) + rocket notify ( "death" ); + + if ( level.teamBased ) + { + foreach ( uav in level.uavModels["allies"] ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + + foreach ( uav in level.uavModels["axis"] ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + } + else + { + foreach ( uav in level.uavModels ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + } + + if ( isDefined( level.ac130player ) ) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000 ); + } +} + +destroyActiveVehiclesTeam( Team, attacker ) +{ + if ( isDefined( attacker ) ) + { + foreach ( heli in level.helis ) + if(heli.team == Team) + radiusDamage( heli.origin, 384, 5000, 5000, attacker ); + + foreach ( littleBird in level.littleBird ) + if(littleBird.team == Team) + radiusDamage( littleBird.origin, 384, 5000, 5000, attacker ); + + foreach ( turret in level.turrets ) + if(turret.team == Team) + radiusDamage( turret.origin, 16, 5000, 5000, attacker ); + + foreach ( rocket in level.rockets ) + if(rocket.team == Team) + rocket notify ( "death" ); + + if ( Team == "allies" ) + { + foreach ( uav in level.uavModels["allies"] ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + } + else + { + foreach ( uav in level.uavModels["axis"] ) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + } + + if ( isDefined( level.ac130player ) ) + if(level.ac130player.team == Team) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000, attacker ); + } + else + { + foreach ( heli in level.helis ) + if(heli.team == Team) + radiusDamage( heli.origin, 384, 5000, 5000 ); + + foreach ( littleBird in level.littleBird ) + if(littleBird.team == Team) + radiusDamage( littleBird.origin, 384, 5000, 5000 ); + + foreach ( turret in level.turrets ) + if(turret.team == Team) + radiusDamage( turret.origin, 16, 5000, 5000 ); + + foreach ( rocket in level.rockets ) + if(rocket.team == Team) + rocket notify ( "death" ); + + if ( Team == "allies" ) + { + foreach ( uav in level.uavModels["allies"] ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + } + else + { + foreach ( uav in level.uavModels["axis"] ) + radiusDamage( uav.origin, 384, 5000, 5000 ); + } + + if ( isDefined( level.ac130player ) ) + if(level.ac130player.team == Team) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000 ); + } +} \ No newline at end of file diff --git a/userraw/maps/mp/killstreaks/_nuke.gsc b/userraw/maps/mp/killstreaks/_nuke.gsc new file mode 100644 index 0000000..4575906 --- /dev/null +++ b/userraw/maps/mp/killstreaks/_nuke.gsc @@ -0,0 +1,457 @@ +#include common_scripts\utility; +#include maps\mp\_utility; + +init() +{ + precacheItem( "nuke_mp" ); + precacheLocationSelector( "map_nuke_selector" ); + precacheString( &"MP_TACTICAL_NUKE_CALLED" ); + precacheString( &"MP_FRIENDLY_TACTICAL_NUKE" ); + precacheString( &"MP_TACTICAL_NUKE" ); + + level._effect[ "nuke_player" ] = loadfx( "explosions/player_death_nuke" ); + level._effect[ "nuke_flash" ] = loadfx( "explosions/player_death_nuke_flash" ); + level._effect[ "nuke_aftermath" ] = loadfx( "dust/nuke_aftermath_mp" ); + + game["strings"]["nuclear_strike"] = &"MP_TACTICAL_NUKE"; + + level.killstreakFuncs["nuke"] = ::tryUseNuke; + + setDvarIfUninitialized( "scr_nukeTimer", 10 ); + setDvarIfUninitialized( "scr_nukeCancelMode", 0 ); + setDvarIfUninitialized( "scr_nukeEndsGame", true ); + setDvarIfUninitialized( "scr_nukeKillsAll", true ); + + level.nukeTimer = getDvarInt( "scr_nukeTimer" ); + level.cancelMode = getDvarInt( "scr_nukeCancelMode" ); + level.nukeEndsGame = getDvarInt( "scr_nukeEndsGame" ); + level.nukeKillsAll = getDvarInt( "scr_nukeKillsAll" ); + + /# + setDevDvarIfUninitialized( "scr_nukeDistance", 5000 ); + setDevDvarIfUninitialized( "scr_nukeEndsGame", false ); + setDevDvarIfUninitialized( "scr_nukeDebugPosition", false ); + #/ + level.moabXP = []; + + level thread onPlayerConnect(); +} + +onPlayerConnect() +{ + for(;;) + { + level waittill("connected", player); + player thread onPlayerSpawned(); + } +} + +onPlayerSpawned() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "spawned_player" ); + + if(isDefined(level.moabXP[self.team]) || isDefined(level.moabXP[self.guid])) + self.xpScaler = 2; + } +} + +tryUseNuke( lifeId, allowCancel ) +{ + if( isDefined( level.nukeIncoming ) ) + { + self iPrintLnBold( &"MP_NUKE_ALREADY_INBOUND" ); + return false; + } + + if ( self isUsingRemote() && ( !isDefined( level.gtnw ) || !level.gtnw ) ) + return false; + + if ( !isDefined( allowCancel ) ) + allowCancel = true; + + self thread doNuke( allowCancel ); + self notify( "used_nuke" ); + + return true; +} + +delaythread_nuke( delay, func ) +{ + level endon ( "nuke_cancelled" ); + + wait ( delay ); + + thread [[ func ]](); +} + +doNuke( allowCancel ) +{ + level notify ( "nuke_cancelled" ); + level endon ( "nuke_cancelled" ); + + level.nukeInfo = spawnStruct(); + level.nukeInfo.player = self; + level.nukeInfo.team = self.pers["team"]; + + level.nukeIncoming = true; + + if(level.nukeEndsGame) + maps\mp\gametypes\_gamelogic::pauseTimer(); + + level.timeLimitOverride = true; + level.scoreLimitOverride = true; + setGameEndTime( int( gettime() + (level.nukeTimer * 1000) ) ); + setDvar( "ui_bomb_timer", 4 ); // Nuke sets '4' to avoid briefcase icon showing + + if ( level.teambased ) + { + thread teamPlayerCardSplash( "used_nuke", self, self.team ); + /* + players = level.players; + + foreach( player in level.players ) + { + playerteam = player.pers["team"]; + if ( isdefined( playerteam ) ) + { + if ( playerteam == self.pers["team"] ) + player iprintln( &"MP_TACTICAL_NUKE_CALLED", self ); + } + } + */ + } + else + { + if ( !level.hardcoreMode ) + self iprintlnbold(&"MP_FRIENDLY_TACTICAL_NUKE"); + } + + level thread delaythread_nuke( (level.nukeTimer - 3.3), ::nukeSoundIncoming ); + level thread delaythread_nuke( level.nukeTimer, ::nukeSoundExplosion ); + level thread delaythread_nuke( level.nukeTimer, ::nukeSlowMo ); + level thread delaythread_nuke( level.nukeTimer, ::nukeEffects ); + level thread delaythread_nuke( (level.nukeTimer + 0.25), ::nukeVision ); + level thread delaythread_nuke( (level.nukeTimer + 1.5), ::nukeDeath ); + level thread delaythread_nuke( (level.nukeTimer + 1.5), ::nukeEarthquake ); + level thread nukeAftermathEffect(); + + if ( level.cancelMode && allowCancel ) + level thread cancelNukeOnDeath( self ); + + clockObject = spawn( "script_origin", (0,0,0) ); + clockObject hide(); + level thread killClockObjectOnEndOn(clockObject); + + while ( !isDefined( level.nukeDetonated ) ) + { + clockObject playSound( "ui_mp_nukebomb_timer" ); + wait( 1.0 ); + } + + clockObject notify("death"); + clockObject delete(); +} + +killClockObjectOnEndOn(clockObject) +{ + clockObject endon("death"); + level waittill( "nuke_cancelled" ); + clockObject delete(); +} + +cancelNukeOnDeath( player ) +{ + level endon ( "nuke_cancelled" ); + player waittill_any( "death", "disconnect" ); + + if ( isDefined( player ) && level.cancelMode == 2 ) + player thread maps\mp\killstreaks\_emp::EMP_Use( 0, 0 ); + + level.nukeIncoming = undefined; + + level.nukeDetonated = undefined; + + maps\mp\gametypes\_gamelogic::resumeTimer(); + level.timeLimitOverride = false; + level.scoreLimitOverride = false; + level notify( "update_scorelimit" ); + + foreach(player in level.players) + player.nuked = undefined; + + setDvar( "ui_bomb_timer", 0 ); // Nuke sets '4' to avoid briefcase icon showing + + level notify ( "nuke_cancelled" ); +} + +nukeSoundIncoming() +{ + level endon ( "nuke_cancelled" ); + + foreach( player in level.players ) + player playlocalsound( "nuke_incoming" ); +} + +nukeSoundExplosion() +{ + level endon ( "nuke_cancelled" ); + + foreach( player in level.players ) + { + player playlocalsound( "nuke_explosion" ); + player playlocalsound( "nuke_wave" ); + } +} + +nukeEffects() +{ + level endon ( "nuke_cancelled" ); + + setDvar( "ui_bomb_timer", 0 ); + setGameEndTime( 0 ); + + level.nukeDetonated = true; + + if ( !level.nukeEndsGame ) + { + if ( level.teamBased ) + { + level thread maps\mp\killstreaks\_emp::doSilentEMPTeam(level.otherTeam[level.nukeInfo.team], 60, 5, level.nukeInfo.player); + + foreach (player in level.players) + { + if(level.nukeInfo.team == player.team) + { + player.xpScaler = 2; + } + } + level.moabXP[level.nukeInfo.team] = true; + } + else + { + level thread maps\mp\killstreaks\_emp::doSilentEMPPlayer(level.nukeInfo.player, 60, 5); + if(isDefined(level.nukeInfo.player)) + { + level.nukeInfo.player.xpScaler = 2; + level.moabXP[level.nukeInfo.player.guid] = true; + } + } + } + else + level maps\mp\killstreaks\_emp::destroyActiveVehicles( level.nukeInfo.player ); + + foreach( player in level.players ) + { + playerForward = anglestoforward( player.angles ); + playerForward = ( playerForward[0], playerForward[1], 0 ); + playerForward = VectorNormalize( playerForward ); + + nukeDistance = 5000; + /# nukeDistance = getDvarInt( "scr_nukeDistance" ); #/ + + nukeEnt = Spawn( "script_model", player.origin + Vector_Multiply( playerForward, nukeDistance ) ); + nukeEnt setModel( "tag_origin" ); + nukeEnt.angles = ( 0, (player.angles[1] + 180), 90 ); + + /# + if ( getDvarInt( "scr_nukeDebugPosition" ) ) + { + lineTop = ( nukeEnt.origin[0], nukeEnt.origin[1], (nukeEnt.origin[2] + 500) ); + thread draw_line_for_time( nukeEnt.origin, lineTop, 1, 0, 0, 10 ); + } + #/ + + nukeEnt thread nukeEffect( player ); + + level thread killClockObjectOnEndOn(nukeEnt); + level thread killNukeEntOn(nukeEnt); + } +} + +killNukeEntOn(nukeEnt) +{ + nukeEnt endon("death"); + level endon ( "nuke_cancelled" ); + level waittill("nuke_death"); + nukeEnt notify("death"); + nukeEnt delete(); +} + +nukeEffect( player ) +{ + level endon ( "nuke_cancelled" ); + + player endon( "disconnect" ); + + waitframe(); + PlayFXOnTagForClients( level._effect[ "nuke_flash" ], self, "tag_origin", player ); +} + +nukeAftermathEffect() +{ + level endon ( "nuke_cancelled" ); + + level waittill ( "spawning_intermission" ); + + afermathEnt = getEntArray( "mp_global_intermission", "classname" ); + afermathEnt = afermathEnt[0]; + up = anglestoup( afermathEnt.angles ); + right = anglestoright( afermathEnt.angles ); + + PlayFX( level._effect[ "nuke_aftermath" ], afermathEnt.origin, up, right ); +} + +nukeSlowMo() +{ + level endon ( "nuke_cancelled" ); + + //SetSlowMotion( , , ) + setSlowMotion( 1.0, 0.25, 0.5 ); + level waittill( "nuke_death" ); + setSlowMotion( 0.25, 1, 2.0 ); +} + +fixVisionOnCancel() +{ + level waittill ( "nuke_cancelled" ); + //reset nuke vision + visionSetNaked( getDvar( "mapname" ), 2.0 ); + level.nukeVisionInProgress = undefined; +} + +nukeVision() +{ + level endon ( "nuke_cancelled" ); + + level.nukeVisionInProgress = true; + visionSetNaked( "mpnuke", 3 ); + + level waittill( "nuke_death" ); + + visionSetNaked( "mpnuke_aftermath", 5 ); + + level thread fixVisionOnCancel(); + + + if( level.NukeEndsGame ) + { + wait 5; + level.nukeVisionInProgress = undefined; + } + else + { + wait 3.5; + level notify ( "nuke_cancelled" ); + } +} + +nukeDeath() +{ + level endon ( "nuke_cancelled" ); + + level notify( "nuke_death" ); + + maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone(); + + foreach( player in level.players ) + { + if(level.teamBased) + { + if ( !level.nukeKillsAll && level.nukeInfo.team == player.pers["team"] ) + continue; + } + else + { + if ( !level.nukeKillsAll && level.nukeInfo.player == player ) + continue; + } + + player.nuked = true; + + if ( isAlive( player ) ) + player thread maps\mp\gametypes\_damage::finishPlayerDamageWrapper( level.nukeInfo.player, level.nukeInfo.player, 999999, 0, "MOD_EXPLOSIVE", "nuke_mp", player.origin, player.origin, "none", 0, 0 ); + } + + if( level.NukeEndsGame ) + { + AmbientStop(1); + + level.postRoundTime = 10; + + if ( level.teamBased ) + thread maps\mp\gametypes\_gamelogic::endGame( level.nukeInfo.team, game["strings"]["nuclear_strike"], true ); + else + { + if ( isDefined( level.nukeInfo.player ) ) + thread maps\mp\gametypes\_gamelogic::endGame( level.nukeInfo.player, game["strings"]["nuclear_strike"], true ); + else + thread maps\mp\gametypes\_gamelogic::endGame( level.nukeInfo, game["strings"]["nuclear_strike"], true ); + } + } + else + { + wait 0.05; + + maps\mp\gametypes\_gamelogic::resumeTimer(); + level.timeLimitOverride = false; + level.scoreLimitOverride = false; + level notify( "update_scorelimit" ); + + //allow next nuke to be called in, reset nuke variables + level.nukeIncoming = undefined; + level.nukeDetonated = undefined; + + //allow ridable killstreaks + foreach(player in level.players) + player.nuked = undefined; + } +} + +nukeEarthquake() +{ + level endon ( "nuke_cancelled" ); + + level waittill( "nuke_death" ); + + // TODO: need to get a different position to call this on + //earthquake( 0.6, 10, nukepos, 100000 ); + + //foreach( player in level.players ) + //player PlayRumbleOnEntity( "damage_heavy" ); +} + + +waitForNukeCancel() +{ + self waittill( "cancel_location" ); + self setblurforplayer( 0, 0.3 ); +} + +endSelectionOn( waitfor ) +{ + self endon( "stop_location_selection" ); + self waittill( waitfor ); + self thread stopNukeLocationSelection( (waitfor == "disconnect") ); +} + +endSelectionOnGameEnd() +{ + self endon( "stop_location_selection" ); + level waittill( "game_ended" ); + self thread stopNukeLocationSelection( false ); +} + +stopNukeLocationSelection( disconnected ) +{ + if ( !disconnected ) + { + self setblurforplayer( 0, 0.3 ); + self endLocationSelection(); + self.selectingLocation = undefined; + } + self notify( "stop_location_selection" ); +}