This commit is contained in:
reaaLx
2024-09-04 23:46:54 +10:00
parent 5f950a3356
commit 1ea2370337
471 changed files with 108331 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,211 @@
#include maps\mp\_utility;
#include common_scripts\utility;
// Each Killstreak has its own initialization function. This Script has two main purposes.
// (1). All global data and assets used by this killstreak should be initialized here.
// (2). The callback that executes when a player activates this killstreak should be set here.
// TODO: A call to this script must be added to the script init() in the file c:\trees\nx1\game\share\raw\maps\mp\killstreaks\_killstreaks.gsc,
// this is were each individual killstreak is initialized.
init()
{
//This is a good place to precache assets, load up fx, or setup any global data that might be needed, NOTE: Everything defined in killstreakTable.csv
//will be precached automatically ( see initKillstreakData() in _killstreaks.gsc if interested ) so you do not need to worry about initializing the
//strings/weapons/materials/sounds defined there. If, for example, you were going to manually script up a plane flyiing over when this killstreak was
//activated you would want to precache that model here.
//load the fx
level._effect[ "blueshell" ] = loadfx( "nx/misc/prototype_saul" );
//This is were the killstreak activation callback is set
//TODO: Replace "killstreak_template" with the name of the new killstreak as defined in killstreakTable.csv
//Most killstreaks use a try fuction ( which i recommend, even if it is not necessary for this particualr killstreak it is nice to have a consistent model )
//the try script will make sure it is ok to fire the killstreak before the actual killstreak script is called.
level._killstreakFuncs["blueshell"] = ::try_use_killstreak;
//Use this script to update/initialize players as they connect to the game
level thread onPlayerConnect();
}
// This script is running on the global level object, it monitors players connecting to the game.
// Its main purpose is to apply the onPlayerSpawned script to each player as they connect to the game.
onPlayerConnect()
{
for(;;)
{
level waittill("connected", player);
player thread onPlayerSpawned();
}
}
// This script is running on each player in the game, it recieves a notification each time the player it is running on spawns in the game
// Its main purpose is to initialize any per player data, as well as update the player subject to any global killstreak data when that player spawns.
onPlayerSpawned()
{
self endon("disconnect");
for(;;)
{
self waittill( "spawned_player" );
println( "player spwaned" );
// init/manage any per player killstreak data here
}
}
//Many of the killstreaks have a try block that will test level conditions to make sure it is ok to fire the killstreak now. A good example of this is for the air killstreaks.
//Only a certain number of vehicles are allowed in the air at any given time, so if the airspace is full and the killstreak cannot be fired this try should return false.
//If there are any preconditions that must be met in order to fire this killstreak they should be checked in this script.
//NOTE: If this script returns true the killstreak system will consider this killstreak usage complete and the dpad icon will be removed, if this script returns false nothing will
//change and the system will just continue to wait for the the player to activate the killstreak by pressing right on the dpad.
try_use_killstreak( lifeId )
{
is_ok_to_use_killstreak = true;
if( is_ok_to_use_killstreak )
{
if( killstreak_template_use( lifeId ))
{
return true;
}
}
return false;
}
// This is the callback that executes when the killstreak is activated by a player pressing on the dpad. This is called from the script killstreakUsePressed()
// located in the file _killstreaks.gsc
killstreak_template_use( lifeId )
{
assert( isDefined( self ) );
println( "Killstreak Template Fired!!" );
player = self getHighestKillstreakPlayerNotOnMyTeam();
//if we couldnt find a target bail out.
if( !isDefined( player ))
{
return false;
}
fxObj = player createFxObj();
wait( 0.10 ); //wait two server frames before playing fx
fxobj thread doTheFx();
fxobj thread waitAndDelete( 10.0 );
wait( 1.6 );
player playSound( "prototype_missile_incoming" );
// This works
/*
PlayFX( level._effect["blueshell"], player.origin );
wait( 1.7 );
player playSound( "prototype_missile_incoming" );
*/
wait( 3.4 );
RadiusDamage( fxobj.origin, 100, 300, 25, self );
return true;
}
waitAndDelete( time )
{
wait( time );
self delete();
}
doTheFx()
{
PlayFXOnTagForClients( level._effect["blueshell"], self, "TAG_ORIGIN", level._players );
}
createFxObj()
{
tag_origin = spawn( "script_model", self.origin );
tag_origin setmodel( "tag_origin" );
//tag_origin hide();
if ( isdefined( self.origin ) )
tag_origin.origin = self.origin;
if ( isdefined( self.angles ) )
tag_origin.angles = self.angles;
return tag_origin;
}
getHighestKillstreakPlayerNotOnMyTeam()
{
team = self.pers["team"];
curr_highest_killstreak = -1;
curr_player = undefined;
//TagZP<TODO> add los checks from above to make sure the player is outside.
//possibly return a list of random targets for fun.
//possibly use player score insted of killstreak to select a target.
//this implies that we are in a team based game mode such as TDM or DOM
if( level._teamBased )
{
foreach( player in level._players )
{
//if the player is not on my team check if they have the highest killstreak!!!!!
if( player.pers["team"] != team )
{
if( player.pers["cur_kill_streak"] > curr_highest_killstreak )
{
curr_highest_killstreak = player.pers["cur_kill_streak"];
curr_player = player;
}
}
}
}
else
{
//If we are not in a team based game we must be in a FFA game
foreach( player in level._players )
{
//if the player is not on my team kill them!!!!!
if( player != self )
{
if( player.pers["cur_kill_streak"] > curr_highest_killstreak )
{
curr_highest_killstreak = player.pers["cur_kill_streak"];
curr_player = player;
}
}
}
}
assert( isDefined( curr_player ));
return curr_player;
}
// A helper script that will kill a player. Used by the example killstreak.
killPlayer( player )
{
player thread [[level._callbackPlayerDamage]](
self, // eInflictor The entity that causes the damage.(e.g. a turret)
self, // eAttacker The entity that is attacking.
500, // iDamage Integer specifying the amount of damage done
0, // iDFlags Integer specifying flags that are to be applied to the damage
"MOD_SUICIDE", // sMeansOfDeath Integer specifying the method of death MOD_RIFLE_BULLET
player.primaryweapon, // sWeapon The weapon number of the weapon used to inflict the damage
player.origin, // vPoint The point the damage is from?
(0, 0, 0), // vDir The direction of the damage
"none", // sHitLoc The location of the hit
0 // psOffsetTime The time offset for the damage
);
}

View File

@ -0,0 +1,414 @@
#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;
if( level._multiTeamBased )
{
for( i = 0; i < level._teamNameList.size; i++ )
{
level._teamEMPed[level._teamNameList[i]] = false;
}
}
level._empPlayer = undefined;
if ( level._teamBased )
level thread EMP_TeamTracker();
else
level thread EMP_PlayerTracker();
level._killstreakFuncs["emp"] = ::EMP_Use;
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"];
if ( level._teamBased )
self thread EMP_JamTeams( myTeam, 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_JamTeams( teamName, duration, delay )
{
level endon ( "game_ended" );
thread teamPlayerCardSplash( "used_emp", self );
level notify ( "EMP_JamTeams" + teamName );
level endon ( "EMP_JamTeams" + teamName );
foreach ( player in level._players )
{
player playLocalSound( "emp_activate" );
if ( player.team == teamName )
{
continue;
}
else
{
player.gotEMPed = true;
if ( player _hasPerk( "specialty_flakjacket" ))
{
player notify ( "disableTrophy" );
}
}
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 );
foreach( team in level._teamNameList )
{
if ( team != teamName )
{
level._teamEMPed[team] = true;
}
}
level notify ( "emp_update" );
level destroyActiveVehicles( self );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration );
foreach( team in level._teamNameList )
{
if ( team != teamName )
{
level._teamEMPed[team] = false;
}
}
foreach ( player in level._players )
{
if ( player.team == teamName )
{
continue;
}
else
{
player.gotEMPed = false;
if ( (player _hasPerk( "specialty_flakjacket" )) && !(isDefined ( player.gotEMPGrenaded ) && player.gotEMPGrenaded == true))
{
player notify ( "enableTrophy" );
}
}
if ( player _hasPerk( "specialty_localjammer" ) )
player RadarJamOn();
}
level notify ( "emp_update" );
level notify ( "enableTrophy" );
}
EMPGrenade_JamPlayer( duration )
{
level endon ( "EMP_JamPlayers" );
self endon ( "death" );
self endon ( "disconnect" );
self playLocalSound( "emp_activate" );
if ( self _hasPerk( "specialty_localjammer" ) )
self RadarJamOff();
self.gotEMPGrenaded = true;
if (self _hasPerk( "specialty_flakjacket" ))
{
self notify ( "disableTrophy" );
}
wait ( 0.1 );
self setEMPJammed( true );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration );
self setEMPJammed( false );
if ( self _hasPerk( "specialty_localjammer" ) )
self RadarJamOn();
self.gotEMPGrenaded = false;
if ( (self _hasPerk( "specialty_flakjacket" )) && !(isDefined ( self.gotEMPed ) && self.gotEMPed == true ))
{
self notify ( "enableTrophy" );
}
}
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;
}
else
{
player.gotEMPed = true;
if ( player _hasPerk( "specialty_flakjacket" ))
{
player notify ( "disableTrophy" );
}
}
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();
level destroyActiveVehicles( owner );
level notify ( "emp_update" );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration );
foreach ( player in level._players )
{
if ( player == owner )
{
continue;
}
else
{
player.gotEMPed = false;
if ( (player _hasPerk( "specialty_flakjacket" )) && !(isDefined ( player.gotEMPGrenaded ) && player.gotEMPGrenaded == true))
{
player notify ( "enableTrophy" );
}
}
if ( player _hasPerk( "specialty_localjammer" ) )
player RadarJamOn();
}
level._empPlayer = undefined;
level notify ( "emp_update" );
level notify ( "emp_ended" );
level notify ( "enableTrophy" );
}
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 );
}
}
}
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, 2, 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, 2, 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 );
}
}

View File

@ -0,0 +1,229 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
EXOSUIT_CHANGE_TIME_SECONDS = 3.0;
EXOSUIT_TABLE_FILE = "mp/exosuitTable.csv";
//*******************************************************************
// *
// *
//*******************************************************************
init()
{
precacheString( &"MPUI_CHANGING_SUIT" );
PrecacheItem( "aresminigun_mp" );
level._killStreakFuncs[ "exosuit" ] = ::tryUseExosuit;
}
//*******************************************************************
// *
// *
//*******************************************************************
tryUseExosuit( lifeId )
{
self thread chooseExosuit();
self waittill ( "suit_chosen" );
// suit perk will be set if the function above is successful
if ( self _hasPerk( "specialty_stealthsuit" ) || self _hasPerk( "specialty_agisuit" ) ||
self _hasPerk( "specialty_tacsuit" ) || self _hasPerk( "specialty_juggersuit" ) ||
self _hasPerk( "specialty_jetsuit" ))
{
return true;
}
else
{
return false;
}
}
//*******************************************************************
// *
// *
//*******************************************************************
chooseExosuit()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
suitName = "specialty_juggersuit";
if ( self isUsingRemote() )
{
if ( self getCurrentWeapon() == "killstreak_uav_mp" )
{
self _disableWeaponSwitch();
self _disableOffhandWeapons();
self _disableUsability();
self switchToWeapon( self getLastWeapon() );
self waittill ( "weapon_change" );
self _enableWeaponSwitch();
self _enableOffhandWeapons();
self _enableUsability();
}
self notify ( "suit_chosen" );
return;
}
else
{
assert( suitName == "specialty_stealthsuit" || suitName == "specialty_agisuit" ||
suitName == "specialty_tacsuit" || suitName == "specialty_juggersuit" ||
suitName == "specialty_jetsuit" );
self thread tryWearSuit( suitName );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
closeExosuitMenuOnDeath()
{
self endon ( "menuresponse" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self waittill ( "death" );
self closePopupMenu();
}
//*******************************************************************
// *
// *
//*******************************************************************
tryWearSuit( suitName )
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
// tagTMR<TODO>: Add playLocalSound and playTeamSound here
if ( self _hasPerk( "specialty_twoprimaries" ))
{
self thread maps\mp\gametypes\_class::cleanHULChud();
self notify ( "disable_HULC" );
}
self _disableWeapon();
self _disableOffhandWeapons();
self _disableUsability();
// Don't want overpowered combinations so no perks will coexist with suits for now
self _clearPerks();
maps\mp\perks\_perks::givePerk( suitName );
self _enableWeapon();
self _enableOffhandWeapons();
self _enableUsability();
// tagSS<NOTE>: No attempt is made to save the previous model. This would be needed if the suit was able to be removed
// before dying, in order to restore the proper randomized character. Note that this also sets the model.
self detachAll();
self giveSuitWeapons( suitName );
// tagTMR<NOTE>: The detatchAll() above will remove the flag carried, reattached if the player's spoda have one
if ( isDefined( self.carryFlag ))
{
self attach( self.carryFlag, "J_spine4", true );
}
waitframe();
self notify ( "suit_chosen" );
}
//*******************************************************************
// *
// *
//*******************************************************************
exosuitUseBar()
{
self endon ( "disconnect" );
useBar = createPrimaryProgressBar( 25 );
useBarText = createPrimaryProgressBarText( 25 );
useBarText setText( &"MPUI_CHANGING_SUIT" );
useBar updateBar( 0, 1 / EXOSUIT_CHANGE_TIME_SECONDS );
for ( waitedTime = 0; waitedTime < EXOSUIT_CHANGE_TIME_SECONDS && isAlive( self ) && !level._gameEnded; waitedTime += 0.05 )
{
wait ( 0.05 );
}
useBar destroyElem();
useBarText destroyElem();
}
//*******************************************************************
// *
// *
//*******************************************************************
giveSuitWeapons( suitName )
{
primaryWeapon = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 2 );
primaryAttachment = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 3 );
primaryAttachment2 = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 4 );
secondaryWeapon = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 5 );
secondaryAttachment = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 6 );
secondaryAttachment2 = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 7 );
equipment = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 8 );
loadoutOffhand = tablelookup( EXOSUIT_TABLE_FILE, 1, suitName, 9 );
// tagTMR<NOTE>: if there is no primary weapon, this suit will not have a weapon loadout to sub
if (primaryWeapon != "none")
{
self takeAllWeapons();
self.loadoutPrimary = primaryWeapon;
self.loadoutSecondary = secondaryWeapon;
primaryName = maps\mp\gametypes\_class::buildWeaponName( primaryWeapon, primaryAttachment, primaryAttachment2 );
self _giveWeapon( primaryName, self.loadoutPrimaryCamo );
self SwitchToWeapon ( primaryWeapon + "_mp" );
secondaryName = maps\mp\gametypes\_class::buildWeaponName( secondaryWeapon, secondaryAttachment, secondaryAttachment2 );
self _giveWeapon( secondaryName, self.loadoutSecondaryCamo );
self SetOffhandPrimaryClass( "other" );
equipment = maps\mp\perks\_perks::validatePerk( 1, equipment );
self maps\mp\perks\_perks::givePerk( equipment );
// Secondary Offhand
offhandSecondaryWeapon = loadoutOffhand + "_mp";
if ( loadoutOffhand == "flash_grenade" )
self SetOffhandSecondaryClass( "flash" );
else
self SetOffhandSecondaryClass( "smoke" );
self giveWeapon( offhandSecondaryWeapon );
if( loadOutOffhand == "smoke_grenade" )
self setWeaponAmmoClip( offhandSecondaryWeapon, 1 );
else if( loadOutOffhand == "flash_grenade" )
self setWeaponAmmoClip( offhandSecondaryWeapon, 2 );
else if( loadOutOffhand == "concussion_grenade" )
self setWeaponAmmoClip( offhandSecondaryWeapon, 2 );
else
self setWeaponAmmoClip( offhandSecondaryWeapon, 1 );
self.primaryWeapon = primaryName;
self.secondaryWeapon = secondaryName;
primaryTokens = strtok( primaryName, "_" );
self.pers["primaryWeapon"] = primaryTokens[0];
self.isSniper = (weaponClass( self.primaryWeapon ) == "sniper");
}
self maps\mp\gametypes\_teams::playerModelForWeapon( self.pers["primaryWeapon"], getBaseWeaponName( self.secondaryWeapon ) );
self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" );
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,440 @@
#include maps\mp\_utility;
#include common_scripts\utility;
JET_MISSILE_DIRECTION = ( 1.0, 1.0, 20.0 );
// Each Killstreak has its own initialization function. This Script has two main purposes.
// (1). All global data and assets used by this killstreak should be initialized here.
// (2). The callback that executes when a player activates this killstreak should be set here.
// TODO: A call to this script must be added to the script init() in the file c:\trees\nx1\game\share\raw\maps\mp\killstreaks\_killstreaks.gsc,
// this is were each individual killstreak is initialized.
init()
{
//precacheItem( "f50_remote_mp" );
precacheModel( "vehicle_f50" );
PrecacheMiniMapIcon( "compass_objpoint_airstrike_friendly" );
PrecacheMiniMapIcon( "compass_objpoint_airstrike_busy" );
PrecacheMiniMapIcon( "compass_objpoint_b2_airstrike_friendly" );
PrecacheMiniMapIcon( "compass_objpoint_b2_airstrike_enemy" );
level._killStreakFuncs["jet"] = ::tryUseJet;
level._onfirefx = loadfx ("fire/fire_smoke_trail_L");
level._fx_airstrike_afterburner = loadfx ("fire/jet_afterburner");
level._fx_airstrike_contrail = loadfx ("smoke/jet_contrail");
level._planes = 0;
level._rockets = [];
}
tryUseJet( lifeId )
{
println( "tryuseJet" );
if ( isDefined( level._civilianJetFlyBy ) )
{
self iPrintLnBold( &"MP_CIVILIAN_AIR_TRAFFIC" );
return false;
}
if ( self isUsingRemote() )
{
return false;
}
result = self selectJetLocation( lifeId );
if ( !isDefined( result ) || !result )
return false;
return true;
}
selectJetLocation( lifeId )
{
println( "SelectJetLocation" );
chooseDirection = true;
targetSize = level._mapSize / 5.625; // 138 in 720
if ( level._splitscreen )
targetSize *= 1.5;
self beginLocationSelection( "map_artillery_selector", chooseDirection, false, targetSize );
self.selectingLocation = true;
self setblurforplayer( 4.0, 0.3 );
self thread waitForJetCancel();
self thread endJetSelectionOn( "cancel_location" );
self thread endJetSelectionOn( "death" );
self thread endJetSelectionOn( "disconnect" );
self thread endJetSelectionOn( "used" ); // so that this thread doesn't kill itself when we use an airstrike
self thread endJetSelectionOnGameEnd();
self thread endJetSelectionOnEMP();
self endon( "stop_location_selection" );
// wait for the selection. randomize the yaw if we're not doing a precision airstrike.
self waittill( "confirm_location", location, directionYaw );
self setblurforplayer( 0, 0.3 );
self thread finishJetUsage( lifeId, location, directionYaw );
return true;
}
finishJetUsage( lifeId, location, directionYaw )
{
println( "finishJetUsage" );
self notify( "used" );
// find underside of top of skybox
trace = bullettrace( level._mapCenter + (0,0,1000000), level._mapCenter, false, undefined );
location = (location[0], location[1], trace["position"][2] - 514);
self thread doJetAirStrike( lifeId, location, directionYaw, self, self.pers["team"] );
}
doJetAirStrike( lifeId, origin, yaw, owner, team )
{
println( "doJetAirStrike" );
assert( isDefined( origin ) );
assert( isDefined( yaw ) );
if ( isDefined( level._airstrikeInProgress ) )
{
while ( isDefined( level._airstrikeInProgress ) )
level waittill ( "begin_airstrike" );
level._airstrikeInProgress = true;
wait ( 2.0 );
}
if ( !isDefined( owner ) )
{
return;
}
level._airstrikeInProgress = true;
num = 17 + randomint(3);
trace = bullettrace(origin, origin + (0,0,-1000000), false, undefined);
targetpos = trace["position"];
if ( level._teambased )
{
players = level._players;
for ( i = 0; i < level._players.size; i++ )
{
player = level._players[i];
playerteam = player.pers["team"];
if ( isdefined( playerteam ) )
{
player iprintln( &"MP_WAR_AIRSTRIKE_INBOUND", owner );
}
}
}
self callJetStrike( lifeId, owner, targetpos, yaw );
wait( 1.0 );
level._airstrikeInProgress = undefined;
owner notify ( "begin_airstrike" );
level notify ( "begin_airstrike" );
wait 7.5;
found = false;
}
callJetStrike( lifeId, owner, coord, yaw )
{
println( "calljetstrike" );
heightEnt = undefined;
// Get starting and ending point for the plane
direction = ( 0, yaw, 0 );
heightEnt = GetEnt( "airstrikeheight", "targetname" );
thread teamPlayerCardSplash( "used_stealth_airstrike", owner, owner.team );
planeHalfDistance = 12000;
planeFlySpeed = 2000;
if ( !isDefined( heightEnt ) )//old system
{
println( "NO DEFINED AIRSTRIKE HEIGHT SCRIPT_ORIGIN IN LEVEL" );
planeFlyHeight = 2000;
if ( isdefined( level._airstrikeHeightScale ) )
{
planeFlyHeight *= level._airstrikeHeightScale;
}
}
else
{
planeFlyHeight = heightEnt.origin[2];
}
startPoint = coord + vector_multiply( anglestoforward( direction ), -1 * planeHalfDistance );
if ( isDefined( heightEnt ) )// used in the new height system
startPoint *= (1,1,0);
startPoint += ( 0, 0, planeFlyHeight );
endPoint = coord + vector_multiply( anglestoforward( direction ), planeHalfDistance*4 );
if ( isDefined( heightEnt ) )// used in the new height system
endPoint *= (1,1,0);
endPoint += ( 0, 0, planeFlyHeight );
// Make the plane fly by
d = length( startPoint - endPoint );
flyTime = ( d / planeFlySpeed );
owner endon("disconnect");
requiredDeathCount = lifeId;
self doJetStrike( lifeId, owner, startPoint+(0,0,randomInt(1000)), endPoint+(0,0,randomInt(1000)), flyTime, direction );
}
endJetSelectionOn( waitfor )
{
self endon( "stop_location_selection" );
self waittill( waitfor );
self thread stopJetLocationSelection( (waitfor == "disconnect") );
}
endJetSelectionOnGameEnd()
{
self endon( "stop_location_selection" );
level waittill( "game_ended" );
self thread stopJetLocationSelection( false );
}
endJetSelectionOnEMP()
{
self endon( "stop_location_selection" );
for ( ;; )
{
level waittill( "emp_update" );
if ( !self isEMPed() )
continue;
self thread stopJetLocationSelection( false );
return;
}
}
doJetStrike( lifeId, owner, startPoint, endPoint, flyTime, direction )
{
self notifyOnPlayerCommand( "trigger_pulled", "+attack" );
// plane spawning randomness = up to 125 units, biased towards 0
// radius of bomb damage is 512
println( "doJetStrike" );
if ( !isDefined( owner ) )
return;
startPathRandomness = 100;
endPathRandomness = 150;
pathStart = startPoint + ( (randomfloat(2) - 1)*startPathRandomness, (randomfloat(2) - 1)*startPathRandomness, 0 );
pathEnd = endPoint + ( (randomfloat(2) - 1)*endPathRandomness , (randomfloat(2) - 1)*endPathRandomness , 0 );
// Spawn the planes
plane = spawnplane( owner, "script_model", pathStart, "compass_objpoint_b2_airstrike_friendly", "compass_objpoint_b2_airstrike_enemy" );
plane playLoopSound( "veh_b2_dist_loop" );
plane setModel( "vehicle_f50" );
plane thread handleJetEMP( owner );
plane.lifeId = lifeId;
plane.angles = direction;
forward = anglesToForward( direction );
plane thread playJetPlaneFx();
//self HideHud();
//self VisionSetMissilecamForPlayer( game["thermal_vision"], 1.0 );
self PlayerLinkWeaponviewToDelta( plane, "tag_player", 1.0, 45, 45, 0, 45, false );
//self CameraLinkTo( plane, "tag_player" );
//self ThermalVisionOn();
//self ThermalVisionFOFOverlayOn();
self _giveWeapon("heli_remote_mp");
self SwitchToWeapon( "heli_remote_mp" );
self DisableWeaponSwitch();
self _disableOffhandWeapons();
plane moveTo( pathEnd, flyTime, 0, 0 );
println ("Before loop");
plane thread jetTimeout( flyTime );
self waittill ("trigger_pulled");
println ("Fired Gun" );
origin = self GetEye();
forward = AnglesToForward( self GetPlayerAngles() );
endpoint = origin + forward;
println ( "origin :" + origin );
println ( "endpoint :" + endpoint );
println ( "forward :" + forward );
//bomb = spawnbomb( plane.origin, plane.angles );
//bomb moveGravity( vector_multiply( anglestoforward( plane.angles ), 7000/1.5 ), 3.0 );
rocket = MagicBullet( "remotemissile_projectile_mp", origin, endpoint, owner );
rocket thread JetMissilehandleDamage();
self unlink();
self CameraLinkTo( rocket, "tag_origin" );
self ControlsLinkTo( rocket );
//self ThermalVisionFOFOverlayOff();
rocket thread JetRocket_CleanupOnDeath();
rocket waittill( "death" );
self thread staticEffect( 0.5 );
self ControlsUnlink();
self CameraUnlink();
self thread Weapon_Return ();
println ("done with loop");
}
jetTimeout( flyTime )
{
// Delete the plane after its flyby
wait ( flyTime / 2.3 );
self notify( "delete" );
self delete();
}
waitForJetCancel()
{
self waittill( "cancel_location" );
self setblurforplayer( 0, 0.3 );
}
stopJetLocationSelection( disconnected )
{
if ( !disconnected )
{
self setblurforplayer( 0, 0.3 );
self endLocationSelection();
self.selectingLocation = undefined;
}
self notify( "stop_location_selection" );
}
useJet( lifeId, pos, yaw )
{
}
handleJetEMP( owner )
{
self endon ( "death" );
if ( owner isEMPed() )
{
playFxOnTag( level._onfirefx, self, "tag_engine_right" );
playFxOnTag( level._onfirefx, self, "tag_engine_left" );
return;
}
for ( ;; )
{
level waittill ( "emp_update" );
if ( !owner isEMPed() )
continue;
playFxOnTag( level._onfirefx, self, "tag_engine_right" );
playFxOnTag( level._onfirefx, self, "tag_engine_left" );
}
}
JetRocket_CleanupOnDeath()
{
entityNumber = self getEntityNumber();
level._rockets[ entityNumber ] = self;
self waittill( "death" );
level._rockets[ entityNumber ] = undefined;
}
Weapon_Return()
{
//self showhud;
self takeWeapon( "heli_remote_mp" );
self enableWeaponSwitch();
self switchToWeapon( self getLastWeapon() );
self _enableOffhandWeapons();
}
JetMissilehandleDamage()
{
self endon ( "death" );
self endon ( "deleted" );
self setCanDamage( true );
for ( ;; )
{
self waittill( "damage" );
println ( "projectile damaged!" );
}
}
playJetPlaneFx()
{
self endon ( "death" );
wait( 0.5);
playfxontag( level._fx_airstrike_afterburner, self, "tag_engine_right" );
wait( 0.5);
playfxontag( level._fx_airstrike_afterburner, self, "tag_engine_left" );
wait( 0.5);
playfxontag( level._fx_airstrike_contrail, self, "tag_right_wingtip" );
wait( 0.5);
playfxontag( level._fx_airstrike_contrail, self, "tag_left_wingtip" );
}
staticEffect( duration )
{
self endon ( "disconnect" );
staticBG = newClientHudElem( self );
staticBG.horzAlign = "fullscreen";
staticBG.vertAlign = "fullscreen";
staticBG setShader( "white", 640, 480 );
staticBG.archive = true;
staticBG.sort = 10;
static = newClientHudElem( self );
static.horzAlign = "fullscreen";
static.vertAlign = "fullscreen";
static setShader( "ac130_overlay_grain", 640, 480 );
static.archive = true;
static.sort = 20;
wait ( duration );
static destroy();
staticBG destroy();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,316 @@
#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 );
level._nukeTimer = getDvarInt( "scr_nukeTimer" );
level._cancelMode = getDvarInt( "scr_nukeCancelMode" );
/#
setDevDvarIfUninitialized( "scr_nukeDistance", 5000 );
setDevDvarIfUninitialized( "scr_nukeEndsGame", true );
setDevDvarIfUninitialized( "scr_nukeDebugPosition", false );
#/
}
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 endon ( "nuke_cancelled" );
level._nukeInfo = spawnStruct();
level._nukeInfo.player = self;
level._nukeInfo.team = self.pers["team"];
level._nukeIncoming = true;
maps\mp\gametypes\_gamelogic::pauseTimer();
level._timeLimitOverride = 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 );
// leaks if lots of nukes are called due to endon above.
clockObject = spawn( "script_origin", (0,0,0) );
clockObject hide();
while ( !isDefined( level._nukeDetonated ) )
{
clockObject playSound( "ui_mp_nukebomb_timer" );
wait( 1.0 );
}
}
cancelNukeOnDeath( player )
{
player waittill_any( "death", "disconnect" );
if ( isDefined( player ) && level._cancelMode == 2 )
player thread maps\mp\killstreaks\_emp::EMP_Use( 0, 0 );
maps\mp\gametypes\_gamelogic::resumeTimer();
level._timeLimitOverride = false;
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;
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 );
player.nuked = true;
}
}
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( <startTimescale>, <endTimescale>, <deltaTime> )
setSlowMotion( 1.0, 0.25, 0.5 );
level waittill( "nuke_death" );
setSlowMotion( 0.25, 1, 2.0 );
}
nukeVision()
{
level endon ( "nuke_cancelled" );
level._nukeVisionInProgress = true;
visionSetNaked( "mpnuke", 3 );
level waittill( "nuke_death" );
visionSetNaked( "mpnuke_aftermath", 5 );
wait 5;
level._nukeVisionInProgress = undefined;
}
nukeDeath()
{
level endon ( "nuke_cancelled" );
level notify( "nuke_death" );
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
AmbientStop(1);
foreach( player in level._players )
{
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 );
}
level._postRoundTime = 10;
nukeEndsGame = true;
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 );
}
}
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" );
}

View File

@ -0,0 +1,711 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
init()
{
precacheString( &"MP_LASE_TARGET_FOR_GUIDED_MORTAR" );
precacheString( &"MP_WAIT_FOR_MORTAR_READY" );
precacheString( &"MP_MORTAR_ROUNDS_DEPLETED" );
precacheString( &"SPLASHES_DESTROYED_REMOTE_MORTAR" );
precacheModel( "vehicle_predator_b" );
precacheItem( "remote_mortar_missile_mp" );
precacheItem( "mortar_remote_mp" );
precacheItem( "mortar_remote_zoom_mp" );
precacheShader( "compass_waypoint_bomb" );
precacheShader( "viper_locked_box" );
PrecacheMiniMapIcon( "compass_objpoint_reaper_friendly" );
PrecacheMiniMapIcon( "compass_objpoint_reaper_enemy" );
level._remote_mortar_fx["laserTarget"] = loadfx("nx/misc/nx_laser_glow");
level._killstreakFuncs["reaper"] = ::tryUseRemoteMortar;
/#
SetDevDvarIfUninitialized( "scr_remote_mortar_timeout", 40.0 );
#/
}
tryUseRemoteMortar( lifeId )
{
if ( isDefined( self.lastStand ) && !self _hasPerk( "specialty_finalstand" ) )
{
self iPrintLnBold( &"MP_UNAVILABLE_IN_LASTSTAND" );
return false;
}
self setUsingRemote( "remote_mortar" );
/* result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak();
if ( result != "success" )
{
if ( result != "disconnect" )
self clearUsingRemote();
return false;
}
*/
self maps\mp\_matchdata::logKillstreakEvent( "remote_mortar", self.origin );
return startRemoteMortar( lifeId );
}
startRemoteMortar( lifeId )
{
remote = spawnRemote( lifeId, self );
if ( !isDefined( remote ) )
return false;
self setPlayerData( "reaperHUD", "targetDistance", -1 );
self remoteRide( remote );
self thread teamPlayerCardSplash( "used_remote_mortar", self );
return true;
}
spawnRemote( lifeId, owner )
{
remote = spawnPlane( owner, "script_model", level._UAVRig getTagOrigin( "tag_origin" ), "compass_objpoint_reaper_friendly", "compass_objpoint_reaper_enemy" );
if ( !isDefined( remote ) )
return undefined;
remote setModel( "vehicle_predator_b" );
remote.lifeId = lifeId;
remote.team = owner.team;
remote.owner = owner;
remote.numFlares = 1;
remote setCanDamage( true );
remote thread damageTracker();
remote.heliType = "remote_mortar";
// for target lists (javelin, stinger, sam, emp, etc)
remote.uavType = "remote_mortar";
maps\mp\killstreaks\_uav::addUAVModel( remote );
// same height and radius as the AC130 with random angle and counter rotation
zOffset = 6300;
angle = randomInt( 360 );
radiusOffset = 6100;
xOffset = cos( angle ) * radiusOffset;
yOffset = sin( angle ) * radiusOffset;
angleVector = vectorNormalize( (xOffset,yOffset,zOffset) );
angleVector = ( angleVector * 6100 );
remote linkTo( level._UAVRig, "tag_origin", angleVector, (0,angle-90,10) );
remote thread handleDeath( owner );
remote thread handleTimeout( owner );
remote thread handleOwnerChangeTeam( owner );
remote thread handleOwnerDisconnect( owner );
remote thread handleIncomingStinger();
remote thread handleIncomingSAM();
return remote;
}
lookCenter()
{
wait( 0.05 );
lookVec = vectorToAngles( level._UAVRig.origin - self GetEye() );
self setPlayerAngles( lookVec );
}
remoteRide( remote )
{
self setPlayerData( "reaperHUD", "zoomed", false );
self _giveWeapon("mortar_remote_mp");
self SwitchToWeapon("mortar_remote_mp");
self ThermalVisionFOFOverlayOn();
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( false );
self PlayerLinkWeaponviewToDelta( remote, "tag_player", 1.0, 35, 35, 15, 55 );
self thread lookCenter();
self thread remoteTargeting( remote );
self thread remoteFiring( remote );
self thread remoteZoom( remote );
}
remoteTargeting( remote )
{
level endon( "game_ended" );
self endon( "disconnect" );
remote endon( "remote_done" );
remote endon( "death" );
remote.targetEnt = SpawnFx( level._remote_mortar_fx["laserTarget"], (0,0,0) );
remote.targetEnt.icon = remote.targetEnt maps\mp\_entityheadIcons::setHeadIcon( self, "viper_locked_box", (0,0,-270), 100, 100, false, 0.05, false, false, false, false );
remote.targetEnt.icon.color = (0.9, 0.7, 0.2);
/*laserPos = remote getTagOrigin( "tag_player" );
remote.laserEnt = Spawn( "script_model", laserPos );
remote.laserEnt linkTo( remote, "tag_player", (0,0,0), (0,0,0) );
remote.laserEnt LaserOn();*/
while ( true )
{
origin = self GetEye();
forward = AnglesToForward( self GetPlayerAngles() );
endpoint = origin + forward * 15000;
traceData = BulletTrace( origin, endpoint, false, remote.targetEnt );
if ( isDefined( traceData["position"] ) )
{
remote.targetEnt.origin = traceData["position"];
triggerFX( remote.targetEnt );
}
wait( 0.05 );
}
}
remoteFiring( remote )
{
level endon( "game_ended" );
self endon( "disconnect" );
remote endon( "remote_done" );
remote endon( "death" );
curTime = getTime();
lastFireTime = curTime-750;
shotsFired = 0;
while( true )
{
curTime = getTime();
if ( self attackButtonPressed() && ( curTime - lastFireTime > 3000 ) )
{
shotsFired++;
lastFireTime = curTime;
self playLocalSound( "stinger_locking" );
self PlayRumbleOnEntity( "damage_heavy" );
origin = self GetEye();
forward = AnglesToForward( self GetPlayerAngles() );
right = AnglesToRight( self GetPlayerAngles() );
offset = origin + ( forward * 100 ) + ( right * -100 );
missile = MagicBullet( "remote_mortar_missile_mp", offset, remote.targetEnt.origin, self );
missile Missile_SetTargetEnt( remote.targetEnt );
missile Missile_SetFlightmodeDirect();
missile.icon = missile maps\mp\_entityheadIcons::setHeadIcon( self, "compass_waypoint_bomb", (0,0,-10), 10, 10, false, 0.05, false, false, false, false );
missile thread remoteMissileDistance( remote );
remote.missileIcon = missile.icon;
missile waittill( "death" );
if ( isDefined( missile.icon ) )
{
missile.icon destroy();
missile.icon = undefined;
}
self setPlayerData( "reaperHUD", "targetDistance", -1 );
if ( shotsFired == 14 )
break;
}
else
wait( 0.05 );
}
self remoteEndRide( remote );
remote thread remoteLeave();
}
remoteZoom( remote )
{
level endon( "game_ended" );
self endon( "disconnect" );
remote endon( "remote_done" );
remote endon( "death" );
remote.zoomed = false;
while ( true )
{
if ( self adsButtonPressed() )
{
if ( remote.zoomed == false )
{
self _giveWeapon("mortar_remote_zoom_mp");
self SwitchToWeapon("mortar_remote_zoom_mp");
remote.zoomed = true;
self setPlayerData( "reaperHUD", "zoomed", true );
if ( isDefined( remote.targetEnt.icon ) )
{
remote.targetEnt.icon destroy();
remote.targetEnt.icon = undefined;
remote.targetEnt.icon = remote.targetEnt maps\mp\_entityheadIcons::setHeadIcon( self, "viper_locked_box", (0,0,-50), 100, 100, false, 0.05, false, false, false, false );
remote.targetEnt.icon.color = (0.9, 0.7, 0.2);
}
}
}
else
{
if ( remote.zoomed == true )
{
self _giveWeapon("mortar_remote_mp");
self SwitchToWeapon("mortar_remote_mp");
remote.zoomed = false;
self setPlayerData( "reaperHUD", "zoomed", false );
if ( isDefined( remote.targetEnt.icon ) )
{
remote.targetEnt.icon destroy();
remote.targetEnt.icon = undefined;
remote.targetEnt.icon = remote.targetEnt maps\mp\_entityheadIcons::setHeadIcon( self, "viper_locked_box", (0,0,-270), 100, 100, false, 0.05, false, false, false, false );
remote.targetEnt.icon.color = (0.9, 0.7, 0.2);
}
}
}
wait( 0.05 );
}
}
remoteMissileDistance( remote )
{
level endon( "game_ended" );
remote endon( "death" );
remote endon( "remote_done" );
self endon( "death" );
while( true )
{
targetDist = distance( self.origin, remote.targetent.origin );
remote.owner setPlayerData( "reaperHUD", "targetDistance", int( targetDist / 12 ) );
wait( 0.05 );
}
}
remoteEndRide( remote )
{
if ( isDefined( remote ) )
{
remote notify( "helicopter_done" );
if ( isDefined( remote.laserEnt ) )
remote.laserEnt LaserOff();
if ( isDefined( remote.targetEnt ) && isDefined( remote.targetEnt.icon ) )
{
remote.targetEnt.icon destroy();
remote.targetEnt.icon = undefined;
}
if ( isDefined( remote.missileIcon ) )
{
remote.missileIcon destroy();
remote.missileIcon = undefined;
}
}
self ThermalVisionFOFOverlayOff();
self unlink();
self clearUsingRemote();
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( true );
self switchToWeapon( self getLastWeapon() );
weaponList = self GetWeaponsListExclusives();
foreach ( weapon in weaponList )
self takeWeapon( weapon );
}
handleTimeout( owner )
{
level endon( "game_ended" );
owner endon( "disconnect" );
self endon( "death" );
lifeSpan = 40.0;
/#
lifeSpan = GetDvarInt( "scr_remote_mortar_timeout", lifeSpan );
#/
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( lifeSpan );
if ( isDefined( owner ) )
owner remoteEndRide( self );
self thread remoteLeave();
}
handleDeath( owner )
{
level endon( "game_ended" );
owner endon( "disconnect" );
self endon( "remote_done" );
self waittill( "death" );
if ( isDefined( owner ) )
owner remoteEndRide( self );
level thread removeRemote( self );
}
handleOwnerChangeTeam( owner )
{
level endon( "game_ended" );
self endon( "remote_done" );
self endon( "death" );
owner endon( "disconnect" );
owner waittill_any( "joined_team", "joined_spectators" );
if ( isDefined( owner ) )
owner remoteEndRide( self );
self thread remoteLeave();
}
handleOwnerDisconnect( owner )
{
level endon( "game_ended" );
self endon( "remote_done" );
self endon( "death" );
owner waittill( "disconnect" );
self thread remoteLeave();
}
removeRemote( remote )
{
self notify( "remote_removed" );
if ( isDefined( remote.targetEnt ) )
{
if ( isDefined( remote.targetEnt.icon ) )
{
remote.targetEnt.icon destroy();
remote.targetEnt.icon = undefined;
}
remote.targetEnt delete();
}
if ( isDefined( remote.laserEnt ) )
remote.laserEnt delete();
if( IsDefined( remote ) )
{
remote delete();
maps\mp\killstreaks\_uav::removeUAVModel( remote );
}
}
remoteLeave()
{
level endon( "game_ended" );
self endon( "death" );
self notify( "remote_done" );
self unlink();
destPoint = self.origin + ( AnglesToForward( self.angles ) * 20000 );
self moveTo( destPoint, 30 );
PlayFXOnTag( level._effect[ "ac130_engineeffect" ] , self, "tag_origin" );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 3 );
self moveTo( destPoint, 4, 4, 0.0 );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 4 );
level thread removeRemote( self );
}
// Entities spawned from SpawnPlane do not respond to pre-damage callbacks
// so we have to wait until we get the post-damage event.
//
// Because the damage has already happened by the time we find out about it,
// we need to use an artificially high health value, restore it on erroneous damage
// events and track a virtual damage taken against a virtual max health.
damageTracker()
{
level endon( "game_ended" );
self.owner endon( "disconnect" );
self.health = 999999; // keep it from dying anywhere in code
self.maxHealth = 1000; // this is the health we'll check
self.damageTaken = 0; // how much damage has it taken
while( true )
{
self waittill( "damage", damage, attacker, direction_vec, point, meansOfDeath, modelName, tagName, partName, iDFlags, weapon );
// don't allow people to destroy things on their team if FF is off
if ( !maps\mp\gametypes\_weapons::friendlyFireCheck( self.owner, attacker ) )
continue;
if ( !IsDefined( self ) )
return;
if ( isDefined( iDFlags ) && ( iDFlags & level._iDFLAGS_PENETRATION ) )
self.wasDamagedFromBulletPenetration = true;
self.wasDamaged = true;
modifiedDamage = damage;
if( IsPlayer( attacker ) )
{
attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "" );
if( meansOfDeath == "MOD_RIFLE_BULLET" || meansOfDeath == "MOD_PISTOL_BULLET" )
{
if ( attacker _hasPerk( "specialty_armorpiercing" ) )
modifiedDamage += damage * level._armorPiercingMod;
}
}
if( IsDefined( weapon ) )
{
switch( weapon )
{
case "stinger_mp":
case "javelin_mp":
self.largeProjectileDamage = true;
modifiedDamage = self.maxhealth + 1;
break;
case "sam_projectile_mp":
self.largeProjectileDamage = true;
modifiedDamage *= 2.0; // takes about 1 burst of sam rockets
break;
}
}
self.damageTaken += modifiedDamage;
if ( self.damageTaken >= self.maxHealth )
{
if ( isPlayer( attacker ) && ( !isDefined( self.owner ) || attacker != self.owner ) )
{
self Hide();
forward = ( AnglesToRight( self.angles ) * 200 );
playFx ( level._uav_fx[ "explode" ], self.origin, forward );
attacker notify( "destroyed_killstreak", weapon );
thread teamPlayerCardSplash( "callout_destroyed_remote_mortar", attacker );
//attacker thread maps\mp\gametypes\_rank::giveRankXP( "kill", 50, weapon, meansOfDeath );
//attacker thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DESTROYED_REMOTE_MORTAR" );
//thread maps\mp\gametypes\_missions::vehicleKilled( self.owner, self, undefined, attacker, damage, meansOfDeath, weapon );
}
self notify( "death" );
return;
}
}
}
handleIncomingStinger() // self == remote mortar
{
level endon ( "game_ended" );
self endon ( "death" );
while( true )
{
level waittill ( "stinger_fired", player, missile, lockTarget );
if ( !IsDefined( lockTarget ) || (lockTarget != self) )
continue;
missile thread stingerProximityDetonate( lockTarget, player );
}
}
stingerProximityDetonate( missileTarget, player ) // self == missile
{
self endon ( "death" );
if( IsDefined( missileTarget.owner ) )
missileTarget.owner PlayLocalSound( "missile_incoming" );
self Missile_SetTargetEnt( missileTarget );
minDist = Distance( self.origin, missileTarget GetPointInBounds( 0, 0, 0 ) );
lastCenter = missileTarget GetPointInBounds( 0, 0, 0 );
while( true )
{
// already destroyed
if( !IsDefined( missileTarget ) )
center = lastCenter;
else
center = missileTarget GetPointInBounds( 0, 0, 0 );
lastCenter = center;
curDist = Distance( self.origin, center );
if( curDist < 3000 && missileTarget.numFlares > 0 )
{
missileTarget.numFlares--;
missileTarget thread maps\mp\killstreaks\_helicopter::playFlareFx();
newTarget = missileTarget maps\mp\killstreaks\_helicopter::deployFlares();
self Missile_SetTargetEnt( newTarget );
missileTarget = newTarget;
if( IsDefined( missileTarget.owner ) )
missileTarget.owner StopLocalSound( "missile_incoming" );
return;
}
if( curDist < minDist )
minDist = curDist;
if( curDist > minDist )
{
if( curDist > 1536 )
return;
if( IsDefined( missileTarget.owner ) )
{
missileTarget.owner stopLocalSound( "missile_incoming" );
if( level._teambased )
{
if( missileTarget.team != player.team )
RadiusDamage( self.origin, 1000, 1000, 1000, player, "MOD_EXPLOSIVE", "stinger_mp" );
}
else
{
RadiusDamage( self.origin, 1000, 1000, 1000, player, "MOD_EXPLOSIVE", "stinger_mp" );
}
}
self Hide();
wait( 0.05 );
self delete();
}
wait ( 0.05 );
}
}
handleIncomingSAM() // self == remote mortar
{
level endon ( "game_ended" );
self endon ( "death" );
while( true )
{
level waittill ( "sam_fired", player, missileGroup, lockTarget );
if ( !IsDefined( lockTarget ) || (lockTarget != self) )
continue;
level thread samProximityDetonate( lockTarget, player, missileGroup );
}
}
samProximityDetonate( missileTarget, player, missileGroup )
{
missileTarget endon( "death" );
if( IsDefined( missileTarget.owner ) )
missileTarget.owner PlayLocalSound( "missile_incoming" );
sam_projectile_damage = 150; // this should match the gdt entry
sam_projectile_damage_radius = 1000;
minDist = [];
for( i = 0; i < missileGroup.size; i++ )
{
if( IsDefined( missileGroup[ i ] ) )
minDist[ i ] = Distance( missileGroup[ i ].origin, missileTarget GetPointInBounds( 0, 0, 0 ) );
else
minDist[ i ] = undefined;
}
while( true )
{
center = missileTarget GetPointInBounds( 0, 0, 0 );
curDist = [];
for( i = 0; i < missileGroup.size; i++ )
{
if( IsDefined( missileGroup[ i ] ) )
curDist[ i ] = Distance( missileGroup[ i ].origin, center );
}
for( i = 0; i < curDist.size; i++ )
{
if( IsDefined( curDist[ i ] ) )
{
// if one of the missiles in the group get close, set off flares and redirect them all
if( curDist[ i ] < 3000 && missileTarget.numFlares > 0 )
{
missileTarget.numFlares--;
missileTarget thread maps\mp\killstreaks\_helicopter::playFlareFx();
newTarget = missileTarget maps\mp\killstreaks\_helicopter::deployFlares();
for( j = 0; j < missileGroup.size; j++ )
{
if( IsDefined( missileGroup[ j ] ) )
{
missileGroup[ j ] Missile_SetTargetEnt( newTarget );
}
}
if( IsDefined( missileTarget.owner ) )
missileTarget.owner StopLocalSound( "missile_incoming" );
return;
}
if( curDist[ i ] < minDist[ i ] )
minDist[ i ] = curDist[ i ];
if( curDist[ i ] > minDist[ i ] )
{
if( curDist[ i ] > 1536 )
return;
if( IsDefined( missileTarget.owner ) )
{
missileTarget.owner StopLocalSound( "missile_incoming" );
if( level._teambased )
{
if( missileTarget.team != player.team )
RadiusDamage( missileGroup[ i ].origin, sam_projectile_damage_radius, sam_projectile_damage, sam_projectile_damage, player, "MOD_EXPLOSIVE", "sam_projectile_mp" );
}
else
{
RadiusDamage( missileGroup[ i ].origin, sam_projectile_damage_radius, sam_projectile_damage, sam_projectile_damage, player, "MOD_EXPLOSIVE", "sam_projectile_mp" );
}
}
missileGroup[ i ] Hide();
wait ( 0.05 );
missileGroup[ i ] delete();
}
}
}
wait ( 0.05 );
}
}

View File

@ -0,0 +1,774 @@
#include maps\mp\_utility;
#include common_scripts\utility;
DOG_TIMEOUT_SEC = 45;
DOG_HUD_TIMER_POS_X = 0;
DOG_HUD_TIMER_POS_Y = -35;
DOG_TURRET_MAX_TARGETING_RANGE = 600; // 45 feet
DOG_TURRET_SPAWN_GRACE_TIME = 3; // dog wont shoot any anyone who hasn't been spawned for 3 seconds
DOG_TURRET_MIN_SHOTS = 10; // minimum shots to fire at a player
DOG_TURRET_MAX_SHOTS = 20; // maximum shots to fire at a player
DOG_TURRET_FIRE_DELAY = .1; // how long to wait between shots at a target
DOG_TURRET_MIN_BARRAGE_DELAY = 0; // how long to wait between firing bursts of shots at a target
DOG_TURRET_MAX_BARRAGE_DELAY = .1; // how long between burts of shots
DOG_TURRET_MAX_YAW = 60; // how far the turret can turn from the dogs centerline
//*******************************************************************
// *
// *
//*******************************************************************
init()
{
level._killstreakFuncs["remote_dog"] = ::tryRemoteDog;
level._remoteDogVehicleInfo = "PROTO_nx_remote_dog_play_mp";
level._remoteDogVehicleModel = "prototype_vehicle_remotedog_vehicle"; // "defaultvehicle"
level._remoteDogScriptModel = "prototype_vehicle_remotedog";
level._remoteDogMoveAnim = "german_shepherd_run";
level._remoteDogIdleAnim = "german_shepherd_idle";
level._remoteDogTranProp = "miniuav_transition_prop";
level._remoteDogTurretInfo = "proto_robot_dog_turret_mp";
level._remoteDogTurretModel = "proto_remotedog_turret";
level._remoteDogFOV = 120;
level._remoteDogHealth = 200;
level._remoteDogAmmo = 100;
level._remoteDogFireRate = 1; // in tenths of a second, so 10 is fires once a second
level._remoteDogCrossHair = "ac130_overlay_25mm";
PreCacheItem( level._remoteDogTranProp );
precacheString( &"NX_MINIUAV_USE_DRONE" );
PreCacheShader( "ac130_overlay_grain" );
PreCacheShader( level._remoteDogCrossHair );
precacheVehicle( level._remoteDogVehicleInfo );
precacheModel( level._remoteDogVehicleModel );
precacheMpAnim( level._remoteDogMoveAnim );
precacheMpAnim( level._remoteDogIdleAnim );
precacheModel( level._remoteDogScriptModel );
precacheTurret( level._remoteDogTurretInfo );
precacheModel( level._remoteDogTurretModel );
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogDebugPrint( msg )
{
IPrintLnBold( msg );
}
//*******************************************************************
// *
// *
//*******************************************************************
tryRemoteDog( lifeId )
{
self thread remoteDogStartup(); // Kick of main UAV loop.
msg = self waittill_any_return( "death", "cleanup_remote_dog" ); // Wait for death or timeout.
if( msg == "cleanup_remote_dog" )
{
// Wait for weapon transition to happen.
wait 2.0;
}
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogPlayerEventListenerThread()
{
self waittill( "exit_remote_dog" );
self.remotedog notify( "exit_remote_dog" );
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogStartup()
{
self endon( "death" );
self endon( "remote_dog_time_is_up" );
self endon( "remote_dog_out_of_ammo" );
// self NotifyOnPlayerCommand( "switch_to_remote_dog", "+actionslot 4" );
self DisableOffhandWeapons();
self._dogPlayerOrigin = self GetOrigin();
self._dogPlayerAngles = self GetPlayerAngles();
// Wait for transition anim to finish.
wait 1.75;
// Enter the Dawg.
pos = self._dogPlayerOrigin + ( 0, 0, 50 );
// setup vehicle
self.remotedog = spawnVehicle( level._remoteDogVehicleModel, "test_dog", level._remoteDogVehicleInfo, pos, self._dogPlayerAngles );
self.remotedog.health = level._remoteDogHealth;
self.remotedog.maxhealth = self.remotedog.health;
self.remotedog setCanDamage( true );
self.remotedog.owner = self;
self.remotedog.team = self.team;
self.remotedog.ammo = level._remoteDogAmmo;
self.remotedog.fireRate = level._remoteDogFireRate;
self.remotedog.damageCallback = ::Callback_DogDamage;
// hide the remote dog, we're going to attach another model to it
self.remotedog Hide();
// setup dog model
self.remotedog.remoteDogModel = spawn( "script_model", pos );
self.remotedog.remoteDogModel.owner = self;
self.remotedog.remoteDogModel setModel( level._remoteDogScriptModel );
self.remotedog.remoteDogModel ScriptModelPlayAnim( level._remoteDogIdleAnim );
self.remotedog.remoteDogModel.angles = self._dogPlayerAngles;
self.remotedog.currAnim = level._remoteDogIdleAnim;
self.remotedog.remoteDogModel linkto( self.remotedog );
// setup hud and stuff
self.remotedog notify( "stop_turret_shoot" );
self.in_dog = true;
self thread remotedogHud();
self CameraLinkTo( self.remotedog, "tag_player" );
self.remote_dog_orig_fov = GetDvarFloat( "cg_fov" );
self setClientDvar( "cg_fov", level._remoteDogFOV );
self ThermalVisionFOFOverlayOn();
self visionSetNakedForPlayer( "cheat_bw", 0 );
// create the turret for the dawg
turretPoint = self.remotedog getTagOrigin( "TAG_TURRET" );
self.remotedog.turret = spawnTurret( "misc_turret", turretPoint, level._remoteDogTurretInfo );
self.remotedog.turret linkTo( self.remotedog, "TAG_TURRET", (0,0,0), (0,0,0) );
self.remotedog.turret setModel( level._remoteDogTurretModel );
self.remotedog.turret.angles = self.remotedog.angles;
self.remotedog.turret.owner = self.remotedog.owner;
self.remotedog.turret makeTurretInoperable();
self.remotedog.turret SetDefaultDropPitch( 0 );
//self.remotedog.turret.owner = self;
// find a point to for the turret to look at when it isn't trying to fire
offset = turretPoint - self.remotedog.origin;
neutralTargetEnt = spawn("script_origin", self.remotedog.turret getTagOrigin("tag_flash") );
neutralTargetEnt linkTo( self, "tag_origin", offset, (0,0,0) );
neutralTargetEnt hide();
self.remotedog.neutralTarget = neutralTargetEnt;
// spawn a thread to control the turret
self.remotedog thread remoteDogFindTargets();
// get them controls hooked up!
// self ControlsLinkTo( self.remotedog );
self MiniUAVOn( self.remotedog );
// Kick off timer.
self hudRemoteDogTimer( DOG_TIMEOUT_SEC );
self.remotedog thread RemoteDogWaitForTimeout( DOG_TIMEOUT_SEC );
// loop for the dog
self thread remoteDogLoop( self.remotedog );
// setup a thread to listen for the exit
self thread remoteDogPlayerEventListenerThread();
self.remotedog thread remoteDogExitCleanup();
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogExitCleanup()
{
remoteDogDebugPrint( "remoteDogExitCleanup()" );
msg = self waittill_any_return( "death", "exit_remote_dog", "remote_dog_time_is_up", "remote_dog_out_of_ammo" ); // Wait for either way of exiting a uav.
remoteDogDebugPrint( "Running cleanup after msg " + msg );
self.owner thread remoteDogExitPlayer();
self notify( "cleanup_remote_dog" );
self.owner notify( "cleanup_remote_dog" );
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogFindTargets()
{
self endon( "death" );
self endon( "cleanup_remote_dog" );
println( "Geting Targets" );
for ( ;; )
{
targets = [];
players = level._players;
for (i = 0; i <= players.size; i++)
{
if ( isDogTarget( players[i] ) && isdefined( players[i] ) )
{
targets[targets.size] = players[i];
}
else
{
continue;
}
wait( .05 );
}
if ( targets.size > 0 )
{
self acquireTarget( targets );
return;
}
else
{
wait( .05 );
}
}
}
//*******************************************************************
// *
// *
//*******************************************************************
isDogTarget( potentialTarget )
{
self endon( "death" );
if ( !isalive( potentialTarget ) || potentialTarget.sessionstate != "playing" )
return false;
if ( !isdefined( potentialTarget.pers["team"] ) )
return false;
if ( potentialTarget == self.owner )
return false;
if ( distanceSquared( potentialTarget.origin , self.origin ) > DOG_TURRET_MAX_TARGETING_RANGE*DOG_TURRET_MAX_TARGETING_RANGE )
return false;
if ( level._teamBased && potentialTarget.pers["team"] == self.team )
return false;
if ( potentialTarget.pers["team"] == "spectator" )
return false;
if ( isdefined( potentialTarget.spawntime ) && ( gettime() - potentialTarget.spawntime )/1000 <= DOG_TURRET_SPAWN_GRACE_TIME )
return false;
// check to see if they are in our yaw range
vecToTarget = potentialTarget.origin - self.origin;
targetYaw = AngleClamp( VectorToYaw( vecToTarget ) );
turretYaw = AngleClamp( self.angles[1] );
degrees = abs( targetYaw - self.angles[1] );
degrees = AngleClamp( degrees );
if( degrees > DOG_TURRET_MAX_YAW && ( 360 - degrees ) > DOG_TURRET_MAX_YAW )
{
// println( "bad degrees " + degrees + " angles " + turretYaw + " target yaw " + targetYaw );
return false;
}
// println( "good degrees " + degrees + " angles " + turretYaw + " target yaw " + targetYaw );
if ( isDefined( self ) )
{
minTurretEye = self.turret.origin + ( 0, 0, 64 );
minTurretCanSeeTarget = potentialTarget sightConeTrace( minTurretEye, self );
if ( minTurretCanSeeTarget < 1 )
return false;
}
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
getBestTarget( targets )
{
self endon( "death" );
origin = self.origin;
closest = undefined;
bestTarget = undefined;
foreach ( targ in targets )
{
curDist = Distance( self.origin, targ.origin );
if ( !isDefined( closest ) )
{
closest = curDist;
bestTarget = targ;
}
else if ( closest > curDist )
{
closest = curDist;
bestTarget = targ;
}
}
return ( bestTarget );
}
//*******************************************************************
// *
// *
//*******************************************************************
acquireTarget( targets )
{
self endon( "death" );
if ( targets.size == 1 )
{
self.bestTarget = targets[0];
}
else
{
self.bestTarget = self getBestTarget( targets );
}
self notify( "acquiringTarget" );
self.turret SetTargetEntity( self.bestTarget, ( 0,0,42 ) ); // sets turret to target entity
wait( .15 );
self thread fireOnTarget(); // fires on current target.
self thread watchTargetDeath( targets ); //abandons target when target killed
self thread watchTargetDistance( targets );
self thread watchTargetAngle( targets );
self thread watchTargetThreat( self.bestTarget );
}
//*******************************************************************
// *
// *
//*******************************************************************
fireOnTarget()
{
self endon( "death" );
self endon( "abandonedTarget" );
self endon( "killedTarget" );
noTargTime = undefined;
acquiredTime = getTime();
if ( !isDefined( self.bestTarget ) )
{
println("No Targ to fire on");
return;
}
println("firing on best target");
while( 1 )
{
if ( !isDefined ( self.turret getTurretTarget( true ) ) )
{
if ( !isDefined( noTargTime ) )
noTargTime = getTime();
curTime = getTime();
if ( noTargTime - curTime > 1 )
{
noTargTime = undefined;
self thread explicitAbandonTarget();
return;
}
println("Waiting because the turret doesnt have a target" );
wait ( .5 );
continue;
}
numShots = randomIntRange( DOG_TURRET_MIN_SHOTS, DOG_TURRET_MAX_SHOTS );
for ( i = 0; i < numShots; i++ )
{
println( "actually shooting turret" );
self.turret ShootTurret();
wait ( DOG_TURRET_FIRE_DELAY );
}
wait ( randomFloatRange( DOG_TURRET_MIN_BARRAGE_DELAY, DOG_TURRET_MAX_BARRAGE_DELAY ) );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
watchTargetDeath( targets )
{
self endon( "abandonedTarget" );
self endon( "death" );
if ( !isDefined( self.bestTarget ) )
return;
self.bestTarget waittill( "death" );
self notify( "killedTarget" );
println( "Killed Target" );
self.bestTarget = undefined;
self.turret ClearTargetEntity();
self remoteDogFindTargets();
}
//*******************************************************************
// *
// *
//*******************************************************************
watchTargetAngle( targets )
{
self endon( "abandonedTarget" );
self endon( "death" );
for ( ;; )
{
if ( !isDefined( self.bestTarget ) )
return;
// check to see if they are in our yaw range
vecToTarget = self.bestTarget.origin - self.origin;
targetYaw = AngleClamp( VectorToYaw( vecToTarget ) );
turretYaw = AngleClamp( self.angles[1] );
degrees = abs( targetYaw - self.angles[1] );
degrees = AngleClamp( degrees );
if( degrees > DOG_TURRET_MAX_YAW && ( 360 - degrees ) > DOG_TURRET_MAX_YAW )
{
println( "Abandon! degrees " + degrees + " angles " + self.angles[1] + " target yaw " + targetYaw );
self thread explicitAbandonTarget();
return;
}
wait ( 0.5 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
watchTargetDistance( targets )
{
self endon( "abandonedTarget" );
self endon( "death" );
for ( ;; )
{
if ( !isDefined( self.bestTarget ) )
return;
trace = BulletTrace( self.turret.origin, self.bestTarget.origin, false, self );
traceDistance = Distance(self.origin, trace["position"] );
if ( traceDistance > DOG_TURRET_MAX_TARGETING_RANGE )
{
println( "TARGET DIST TOO FAR!!!" );
self thread explicitAbandonTarget();
return;
}
println( traceDistance );
wait ( 2 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
watchTargetThreat( curTarget )
{
self endon( "abandonedTarget" );
self endon( "death" );
self endon( "killedTarget" );
for ( ;; )
{
targets = [];
players = level._players;
for (i = 0; i <= players.size; i++)
{
if ( isDogTarget( players[i] ) )
{
if( !isdefined( players[i] ) )
continue;
if( !isdefined(curTarget) )
return;
traceOldTarg = Distance(self.origin, CurTarget.origin );
traceNewTarg = Distance(self.origin, players[i].origin );
if ( traceNewTarg < traceOldTarg )
{
self thread explicitAbandonTarget();
return;
}
}
wait( .05 );
}
wait( .25 );
}
}
explicitAbandonTarget( noNewTarget )
{
self notify( "abandonedTarget" );
println( "ABANDONED TARGET" );
self.bestTarget = undefined;
self.turret ClearTargetEntity();
if ( isDefined(noNewTarget) && noNewTarget )
return;
self thread remoteDogFindTargets();
return;
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogLoop( vehicle )
{
self endon( "death" );
vehicle endon( "cleanup_remote_dog" );
self NotifyOnPlayerCommand( "exit_remote_dog", "+usereload" ); // BUTTON_X
vehicle._oldOrigin = vehicle.origin;
vehicle.fireCycle = 0;
while ( isalive( self ) )
{
if( vehicle.fireCycle > 0 )
{
vehicle.fireCycle = vehicle.fireCycle - 1;
}
// steal the player's angles to control turning the dog, for now...
angles = vehicle.angles;
player_angles = self GetPlayerAngles();
angles = ( player_angles[0], angles[1], angles[2] );
target = vehicle.origin + vector_multiply( AnglesToForward( angles ), 2000.0 );
// don't do this anymore, the turret is auto targetting now
// vehicle SetTurretTargetVec( target );
vehicle.remoteDogModel.angels = vehicle.angles;
// no more attack buttons to shoot
/*
if( self AttackButtonPressed() )
{
if( vehicle.ammo > 0 && vehicle.fireCycle == 0)
{
vehicle fireweapon();
vehicle.fireCycle = vehicle.fireRate;
vehicle.ammo = vehicle.ammo - 1;
// out of ammo! lets get out of this thing!
if( vehicle.ammo == 0 )
{
self thread remotedogOutOfAmmoThead( vehicle );
}
}
}
*/
if( distance( vehicle._oldOrigin, vehicle.origin ) > 0 )
{
if( vehicle.currAnim != level._remoteDogMoveAnim )
{
vehicle.remoteDogModel ScriptModelPlayAnim( level._remoteDogMoveAnim );
vehicle.currAnim = level._remoteDogMoveAnim;
}
}
else
{
if( vehicle.currAnim != level._remoteDogIdleAnim )
{
vehicle.remoteDogModel ScriptModelPlayAnim( level._remoteDogIdleAnim );
vehicle.currAnim = level._remoteDogIdleAnim;
}
}
vehicle._oldOrigin = vehicle.origin;
wait 0.1;
}
}
//*******************************************************************
// *
// *
//*******************************************************************
remotedogOutOfAmmoThead( vehicle )
{
remoteDogDebugPrint( "remotedogOutOfAmmoThead() out of ammo!" );
vehicle endon( "cleanup_remote_dog" );
wait 2;
vehicle notify( "remote_dog_out_of_ammo" );
}
//*******************************************************************
// *
// *
//*******************************************************************
Callback_DogDamage( inflictor, attacker, damage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName )
{
remoteDogDebugPrint( "damage callback" );
if ( ( attacker == self || ( isDefined( attacker.pers ) && attacker.pers["team"] == self.team ) ) && attacker != self.owner )
return;
remoteDogDebugPrint( "damaged dog! " + damage );
self Vehicle_FinishDamage( inflictor, attacker, damage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName );
}
//*******************************************************************
// *
// *
//*******************************************************************
remoteDogExitPlayer()
{
// cleanup the models
self.remotedog.remoteDogModel Unlink();
self.remotedog.remoteDogModel Delete();
// cleanup the actual things
self.remotedog.turret Delete();
self.remotedog Delete();
self ThermalVisionFOFOverlayOff();
self CameraUnlink();
self setClientDvar( "cg_fov", self.remote_dog_orig_fov );
self MiniUAVOff();
// self ControlsUnlink();
self visionSetNakedForPlayer( getDvar( "mapname" ), 0 );
self setVelocity(( 0, 0, 0 ));
self setOrigin( self._dogPlayerOrigin );
self setPlayerAngles( self._dogPlayerAngles );
self switchToWeapon( self._pre_killstreak_weapon_name );
self destroyRemoteDogTimer();
wait 2.0;
self EnableOffhandWeapons();
self.in_dog = false;
}
//*******************************************************************
// *
// *
//*******************************************************************
remotedogHud()
{
/*
crossHair = newClientHudElem( self );
crossHair.x = 0;
crossHair.y = 0;
crossHair.alignX = "center";
crossHair.alignY = "middle";
crossHair.horzAlign = "center";
crossHair.vertAlign = "middle";
crossHair setshader( level._remoteDogCrossHair, 640, 480 );
static = NewClientHudElem( self );
static.horzAlign = "fullscreen";
static.vertAlign = "fullscreen";
static SetShader( "ac130_overlay_grain", 640, 480 );
self waittill( "cleanup_remote_dog" ); // Wait for either way of exiting a uav.
crossHair Destroy();
*/
}
//*******************************************************************
// *
// *
//*******************************************************************
hudRemoteDogTimer( duration )
{
remoteDogDebugPrint( "hudRemoteDogTimer()" );
self.remoteDogTimer = newClientHudElem( self );
self.remoteDogTimer.x = DOG_HUD_TIMER_POS_X;
self.remoteDogTimer.y = DOG_HUD_TIMER_POS_Y;
self.remoteDogTimer.alignX = "center";
self.remoteDogTimer.alignY = "bottom";
self.remoteDogTimer.horzAlign = "center_adjustable";
self.remoteDogTimer.vertAlign = "bottom_adjustable";
self.remoteDogTimer.fontScale = 2.5;
self.remoteDogTimer setTimer( 1.0 );
self.remoteDogTimer.alpha = 1.0;
self.remoteDogTimer setTimer( duration );
println( "done setting hud timer" );
}
//*******************************************************************
// *
// *
//*******************************************************************
RemoteDogWaitForTimeout( duration )
{
self endon( "cleanup_remote_dog" );
wait duration;
remoteDogDebugPrint( "RemoteDogWaitForTimeout() Time's up!" );
self notify( "remote_dog_time_is_up" );
self._time_is_up = 1;
}
//*******************************************************************
// *
// *
//*******************************************************************
destroyRemoteDogTimer()
{
remoteDogDebugPrint( "cleanup timer!" );
self.remoteDogTimer Destroy();
}
/*
QUAKED script_vehicle_nx_miniuav_player_mp (1 0 0) (-16 -16 -24) (16 16 32) USABLE SPAWNER
put this in your GSC:
maps\mp\killstreaks\_miniuav::main( "nx_vehicle_miniuav" );
and these lines in your CSV:
include,nx_vehicle_miniuav_player
defaultmdl="nx_vehicle_miniuav"
default:"vehicletype" "nx_miniuav_player"
default:"script_team" "allies"
*/

View File

@ -0,0 +1,461 @@
#include maps\mp\_utility;
#include common_scripts\utility;
init()
{
mapname = getDvar( "mapname" );
if ( mapname == "mp_suburbia" )
{
level._missileRemoteLaunchVert = 7000;
level._missileRemoteLaunchHorz = 10000;
level._missileRemoteLaunchTargetDist = 2000;
}
else if ( mapname == "mp_mainstreet" )
{
level._missileRemoteLaunchVert = 7000;
level._missileRemoteLaunchHorz = 10000;
level._missileRemoteLaunchTargetDist = 2000;
}
else
{
level._missileRemoteLaunchVert = 14000;
level._missileRemoteLaunchHorz = 7000;
level._missileRemoteLaunchTargetDist = 1500;
}
precacheItem( "remotemissile_projectile_mp" );
precacheShader( "ac130_overlay_grain" );
precacheString( &"MP_CIVILIAN_AIR_TRAFFIC" );
level._rockets = [];
level._killstreakFuncs["predator_missile"] = ::tryUsePredatorMissile;
level._killstreakFuncs["predator_marker"] = ::tryUsePredatorMarker;
level._missilesForSightTraces = [];
}
tryUsePredatorMarker( lifeId )
{
//okToUsePredatorMarker = true;
//level endon( "game_ended" );
//self endon( "death" );
//println( "Got off" );
//if (okToUsePredatorMarker == true)
//{
self usePredatorMarker();
return true;
//}
//msg = self waittill_any_return( "pred_grenade_thrown" );
//if ( msg != "pred_grenade_thrown" )
// self switchToOffhand( grenade );
//return false;
}
usePredatorMarker()
{
level endon( "game_ended" );
self endon( "death" );
self endon("disconnect");
ognade = self GetCurrentOffhand();
ognadeCount = self GetWeaponAmmoClip(ognade);
self SetWeaponAmmoClip( ognade, 0 );
self _giveWeapon("pred_grenade_mp");
//println( "gave pred" );
self thread waitForPredatorMarker( ognade, ognadeCount );
}
waitForPredatorMarker( nadeId, nadeCount){
level endon( "game_ended" );
self endon( "death" );
self endon("disconnect");
for(;;)
{
self waittill( "grenade_fire", grenade, weaponName );
//println( weaponName );
if( weaponName == "pred_grenade_mp" )
{
break;
}
}
if (nadeCount > 0)
{
self _giveWeapon(nadeId);
//println( "gave grenade back" );
}
}
/*
dontLosePredMarker()
{
self endon( "grenade_fire");
self waittill("death");
println( "in dontLose FOR" );
predNadeCheck = self GetCurrentOffhand();
predNadeCount = self GetWeaponAmmoClip(predNadeCheck);
if ( predNadeCheck != "pred_grenade_mp" && predNadeCount != 1 )
{
self SetWeaponAmmoClip( "pred_grenade_mp" , 1 );
println( "not gonna lose it!" );
}
}
*/
tryUsePredatorMissile( lifeId )
{
if ( isDefined( level._civilianJetFlyBy ) )
{
self iPrintLnBold( &"MP_CIVILIAN_AIR_TRAFFIC" );
return false;
}
self setUsingRemote( "remotemissile" );
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak();
if ( result != "success" )
{
if ( result != "disconnect" )
self clearUsingRemote();
return false;
}
level thread _fire( lifeId, self );
return true;
}
getBestSpawnPoint( remoteMissileSpawnPoints )
{
validEnemies = [];
foreach ( spawnPoint in remoteMissileSpawnPoints )
{
spawnPoint.validPlayers = [];
spawnPoint.spawnScore = 0;
}
foreach ( player in level._players )
{
if ( !isReallyAlive( player ) )
continue;
if ( player.team == self.team )
continue;
if ( player.team == "spectator" )
continue;
bestDistance = 999999999;
bestSpawnPoint = undefined;
foreach ( spawnPoint in remoteMissileSpawnPoints )
{
//could add a filtering component here but i dont know what it would be.
spawnPoint.validPlayers[spawnPoint.validPlayers.size] = player;
potentialBestDistance = Distance2D( spawnPoint.targetent.origin, player.origin );
if ( potentialBestDistance <= bestDistance )
{
bestDistance = potentialBestDistance;
bestSpawnpoint = spawnPoint;
}
}
assertEx( isDefined( bestSpawnPoint ), "Closest remote-missile spawnpoint undefined for player: " + player.name );
bestSpawnPoint.spawnScore += 2;
}
bestSpawn = remoteMissileSpawnPoints[0];
foreach ( spawnPoint in remoteMissileSpawnPoints )
{
foreach ( player in spawnPoint.validPlayers )
{
spawnPoint.spawnScore += 1;
if ( bulletTracePassed( player.origin + (0,0,32), spawnPoint.origin, false, player ) )
spawnPoint.spawnScore += 3;
if ( spawnPoint.spawnScore > bestSpawn.spawnScore )
{
bestSpawn = spawnPoint;
}
else if ( spawnPoint.spawnScore == bestSpawn.spawnScore ) // equal spawn weights so we toss a coin.
{
if ( coinToss() )
bestSpawn = spawnPoint;
}
}
}
return ( bestSpawn );
}
drawLine( start, end, timeSlice, color )
{
drawTime = int(timeSlice * 20);
for( time = 0; time < drawTime; time++ )
{
line( start, end, color,false, 1 );
wait ( 0.05 );
}
}
_fire( lifeId, player )
{
remoteMissileSpawnArray = getEntArray( "remoteMissileSpawn" , "targetname" );
//assertEX( remoteMissileSpawnArray.size > 0 && getMapCustom( "map" ) != "", "No remote missile spawn points found. Contact friendly neighborhood designer" );
foreach ( spawn in remoteMissileSpawnArray )
{
if ( isDefined( spawn.target ) )
spawn.targetEnt = getEnt( spawn.target, "targetname" );
}
if ( remoteMissileSpawnArray.size > 0 )
remoteMissileSpawn = player getBestSpawnPoint( remoteMissileSpawnArray );
else
remoteMissileSpawn = undefined;
if ( isDefined( remoteMissileSpawn ) )
{
startPos = remoteMissileSpawn.origin;
targetPos = remoteMissileSpawn.targetEnt.origin;
//thread drawLine( startPos, targetPos, 30, (0,1,0) );
vector = vectorNormalize( startPos - targetPos );
startPos = vector_multiply( vector, 14000 ) + targetPos;
//thread drawLine( startPos, targetPos, 15, (1,0,0) );
rocket = MagicBullet( "remotemissile_projectile_mp", startpos, targetPos, player );
}
else
{
upVector = (0, 0, level._missileRemoteLaunchVert );
backDist = level._missileRemoteLaunchHorz;
targetDist = level._missileRemoteLaunchTargetDist;
forward = AnglesToForward( player.angles );
startpos = player.origin + upVector + forward * backDist * -1;
targetPos = player.origin + forward * targetDist;
rocket = MagicBullet( "remotemissile_projectile_mp", startpos, targetPos, player );
}
if ( !IsDefined( rocket ) )
{
player clearUsingRemote();
return;
}
rocket thread maps\mp\gametypes\_weapons::AddMissileToSightTraces( player.team );
rocket thread handleDamage();
rocket.lifeId = lifeId;
rocket.type = "remote";
MissileEyes( player, rocket );
}
/#
_fire_noplayer( lifeId, player )
{
upVector = (0, 0, level._missileRemoteLaunchVert );
backDist = level._missileRemoteLaunchHorz;
targetDist = level._missileRemoteLaunchTargetDist;
forward = AnglesToForward( player.angles );
startpos = player.origin + upVector + forward * backDist * -1;
targetPos = player.origin + forward * targetDist;
rocket = MagicBullet( "remotemissile_projectile_mp", startpos, targetPos, player );
if ( !IsDefined( rocket ) )
return;
rocket thread handleDamage();
rocket.lifeId = lifeId;
rocket.type = "remote";
player CameraLinkTo( rocket, "tag_origin" );
player ControlsLinkTo( rocket );
rocket thread Rocket_CleanupOnDeath();
wait ( 2.0 );
player ControlsUnlink();
player CameraUnlink();
}
#/
handleDamage()
{
self endon ( "death" );
self endon ( "deleted" );
self setCanDamage( true );
for ( ;; )
{
self waittill( "damage" );
println ( "projectile damaged!" );
}
}
MissileEyes( player, rocket )
{
//level endon ( "game_ended" );
player endon ( "joined_team" );
player endon ( "joined_spectators" );
rocket thread Rocket_CleanupOnDeath();
player thread Player_CleanupOnGameEnded( rocket );
player thread Player_CleanupOnTeamChange( rocket );
player VisionSetMissilecamForPlayer( "black_bw", 0 );
player endon ( "disconnect" );
if ( isDefined( rocket ) )
{
player VisionSetMissilecamForPlayer( game["thermal_vision"], 1.0 );
player thread delayedFOFOverlay();
player CameraLinkTo( rocket, "tag_origin" );
player ControlsLinkTo( rocket );
if ( getDvarInt( "camera_thirdPerson" ) )
player setThirdPersonDOF( false );
rocket waittill( "death" );
// is defined check required because remote missile doesnt handle lifetime explosion gracefully
// instantly deletes its self after an explode and death notify
if ( isDefined(rocket) )
player maps\mp\_matchdata::logKillstreakEvent( "predator_missile", rocket.origin );
player ControlsUnlink();
player freezeControlsWrapper( true );
// If a player gets the final kill with a hellfire, level.gameEnded will already be true at this point
if ( !level._gameEnded || isDefined( player.finalKill ) )
player thread staticEffect( 0.5 );
wait ( 0.5 );
player ThermalVisionFOFOverlayOff();
player CameraUnlink();
if ( getDvarInt( "camera_thirdPerson" ) )
player setThirdPersonDOF( true );
}
player clearUsingRemote();
}
delayedFOFOverlay()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
wait ( 0.15 );
self ThermalVisionFOFOverlayOn();
}
staticEffect( duration )
{
self endon ( "disconnect" );
staticBG = newClientHudElem( self );
staticBG.horzAlign = "fullscreen";
staticBG.vertAlign = "fullscreen";
staticBG setShader( "white", 640, 480 );
staticBG.archive = true;
staticBG.sort = 10;
static = newClientHudElem( self );
static.horzAlign = "fullscreen";
static.vertAlign = "fullscreen";
static setShader( "ac130_overlay_grain", 640, 480 );
static.archive = true;
static.sort = 20;
wait ( duration );
static destroy();
staticBG destroy();
}
Player_CleanupOnTeamChange( rocket )
{
rocket endon ( "death" );
self endon ( "disconnect" );
self waittill_any( "joined_team" , "joined_spectators" );
if ( self.team != "spectator" )
{
self ThermalVisionFOFOverlayOff();
self ControlsUnlink();
self CameraUnlink();
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( true );
}
self clearUsingRemote();
level._remoteMissileInProgress = undefined;
}
Rocket_CleanupOnDeath()
{
entityNumber = self getEntityNumber();
level._rockets[ entityNumber ] = self;
self waittill( "death" );
level._rockets[ entityNumber ] = undefined;
}
Player_CleanupOnGameEnded( rocket )
{
rocket endon ( "death" );
self endon ( "death" );
level waittill ( "game_ended" );
self ThermalVisionFOFOverlayOff();
self ControlsUnlink();
self CameraUnlink();
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( true );
}

View File

@ -0,0 +1,334 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
init()
{
precacheString( &"MP_LASE_TARGET_FOR_GUIDED_MORTAR" );
precacheString( &"MP_WAIT_FOR_MORTAR_READY" );
precacheString( &"MP_MORTAR_ROUNDS_DEPLETED" );
precacheItem( "remote_mortar_missile_mp" );
PreCacheItem( "mortar_remote_mp" );
level._remote_mortar_fx["tracer"] = loadFx( "misc/tracer_incoming" );
level._remote_mortar_fx["explosion"] = loadFx( "explosions/building_explosion_huge_gulag" );
level._effect[ "laserTarget" ] = loadfx("nx/misc/nx_laser_glow");
level._killstreakFuncs["remote_mortar"] = ::tryUseRemoteMortar;
}
tryUseRemoteMortar( lifeId )
{
if ( isDefined( self.lastStand ) && !self _hasPerk( "specialty_finalstand" ) )
{
self iPrintLnBold( &"MP_UNAVILABLE_IN_LASTSTAND" );
return false;
}
self setUsingRemote( "remote_mortar" );
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak();
if ( result != "success" )
{
if ( result != "disconnect" )
self clearUsingRemote();
return false;
}
self thread teamPlayerCardSplash( "used_remote_mortar", self );
return startRemoteMortar( lifeId );
}
startRemoteMortar( lifeId )
{
remote = spawnRemote( lifeId, self );
if ( !isDefined( remote ) )
return false;
self thread linkRemoteTargeting( remote );
self maps\mp\_matchdata::logKillstreakEvent( "remote_mortar", self.origin );
return true;
}
spawnRemote( lifeId, owner )
{
remote = spawnplane( owner, "script_model", level._UAVRig getTagOrigin( "tag_origin" ) );
if ( !isDefined( remote ) )
return undefined;
remote setModel( "vehicle_uav_static_mp" );
remote thread maps\mp\killstreaks\_uav::damageTracker( false );
remote.team = owner.team;
remote.owner = owner;
remote.lifeId = lifeId;
remote.heliType = "remote_mortar";
remote thread maps\mp\killstreaks\_helicopter::heli_flares_monitor();
maps\mp\killstreaks\_uav::addUAVModel( remote );
// 3000, 4000, and 6500 are all average numbers pulled from the random ranges UAV uses
// since the player's camera is linked to this vehicle, we want to control the location
zOffset = 3000;
angle = 0;
radiusOffset = 4000;
xOffset = cos( angle ) * radiusOffset;
yOffset = sin( angle ) * radiusOffset;
angleVector = vectorNormalize( (xOffset,yOffset,zOffset) );
angleVector = ( angleVector * 6500 );
remote linkTo( level._UAVRig, "tag_origin", angleVector, (0,angle-90,0) );
remote thread handleDeath( owner );
remote thread handleTimeout( owner );
remote thread handleOwnerDisconnect( owner );
return remote;
}
showLazeMessage( remote, state, time )
{
level endon( "game_ended" );
self endon ( "disconnect" );
remote endon ( "death" );
self notify( "showing_laze_message" );
self endon( "showing_laze_message" );
if ( isDefined( remote.msg ) )
remote.msg destroyElem();
text = "";
switch( state )
{
case "ready":
text = &"MP_LASE_TARGET_FOR_GUIDED_MORTAR";
color = (0.2, 1.0, 0.2);
break;
case "wait":
text = &"MP_WAIT_FOR_MORTAR_READY";
color = (0.8, 0.8, 0.2);
break;
case "done":
text = &"MP_MORTAR_ROUNDS_DEPLETED";
color = (1.0, 0.2, 0.2);
break;
default:
return;
}
remote.msg = self maps\mp\gametypes\_hud_util::createFontString( "objective", 1.5 );
remote.msg maps\mp\gametypes\_hud_util::setPoint( "CENTER", "CENTER", 0 , 150 );
remote.msg setText( text );
remote.msg.color = color;
if ( !isDefined( time ) )
time = 2.0;
wait( time );
if ( isDefined( remote.msg ) )
remote.msg destroyElem();
}
lookCenter()
{
wait( 0.05 );
lookVec = vectorToAngles( level._UAVRig.origin - self GetEye() );
self setPlayerAngles( lookVec );
}
linkRemoteTargeting( remote )
{
level endon( "game_ended" );
self endon( "disconnect" );
remote endon( "helicopter_done" );
remote endon( "death" );
self VisionSetThermalForPlayer( game["thermal_vision"], 0 );
self _giveWeapon("mortar_remote_mp");
self SwitchToWeapon("mortar_remote_mp");
self ThermalVisionOn();
self ThermalVisionFOFOverlayOn();
self thread maps\mp\killstreaks\_helicopter::thermalVision( remote );
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( false );
self PlayerLinkWeaponviewToDelta( remote, "tag_player", 1.0, 180, 180, 0, 180, true );
self thread lookCenter();
remote thread maps\mp\killstreaks\_helicopter::heli_targeting();
self thread maps\mp\killstreaks\_helicopter::weaponLockThink( remote );
// msg
self thread showLazeMessage( remote, "ready", 5 );
// fire
shotsFired = 0;
while ( true )
{
if ( self attackButtonPressed() )
{
origin = self GetEye();
forward = AnglesToForward( self GetPlayerAngles() );
endpoint = origin + forward * 15000;
traceData = BulletTrace( origin, endpoint, true, self );
if ( isDefined( traceData["position"] ) )
{
self playLocalSound( "stinger_locking" );
self PlayRumbleOnEntity( "ac130_25mm_fire" );
remote.fxEnt = SpawnFx( level._effect[ "laserTarget" ], traceData["position"] );
TriggerFx( remote.fxEnt );
// wait ( 1.0 );
self thread launchMortar( remote, traceData["position"] );
shotsFired++;
if ( shotsFired < 3 )
{
self thread showLazeMessage( remote, "wait" );
wait( 2.0 );
remote.fxEnt delete();
self thread showLazeMessage( remote, "ready" );
}
else
{
self thread showLazeMessage( remote, "wait" );
wait( 2.0 );
remote.fxEnt delete();
self thread showLazeMessage( remote, "done" );
wait( 2.0 );
break;
}
}
else
wait( 0.05 );
}
else
wait( 0.05 );
}
self unlinkRemoteTargeting();
remote thread remoteLeave();
}
launchMortar( remote, pos )
{
PlayFx( level._remote_mortar_fx["tracer"], pos );
thread playSoundinSpace( "fast_artillery_round", pos );
wait( 1 );
PlayFx( level._remote_mortar_fx["explosion"], pos );
Earthquake( 1.0, 0.6, pos, 2000 );
thread playSoundinSpace( "exp_suitcase_bomb_main", pos );
physicsExplosionSphere( pos + (0,0,30), 250, 125, 2 );
if ( isDefined( self ) )
remote RadiusDamage( pos, 400, 200, 50, self, "MOD_EXPLOSIVE", "remote_mortar_missile_mp" );
else
remote RadiusDamage( pos, 400, 200, 50, undefined, "MOD_EXPLOSIVE", "remote_mortar_missile_mp" );
}
unlinkRemoteTargeting()
{
self RemoteCameraSoundscapeOff();
self ThermalVisionOff();
self ThermalVisionFOFOverlayOff();
self unlink();
self clearUsingRemote();
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( true );
self visionSetThermalForPlayer( game["thermal_vision"], 0 );
self switchToWeapon( self getLastWeapon() );
weaponList = self GetWeaponsListExclusives();
foreach ( weapon in weaponList )
self takeWeapon( weapon );
}
handleTimeout( owner )
{
level endon( "game_ended" );
owner endon( "disconnect" );
self endon( "death" );
self endon( "helicopter_done" );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 45.0 );
if ( isDefined( owner ) )
owner unlinkRemoteTargeting();
self thread remoteLeave();
}
handleDeath( owner )
{
level endon( "game_ended" );
owner endon( "disconnect" );
self endon( "helicopter_done" );
self waittill( "death" );
owner unlinkRemoteTargeting();
forward = ( AnglesToRight( self.angles ) * 200 );
playFx ( level._uav_fx[ "explode" ], self.origin, forward );
level thread removeRemote( self );
self notify( "helicopter_done" );
}
handleOwnerDisconnect( owner )
{
level endon( "game_ended" );
owner endon( "death" );
self endon( "death" );
owner waittill( "disconnect" );
self thread remoteLeave();
}
removeRemote( remote )
{
if ( isDefined( remote.msg ) )
remote.msg destroyElem();
if ( isDefined( remote.fxEnt ) )
remote.fxEnt delete();
remote delete();
maps\mp\killstreaks\_uav::removeUAVModel( remote );
}
remoteLeave()
{
level endon( "game_ended" );
self endon( "death" );
self notify( "helicopter_done" );
self unlink();
destPoint = self.origin + ( AnglesToForward( self.angles ) * 20000 );
self moveTo( destPoint, 60 );
PlayFXOnTag( level._effect[ "ac130_engineeffect" ] , self, "tag_origin" );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 3 );
self moveTo( destPoint, 4, 4, 0.0 );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 4 );
level thread removeRemote( self );
}

View File

@ -0,0 +1,816 @@
#include maps\mp\_utility;
#include common_scripts\utility;
//****************************************************************************
// **
// Confidential - (C) Activision Publishing, Inc. 2010 **
// **
//****************************************************************************
// **
// Module: Prototype killstreak - Roboturret **
// Once the killstreak is deployed, it will follow the player **
// around the map and kill enemies. **
// **
// Created: May 31th, 2011 - James Chen **
// **
//***************************************************************************/
//tagJC<NOTE>: The current implementation consists of three components: one very small joint as vehicle serving as the connecting
// base for the turret and the legs.
//tagJC<TODO>: Known Issues (bugs)
// (1) The animation for the turret is controlled by the another underlying (turret) script. Currently, the turret
// does not play the proper animation when tracking/shooting enemies.
// (2) The robo legs is 90 degree from the correct orientation of the vehicle.
//tagJC<TODO>: Determine a better pathing logic under the current vehicle pathing limitation so the roboturret can really follow
// the players around the level.
init()
{
//tagJC<NOTE>: Precache all the assets needed.
//tagJC<NOTE>: nx_vehicle_roboturret_legs_vehicle is a very small joint which has all the required TAG for a vehicle.
// It is used so the robo legs and the roboturrets can be attached to it and the game will handle it properly
// according to the default vehicle animation.
PrecacheVehicle( "proto_nx_vehicle_roboturret_legs_vehicle" );
precacheModel( "nx_vehicle_roboturret_legs_vehicle" );
//tagJC<NOTE>: nx_vehicle_spider is the robo legs.
PrecacheVehicle( "nx_spider_mp" );
precacheModel( "nx_vehicle_spider" );
//tagJC<NOTE>: nx_ugv_robo_turret is the robo turret.
precacheTurret( "ugv_robo_turret_mp" );
precacheModel( "nx_ugv_robo_turret" );
//tagJC<NOTE>: These are the animations for the robo legs.
precacheMpAnim( "nx_vh_roboturret_run" );
precacheMpAnim( "nx_vh_roboturret_walk" );
precacheMpAnim( "nx_vh_roboturret_idle" );
//level._spiderSpawners = Vehicle_GetSpawnerArray();
//tagJC<NOTE>: This is the killstreak activation callback for the roboturret.
level._killstreakFuncs["spider"] = ::try_use_killstreak;
//tagJC<NOTE>: Use this script to update/initialize players as they connect to the game.
level thread onPlayerConnect();
//tagJC<NOTE>: In order for the roboturret to work correctly, the level needs to have at least one "spidernode".
level._spiderNodes = getVehicleNodeArray( "spidernode", "script_noteworthy" );
StartNodeMappingTable();
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Checking whether the level is properly set up for the roboturret killstreak.
try_use_killstreak( lifeId )
{
if ( ! level._spiderNodes.size )
{
self iPrintLnBold( "Spider is currently not supported in this level, bug your friendly neighborhood Level Designer, Failed to locate valid spider node." );
return false;
}
//tagJC<NOTE>: Test script of which any desired testing can be performed before integrated into working prototype.
//testscript();
killstreak_template_use( lifeId );
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: This function creates a mapping table for all the start nodes. It uses the coordinate of the start node as the
// the index for the first dimension of the array. The second dimension of the array stores all the start nodes that
// the current start node can travel to.
StartNodeMappingTable()
{
println( "StartNodeMappingTable" );
level._StartNodeMapping = [];
println( "################################" );
for ( i = 0; i < level._spiderNodes.size; i++ )
{
StartNode = level._spiderNodes[i];
//tagJC<NOTE>: Getting the end node of the path whose start node is StartNode
EndNode = GetVehicleNode( StartNode.target, "targetname" );
//tagJC<NOTE>: Creating the index using the StartNode's coordinate
index = "X" + StartNode.origin[0] + "Y" + StartNode.origin[1] + "Z" + StartNode.origin[2];
println( "The index is " + index );
for ( j = 0; j < level._spiderNodes.size; j++ )
{
TargetStartNode = level._spiderNodes[j];
//tagJC<NOTE>: Store the TargetStartNode into the array if its distance is less than 250 units from the EndNode
if ( distance( EndNode.origin, TargetStartNode.origin ) < 250 )
{
if ( ! IsDefined (level._StartNodeMapping[index]) )
{
level._StartNodeMapping[index][0] = TargetStartNode;
}
else
{
ArraySize = level._StartNodeMapping[index].size;
level._StartNodeMapping[index][ArraySize] = TargetStartNode;
}
}
}
//tagJC<NOTE>: Debugging output to look at the array
println( "There are " + level._StartNodeMapping[index].size + " startnodes connected" );
for ( r = 0; r < level._StartNodeMapping[index].size; r++)
{
println( " The coordinate is " + level._StartNodeMapping[index][r].origin );
}
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Test script for any desired functionality, such as loading model, playing certain animation etc..
// This is to make sure things are working properly before they are integrated into the working prototype.
testscript()
{
}
//*******************************************************************
// *
// *
//*******************************************************************
// tagJC<NOTE>: This is the callback that executes when the killstreak is activated by a player pressing on the dpad.
killstreak_template_use( lifeId )
{
assert( isDefined( self ) );
//tagJC<NOTE>: spawning the small joint as the vehicle and setting the associated attributes.
level._spider = spawnVehicle( "nx_vehicle_roboturret_legs_vehicle", "roboturret", "proto_nx_vehicle_roboturret_legs_vehicle", (0, 0, 0), (0, 0, 0) );
level._spider.health = 3000;
level._spider.targeting_delay = 1;
level._spider.team = self.team;
level._spider.pers["team"] = level._spider.team;
level._spider.owner = self;
level._spider setCanDamage( true );
level._spider.standardSpeed = 10;
level._spider.evadeSpeed = 50;
level._spider.dangerSpeed = 15;
level._spider.miniEngagementSpeed = 15;
level._spider.engagementSpeed = 15;
//tagJC<NOTE>: Kill the vehicle if it is dropped for more than 2048 units
level._spider thread deleteOnZ();
//tagJC<NOTE>: Spawning the robo legs
spiderScriptModel = spawn ( "script_model", level._spider.origin );
spiderScriptModel setModel ( "nx_vehicle_spider" );
spiderScriptModel ScriptModelPlayAnim ( "nx_vh_roboturret_idle" );
level._spiderCurrentAnimation = "nx_vh_roboturret_idle";
//tagJC<NOTE>: Linking the robo legs to the vehicle.
spiderScriptModel linkTo ( level._spider, "TAG_ORIGIN" , (0, 0, 0), (0, 0, 0) );
spiderScriptModel thread loopOnLegs ( level._spider );
//tagJC<NOTE>: Spawning the roboturret and setting its attributes.
spiderTurret = spawnTurret( "misc_turret", level._spider.origin, "ugv_main_turret_mp" );
//tagJC<NOTE>: Linking the turret to the scripted robo legs model.
spiderTurret linkTo( spiderScriptModel, "TAG_TURRET", (0,0,0), (0,0,0) );
spiderTurret setModel( "nx_ugv_robo_turret" );
spiderTurret.angles = level._spider.angles;
spiderTurret.owner = level._spider.owner;
spiderTurret makeTurretInoperable();
level._spider.mgTurret = spiderTurret;
level._spider.mgTurret SetDefaultDropPitch( 0 );
//tagJC<NOTE>: Start the turret to track and shoot enemies.
level._spider thread tankGetMiniTargets();
//tagJC<NOTE>: Finding the spider start node that is closest to the player.
closest_spidernode = find_closest_spidernode( self, level._spiderNodes );
//tagJC<NOTE>: Start moving the roboturret according to player's position.
level._spider thread move_spider ( self, closest_spidernode );
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: There are three animations that the robo legs can play: idel, walk and run
loopOnLegs ( vehicle )
{
timer = 0;
while ( 1 )
{
self.angle = vehicle.angle;
speed = vehicle Vehicle_GetSpeed();
//tagJC<NOTE>: If the vehicle speed is faster than 10 MPH, the legs will run
if ( speed > 10 )
{
timer = 0;
if ( level._spiderCurrentAnimation != "nx_vh_roboturret_run" )
{
self ScriptModelPlayAnim ( "nx_vh_roboturret_run" );
level._spiderCurrentAnimation = "nx_vh_roboturret_run";
self stoploopsound("robot_sentry_walk");
self playloopsound("robot_sentry_run");
}
}
//tagJC<NOTE>: If the vehicle speed is between 10 and 0 MPH, the legs will walk
else if ( speed < 10 && speed > 0 )
{
timer = 0;
if ( level._spiderCurrentAnimation != "nx_vh_roboturret_walk" )
{
self ScriptModelPlayAnim ( "nx_vh_roboturret_walk" );
level._spiderCurrentAnimation = "nx_vh_roboturret_walk";
self stoploopsound("robot_sentry_run");
self playloopsound("robot_sentry_walk");
}
}
//tagJC<NOTE>: If the vehicle speed is 0 MPH, the legs will be idel
else
{
timer = timer + 1;
//tagJC<NOTE>: If the roboturret has been idle for 15 seconds
if ( timer == 30 )
{
vehicle playsound ( "roboturret_idle_vo" );
//vehicle playsound ( "roboturret_kill_vo" );
timer = 0;
}
if ( level._spiderCurrentAnimation != "nx_vh_roboturret_idle" )
{
self stoploopsound("robot_sentry_run");
self stoploopsound("robot_sentry_walk");
self ScriptModelPlayAnim ( "nx_vh_roboturret_idle" );
level._spiderCurrentAnimation = "nx_vh_roboturret_idle";
}
}
println ( "timer is: " + timer );
wait ( 0.5 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Currently, in order for this implementation to work, designers would have to place many pairs of bi-directional vehicle nodes
// in the level. Given the limitation that vehicle seems to be only moving when it is on a vehicle path, the roboturret
// cannot quite follow the players perfectly yet. Players would have to get close to the roboturret and then guide
// it to a different position.
move_spider ( owner, startNode )
{
//self playsound( "roboturret_deploy_vo" );
self Vehicle_SetSpeed( 30, 5, 5 );
//tagJC<NOTE>: Starting the roboturret along the path where its starting node is the roboturret's spawning node
self AttachPath( startNode );
self StartPath( startNode );
self waittill( "reached_end_node" );
self playsound( "roboturret_deploy_vo" );
prev_node = startNode;
while ( 1 )
{
index = "X" + prev_node.origin[0] + "Y" + prev_node.origin[1] + "Z" + prev_node.origin[2];
best_node = find_best_spidernode( owner, level._StartNodeMapping[index] );
//if ( distance ( owner.origin, level._spider.origin ) > 50 )
if ( isGettingCloserToPlayer ( owner, best_node ) )
{
//if ( prev_node != best_node )
//{
self StartPath( best_node );
self waittill( "reached_end_node" );
prev_node = best_node;
//println( "This is after subsequent reached_end_node" );
//}
}
else
{
wait 0.5;
}
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: This function checks whether the turret will be moving away from the player or not
isGettingCloserToPlayer ( owner, StartNode )
{
EndNode = GetVehicleNode( StartNode.target, "targetname" );
if ( distance ( owner.origin, EndNode.origin ) > distance ( owner.origin, StartNode.origin ) )
{
return false;
}
else
{
return true;
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: From the ReachableNodeList, determine the node that is will lead the turret to the player
find_best_spidernode( owner, ReachableNodeList )
{
target_vector = VectorNormalize ( owner.origin - level._spider.origin );
//tagJC<NOTE>: Creating an arbitrary base line using the first node in the node awway
best_node = ReachableNodeList [0];
best_dot_product = VectorDot ( VectorNormalize( best_node.origin - level._spider.origin ), target_vector );
for ( i = 1; i < ReachableNodeList.size; i++)
{
//tagJC<NOTE>: If another node in the list can produce a larger dot product, that node is the best node
dot_product = VectorDot ( VectorNormalize( ReachableNodeList[i].origin - level._spider.origin ), target_vector );
if ( dot_product > best_dot_product )
{
best_node = ReachableNodeList[i];
}
}
return best_node;
}
//*******************************************************************
// *
// *
//*******************************************************************
tankGetMiniTargets()
{
self endon( "death" );
self endon( "leaving" );
miniTargets = [];
println( "Geting Mini Targets" );
for ( ;; )
{
miniTargets = [];
players = level._players;
//tagJC<NOTE>: Putting all the players on the oppositing team into a array.
for (i = 0; i <= players.size; i++)
{
if ( isMiniTarget( players[i] ) )
{
if( isdefined( players[i] ) )
miniTargets[miniTargets.size] = players[i];
}
else
{
continue;
}
wait( .05 );
}
//tagJC<NOTE>: If there is at least one enemy, start acquiring the target
if ( miniTargets.size > 0 )
{
self acquireMiniTarget( miniTargets );
return;
}
else
wait( 0.5 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: From the potential target list, determine whether there is any target that is feasible/practical for the turret
// to target.
isMiniTarget( potentialTarget )
{
self endon( "death" );
if ( !isalive( potentialTarget ) || potentialTarget.sessionstate != "playing" )
return false;
if ( !isdefined( potentialTarget.pers["team"] ) )
return false;
if ( potentialTarget == self.owner )
return false;
if ( distanceSquared( potentialTarget.origin , self.origin ) > 1024*1024 )
return false;
if ( level._teamBased && potentialTarget.pers["team"] == self.team )
return false;
if ( potentialTarget.pers["team"] == "spectator" )
return false;
if ( isdefined( potentialTarget.spawntime ) && ( gettime() - potentialTarget.spawntime )/1000 <= 5 )
return false;
if ( isDefined( self ) )
{
minTurretEye = self.mgTurret.origin + ( 0, 0, 64 );
minTurretCanSeeTarget = potentialTarget sightConeTrace( minTurretEye, self );
if ( minTurretCanSeeTarget < 1 )
{
return false;
}
}
return true;
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: From the target list, determine which one is the best target and shoot it.
acquireMiniTarget( targets )
{
self endon( "death" );
//tagJC<NOTE>: If there is only one target in the list, it is the best target.
if ( targets.size == 1 )
{
self.bestMiniTarget = targets[0];
}
//tagJC<NOTE>: Else, determine the best target in the list.
else
{
self.bestMiniTarget = self getBestMiniTarget( targets );
}
self notify( "acquiringMiniTarget" );
//tagJC<NOTE>: Set turret to target the best target.
self.mgTurret SetTargetEntity( self.bestMiniTarget, ( 0,0,42 ) );
wait( .15 );
//tagJC<NOTE>: Set turret to fire at the best target.
self thread fireMiniOnTarget();
//tagJC<NOTE>: Abandon the target when it is killed.
self thread watchMiniTargetDeath( targets );
self thread watchMiniTargetDistance( targets );
self thread watchMiniTargetThreat( self.bestMiniTarget );
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Determine the best target from the target list
getBestMiniTarget( targets )
{
self endon( "death" );
tankOrigin = self.origin;
closest = undefined;
bestTarget = undefined;
foreach ( targ in targets )
{
curDist = Distance( self.origin, targ.origin );
//tagJC<NOTE>: If the target is holding or using explosives, push the target to a higher priority
curWeaon = targ GetCurrentWeapon();
if ( isSubStr( curWeaon, "at4" ) || isSubStr( curWeaon, "jav" ) || isSubStr( curWeaon, "c4" ) || isSubStr( curWeaon, "smart" ) || isSubStr( curWeaon, "grenade" ) )
{
curDist -= 200;
}
if ( !isDefined( closest ) )
{
closest = curDist;
bestTarget = targ;
}
else if ( closest > curDist )
{
closest = curDist;
bestTarget = targ;
}
}
return ( bestTarget );
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Firing the turret at the target.
fireMiniOnTarget()
{
self endon( "death" );
self endon( "abandonedMiniTarget" );
self endon( "killedMiniTarget" );
noTargTime = undefined;
miniAcquiredTime = getTime();
if ( !isDefined( self.bestMiniTarget ) )
{
println( "No Targ to fire on" );
return;
}
println( "firing at best target" );
while( 1 )
{
if ( !isDefined ( self.mgTurret getTurretTarget( true ) ) )
{
if ( !isDefined( noTargTime ) )
{
noTargTime = getTime();
}
curTime = getTime();
//tagJC<NOTE>: If there has been more than 1 milliseconds without a target, abandon the target.
if ( noTargTime - curTime > 1 )
{
noTargTime = undefined;
self thread explicitAbandonMiniTarget();
return;
}
println("Waiting because the turret doesnt have a target" );
wait ( .5 );
continue;
}
//tagJC<NOTE>: Firing a random number of shots between 2 to 6.
numShots = randomIntRange( 2, 6 );
for ( i = 0; i < numShots; i++ )
{
println( "actually shooting turret" );
self.mgTurret ShootTurret();
wait ( .25 );
}
wait ( randomFloatRange( 0.05, 0.1 ) );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Clearing the current target list for the turret and starting to get more targets.
explicitAbandonMiniTarget( noNewTarget )
{
self notify( "abandonedMiniTarget" );
println( "ABANDONED MINI TARGET" );
self.bestMiniTarget = undefined;
self.mgTurret ClearTargetEntity();
if ( isDefined(noNewTarget) && noNewTarget )
{
return;
}
self thread tankGetMiniTargets();
return;
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Wait for the target's death. Once the target is killed, clear the target list and get more targets.
watchMiniTargetDeath( targets )
{
self endon( "abandonedMiniTarget" );
self endon( "death" );
if ( ! isDefined( self.bestMiniTarget ) )
return;
self.bestMiniTarget waittill( "death" );
//self playsound ( "roboturret_idle_vo" );
self playsound ( "roboturret_kill_vo" );
self notify( "killedMiniTarget" );
println( "Killed Mini Target" );
self.bestMiniTarget = undefined;
self.mgTurret ClearTargetEntity();
self tankGetMiniTargets();
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: If the target is more than 1024 units away, abandon the target
watchMiniTargetDistance( targets )
{
self endon( "abandonedMiniTarget" );
self endon( "death" );
for ( ;; )
{
if (! isDefined( self.bestMiniTarget ) )
return;
trace = BulletTrace( self.mgTurret.origin, self.bestMiniTarget.origin, false, self );
traceDistance = Distance(self.origin, trace["position"] );
if ( traceDistance > 1024 )
{
println( "MINI TARGET DIST TOO FAR!!!" );
self thread explicitAbandonMiniTarget();
return;
}
println( traceDistance );
wait ( 2 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: If there is a target that is closer to the current target, abandon the curret target
watchMiniTargetThreat( curTarget )
{
self endon( "abandonedMiniTarget" );
self endon( "death" );
self endon( "killedMiniTarget" );
for ( ;; )
{
miniTargets = [];
players = level._players;
for (i = 0; i <= players.size; i++)
{
if ( isMiniTarget( players[i] ) )
{
if( !isdefined( players[i] ) )
{
continue;
}
if( !isdefined(curTarget) )
{
return;
}
traceOldTarg = Distance(self.origin, CurTarget.origin );
traceNewTarg = Distance(self.origin, players[i].origin );
if ( traceNewTarg < traceOldTarg )
{
self thread explicitAbandonMiniTarget();
return;
}
}
wait( .05 );
}
wait( .25 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: From the entity_list, return the one that is closest to the entity
find_closest_spidernode ( target, entity_list )
{
//tagJC<NOTE>: Use an arbitrary distance as the base for comparision
closest_distance = distance( target.origin , entity_list[0].origin );
closest_entity = entity_list[0];
for ( i = 1; i < entity_list.size; i++ )
{
//tagJC<NOTE>: If another entity on the list results in a shorter distance, update the results accordingly
if ( distance( target.origin , entity_list[i].origin ) < closest_distance )
{
closest_distance = distance( target.origin , entity_list[i].origin );
closest_entity = entity_list[i];
}
}
return closest_entity;
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: If a vehicle is dropped more than 2048 units, kill it.
deleteOnZ()
{
self endon ( "death" );
originalZ = self.origin[2];
for ( ;; )
{
if ( originalZ - self.origin[2] > 2048 )
{
self.health = 0;
self notify( "death" );
return;
}
wait ( 1.0 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: This function tracks player's movement and put the closest node to the player into a queue
TrackingPlayers( owner )
{
self.PlayerLocations = [];
while ( 1 )
{
close_node = find_closest_spidernode( owner, level._spiderNodes );
if ( self.PlayerLocations.size == 0 )
{
self.PlayerLocations[0] = close_node;
}
else
{
size = self.PlayerLocations.size;
Player_last_location = self.PlayerLocations[ size - 1 ];
if ( close_node != Player_last_location )
{
self.PlayerLocations[ size ] = close_node;
//println ( "========== This is inside Tracking Player ============" );
//println ( "The location of the node being added is: " + self.PlayerLocations[ size ].origin);
//println ( "The size of PlayerLocations is: " + self.PlayerLocations.size );
//println ( "======================================================" );
}
}
wait( 0.5 );
}
}
//*******************************************************************
// *
// *
//*******************************************************************
//tagJC<NOTE>: Remove the first item in the list by shifting entities in the list forward by one slot in the list
RemoveFirstItem ( list )
{
if ( list.size > 0 )
{
for ( i = 0 ; i < list.size - 1 ; i ++ )
{
list[ i ] = list[ i + 1 ];
}
list[ list.size - 1 ] = undefined;
}
}
//*******************************************************************
// *
// *
//*******************************************************************
// tagJC<NOTE>: This script is running on the global level object, it monitors players connecting to the game.
// Its main purpose is to apply the onPlayerSpawned script to each player as they connect to the game.
onPlayerConnect()
{
for(;;)
{
level waittill("connected", player);
player thread onPlayerSpawned();
}
}
//*******************************************************************
// *
// *
//*******************************************************************
// tagJC<NOTE>: This script is running on each player in the game, it recieves a notification each time the player it is running on spawns in the game
// Its main purpose is to initialize any per player data, as well as update the player subject to any global killstreak data when that player spawns.
onPlayerSpawned()
{
self endon("disconnect");
for(;;)
{
self waittill( "spawned_player" );
println( "player spwaned" );
// init/manage any per player killstreak data here
}
}
main ( vehicle, model )
{
}
//*******************************************************************
// *
// *
//*******************************************************************
/*
QUAKED script_vehicle_nx_proto_roboturret (1 0 0) (-16 -16 -24) (16 16 32) USABLE SPAWNER
maps\mp\killstreaks\_spider::main( "nx_vehicle_roboturret_legs_vehicle", "proto_nx_vehicle_roboturret_legs_vehicle" );
include,prototype_nx_vehicle_roboturret
defaultmdl="nx_vehicle_roboturret_legs_vehicle"
default:"vehicletype" "proto_nx_vehicle_roboturret_legs_vehicle"
default:"script_team" "allies"
*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,881 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
init()
{
precacheString( &"MP_WAR_RADAR_ACQUIRED" );
precacheString( &"MP_WAR_RADAR_ACQUIRED_ENEMY" );
precacheString( &"MP_WAR_RADAR_EXPIRED" );
precacheString( &"MP_WAR_RADAR_EXPIRED_ENEMY" );
precacheString( &"MP_WAR_COUNTER_RADAR_ACQUIRED" );
precacheString( &"MP_WAR_COUNTER_RADAR_ACQUIRED_ENEMY" );
precacheString( &"MP_WAR_COUNTER_RADAR_EXPIRED" );
precacheString( &"MP_WAR_COUNTER_RADAR_EXPIRED_ENEMY" );
precacheString( &"MP_LASE_TARGET_FOR_PREDATOR_STRIKE" );
precacheModel( "vehicle_uav_static_mp" );
precacheItem( "uavstrikebinoculars_mp" );
precacheItem( "uav_strike_projectile_mp" );
level._radarViewTime = 30; // time radar remains active
level._uavBlockTime = 30; // this only seems to be used for the FFA version.
assert( level._radarViewTime > 7 );
assert( level._uavBlockTime > 7 );
level._uav_fx[ "explode" ] = loadFx( "explosions/helicopter_explosion_cobra_low" );
level._killStreakFuncs["uav"] = ::tryUseUAV;
level._killStreakFuncs["double_uav"] = ::tryUseDoubleUAV;
level._killStreakFuncs["counter_uav"] = ::tryUseCounterUAV;
level._killstreakFuncs["uav_strike"] = ::tryUseUAVStrike;
level._killstreakSetupFuncs["uav_strike"] = ::UAVStrikeSetup;
level._effect[ "laserTarget" ] = loadfx("nx/misc/nx_laser_glow");
minimapOrigins = getEntArray( "minimap_corner", "targetname" );
if ( miniMapOrigins.size )
uavOrigin = maps\mp\gametypes\_spawnlogic::findBoxCenter( miniMapOrigins[0].origin, miniMapOrigins[1].origin );
else
uavOrigin = (0,0,0);
level._UAVRig = spawn( "script_model", uavOrigin );
level._UAVRig setModel( "c130_zoomrig" );
level._UAVRig.angles = (0,115,0);
level._UAVRig hide();
level._UAVRig thread rotateUAVRig();
if ( level._teamBased )
{
level._radarMode["allies"] = "normal_radar";
level._radarMode["axis"] = "normal_radar";
level._activeUAVs["allies"] = 0;
level._activeUAVs["axis"] = 0;
level._activeCounterUAVs["allies"] = 0;
level._activeCounterUAVs["axis"] = 0;
level._uavModels["allies"] = [];
level._uavModels["axis"] = [];
if( level._multiTeamBased )
{
for( i = 0; i < level._teamNameList.size; i++ )
{
level._radarMode[level._teamNameList[i]] = "normal_radar";
level._activeUAVs[level._teamNameList[i]] = 0;
level._activeCounterUAVs[level._teamNameList[i]] = 0;
level._uavModels[level._teamNameList[i]] = [];
}
}
}
else
{
level._radarMode = [];
level._activeUAVs = [];
level._activeCounterUAVs = [];
level._uavModels = [];
level thread onPlayerConnect();
}
level thread UAVTracker();
}
onPlayerConnect()
{
for(;;)
{
level waittill( "connected", player );
level._activeUAVs[ player.guid ] = 0;
level._activeCounterUAVs[ player.guid ] = 0;
level._radarMode[ player.guid ] = "normal_radar";
}
}
rotateUAVRig()
{
for (;;)
{
self rotateyaw( -360, 60 );
wait ( 60 );
}
}
launchUAV( owner, team, duration, isCounter )
{
UAVModel = spawn( "script_model", level._UAVRig getTagOrigin( "tag_origin" ) );
UAVModel setModel( "vehicle_uav_static_mp" );
UAVModel thread damageTracker( isCounter );
UAVModel.team = team;
UAVModel.owner = owner;
UAVModel thread handleIncomingStinger();
addUAVModel( UAVModel );
zOffset = randomIntRange( 3000, 5000 );
angle = randomInt( 360 );
radiusOffset = randomInt( 2000 ) + 5000;
xOffset = cos( angle ) * radiusOffset;
yOffset = sin( angle ) * radiusOffset;
angleVector = vectorNormalize( (xOffset,yOffset,zOffset) );
angleVector = vector_multiply( angleVector, randomIntRange( 6000, 7000 ) );
UAVModel linkTo( level._UAVRig, "tag_origin", angleVector, (0,angle - 90,0) );
UAVModel thread updateUAVModelVisibility();
if ( isCounter )
UAVModel addActiveCounterUAV();
else
UAVModel addActiveUAV();
level notify ( "uav_update" );
UAVModel waittill_notify_or_timeout_hostmigration_pause( "death", duration - 7 );
if ( UAVModel.health <= 0 )
{
forward = vector_multiply( anglesToRight( UAVModel.angles ), 200 );
playFx ( level._uav_fx[ "explode" ], UAVModel.origin, forward );
}
else
{
UAVModel unlink();
destPoint = UAVModel.origin + vector_multiply( anglestoforward( UAVModel.angles ), 20000 );
UAVModel moveTo( destPoint, 60 );
PlayFXOnTag( level._effect[ "ac130_engineeffect" ] , UAVModel, "tag_origin" );
UAVModel waittill_notify_or_timeout_hostmigration_pause( "death", 3 );
UAVModel moveTo( destPoint, 4, 4, 0.0 );
UAVModel waittill_notify_or_timeout_hostmigration_pause( "death", 4 );
}
if ( isCounter )
UAVModel removeActiveCounterUAV();
else
UAVModel removeActiveUAV();
UAVModel delete();
removeUAVModel( UAVModel );
level notify ( "uav_update" );
}
monitorUAVStrike()
{
level endon( "game_ended" );
for ( ;; )
{
msg = self waittill_any_return( "death", "uav_strike_cancel", "uav_strike_successful" );
if ( msg == "uav_strike_successful" )
return true;
else
return false;
}
}
showLazeMessage()
{
msg = self maps\mp\gametypes\_hud_util::createFontString( "bigfixed", 0.75 );
msg maps\mp\gametypes\_hud_util::setPoint( "CENTER", "CENTER", 0 , 150 );
msg setText( &"MP_LASE_TARGET_FOR_PREDATOR_STRIKE" );
self waittill_any_timeout( 4.0, "death", "uav_strike_cancel", "uav_strike_successful" );
msg destroyElem();
}
waitForLazeDiscard()
{
level endon( "game_ended" );
self endon( "death" );
self endon( "uav_strike_used" );
for ( ;; )
{
self waittill ( "weapon_change", newWeapon );
if ( newWeapon != "uavstrikebinoculars_mp" )
{
self notify( "uav_strike_cancel" );
break;
}
else
wait( 0.05 );
}
}
waitForLazedTarget()
{
level endon( "game_ended" );
self endon( "death" );
self thread showLazeMessage();
self thread waitForLazeDiscard();
weapon = self getLastWeapon();
secondaryWeapon = undefined;
primaryWeapons = self GetWeaponsListPrimaries();
foreach ( primaryWeapon in primaryWeapons )
{
if ( primaryWeapon != weapon )
{
secondaryWeapon = primaryWeapon;
self takeWeapon( secondaryWeapon );
break;
}
}
self _giveWeapon("uavstrikebinoculars_mp");
self switchToWeapon( "uavstrikebinoculars_mp" );
traceData = undefined;
for(;;)
{
msg = self waittill_any_return( "weapon_fired", "uav_strike_cancel" );
if ( msg == "uav_strike_cancel" )
break;
origin = self GetEye();
forward = AnglesToForward( self GetPlayerAngles() );
endpoint = origin + forward * 15000;
traceData = BulletTrace( origin, endpoint, true, self );
if ( isDefined(traceData["position"]) )
break;
}
if ( isDefined( traceData ) )
{
targetPosition = traceData["position"];
fxEnt = SpawnFx( level._effect[ "laserTarget" ], targetPosition);
TriggerFx( fxEnt );
fxEnt thread waitFxEntDie();
magicBullet( "uav_strike_projectile_mp", targetPosition + (0,0,4000) , targetPosition, self );
self notify( "uav_strike_used" );
}
self takeWeapon( "uavstrikebinoculars_mp" );
if ( msg != "uav_strike_cancel" )
self switchToWeapon( weapon );
if ( isDefined( secondaryWeapon ) )
self _giveWeapon( secondaryWeapon );
if ( isDefined( traceData ) )
self notify( "uav_strike_successful" );
}
waitFxEntDie()
{
wait( 2 );
self delete();
}
waittill_notify_or_timeout_hostmigration_pause( msg, timer )
{
self endon( msg );
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( timer );
}
updateUAVModelVisibility()
{
self endon ( "death" );
for ( ;; )
{
level waittill_either ( "joined_team", "uav_update" );
self hide();
foreach ( player in level._players )
{
if ( level._teamBased )
{
if ( player.team != self.team )
self showToPlayer( player );
}
else
{
if ( isDefined( self.owner ) && player == self.owner )
continue;
self showToPlayer( player );
}
}
}
}
damageTracker( isCounterUAV )
{
level endon ( "game_ended" );
self setCanDamage( true );
self.maxhealth = 700;
self.health = self.maxhealth;
for ( ;; )
{
self waittill ( "damage", damage, attacker, direction_vec, point, sMeansOfDeath );
if ( !isPlayer( attacker ) )
{
if ( !isDefined( self ) )
return;
continue;
}
attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "" );
if ( attacker _hasPerk( "specialty_armorpiercing" ) && isDefined( self ) )
{
damageAdd = damage*level._armorPiercingMod;
self.health -= int(damageAdd);
}
if ( !isDefined( self ) )
{
if ( isPlayer( attacker ) && (!isDefined(self.owner) || attacker != self.owner) )
{
if ( isCounterUAV )
thread teamPlayerCardSplash( "callout_destroyed_counter_uav", attacker );
else
thread teamPlayerCardSplash( "callout_destroyed_uav", attacker );
thread maps\mp\gametypes\_missions::vehicleKilled( self.owner, self, undefined, attacker, damage, sMeansOfDeath );
attacker thread maps\mp\gametypes\_rank::giveRankXP( "kill", 50 );
attacker notify( "destroyed_killstreak" );
}
return;
}
}
}
tryUseUAV( lifeId )
{
return useUAV( "uav" );
}
tryUseDoubleUAV( lifeId )
{
return useUAV( "double_uav" );
}
tryUseCounterUAV( lifeId )
{
return useUAV( "counter_uav" );
}
UAVStrikeSetup()
{
self.usedStrikeUAV = 0;
}
tryUseUAVStrike( lifeId )
{
if ( self.usedStrikeUAV == 0 )
{
self.usedStrikeUAV = 1;
//useUAV( "uav_strike" );
}
self thread waitForLazedTarget();
return monitorUAVStrike();
}
useUAV( uavType )
{
self maps\mp\_matchdata::logKillstreakEvent( uavType, self.origin );
team = self.pers["team"];
useTime = level._radarViewTime;
level thread launchUAV( self, team, useTime, uavType == "counter_uav" );
if ( uavType == "counter_uav" )
self notify( "used_counter_uav" );
else
self notify( "used_uav" );
return true;
}
UAVTracker()
{
level endon ( "game_ended" );
for ( ;; )
{
level waittill ( "uav_update" );
if ( level._multiTeamBased )
{
for( i = 0; i < level._teamNameList.size; i++ )
{
updateTeamUAVStatus( level._teamNameList[i] );
}
}
else if ( level._teamBased )
{
updateTeamUAVStatus( "allies" );
updateTeamUAVStatus( "axis" );
}
else
{
updatePlayersUAVStatus();
}
}
}
updateTeamUAVStatus( team )
{
activeUAVs = level._activeUAVs[team];
activeCounterUAVs = 0;
if( level._multiTeamBased )
{
for( i = 0; i < level._teamNameList.size; i++ )
{
if( team != level._teamNameList[i] )
{
activeCounterUAVs += level._activeCounterUAVs[level._teamNameList[i]];
}
}
}
else
{
activeCounterUAVs = level._activeCounterUAVs[level._otherTeam[team]];
}
if ( !activeCounterUAVs )
unblockTeamRadar( team );
else
blockTeamRadar( team );
if ( !activeUAVs )
{
setTeamRadarWrapper( team, 0 );
return;
}
if ( activeUAVs > 1 )
level._radarMode[team] = "fast_radar";
else
level._radarMode[team] = "normal_radar";
updateTeamUAVType();
setTeamRadarWrapper( team, 1 );
}
updatePlayersUAVStatus()
{
totalActiveCounterUAVs = 0;
counterUAVPlayer = undefined;
foreach ( player in level._players )
{
activeUAVs = level._activeUAVs[ player.guid ];
activeCounterUAVs = level._activeCounterUAVs[ player.guid ];
if ( activeCounterUAVs )
{
totalActiveCounterUAVs++;
counterUAVPlayer = player;
}
if ( !activeUAVs )
{
player.hasRadar = false;
if( player.radarMode != "directional_radar" )
{
player.radarMode = "normal_radar";
player.nextRadarMode = "normal_radar";
}
else
{
player.nextRadarMode = "normal_radar";
}
continue;
}
if ( activeUAVs > 1 )
if( player.radarMode != "directional_radar" )
{
player.radarMode = "fast_radar";
}
else
{
player.nextRadarMode = "fast_radar";
}
else
{
if( player.radarMode != "directional_radar" )
{
player.radarMode = "normal_radar";
player.nextRadarMode = "normal_radar";
}
else
{
player.nextRadarMode = "normal_radar";
}
}
player.hasRadar = true;
}
foreach ( player in level._players )
{
if ( !totalActiveCounterUAVs )
{
player.isRadarBlocked = false;
continue;
}
if ( totalActiveCounterUAVs == 1 && player == counterUAVPlayer )
player.isRadarBlocked = false;
else
player.isRadarBlocked = true;
}
}
blockPlayerUAV()
{
self endon ( "disconnect" );
self notify ( "blockPlayerUAV" );
self endon ( "blockPlayerUAV" );
self.isRadarBlocked = true;
wait ( level._uavBlockTime );
self.isRadarBlocked = false;
//self iPrintLn( &"MP_WAR_COUNTER_RADAR_EXPIRED" );
}
updateTeamUAVType()
{
foreach ( player in level._players )
{
if ( player.team == "spectator" )
continue;
if( player.radarMode != "directional_radar" )
{
player.radarMode = level._radarMode[player.team];
}
else
{
player.nextRadarMode = level._radarMode[player.team];
}
}
}
usePlayerUAV( doubleUAV, useTime )
{
level endon("game_ended");
self endon("disconnect");
self notify ( "usePlayerUAV" );
self endon ( "usePlayerUAV" );
if ( doubleUAV )
{
if( self.radarMode != "directional_radar" )
{
self.radarMode = "fast_radar";
}
else
{
self.nextRadarMode = "fast_radar";
}
}
else
{
if( self.radarMode != "directional_radar" )
{
self.radarMode = "normal_radar";
self.nextRadarMode = "normal_radar";
}
else
{
self.nextRadarMode = "normal_radar";
}
}
self.hasRadar = true;
wait ( useTime );
if( self.radarMode != "directional_radar" )
{
self.hasRadar = false;
}
//self iPrintLn( &"MP_WAR_RADAR_EXPIRED" );
}
setTeamRadarWrapper( team, value )
{
setTeamRadar( team, value );
level notify( "radar_status_change", team );
}
handleIncomingStinger()
{
level endon ( "game_ended" );
self endon ( "death" );
for ( ;; )
{
level waittill ( "stinger_fired", player, missile, lockTarget );
if ( !IsDefined( lockTarget ) || (lockTarget != self) )
continue;
missile thread stingerProximityDetonate( lockTarget, player );
}
}
stingerProximityDetonate( targetEnt, player )
{
self endon ( "death" );
minDist = distance( self.origin, targetEnt GetPointInBounds( 0, 0, 0 ) );
lastCenter = targetEnt GetPointInBounds( 0, 0, 0 );
for ( ;; )
{
// UAV already destroyed
if ( !isDefined( targetEnt ) )
center = lastCenter;
else
center = targetEnt GetPointInBounds( 0, 0, 0 );
lastCenter = center;
curDist = distance( self.origin, center );
if ( curDist < minDist )
minDist = curDist;
if ( curDist > minDist )
{
if ( curDist > 1536 )
return;
radiusDamage( self.origin, 1536, 600, 600, player );
playFx( level._stingerFXid, self.origin );
//self playSound( "remotemissile_explode" );
self hide();
self notify("deleted");
wait ( 0.05 );
self delete();
player notify( "killstreak_destroyed" );
}
wait ( 0.05 );
}
}
addUAVModel( UAVModel )
{
if ( level._teamBased )
level._UAVModels[UAVModel.team][level._UAVModels[UAVModel.team].size] = UAVModel;
else
level._UAVModels[UAVModel.owner.guid + "_" + getTime()] = UAVModel;
}
removeUAVModel( UAVModel )
{
UAVModels = [];
if ( level._teamBased )
{
team = UAVModel.team;
foreach ( uavModel in level._UAVModels[team] )
{
if ( !isDefined( uavModel ) )
continue;
UAVModels[UAVModels.size] = uavModel;
}
level._UAVModels[team] = UAVModels;
}
else
{
foreach ( uavModel in level._UAVModels )
{
if ( !isDefined( uavModel ) )
continue;
UAVModels[UAVModels.size] = uavModel;
}
level._UAVModels = UAVModels;
}
}
addActiveUAV()
{
if ( level._teamBased )
level._activeUAVs[self.team]++;
else
level._activeUAVs[self.owner.guid]++;
/*
if ( level._teamBased )
{
foreach ( player in level._players )
{
if ( player.team == self.team )
player iPrintLn( &"MP_WAR_RADAR_ACQUIRED", self.owner, level._radarViewTime );
else if ( player.team == level._otherTeam[self.team] )
player iPrintLn( &"MP_WAR_RADAR_ACQUIRED_ENEMY", level._radarViewTime );
}
}
else
{
foreach ( player in level._players )
{
if ( player == self.owner )
player iPrintLn( &"MP_WAR_RADAR_ACQUIRED", self.owner, level._radarViewTime );
else
player iPrintLn( &"MP_WAR_RADAR_ACQUIRED_ENEMY", level._radarViewTime );
}
}
*/
}
addActiveCounterUAV()
{
if ( level._teamBased )
level._activeCounterUAVs[self.team]++;
else
level._activeCounterUAVs[self.owner.guid]++;
/*
if ( level._teamBased )
{
foreach ( player in level._players )
{
if ( player.team == self.team )
player iPrintLn( &"MP_WAR_COUNTER_RADAR_ACQUIRED", self.owner, level._uavBlockTime );
else if ( player.team == level._otherTeam[self.team] )
player iPrintLn( &"MP_WAR_COUNTER_RADAR_ACQUIRED_ENEMY", level._uavBlockTime );
}
}
else
{
foreach ( player in level._players )
{
if ( player == self.owner )
player iPrintLn( &"MP_WAR_COUNTER_RADAR_ACQUIRED", self.owner, level._uavBlockTime );
else
player iPrintLn( &"MP_WAR_COUNTER_RADAR_ACQUIRED_ENEMY", level._uavBlockTime );
}
}
*/
}
removeActiveUAV()
{
if ( level._teamBased )
{
level._activeUAVs[self.team]--;
if ( !level._activeUAVs[self.team] )
{
//printOnTeam( &"MP_WAR_RADAR_EXPIRED", self.team );
//printOnTeam( &"MP_WAR_RADAR_EXPIRED_ENEMY", level._otherTeam[self.team] );
}
}
else if ( isDefined( self.owner ) )
{
level._activeUAVs[self.owner.guid]--;
}
}
removeActiveCounterUAV()
{
if ( level._teamBased )
{
level._activeCounterUAVs[self.team]--;
if ( !level._activeCounterUAVs[self.team] )
{
//printOnTeam( &"MP_WAR_COUNTER_RADAR_EXPIRED", self.team );
//printOnTeam( &"MP_WAR_COUNTER_RADAR_EXPIRED_ENEMY", level._otherTeam[self.team] );
}
}
else if ( isDefined( self.owner ) )
{
level._activeCounterUAVs[self.owner.guid]--;
}
}
MeleeUAV()
{
level endon ( "game_ended" );
self endon ( "disconnect" );
self.radarMode = "directional_radar";
// self.hasRadar = true;
wait ( 5 );
// self.hasRadar = false;
if( isDefined( self.nextRadarMode ))
{
self.radarMode = self.nextRadarMode;
}
else
{
self.radarMode = "normal_radar";
}
}

View File

@ -0,0 +1,204 @@
#include maps\mp\_utility;
#include common_scripts\utility;
// Each Killstreak has its own initialization function. This Script has two main purposes.
// (1). All global data and assets used by this killstreak should be initialized here.
// (2). The callback that executes when a player activates this killstreak should be set here.
// TODO: A call to this script must be added to the script init() in the file c:\trees\nx1\game\share\raw\maps\mp\killstreaks\_killstreaks.gsc,
// this is were each individual killstreak is initialized.
init()
{
//This is a good place to precache assets, load up fx, or setup any global data that might be needed, NOTE: Everything defined in killstreakTable.csv
//will be precached automatically ( see initKillstreakData() in _killstreaks.gsc if interested ) so you do not need to worry about initializing the
//strings/weapons/materials/sounds defined there. If, for example, you were going to manually script up a plane flyiing over when this killstreak was
//activated you would want to precache that model here.
//generally any global data that is needed would be stored in the level object, here is an example
//level._effect[ "emp_flash" ] = loadfx( "explosions/emp_flash_mp" );
//This is were the killstreak activation callback is set
//TODO: Replace "killstreak_template" with the name of the new killstreak as defined in killstreakTable.csv
//Most killstreaks use a try fuction ( which i recommend, even if it is not necessary for this particualr killstreak it is nice to have a consistent model )
//the try script will make sure it is ok to fire the killstreak before the actual killstreak script is called.
precacheString ( &"MP_AIR_SPACE_TOO_CROWDED" );
precacheString ( &"MP_HOLD_USERELOAD_TO_THROWAWAY" );
level._killstreakFuncs["weapdrop"] = ::try_use_weapdrop;
//Use this script to update/initialize players as they connect to the game
level thread onPlayerConnect();
}
// This script is running on the global level object, it monitors players connecting to the game.
// Its main purpose is to apply the onPlayerSpawned script to each player as they connect to the game.
onPlayerConnect()
{
for(;;)
{
level waittill("connected", player);
player thread onPlayerSpawned();
}
}
// This script is running on each player in the game, it recieves a notification each time the player it is running on spawns in the game
// Its main purpose is to initialize any per player data, as well as update the player subject to any global killstreak data when that player spawns.
onPlayerSpawned()
{
self endon("disconnect");
for(;;)
{
self waittill( "spawned_player" );
println( "player spwaned" );
// init/manage any per player killstreak data here
}
}
//Many of the killstreaks have a try block that will test level conditions to make sure it is ok to fire the killstreak now. A good example of this is for the air killstreaks.
//Only a certain number of vehicles are allowed in the air at any given time, so if the airspace is full and the killstreak cannot be fired this try should return false.
//If there are any preconditions that must be met in order to fire this killstreak they should be checked in this script.
//NOTE: If this script returns true the killstreak system will consider this killstreak usage complete and the dpad icon will be removed, if this script returns false nothing will
//change and the system will just continue to wait for the the player to activate the killstreak by pressing right on the dpad.
try_use_weapdrop()
{
is_ok_to_use_killstreak = true;
if( is_ok_to_use_killstreak )
{
weapdrop_use();
return true;
}
return false;
}
// This is the callback that executes when the killstreak is activated by a player pressing on the dpad. This is called from the script killstreakUsePressed()
// located in the file _killstreaks.gsc
weapdrop_use()
{
assert( isDefined( self ) );
//println( "Killstreak Template Fired!!" );
/*
// don't allow use if theres 3 or more little birds up in the air already. this is consistent with the care package drop ks.
if ( level._littleBirds >= 3 )
{
self iPrintLnBold( &"MP_AIR_SPACE_TOO_CROWDED" );
return false;
}
*/
weapdrop_weapon = undefined;
// randomInt is confusing. 0 based and the number passed is how many ints it can return. 4 = 0-3.
switch( randomInt( 4 ) )
{
case 0:
weapdrop_weapon = "augks_mp";
break;
case 1:
weapdrop_weapon = "xm25ks_mp";
break;
case 2:
weapdrop_weapon = "aa12_akimbo_mp";
break;
case 3:
weapdrop_weapon = "javelinks_mp";
break;
}
// spawn a new script to give and switch to the weapdrop weapon
// the drop ks's need to return true asap otherwise you're still holding the trigger in your hand
self thread weapdrop_equip( weapdrop_weapon );
return true;
}
weapdrop_equip( weapdrop_weapon )
{
self endon( "death" );
self endon( "disconnect" );
assert( isDefined( weapdrop_weapon ) );
// hack. sometimes getCurrentWeapon will return none but getWeaponsListPrimaries wont...hmm...
/*
initial_weapon = self getCurrentWeapon();
if ( initial_weapon == "none" )
{
weapList = self GetWeaponsListPrimaries();
initial_weapon = weapList[0];
}
//printLn( initial_weapon );
*/
// make sure the script that spawned this one has returned true before I switch your weapon. this is probably unnecessary.
wait .1;
// akimbo weapons must be given a specific way.
if ( weapdrop_weapon == "aa12_akimbo_mp" )
{
self giveWeapon( weapdrop_weapon, 0 , true );
}
else
{
self giveWeapon( weapdrop_weapon );
}
self switchToWeapon( weapdrop_weapon );
for( ;; )
{
// when you run out of ammo, switch back to your first primary and take the weapdrop weapon
if ( self hasWeapon ( weapdrop_weapon ) )
{
if ( self getAmmoCount( weapdrop_weapon ) == 0 )
{
//self switchToWeapon( initial_weapon );
self takeWeapon ( weapdrop_weapon );
break;
}
}
else
{
break;
}
wait 0.05;
}
//printLn( "NO LONGER HAS KS WEAPON" );
}
weapdrop_hud()
{
hudelem = newClientHudElem( self );
// put something on screen that tells you, you can throw away this weapon
hudelem.x = -30;
hudelem.y = -20;
hudelem.alignX = "left";
hudelem.alignY = "bottom";
hudelem.horzAlign = "center";
hudelem.vertAlign = "bottom";
hudelem.sort = 1;// force to draw after the background
hudelem.foreground = true;
hudelem SetText( &"MP_HOLD_USERELOAD_TO_THROWAWAY" );
hudelem.alpha = 0;
hudelem FadeOverTime( 0.2 );
hudelem.alpha = 1;
hudelem.hidewheninmenu = true;
hudelem.fontScale = 1.25;
hudelem.font = "fwmed";
//hudelem.color = ( getdvarfloat( "color_neutral_r" ), getdvarfloat( "color_neutral_g" ), getdvarfloat( "color_neutral_b" ) );
//hudelem SetPulseFX( 30, duration, 700 );// something, decay start, decay duration
self waittill_any( "death", "disconnect", "weapdrop_done" );
hudelem Destroy();
}