iw6-scripts-dev/maps/mp/perks/_perkfunctions.gsc
2024-12-11 11:28:08 +01:00

3353 lines
76 KiB
Plaintext

/*******************************************************************
// _perkfunctions.gsc
//
// Holds all the perk set/unset and listening functions
//
// Jordan Hirsh Sept. 11th 2008
********************************************************************/
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include maps\mp\perks\_perks;
setOverkillPro()
{
}
unsetOverkillPro()
{
}
setEMPImmune()
{
}
unsetEMPImmune()
{
}
// highlight enemies while sniping
setAutoSpot()
{
if( !IsPlayer(self) )
return;
self autoSpotAdsWatcher();
self autoSpotDeathWatcher();
}
autoSpotDeathWatcher()
{
self waittill( "death" );
self endon ( "disconnect" );
self endon ( "endAutoSpotAdsWatcher" );
level endon ( "game_ended" );
self AutoSpotOverlayOff();
}
unsetAutoSpot()
{
if( !IsPlayer(self) )
return;
self notify( "endAutoSpotAdsWatcher" );
self AutoSpotOverlayOff();
}
autoSpotAdsWatcher()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "endAutoSpotAdsWatcher" );
level endon ( "game_ended" );
spotter = false;
for( ;; )
{
wait( 0.05 );
if( self IsUsingTurret() )
{
self AutoSpotOverlayOff();
continue;
}
adsLevel = self PlayerADS();
if( adsLevel < 1 && spotter )
{
spotter = false;
self AutoSpotOverlayOff();
}
if( adsLevel < 1 && !spotter )
continue;
if( adsLevel == 1 && !spotter )
{
spotter = true;
self AutoSpotOverlayOn();
}
}
}
//faster health regen
setRegenFaster()
{
// the commented out section is if we want it to only be on for a certain amount of time
// self endon( "disconnect" );
// level endon( "game_ended" );
//
// regenFasterTime = 60;
// self.hasRegenFaster = true;
//
// endTime = ( regenFasterTime * 1000 ) + GetTime();
// self SetClientDvar( "ui_regen_faster_end_milliseconds", endTime );
//
// wait( regenFasterTime );
//
// self timeOutRegenFaster();
}
unsetRegenFaster()
{
}
timeOutRegenFaster()
{
self.hasRegenFaster = undefined;
self _unsetPerk( "specialty_regenfaster" );
self SetClientDvar( "ui_regen_faster_end_milliseconds", 0 );
self notify( "timeOutRegenFaster" );
}
//shellshock Reduction
setHardShell()
{
self.shellShockReduction = .25;
}
unsetHardShell()
{
self.shellShockReduction = 0;
}
//viewkick Reduction
setSharpFocus()
{
self thread monitorSharpFocus();
}
monitorSharpFocus()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self endon ( "stop_monitorSharpFocus" );
// JC-12/17/13-To prevent a slow table look up every
// weapon_change hard code the sniper rifles here.
// Next game cache the weapons and their class on the
// level var so the GetWeaponClass() call is fast.
if ( !IsDefined( level.snipers ) )
{
level.snipers = [];
level.snipers[ "iw6_gm6_mp" ] = true;
level.snipers[ "iw6_l115a3_mp" ] = true;
level.snipers[ "iw6_usr_mp" ] = true;
level.snipers[ "iw6_vks_mp" ] = true;
level.snipers[ "iw6_dlcweap03_mp" ] = true;
}
newWeapon = self GetCurrentWeapon();
for ( ;; )
{
baseName = undefined;
if ( IsDefined( newWeapon ) && newWeapon != "none" )
{
baseName = GetWeaponBaseName( newWeapon );
}
if ( IsDefined( baseName ) && IsDefined( level.snipers[ baseName ] ) )
{
self SetViewKickScale( 0.5 );
}
else
{
self SetViewKickScale( 0.25 );
}
self waittill( "weapon_change", newWeapon );
}
}
unsetSharpFocus()
{
self notify( "stop_monitorSharpFocus" );
self setViewKickScale( 1.0 );
}
setDoubleLoad()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "endDoubleLoad" );
level endon ( "game_ended" );
for( ;; )
{
self waittill( "reload" );
weapons = self GetWeaponsList( "primary" );
foreach( weapon in weapons )
{
ammoInClip = self GetWeaponAmmoClip( weapon );
clipSize = weaponClipSize( weapon );
difference = clipSize - ammoInClip;
ammoReserves = self getWeaponAmmoStock( weapon );
if ( ammoInClip != clipSize && ammoReserves > 0 )
{
if ( ammoInClip + ammoReserves >= clipSize )
{
self setWeaponAmmoClip( weapon, clipSize );
self setWeaponAmmoStock( weapon, (ammoReserves - difference ) );
}
else
{
self setWeaponAmmoClip( weapon, ammoInClip + ammoReserves );
if ( ammoReserves - difference > 0 )
self setWeaponAmmoStock( weapon, ( ammoReserves - difference ) );
else
self setWeaponAmmoStock( weapon, 0 );
}
}
}
}
}
unsetDoubleLoad()
{
self notify( "endDoubleLoad" );
}
setMarksman( power )
{
if ( !IsDefined( power ) )
power = 10;
else
power = Int( power ) * 2;
self setRecoilScale( power );
self.recoilScale = power;
}
unsetMarksman()
{
self setRecoilScale( 0 );
self.recoilScale = 0;
}
setRShieldRadar()
{
self endon( "unsetRShieldRadar" );
wait( 0.75 );
self MakePortableRadar();
self thread setRShieldRadar_cleanUp();
}
setRShieldRadar_cleanUp()
{
self endon( "unsetRShieldRadar" );
self waittill_any( "disconnect", "death" );
if ( IsDefined( self ) )
{
self unsetRShieldRadar();
}
}
unsetRShieldRadar()
{
self ClearPortableRadar();
self notify( "unsetRShieldRadar" );
}
setRShieldScrambler()
{
self MakeScrambler();
self thread setRShieldScrambler_cleanUp();
}
setRShieldScrambler_cleanUp()
{
self endon( "unsetRShieldScrambler" );
self waittill_any( "disconnect", "death" );
if ( IsDefined( self ) )
{
self unsetRShieldScrambler();
}
}
unsetRShieldScrambler()
{
self ClearScrambler();
self notify( "unsetRShieldScrambler" );
}
setStunResistance( power )
{
if ( !isDefined( power ) )
power = 10;
power = Int( power );
if ( power == 10 )
self.stunScaler = 0;
else
self.stunScaler = power/10;
}
unsetStunResistance()
{
self.stunScaler = 1;
}
applyStunResistence( time )
{
if ( IsDefined( self.stunScaler ) )
{
return self.stunScaler * time;
}
else
{
return time;
}
}
setWeaponLaser()
{
if ( IsAgent( self ) )
return;
self endon( "unsetWeaponLaser" );
wait( 0.5 );
self thread setWeaponLaser_internal();
}
unsetWeaponLaser()
{
self notify( "unsetWeaponLaser" );
if ( IsDefined( self.perkWeaponLaserOn ) && self.perkWeaponLaserOn )
{
self disableWeaponLaser();
}
self.perkWeaponLaserOn = undefined;
self.perkWeaponLaserOffForSwitchStart = undefined;
}
setWeaponLaser_waitForLaserWeapon( weapon )
{
while ( 1 )
{
weapon = GetWeaponBaseName( weapon );
if ( IsDefined( weapon ) && ( weapon == "iw6_kac_mp" || weapon == "iw6_arx160_mp" ) )
break;
self waittill( "weapon_change", weapon );
}
}
setWeaponLaser_internal()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "unsetWeaponLaser" );
self.perkWeaponLaserOn = false;
weapon = self GetCurrentWeapon();
while ( 1 )
{
self setWeaponLaser_waitForLaserWeapon( weapon );
if ( self.perkWeaponLaserOn == false )
{
self.perkWeaponLaserOn = true;
self enableWeaponLaser();
}
// No laser in ADS
self childthread setWeaponLaser_monitorADS();
// If the player had the quick swap perk and was
// switching to a pistol the laser could end up showing
// on the pistol. To prevent this disable the laser
// whenever a weapon switch starts and enable it
// if no weapon change event happens after n seconds
// JC-09/20/13
self childthread setWeaponLaser_monitorWeaponSwitchStart( 1.0 );
self.perkWeaponLaserOffForSwitchStart = undefined;
self waittill( "weapon_change", weapon );
if ( self.perkWeaponLaserOn == true )
{
self.perkWeaponLaserOn = false;
self disableWeaponLaser();
}
}
}
setWeaponLaser_monitorWeaponSwitchStart( offTime )
{
self endon( "weapon_change" );
while ( 1 )
{
self waittill( "weapon_switch_started" );
childthread setWeaponLaser_onWeaponSwitchStart( offTime );
}
}
setWeaponLaser_onWeaponSwitchStart( offTime )
{
self notify( "setWeaponLaser_onWeaponSwitchStart" );
self endon( "setWeaponLaser_onWeaponSwitchStart" );
if ( self.perkWeaponLaserOn == true )
{
self.perkWeaponLaserOffForSwitchStart = true;
self.perkWeaponLaserOn = false;
self disableWeaponLaser();
}
wait( offTime );
self.perkWeaponLaserOffForSwitchStart = undefined;
if ( self.perkWeaponLaserOn == false && self PlayerAds() <= 0.6 )
{
self.perkWeaponLaserOn = true;
self enableWeaponLaser();
}
}
setWeaponLaser_monitorADS()
{
self endon( "weapon_change" );
while ( 1 )
{
// If the laser is off because of a recent weapon switch start, make sure not to turn it on
if ( !IsDefined( self.perkWeaponLaserOffForSwitchStart ) || self.perkWeaponLaserOffForSwitchStart == false )
{
if ( self PlayerAds() > 0.6 )
{
if ( self.perkWeaponLaserOn == true )
{
self.perkWeaponLaserOn = false;
self disableWeaponLaser();
}
}
else
{
if ( self.perkWeaponLaserOn == false )
{
self.perkWeaponLaserOn = true;
self enableWeaponLaser();
}
}
}
waitframe();
}
}
setSteadyAimPro()
{
self setaimspreadmovementscale( 0.5 );
}
unsetSteadyAimPro()
{
self notify( "end_SteadyAimPro" );
self setaimspreadmovementscale( 1.0 );
}
blastshieldUseTracker( perkName, useFunc )
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "end_perkUseTracker" );
level endon ( "game_ended" );
for ( ;; )
{
self waittill ( "empty_offhand" );
if ( !isOffhandWeaponEnabled() )
continue;
self [[useFunc]]( self _hasPerk( "_specialty_blastshield" ) );
}
}
perkUseDeathTracker()
{
self endon ( "disconnect" );
self waittill("death");
self._usePerkEnabled = undefined;
}
setRearView()
{
//self thread perkUseTracker( "specialty_rearview", ::toggleRearView );
}
unsetRearView()
{
self notify ( "end_perkUseTracker" );
}
/* NO LONGER FUNCTIONS
toggleRearView( isEnabled )
{
if ( isEnabled )
{
self givePerk( "_specialty_rearview" );
self SetRearViewRenderEnabled(true);
}
else
{
self _unsetPerk( "_specialty_rearview" );
self SetRearViewRenderEnabled(false);
}
}
*/
setEndGame()
{
if ( IsDefined( self.endGame ) )
return;
self.maxhealth = ( maps\mp\gametypes\_tweakables::getTweakableValue( "player", "maxhealth" ) * 4 );
self.health = self.maxhealth;
self.endGame = true;
self.attackerTable[0] = "";
self visionSetNakedForPlayer("end_game", 5 );
self thread endGameDeath( 7 );
maps\mp\gametypes\_gamelogic::setHasDoneCombat( self, true );
}
unsetEndGame()
{
self notify( "stopEndGame" );
self.endGame = undefined;
self restoreBaseVisionSet( 1 );
if (! IsDefined( self.endGameTimer ) )
return;
self.endGameTimer destroyElem();
self.endGameIcon destroyElem();
}
endGameDeath( duration )
{
self endon( "death" );
self endon( "disconnect" );
self endon( "joined_team" );
level endon( "game_ended" );
self endon( "stopEndGame" );
//self visionSetNakedForPlayer("end_game2", 1 );
wait( duration + 1 );
self _suicide();
}
setChallenger()
{
if ( !level.hardcoreMode )
{
self.maxhealth = maps\mp\gametypes\_tweakables::getTweakableValue( "player", "maxhealth" );
if ( IsDefined( self.xpScaler ) && self.xpScaler == 1 && self.maxhealth > 30 )
{
self.xpScaler = 2;
}
}
}
unsetChallenger()
{
self.xpScaler = 1;
}
setSaboteur()
{
self.objectiveScaler = 1.2;
}
unsetSaboteur()
{
self.objectiveScaler = 1;
}
setCombatSpeed()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "unsetCombatSpeed" );
self.inCombatSpeed = false;
self unsetCombatSpeedScalar();
for(;;)
{
self waittill( "damage", dmg, attacker );
if( !IsDefined(attacker.team) )
continue;
if ( level.teamBased && attacker.team == self.team )
continue;
if ( self.inCombatSpeed )
continue;
self setCombatSpeedScalar();
self.inCombatSpeed = true;
self thread endOfSpeedWatcher();
}
}
endOfSpeedWatcher()
{
self notify( "endOfSpeedWatcher" );
self endon( "endOfSpeedWatcher" );
self endon ( "death" );
self endon ( "disconnect" );
self waittill( "healed" );
self unsetCombatSpeedScalar();
self.inCombatSpeed = false;
}
setCombatSpeedScalar()
{
if ( IsDefined( self.isJuggernaut ) && self.isJuggernaut )
return;
if ( self.weaponSpeed <= .8 )
self.combatSpeedScalar = 1.4;
else if ( self.weaponSpeed <= .9 )
self.combatSpeedScalar = 1.3;
else
self.combatSpeedScalar = 1.2;
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
unsetCombatSpeedScalar()
{
self.combatSpeedScalar = 1;
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
unsetCombatSpeed()
{
unsetCombatSpeedScalar();
self notify( "unsetCombatSpeed" );
}
setLightWeight()
{
// Making sure we aren't overwriting the moveSpeedScalar already set in Cranked
if ( !IsDefined( self.cranked ) )
{
self.moveSpeedScaler = lightWeightScalar();
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
}
unsetLightWeight()
{
self.moveSpeedScaler = 1;
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
setBlackBox()
{
self.killStreakScaler = 1.5;
}
unsetBlackBox()
{
self.killStreakScaler = 1;
}
setSteelNerves()
{
self givePerk( "specialty_bulletaccuracy", true );
self givePerk( "specialty_holdbreath", false );
}
unsetSteelNerves()
{
self _unsetperk( "specialty_bulletaccuracy" );
self _unsetperk( "specialty_holdbreath" );
}
setDelayMine()
{
}
unsetDelayMine()
{
}
setLocalJammer()
{
if ( !self isEMPed() )
self MakeScrambler();
}
unsetLocalJammer()
{
self ClearScrambler();
}
setAC130()
{
self thread killstreakThink( "ac130", 7, "end_ac130Think" );
}
unsetAC130()
{
self notify ( "end_ac130Think" );
}
setSentryMinigun()
{
self thread killstreakThink( "airdrop_sentry_minigun", 2, "end_sentry_minigunThink" );
}
unsetSentryMinigun()
{
self notify ( "end_sentry_minigunThink" );
}
setTank()
{
self thread killstreakThink( "tank", 6, "end_tankThink" );
}
unsetTank()
{
self notify ( "end_tankThink" );
}
setPrecision_airstrike()
{
println( "!precision airstrike!" );
self thread killstreakThink( "precision_airstrike", 6, "end_precision_airstrike" );
}
unsetPrecision_airstrike()
{
self notify ( "end_precision_airstrike" );
}
setPredatorMissile()
{
self thread killstreakThink( "predator_missile", 4, "end_predator_missileThink" );
}
unsetPredatorMissile()
{
self notify ( "end_predator_missileThink" );
}
setHelicopterMinigun()
{
self thread killstreakThink( "helicopter_minigun", 5, "end_helicopter_minigunThink" );
}
unsetHelicopterMinigun()
{
self notify ( "end_helicopter_minigunThink" );
}
killstreakThink( streakName, streakVal, endonString )
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( endonString );
for ( ;; )
{
self waittill ( "killed_enemy" );
if ( self.pers["cur_kill_streak"] != streakVal )
continue;
self thread maps\mp\killstreaks\_killstreaks::giveKillstreak( streakName );
self thread maps\mp\gametypes\_hud_message::killstreakSplashNotify( streakName, streakVal );
return;
}
}
setThermal()
{
self ThermalVisionOn();
}
unsetThermal()
{
self ThermalVisionOff();
}
setOneManArmy()
{
self thread oneManArmyWeaponChangeTracker();
}
unsetOneManArmy()
{
self notify ( "stop_oneManArmyTracker" );
}
oneManArmyWeaponChangeTracker()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self endon ( "stop_oneManArmyTracker" );
for ( ;; )
{
self waittill( "weapon_change", newWeapon );
if ( newWeapon != "onemanarmy_mp" )
continue;
//if ( self isUsingRemote() )
// continue;
self thread selectOneManArmyClass();
}
}
isOneManArmyMenu( menu )
{
if ( menu == game["menu_onemanarmy"] )
return true;
if ( IsDefined( game["menu_onemanarmy_defaults_splitscreen"] ) && menu == game["menu_onemanarmy_defaults_splitscreen"] )
return true;
if ( IsDefined( game["menu_onemanarmy_custom_splitscreen"] ) && menu == game["menu_onemanarmy_custom_splitscreen"] )
return true;
return false;
}
selectOneManArmyClass()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self _disableWeaponSwitch();
self _disableOffhandWeapons();
self _disableUsability();
self openPopupMenu( game["menu_onemanarmy"] );
self thread closeOMAMenuOnDeath();
self waittill ( "menuresponse", menu, className );
self _enableWeaponSwitch();
self _enableOffhandWeapons();
self _enableUsability();
if ( className == "back" || !isOneManArmyMenu( menu ) || self isUsingRemote() )
{
if ( self getCurrentWeapon() == "onemanarmy_mp" )
{
self _disableWeaponSwitch();
self _disableOffhandWeapons();
self _disableUsability();
self switchToWeapon( self getLastWeapon() );
self waittill ( "weapon_change" );
self _enableWeaponSwitch();
self _enableOffhandWeapons();
self _enableUsability();
}
return;
}
self thread giveOneManArmyClass( className );
}
closeOMAMenuOnDeath()
{
self endon ( "menuresponse" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self waittill ( "death" );
self _enableWeaponSwitch();
self _enableOffhandWeapons();
self _enableUsability();
}
giveOneManArmyClass( className )
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
if ( self _hasPerk( "specialty_omaquickchange" ) )
{
changeDuration = 3.0;
playPlayerAndNpcSounds( self, "foly_onemanarmy_bag3_plr", "foly_onemanarmy_bag3_npc" );
}
else
{
changeDuration = 6.0;
playPlayerAndNpcSounds( self, "foly_onemanarmy_bag6_plr", "foly_onemanarmy_bag6_npc" );
}
self thread omaUseBar( changeDuration );
self _disableWeapon();
self _disableOffhandWeapons();
self _disableUsability();
wait ( changeDuration );
self _enableWeapon();
self _enableOffhandWeapons();
self _enableUsability();
self.OMAClassChanged = true;
self maps\mp\gametypes\_class::giveLoadout( self.pers["team"], className );
// handle the fact that detachAll in giveLoadout removed the CTF flag from our back
// it would probably be better to handle this in _detachAll itself, but this is a safety fix
if ( IsDefined( self.carryFlag ) )
self attach( self.carryFlag, "J_spine4", true );
self notify ( "changed_kit" );
level notify ( "changed_kit" );
}
omaUseBar( duration )
{
self endon( "disconnect" );
useBar = createPrimaryProgressBar();
useBarText = createPrimaryProgressBarText();
useBarText setText( &"MPUI_CHANGING_KIT" );
useBar updateBar( 0, 1 / duration );
for ( waitedTime = 0; waitedTime < duration && isAlive( self ) && !level.gameEnded; waitedTime += 0.05 )
wait ( 0.05 );
useBar destroyElem();
useBarText destroyElem();
}
setBlastShield()
{
//self thread blastshieldUseTracker( "specialty_blastshield", ::toggleBlastShield );
//self givePerk( "_specialty_blastshield" );
self SetWeaponHudIconOverride( "primaryoffhand", "specialty_blastshield" );
}
unsetBlastShield()
{
//self notify ( "end_perkUseTracker" );
//self _unsetPerk( "_specialty_blastshield" );
self SetWeaponHudIconOverride( "primaryoffhand", "none" );
}
//toggleBlastShield( isEnabled )
//{
// if ( !isEnabled )
// {
// self VisionSetNakedForPlayer( "black_bw", 0.15 );
// wait ( 0.15 );
// self givePerk( "_specialty_blastshield" );
// self VisionSetNakedForPlayer( "", 0 ); // go to default visionset
// self playSoundToPlayer( "item_blast_shield_on", self );
// }
// else
// {
// self VisionSetNakedForPlayer( "black_bw", 0.15 );
// wait ( 0.15 );
// self _unsetPerk( "_specialty_blastshield" );
// self VisionSetNakedForPlayer( "", 0 ); // go to default visionset
// self playSoundToPlayer( "item_blast_shield_off", self );
// }
//}
setFreefall()
{
//eventually set a listener to do a roll when falling damage is taken
}
unsetFreefall()
{
}
setTacticalInsertion()
{
self SetOffhandSecondaryClass( "flash" );
self _giveWeapon( "flare_mp", 0 );
self giveStartAmmo( "flare_mp" );
self thread monitorTIUse();
}
unsetTacticalInsertion()
{
self notify( "end_monitorTIUse" );
}
clearPreviousTISpawnpoint()
{
self waittill_any ( "disconnect", "joined_team", "joined_spectators" );
if ( IsDefined ( self.setSpawnpoint ) )
self deleteTI( self.setSpawnpoint );
}
updateTISpawnPosition()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self endon ( "end_monitorTIUse" );
while ( isReallyAlive( self ) )
{
if ( self isValidTISpawnPosition() )
self.TISpawnPosition = self.origin;
wait ( 0.05 );
}
}
isValidTISpawnPosition()
{
if ( CanSpawn( self.origin ) && self IsOnGround() )
return true;
else
return false;
}
TI_overrideMovingPlatformDeath( data )
{
if ( IsReallyAlive( data.owner ) )
data.owner deleteTI( self );
}
monitorTIUse()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
self endon ( "end_monitorTIUse" );
self thread updateTISpawnPosition();
self thread clearPreviousTISpawnpoint();
for ( ;; )
{
self waittill( "grenade_fire", lightstick, weapName );
if ( weapName != "flare_mp" )
continue;
//lightstick delete();
if ( IsDefined( self.setSpawnPoint ) )
self deleteTI( self.setSpawnPoint );
if ( !IsDefined( self.TISpawnPosition ) )
continue;
if ( self touchingBadTrigger() )
continue;
startPos = self.TISpawnPosition + (0,0,16);
endPos = self.TISpawnPosition - (0,0,2048);
TIGroundPosition = PlayerPhysicsTrace( startPos, endPos ) + (0,0,1);
traceResult = BulletTrace( startPos, endPos, false ); // I need this to find out if we're on a platform
glowStick = spawn( "script_model", TIGroundPosition );
glowStick.angles = self.angles;
glowStick.team = self.team;
glowStick.owner = self;
glowStick.enemyTrigger = spawn( "script_origin", TIGroundPosition );
glowStick thread GlowStickSetupAndWaitForDeath( self );
glowStick.playerSpawnPos = self.TISpawnPosition;
glowStick SetOtherEnt( self );
glowStick make_entity_sentient_mp( self.team, true );
glowStick thread maps\mp\gametypes\_weapons::createBombSquadModel( "weapon_light_stick_tactical_bombsquad", "tag_fire_fx", self );
glowStick maps\mp\gametypes\_weapons::explosiveHandleMovers( traceResult["entity" ] );
maps\mp\gametypes\_weapons::onTacticalEquipmentPlanted( glowStick );
self.setSpawnPoint = glowStick;
return;
}
}
CONST_TI_FX_TAG = "tag_fire_fx";
GlowStickSetupAndWaitForDeath( owner )
{
self setModel( level.spawnGlowModel["enemy"] );
if ( level.teamBased )
self maps\mp\_entityheadIcons::setTeamHeadIcon( self.team , (0,0,20) );
else
self maps\mp\_entityheadicons::setPlayerHeadIcon( owner, (0,0,20) );
self thread GlowStickDamageListener( owner );
self thread GlowStickEnemyUseListener( owner );
self thread GlowStickUseListener( owner );
self thread glowStickWaitForOwnerDisconnect( owner );
dummyGlowStick = spawn( "script_model", self.origin+ (0,0,0) );
dummyGlowStick.angles = self.angles;
dummyGlowStick setModel( level.spawnGlowModel["friendly"] );
dummyGlowStick setContents( 0 );
dummyGlowStick LinkTo( self );
dummyGlowStick PlayLoopSound( "emt_road_flare_burn" );
thread GlowStickTeamUpdater( self, dummyGlowStick, owner );
self waittill ( "death" );
dummyGlowStick stopLoopSound();
dummyGlowStick delete();
}
GlowStickTeamUpdater( enemyStick, friendlyStick, owner )
{
enemyStick endon( "death" ); // the enemy model is the main entity
// PlayFXOnTag fails if run on the same frame the parent entity was created
wait ( 0.05 );
glowstickEnts = [];
glowstickEnts[ "enemy" ] = enemyStick;
glowstickEnts[ "friendly" ] = friendlyStick;
for ( ;; )
{
foreach ( glowstick in glowstickEnts )
{
glowstick Hide();
}
foreach ( player in level.players )
{
key = "friendly";
if ( owner isEnemy( player ) )
{
key = "enemy";
}
glowstick = glowstickEnts[ key ];
glowstick Show();
PlayFXOnTagForClients( level.spawnGlow[ key ], glowstick, CONST_TI_FX_TAG, player );
waitframe();
}
level waittill( "joined_team" );
foreach ( key, glowstick in glowstickEnts )
{
StopFXOnTag( level.spawnGlow[ key ], glowstick, CONST_TI_FX_TAG );
}
waitframe();
}
}
deleteOnDeath( ent )
{
self waittill( "death" );
if ( IsDefined( ent ) )
ent delete();
}
GlowStickDamageListener( owner )
{
self maps\mp\gametypes\_damage::monitorDamage(
100,
"tactical_insertion",
::GlowStickModifyDamage,
::GlowStickHandleDeathDamage,
true // isKillstreak
);
}
GlowStickModifyDamage( attacker, weapon, type, damage )
{
return self maps\mp\gametypes\_damage::handleMeleeDamage( weapon, type );
}
GlowStickHandleDeathDamage( attacker, weapon, type, damage )
{
if ( IsDefined( self.owner ) && attacker != self.owner )
{
attacker notify ( "destroyed_insertion", self.owner );
attacker notify( "destroyed_equipment" ); // count towards SitRep Pro challenge
self.owner thread leaderDialogOnPlayer( "ti_destroyed", undefined, undefined, self.origin );
}
attacker thread deleteTI( self );
}
GlowStickUseListener( owner )
{
self endon ( "death" );
level endon ( "game_ended" );
owner endon ( "disconnect" );
self setCursorHint( "HINT_NOICON" );
self setHintString( &"MP_PATCH_PICKUP_TI" );
self thread updateEnemyUse( owner );
for ( ;; )
{
self waittill ( "trigger", player );
player playSound( "tactical_insert_flare_pu" );
if( !player isJuggernaut() )
player thread setTacticalInsertion();
player thread deleteTI( self );
}
}
updateEnemyUse( owner )
{
self endon ( "death" );
for ( ;; )
{
self setSelfUsable( owner );
level waittill_either ( "joined_team", "player_spawned" );
}
}
glowStickWaitForOwnerDisconnect( owner )
{
self endon( "death" );
owner waittill ( "disconnect" );
thread deleteTI( self );
}
deleteTI( TI )
{
if (IsDefined( TI.enemyTrigger ) )
TI.enemyTrigger Delete();
spot = TI.origin;
spotAngles = TI.angles;
parent = TI GetLinkedParent();
TI Delete();
dummyGlowStick = spawn( "script_model", spot );
dummyGlowStick.angles = spotAngles;
dummyGlowStick setModel( level.spawnGlowModel["friendly"] );
dummyGlowStick setContents( 0 );
if ( IsDefined( parent ) )
dummyGlowStick LinkTo( parent );
thread dummyGlowStickDelete( dummyGlowStick );
}
dummyGlowStickDelete( stick )
{
wait(2.5);
stick Delete();
}
GlowStickEnemyUseListener( owner )
{
self endon ( "death" );
level endon ( "game_ended" );
owner endon ( "disconnect" );
self.enemyTrigger setCursorHint( "HINT_NOICON" );
self.enemyTrigger setHintString( &"MP_PATCH_DESTROY_TI" );
self.enemyTrigger makeEnemyUsable( owner );
for ( ;; )
{
self.enemyTrigger waittill ( "trigger", player );
player notify ( "destroyed_insertion", owner );
player notify( "destroyed_equipment" ); // count towards SitRep Pro challenge
//playFX( level.spawnGlowSplat, self.origin);
if ( IsDefined( owner ) && player != owner )
owner thread leaderDialogOnPlayer( "ti_destroyed", undefined, undefined, self.origin );
player thread deleteTI( self );
}
}
setLittlebirdSupport()
{
self thread killstreakThink( "littlebird_support", 2, "end_littlebird_support_think" );
}
unsetLittlebirdSupport()
{
self notify ( "end_littlebird_support_think" );
}
setPainted( attacker ) // self == victim
{
// this is called from cac_modified_damage, not the perk functions
if( IsPlayer( self ) )
{
outlineTime = 1;
// Countered by Incog
if ( !self _hasPerk ( "specialty_incog" ) )
{
self.painted = true;
if ( level.teamBased )
{
id = outlineEnableForTeam( self, "orange", attacker.team, false, "perk" );
self thread watchPainted( id, outlineTime );
self thread watchPaintedAgain( id );
}
else
{
id = outlineEnableForPlayer( self, "orange", attacker, false, "perk" );
self thread watchPainted( id, outlineTime );
self thread watchPaintedAgain( id );
}
}
}
}
watchPainted( id, timeout )
{
// Notify to kill the last outline id
self notify( "painted_again" );
// The notify will also kill the previous waiting thread
self endon( "painted_again" );
self endon( "disconnect" );
level endon( "game_ended" );
self waittill_any_timeout( timeout, "death" );
self.painted = false;
outlineDisable( id, self );
// We know it is going to disable
// So go ahead and send a notification so we have no hanging threads in watchPaintedAgain
self notify ( "painted_end" );
}
watchPaintedAgain( id )
{
self endon( "disconnect" );
level endon( "game_ended" );
// Need to make sure that if we paint the player again
// we need to kill the outline that was applied previously;
// Using "painted_end" as a fail safe in case for some reason this does not get activated by "painted_again"
self waittill_any( "painted_again", "painted_end" );
outlineDisable( id, self );
}
isPainted()
{
return ( IsDefined( self.painted ) && self.painted );
}
setAssists()
{
}
unsetAssists()
{
}
setRefillGrenades()
{
if( IsDefined( self.primaryGrenade ) )
{
self GiveMaxAmmo( self.primaryGrenade );
}
if( IsDefined( self.secondaryGrenade ) )
{
self GiveMaxAmmo( self.secondaryGrenade );
}
}
unsetRefillGrenades()
{
}
setRefillAmmo()
{
if( IsDefined( self.primaryWeapon ) )
{
self GiveMaxAmmo( self.primaryWeapon );
}
if( IsDefined( self.secondaryWeapon ) )
{
self GiveMaxAmmo( self.secondaryWeapon );
}
}
unsetRefillAmmo()
{
}
setGunsmith()
{
self thread setGunsmithInternal();
}
setGunsmithInternal()
{
self endon( "disconnect" );
self endon( "death" );
level endon( "game_ended" );
self endon( "unsetGunsmith" );
self waittill( "giveLoadout" );
if ( self.loadoutPrimaryAttachments.size == 0 && self.loadoutSecondaryAttachments.size == 0 )
return;
while ( 1 )
{
self waittill( "weapon_change", weaponNew );
if ( weaponNew == "none" )
continue;
if ( isKillstreakWeapon( weaponNew ) )
continue;
if ( !isStrStart( weaponNew, "iw5_" ) && !isStrStart( weaponNew, "iw6_" ) )
continue;
// Grab potential attachments
attachmentsLoadout = undefined;
if ( getWeaponClass( weaponNew ) == "weapon_pistol" )
{
if ( self.loadoutSecondaryAttachments.size > 0 )
{
attachmentsLoadout = self.loadoutSecondaryAttachments;
}
}
else
{
if ( self.loadoutPrimaryAttachments.size > 0 )
{
attachmentsLoadout = self.loadoutPrimaryAttachments;
}
}
if ( !IsDefined( attachmentsLoadout ) )
continue;
// Early out if this weapon has the same attachments. Handles load outs
// not getting adjusted.
shouldAdd = false;
attachmentsCurrent = getWeaponAttachmentsBaseNames( weaponNew );
if ( attachmentsCurrent.size == 0 )
{
shouldAdd = true;
}
else
{
foreach ( attachment in attachmentsLoadout )
{
if ( !array_contains( attachmentsCurrent, attachment ) )
{
shouldAdd = true;
break;
}
}
}
if ( !shouldAdd )
continue;
// Remove loadout attachments incompatible with new gun
attachmentsLoadoutCleaned = [];
attachmentsValid = getWeaponAttachmentArrayFromStats( weaponNew );
foreach ( attachment in attachmentsLoadout )
{
if ( array_contains( attachmentsValid, attachment ) )
{
attachmentsLoadoutCleaned[ attachmentsLoadoutCleaned.size ] = attachment;
}
}
attachmentsLoadout = attachmentsLoadoutCleaned;
// Remove new gun attachments overwritten by loadout attachments
attachmentsCompatible = [];
foreach ( attachCurr in attachmentsCurrent )
{
compatible = true;
foreach ( attachLoadout in attachmentsLoadout )
{
if ( !attachmentsCompatible( attachLoadout, attachCurr ) )
{
compatible = false;
break;
}
}
if ( compatible )
{
attachmentsCompatible[ attachmentsCompatible.size ] = attachCurr;
}
}
attachmentsCurrent = attachmentsCompatible;
totalPossible = attachmentsLoadout.size + attachmentsCurrent.size;
// If there are more than needed, randomize the array before adding
// the current attachments to the loadout attachmentss
if ( totalPossible > 4 )
{
attachmentsCurrent = array_randomize( attachmentsCurrent );
}
idx = 0;
while ( attachmentsLoadout.size < 4 && idx < attachmentsCurrent.size )
{
attachmentsLoadout[ attachmentsLoadout.size ] = attachmentsCurrent[ idx ];
idx++;
}
// Build new weapon
weaponNewBase = GetWeaponBaseName( weaponNew );
weaponUpdated = weaponNewBase;
// Convert attachments back to unique name
foreach ( idx, attachment in attachmentsLoadout )
{
attachUnique = attachmentMap_toUnique( attachment, weaponNew );
attachmentsLoadout[ idx ] = attachUnique;
}
attachmentsLoadout = alphabetize( attachmentsLoadout );
foreach ( attachment in attachmentsLoadout )
{
weaponUpdated += "_" + attachment;
}
if ( weaponUpdated != weaponNewBase )
{
ammoClip = self GetWeaponAmmoClip( weaponNew );
ammoStock = self GetWeaponAmmoStock( weaponNew );
self TakeWeapon( weaponNew );
self GiveWeapon( weaponUpdated );
self SetWeaponAmmoClip( weaponUpdated, ammoClip );
self SetWeaponAmmoStock( weaponUpdated, ammoStock );
self SwitchToWeapon( weaponUpdated );
}
}
}
unsetGunsmith()
{
self notify( "unsetGunsmith" );
}
setGambler()
{
self SetClientOmnvar( "ui_gambler_show", -1 );
self setGamblerInternal();
}
setGamblerInternal()
{
level.abilityMaxVal = [];
// Step 1: Get all of the abilities we have available in cacabilitytable.csv
// Step 2: Loop through and compare what the player has (normally, and ones chosen through specialist), vs what is on the table
// There are some util functions available for this
// Step 3: Place valid abilities into a new array for lookup later
// Step 4: Go through the new array and assign weights for each perk based on their point cost
// This will also mean that we will need to look up the cost in perktable.csv using the name of the ability
// Should have a very low chance to grab another cost 1 ability
// Possible weights:
// 1 Cost = 0 (Default if nothing else is found)
// 2 Cost = 30
// 3 Cost = 20
// ... 7 Cost = 5
// Get the number of categories and abilities per category
abilityCategories = maps\mp\gametypes\_class::getNumAbilityCategories();
abilityPerCategory = maps\mp\gametypes\_class::getNumSubAbility();
validAbilities = [];
abilityWeight = 0;
loadoutPerks = undefined;
if ( isAI( self ) )
loadoutPerks = self.pers[ "loadoutPerks" ];
// Cache all of these values so we don't have to do expensive table lookups mid-game
if ( !IsDefined(level.perkNamesForGambler) )
{
level.perkNamesForGambler = [];
level.perkCostsForGambler = [];
level.perkRowsForGambler = [];
for ( abilityCategoryIndex = 0; abilityCategoryIndex < abilityCategories; abilityCategoryIndex++ )
{
for ( abilityIndex = 0; abilityIndex < abilityPerCategory; abilityIndex++ )
{
perkName = TableLookup( "mp/cacAbilityTable.csv", 0, abilityCategoryIndex + 1, 4 + abilityIndex );
level.perkNamesForGambler[abilityCategoryIndex][abilityIndex] = perkName;
for ( row = 0; TableLookupByRow( "mp/perktable.csv", row, 0 ) != ""; row++ )
{
// Find the ability we have in this new table
if ( perkName == TableLookupByRow( "mp/perktable.csv", row, 1 ) )
{
// See what the cost is
level.perkCostsForGambler[abilityCategoryIndex][abilityIndex] = int(TableLookupByRow( "mp/perktable.csv", row, 10 ));
level.perkRowsForGambler[abilityCategoryIndex][abilityIndex] = row;
break;
}
}
}
}
}
// Used to see if Gambler has been picked within the common loadout, or through specialist
isGamblerCommonLoadout = self gamblerCommonChecker();
isGamblerDefaultLoadout = false;
// gamblerCommonChecker will always check your custom loadouts to see if you have gambler selected
// While playing infected with default loadouts, it doesn't matter if custom loadouts also have gambler, so always default it to false
if ( level.gameType == "infect" )
isGamblerCommonLoadout = false;
if ( IsDefined( self.teamName ) )
{
isGamblerDefaultLoadout = getMatchRulesData( "defaultClasses", self.teamName, self.class_num, "class", "abilitiesPicked", 6, 0 );
}
for ( abilityCategoryIndex = 0; abilityCategoryIndex < abilityCategories; abilityCategoryIndex++ )
{
for ( abilityIndex = 0; abilityIndex < abilityPerCategory; abilityIndex++ )
{
// Else let's grab the ability ref and assign a weight based on cost
abilityRef = level.perkNamesForGambler[ abilityCategoryIndex ][ abilityIndex ];
// Check all perks chosen to make sure we don't grab any duplicates
alreadyPicked = perkPickedChecker( abilityRef, abilityCategoryIndex, abilityIndex );
if ( alreadyPicked && (self.streakType == "specialist" || !self.perkPickedSpecialist) )
continue;
// Make sure it is a valid ability before proceeding
if ( !IsDefined( abilityRef ) )
continue;
if ( abilityRef == "" )
continue;
// Fix to stop players from getting these perks in gambler
if ( abilityRef == "specialty_extra_attachment" || abilityRef == "specialty_twoprimaries" )
continue;
// Remove the following perks from being chosen, if the player has specialist gambler, or is playing infected with default loadouts
if ( IsDefined( isGamblerCommonLoadout ) && !isGamblerCommonLoadout && !isGamblerDefaultLoadout )
{
if ( abilityRef == "specialty_extraammo" || abilityRef == "specialty_extra_equipment" || abilityRef == "specialty_extra_deadly" )
continue;
}
// Removing hardline for support due to a potential problem with how killstreaks are earned
// Support Killstreak: SAT COM 4 Kills
// 1: Player gets specialty_blindeye from gambler, kills 3 people
// 2: Player gets killed, and gets hardline from gambler
// It will show that the player has enough kills for SAT COM, but he won't be able to earn it
if ( self.streakType == "support" )
{
if ( abilityRef == "specialty_hardline" )
continue;
}
if ( isAI( self ) && IsDefined( loadoutPerks ) && array_contains( loadoutPerks, abilityRef ) )
continue;
// See what the cost is
abilityCost = level.perkCostsForGambler[abilityCategoryIndex][abilityIndex];
row = level.perkRowsForGambler[abilityCategoryIndex][abilityIndex];
switch( abilityCost )
{
case 1:
abilityWeight = 150;
break;
case 2:
abilityWeight = 40;
break;
case 3:
abilityWeight = 60;
break;
case 4:
abilityWeight = 20;
break;
case 5:
abilityWeight = 20;
break;
default:
AssertMsg( "setGambler() did not handle perk: " + abilityRef + " of cost: " + abilityCost );
break;
}
// Assign the necessary values for each ability
validAbilities[ validAbilities.size ] = SpawnStruct();
validAbilities[ validAbilities.size - 1 ] .row = row;
validAbilities[ validAbilities.size - 1 ] .id = abilityRef;
validAbilities[ validAbilities.size - 1 ] .weight = abilityWeight;
}
}
self.perkPickedSpecialist = undefined;
// Step 5: Sort the array based on weight; this will be used when finding a random ability
// Grab the sum of the weights used in the array
// Step 6: Go through this array and grab a random ability based on weight
// Step 7: Give the player the new perk when they spawn in the game
// JC-12/03/13-Hacked player data can result in no valid abilities for gambler.
// Skip gambler reward in this case.
if ( validAbilities.size > 0 )
{
self thread giveGamblerChoice(validAbilities);
}
}
gamblerCommonChecker() // self = player
{
if ( !isAI( self ) )
{
return self GetCaCPlayerData( "loadouts", self.class_num, "abilitiesPicked", 6, 0 );
}
else
{
// AI Bot Player or Agent Humanoid
itemsToCheck = [];
if ( IsDefined( self.pers[ "loadoutPerks" ] ) )
itemsToCheck = array_combine( itemsToCheck, self.pers[ "loadoutPerks" ] );
foreach ( item in itemsToCheck )
{
if ( getBasePerkName( item ) == "specialty_gambler" )
return true;
}
}
return false;
}
perkPickedChecker( perkName, abilityCategoryIndex, abilityIndex ) // self = player
{
self.perkPickedSpecialist = false;
if ( !IsDefined( perkName ) )
return false;
if ( perkName == "" )
return false;
if ( !isAI( self ) )
{
// Get the number of categories and abilities per category
abilityCategories = maps\mp\gametypes\_class::getNumAbilityCategories();
abilityPerCategory = maps\mp\gametypes\_class::getNumSubAbility();
// Check the loadout
if ( self GetCaCPlayerData( "loadouts", self.class_num, "abilitiesPicked", abilityCategoryIndex, abilityIndex ) )
return true;
// Main 3 Specialist perks
for( index = 0; index < 3; index++ )
{
killstreak = self getCaCPlayerData( "loadouts", self.class_num, "specialistStreaks", index );
if ( IsDefined( killstreak ) && killstreak != "none" )
{
basePerkName = getBasePerkName( killstreak );
if ( basePerkName == perkName )
{
self.perkPickedSpecialist = true;
return true;
}
}
}
// Bonus Specialist Perks
picked = self GetCaCPlayerData( "loadouts", self.class_num, "specialistBonusStreaks", abilityCategoryIndex, abilityIndex );
if( IsDefined( picked ) && picked )
{
bonusPerkName = level.perkNamesForGambler[ abilityCategoryIndex ][ abilityIndex ];
if ( bonusPerkName == perkName )
{
self.perkPickedSpecialist = true;
return true;
}
}
}
else
{
// AI Bot Player or Agent Humanoid
// Must iterate all chosen perks each time
itemsToCheck = [];
if ( IsDefined( self.pers[ "loadoutPerks" ] ) )
itemsToCheck = array_combine( itemsToCheck, self.pers[ "loadoutPerks" ] );
foreach ( item in itemsToCheck )
{
if ( getBasePerkName( item ) == perkName )
return true;
}
itemsToCheck = [];
if ( IsDefined( self.pers[ "specialistStreaks" ] ) )
itemsToCheck = array_combine( itemsToCheck, self.pers[ "specialistStreaks" ] );
if ( IsDefined( self.pers[ "specialistBonusStreaks" ] ) )
itemsToCheck = array_combine( itemsToCheck, self.pers[ "specialistBonusStreaks" ] );
foreach ( item in itemsToCheck )
{
if ( getBasePerkName( item ) == perkName )
{
self.perkPickedSpecialist = true;
return true;
}
}
}
return false;
}
giveGamblerChoice(abilityArray)
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "unsetGambler" );
level endon ( "game_ended" );
// Wait till the prematch is over before initially giving the player a random ability
// Once prematch is loaded, make sure we get the selected loadout before giving the perk
// Perks are given first before killstreaks, so it will break hardline if that is given before killstreaks are set
// Specialist is excluded because we give perks in the middle of the match when your loadout is already set
if ( !gameFlag( "prematch_done" ) )
gameFlagWait( "prematch_done" );
else if ( gameFlag ("prematch_done") && self.streakType != "specialist" )
self waittill( "giveLoadout" );
// When are the times we should give the player a new ability
// + 1: Start with the game (wait till prematch is done)
// + 2: Start while game is still in grace period (wait till grace period is done)
// + 3: Start while game is playing (wait till loadout is done)
// + 4: Respawning in the same game (wait till loadout is done)
if(!IsDefined(self.abilityChosen))
self.abilityChosen = false;
if (!self.abilityChosen)
{
randomAbility = getRandomAbility( abilityArray );
self.gamblerAbility = randomAbility;
}
else
randomAbility = self.gamblerAbility;
// Give the player the random ability
self givePerk( randomAbility.id, false );
// Since we are giving potentially hardline mid life, instead of at the beginning of the loadout,
// we will need to make sure it displays the correct kill count for the next streak
if( randomAbility.id == "specialty_hardline" )
self maps\mp\killstreaks\_killstreaks::setStreakCountToNext();
// Step 8: Make sure this new perk is shown to the player through the HUD
if( showGambler() )
{
self PlayLocalSound( "mp_suitcase_pickup" );
self SetClientOmnvar( "ui_gambler_show", randomAbility.row );
self thread gamblerAnimWatcher();
}
// Each time the player switches between survivors > initial infected or infected, we want to give them a new ability
if ( level.gameType != "infect" )
self.abilityChosen = true;
}
showGambler()
{
// Always show your gambler choice to the player, unless otherwise stated
showGambler = true;
// if the match is already going, and you already had an ability chosen
// We know that you are regetting gambler when your loadout is restored by something else (e.g. Bloodrush)
if ( !level.inGracePeriod && self.abilityChosen )
showGambler = false;
// Certain game modes need to show gambler each time
if ( !allowClassChoice() && level.gameType != "infect" )
showGambler = false;
return showGambler;
}
gamblerAnimWatcher()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "unsetGambler" );
level endon ( "game_ended" );
self waittill( "luinotifyserver", channel, value );
if (channel == "gambler_anim_complete")
self SetClientOmnvar( "ui_gambler_show", -1 );
}
getRandomAbility( abilityArray )
{
weightArray = [];
// Sort the array according to weight, highest to lowest
weightArray = self thread sortByWeight( abilityArray );
// Make sure we get the max value to rand through
weightArray = self thread setBucketVal( weightArray );
randValue = RandomInt( level.abilityMaxVal[ "sum" ] );
newAbility = undefined;
// Time to search through the ability array, use the weight sum we found before
// See if the ability's weight is larger than the randValue
// Then we know that it falls within the range of numbers that we set in the bucket
foreach ( ability in weightArray )
{
if ( !ability.weight || ability.id == "specialty_gambler")
continue;
if ( ability.weight > randValue )
{
newAbility = ability;
break;
}
}
return newAbility;
}
sortByWeight( abilityArray )
{
nextAbility = [];
prevAbility = [];
// Go through the array, starting at index [1]
for ( nextIndex = 1; nextIndex < abilityArray.size; nextIndex++ )
{
// Set the weight that you want to compare
nextWeight = abilityArray[ nextIndex ].weight;
nextAbility = abilityArray[ nextIndex ];
// Next go through the loop through again starting at index [0]
for ( prevIndex = nextIndex - 1; ( prevIndex >= 0 ) && is_weight_a_less_than_b( abilityArray[ prevIndex ].weight, nextWeight ); prevIndex-- )
{
// If the current weight is not less than the current weight
// Set the nextIndex's weight to the prevIndex weight
prevAbility = abilityArray [prevIndex];
abilityArray[ prevIndex ] = nextAbility;
abilityArray[ prevIndex + 1 ] = prevAbility;
}
}
return abilityArray;
}
is_weight_a_less_than_b( a, b )
{
return ( a < b );
}
setBucketVal( abilityArray )
{
level.abilityMaxVal[ "sum" ] = 0;
// For each ability within the passed in validAbilities array
foreach ( ability in abilityArray )
{
// Check to see if the weight of that ability has been defined yet
if ( !ability.weight )
continue;
// Create a bucket by initially adding the ability weight to the new array
// And then setting that ability's weight to the current weight sum
// This is so that each ability will have a certain value range for their weight for use, when we start to find a random ability
level.abilityMaxVal[ "sum" ] += ability.weight;
ability.weight = level.abilityMaxVal[ "sum" ];
}
return abilityArray;
}
unsetGambler()
{
self notify( "unsetGambler" );
}
setComExp()
{
// Start the player off with Eyes On
//self SetEyesOnUplinkEnabled( 1 );
// need to call this in case the player switches to a class with ComExp after uplink updates have happened
assert( IsDefined( level.comExpFuncs ) );
assert( IsDefined( level.comExpFuncs[ "giveComExpBenefits" ] ) );
give_com_exp_func = level.comExpFuncs[ "giveComExpBenefits" ];
self [[ give_com_exp_func ]]();
}
unsetComExp()
{
assert( IsDefined( level.comExpFuncs ) );
assert( IsDefined( level.comExpFuncs[ "removeComExpBenefits" ] ) );
unset_com_exp_func = level.comExpFuncs[ "removeComExpBenefits" ];
self [[ unset_com_exp_func ]]();
}
setTagger()
{
self thread setTaggerInternal();
}
setTaggerInternal()
{
// self == player
self endon( "death" );
self endon( "disconnect" );
self endon( "unsetTagger" );
level endon( "game_ended" );
while( true )
{
// Wait till I am seen
self waittill ("eyesOn");
// Get an array of players who see me
sightingPlayers = self GetPlayersSightingMe();
foreach( otherPlayer in sightingPlayers )
{
// ignore teammates
if( level.teamBased && (otherPlayer.team == self.team) )
continue;
// If the other person is still alive, and playing, go ahead and mark them
if (isAlive(otherPlayer) && otherplayer.sessionstate == "playing")
{
if (!isDefined(otherplayer.perkOutlined))
otherplayer.perkOutlined = false;
if (!otherplayer.perkOutlined)
{
// Removed outline calls from this as the outline wrappers have changed. If this perk is revived this logic will have to change.
// maps\mp\gametypes\_outline::enableOutlineForPlayer( otherplayer, 1, self);
otherplayer.perkOutlined = true;
}
otherplayer thread outlineWatcher(self);
}
}
}
}
outlineWatcher(victim)
{
// Self == attacker
self endon( "death" );
self endon( "disconnect" );
self endon( "eyesOff" );
level endon( "game_ended" );
for ( ;; )
{
notWatching = true;
sightingPlayers = victim GetPlayersSightingMe();
foreach ( otherPlayer in sightingPlayers )
{
if ( otherPlayer == self )
{
notWatching = false;
break;
}
}
if ( notWatching )
{
// Removed outline calls from this as the outline wrappers have changed. If this perk is revived this logic will have to change.
// maps\mp\gametypes\_outline::disableOutlineForPlayer( self, victim );
self.perkOutlined = false;
self notify ( "eyesOff" );
}
wait( 0.5 );
}
}
unsetTagger()
{
self notify( "unsetTagger" );
}
setPitcher()
{
self thread setPitcherInternal();
}
setPitcherInternal()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "unsetPitcher" );
level endon( "game_ended" );
// Scale the time it takes to cook primable grenades (higher the value the faster it will cook)
self _setPerk("specialty_throwback", false);
self SetGrenadeCookScale(1.5);
for(;;)
{
self SetGrenadeThrowScale(1.25);
// Wait till a grenade throw is in progress, then set the throw scale depending on what type of grenade it is
self waittill ( "grenade_pullback", grenadeName );
// Keep the throw distance of airdrops and killstreaks the same as default
if ( grenadeName == "airdrop_marker_mp" || grenadeName == "killstreak_uplink_mp" || grenadeName == "deployable_vest_marker_mp"|| grenadeName == "deployable_weapon_crate_marker_mp" || grenadeName == "airdrop_juggernaut_mp" )
self SetGrenadeThrowScale(1);
// Make sure we wait until the previous grenade is thrown before we reset the grenade throw scale back to 1.25
self waittill ( "grenade_fire", grenade, weaponName );
}
}
unsetPitcher()
{
self SetGrenadeCookScale(1);
self SetGrenadeThrowScale(1);
self _unsetPerk("specialty_throwback");
self notify( "unsetPitcher" );
}
setBoom()
{
}
setBoomInternal( attacker )
{
//self == victim
self endon ("death");
self endon ("disconnect");
self endon ("unsetBoom");
level endon( "game_ended" );
attacker endon("death");
attacker endon ("disconnect");
// Make sure the player is truly dead before activating the ping
waitframe();
TriggerPortableRadarPing( self.origin, attacker );
attacker boomTrackPlayers( self.origin );
}
// 2013-10-17 wallace: could not use the dvars in ship, so set consts to match their hard-coded values
BOOM_DIST_SQ = 700 * 700;
BOOM_DURATION = 2000; // in ms
// we'll only be able track the last guy who ping'd us
boomTrackPlayers( targetPos ) // self == attacker
{
// these should be from portable radar ping
// BOOM_DIST_SQ = GetDvarInt( "compassPortableRadarTriggeredRadius" );
// BOOM_DIST_SQ = BOOM_DIST_SQ * BOOM_DIST_SQ;
// BOOM_DURATION = GetDvarInt( "compassPortableRadarTriggeredSweepTime" ) + 1000; // in ms
foreach ( player in level.players )
{
if ( self isEnemy( player )
&& IsAlive( player )
&& !player _hasPerk("specialty_gpsjammer")
&& (DistanceSquared( targetPos, player.origin ) <= BOOM_DIST_SQ ) )
{
player.markedByBoomPerk[ self getUniqueId() ] = GetTime() + BOOM_DURATION;
}
}
}
unsetBoom()
{
self notify ("unsetBoom");
}
setSilentkill()
{
}
unsetSilentkill()
{
}
setBloodrush()
{
self.bloodrushRegenSpeedMod = 1;
self.bloodrushRegenHealthMod = 1;
}
setBloodrushInternal()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "unsetBloodrush" );
level endon( "game_ended" );
// For X amount of time, increase health regen and speed
if (!isDefined(self.isJuiced) || !self.isJuiced)
{
self.rushtime = 5;
self thread customJuiced( self.rushtime );
self.bloodrushRegenSpeedMod = 0.25; //regen health will start at a percent of the normal speed
self.bloodrushRegenHealthMod = 5; //regen health multiplied times the normal speed
self notify( "bloodrush_active" );
}
self waittill( "unset_custom_juiced" );
self unsetBloodrush();
}
customJuiced( waittime )
{
self endon( "death" );
self endon( "faux_spawn" );
self endon( "disconnect" );
self endon( "unset_custom_juiced" );
level endon( "game_ended" );
self.isJuiced = true;
self.moveSpeedScaler = 1.1;
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
// reloading == specialty_fastreload
self givePerk( "specialty_fastreload", false );
// ads'ing == specialty_quickdraw
self givePerk( "specialty_quickdraw", false );
// movement == specialty_stalker
self givePerk( "specialty_stalker", false );
// throwing grenades == specialty_fastoffhand
self givePerk( "specialty_fastoffhand", false );
// sprint recovery == specialty_fastsprintrecovery
self givePerk( "specialty_fastsprintrecovery", false );
// switching weapons == specialty_quickswap
self givePerk( "specialty_quickswap", false );
self thread unsetCustomJuicedOnDeath();
self thread unsetCustomJuicedOnRide();
self thread unsetCustomJuicedOnMatchEnd();
endTime = ( waittime * 1000 ) + GetTime();
if ( !IsAI( self ) )
{
self SetClientDvar( "ui_juiced_end_milliseconds", endTime );
}
wait(waittime);
self unsetCustomJuiced();
}
unsetCustomJuiced( death )
{
if( !IsDefined( death ) )
{
if( self isJuggernaut() )
{
Assert( IsDefined( self.juggMoveSpeedScaler ) );
if( IsDefined( self.juggMoveSpeedScaler ) )
self.moveSpeedScaler = self.juggMoveSpeedScaler;
else // handle the assert case for ship
self.moveSpeedScaler = 0.7; // compromise of the expected .65 or .75
}
else
{
self.moveSpeedScaler = 1;
if( self _hasPerk( "specialty_lightweight" ) )
self.moveSpeedScaler = lightWeightScalar();
}
Assert( IsDefined( self.moveSpeedScaler ) );
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
// reloading == specialty_fastreload
self _unsetPerk( "specialty_fastreload" );
// ads'ing == specialty_quickdraw
self _unsetPerk( "specialty_quickdraw" );
// movement == specialty_stalker
self _unsetPerk( "specialty_stalker" );
// throwing grenades == specialty_fastoffhand
self _unsetPerk( "specialty_fastoffhand" );
// sprint recovery == specialty_fastsprintrecovery
self _unsetPerk( "specialty_fastsprintrecovery" );
// switching weapons == specialty_quickswap
self _unsetPerk( "specialty_quickswap" );
// restore the new iw6 perks system
if ( IsDefined( self.pers[ "loadoutPerks" ] ) )
{
self maps\mp\perks\_abilities::givePerksFromKnownLoadout( self.pers[ "loadoutPerks" ] );
}
self.isJuiced = undefined;
if ( !IsAI( self ) )
{
self SetClientDvar( "ui_juiced_end_milliseconds", 0 );
}
self notify( "unset_custom_juiced" );
}
unsetCustomJuicedOnRide()
{
self endon ( "disconnect" );
self endon ( "unset_custom_juiced" );
while( true )
{
wait( 0.05 );
if( self isUsingRemote() )
{
self thread unsetCustomJuiced();
break;
}
}
}
unsetCustomJuicedOnDeath()
{
self endon ( "disconnect" );
self endon ( "unset_custom_juiced" );
self waittill_any( "death", "faux_spawn" );
self thread unsetCustomJuiced( true );
}
unsetCustomJuicedOnMatchEnd()
{
self endon ( "disconnect" );
self endon ( "unset_custom_juiced" );
level waittill_any( "round_end_finished", "game_ended" );
self thread unsetCustomJuiced();
}
regenSpeedWatcher()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "unsetBloodrush");
level endon ( "game_ended" );
for (;;)
{
self waittill ("bloodrush_active");
self.regenSpeed = self.bloodrushRegenSpeedMod;
break;
}
}
unsetBloodrush()
{
self.bloodrushRegenSpeedMod = 1;
self.regenSpeed = 1;
self notify( "unsetBloodrush" );
}
setTriggerHappy()
{
}
setTriggerHappyInternal()
{
self endon ("death");
self endon ("disconnect");
self endon ("unsetTriggerHappy");
level endon ("game_ended");
// self == attacker
playerWeapon = self.lastDroppableWeapon;
// Grab how much ammo the player has remaining in their stock
playerOldStock = self GetWeaponAmmoStock(playerWeapon);
// Grab how much ammo the player has remaining in their clip
playerOldClip = self GetWeaponAmmoClip(playerWeapon);
// Set the weapon clip to max to grab the max clip size
self GiveStartAmmo(playerWeapon);
playerDefaultClip = self GetWeaponAmmoClip(playerWeapon);
// Grab how much we need to refill, and set the new stock
clipDifference = playerDefaultClip - playerOldClip;
playerNewStock = playerOldStock - clipDifference;
// If we don't have enough stock ammo to fully refill the clip
if (clipDifference > playerOldStock)
{
self SetWeaponAmmoClip(playerWeapon, playerOldClip + playerOldStock);
playerNewStock = 0;
}
self SetWeaponAmmoStock(playerWeapon, playerNewStock);
// Play the reload sound
self PlayLocalSound( "ammo_crate_use" );
// Set a client omnvar to show a quick overlay when reloading
self SetClientOmnvar( "ui_trigger_happy", true );
wait (0.2);
self SetClientOmnvar( "ui_trigger_happy", false );
}
unsetTriggerHappy()
{
self SetClientOmnvar( "ui_trigger_happy", false );
self notify ("unsetTriggerHappy");
}
setDeadeye()
{
self.critChance = 10;
self.deadeyekillCount = 0;
}
setDeadeyeInternal()
{
//self == attacker
// Give the player a % chance to get a "critial hit" on the victim, regardless of where the bullet hits
// Realistically, it will give the attacker "specialty_moredamage" for that shot, which will modify the damage given
// Start off with a 10% chance to get a critial hit
// With each consecutive kill, increase that chance by 10% until we hit a max (50%)
// Check for the killcount from when the player equips the perk
if ( self.critChance < 50 )
self.critChance = (self.deadeyekillCount + 1) * 10;
else
self.critChance = 50;
chance = randomint(100);
if (chance <= self.critChance)
self givePerk("specialty_moredamage", false);
}
unsetDeadeye()
{
// This should be impossible, but make sure we remove this perk if they some how hold onto it
if ( self _hasPerk( "specialty_moredamage" ) )
self _unsetPerk ( "specialty_moredamage" );
}
setIncog()
{
}
unsetIncog()
{
}
setBlindeye()
{
}
unsetBlindeye()
{
// Make sure to also unset the noplayertarget perk that comes with it
self _unsetPerk("specialty_noplayertarget");
self notify( "removed_specialty_noplayertarget" );
}
setQuickswap()
{
}
unsetQuickswap()
{
// Make sure to also unset the noplayertarget perk that comes with it
self _unsetPerk("specialty_fastoffhand");
}
setExtraAmmo()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "unset_extraammo" );
level endon ( "game_ended" );
if ( self.gettingLoadout )
self waittill ( "giveLoadout" );
playerPrimaries = self getValidExtraAmmoWeapons();
foreach ( primary in playerPrimaries )
{
if ( IsDefined( primary ) && primary != "none" )
self GiveMaxAmmo( primary );
}
}
unsetExtraAmmo()
{
self notify ("unset_extraammo");
}
setExtraEquipment()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "unset_extraequipment" );
level endon ( "game_ended" );
if ( self.gettingLoadout )
self waittill ( "giveLoadout" );
playerTactical = self.loadoutPerkOffhand;
if ( IsDefined( playerTactical ) && playerTactical != "specialty_null" )
{
if ( playerTactical != "specialty_tacticalinsertion" )
self SetWeaponAmmoClip( playerTactical, 2 );
}
}
unsetExtraEquipment()
{
self notify ("unset_extraequipment");
}
setExtraDeadly()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "unset_extradeadly" );
level endon ( "game_ended" );
if ( self.gettingLoadout )
self waittill ( "giveLoadout" );
playerLethal = self.loadoutPerkEquipment;
if ( IsDefined( playerLethal ) && playerLethal != "specialty_null" )
self SetWeaponAmmoClip( playerLethal, 2 );
}
unsetExtraDeadly()
{
self notify ("unset_extradeadly");
}
/***************************************************************************************************************
* DEATH STREAKS
***************************************************************************************************************/
/////////////////////////////////////////////////////////////////
// FINAL STAND: the player falls into last stand but can get back up if they survive long enough
setFinalStand()
{
self givePerk( "specialty_pistoldeath", false );
}
unsetFinalStand()
{
self _unsetperk( "specialty_pistoldeath" );
}
// END FINAL STAND
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// CARE PACKAGE: give the player a care package on spawn
setCarePackage()
{
self thread maps\mp\killstreaks\_killstreaks::giveKillstreak( "airdrop_assault", false, false, self );
}
unsetCarePackage()
{
}
// END CARE PACKAGE
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// UAV: give the player a uav on spawn
setUAV()
{
self thread maps\mp\killstreaks\_killstreaks::giveKillstreak( "uav", false, false, self );
}
unsetUAV()
{
}
// END CARE PACKAGE
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// STOPPING POWER: give the player more bullet damage
setStoppingPower()
{
self givePerk( "specialty_bulletdamage", false );
self thread watchStoppingPowerKill();
}
watchStoppingPowerKill()
{
self notify( "watchStoppingPowerKill" );
self endon( "watchStoppingPowerKill" );
self endon( "disconnect" );
level endon( "game_ended" );
self waittill( "killed_enemy" );
self unsetStoppingPower();
}
unsetStoppingPower()
{
self _unsetperk( "specialty_bulletdamage" );
self notify( "watchStoppingPowerKill" );
}
// END STOPPING POWER
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// C4 DEATH: player falls into last stand with a c4 clacker for an explosive ending
setC4Death()
{
if( !self _hasperk( "specialty_pistoldeath" ) )
self givePerk( "specialty_pistoldeath", false );
}
unsetC4Death()
{
if( self _hasperk( "specialty_pistoldeath" ) )
self _unsetperk( "specialty_pistoldeath" );
}
// END C4 DEATH
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// JUICED: give a speed boost for a set amount of time
setJuiced( waitTime )
{
self endon( "death" );
self endon( "faux_spawn" );
self endon( "disconnect" );
self endon( "unset_juiced" );
level endon( "game_ended" );
self.isJuiced = true;
self.moveSpeedScaler = 1.25;
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
// reloading == specialty_fastreload
self givePerk( "specialty_fastreload", false );
// ads'ing == specialty_quickdraw
self givePerk( "specialty_quickdraw", false );
// movement == specialty_stalker
self givePerk( "specialty_stalker", false );
// throwing grenades == specialty_fastoffhand
self givePerk( "specialty_fastoffhand", false );
// sprint recovery == specialty_fastsprintrecovery
self givePerk( "specialty_fastsprintrecovery", false );
// NOTE: deprecated with new mantling
// mantling == specialty_fastmantle
//self givePerk( "specialty_fastmantle", false );
// switching weapons == specialty_quickswap
self givePerk( "specialty_quickswap", false );
self thread unsetJuicedOnDeath();
self thread unsetJuicedOnRide();
self thread unsetJuicedOnMatchEnd();
if ( !IsDefined( waitTime ) )
{
waitTime = 10;
}
endTime = ( waitTime * 1000 ) + GetTime();
if ( !IsAI( self ) )
{
self SetClientDvar( "ui_juiced_end_milliseconds", endTime );
}
wait( waitTime );
self unsetJuiced();
}
unsetJuiced( death )
{
if( !IsDefined( death ) )
{
if ( !is_aliens() )
Assert( IsAlive( self ) );
if( self isJuggernaut() )
{
Assert( IsDefined( self.juggMoveSpeedScaler ) );
if( IsDefined( self.juggMoveSpeedScaler ) )
self.moveSpeedScaler = self.juggMoveSpeedScaler;
else // handle the assert case for ship
self.moveSpeedScaler = 0.7; // compromise of the expected .65 or .75
}
else
{
self.moveSpeedScaler = 1;
if( self _hasPerk( "specialty_lightweight" ) )
self.moveSpeedScaler = lightWeightScalar();
}
Assert( IsDefined( self.moveSpeedScaler ) );
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
// reloading == specialty_fastreload
self _unsetPerk( "specialty_fastreload" );
// ads'ing == specialty_quickdraw
self _unsetPerk( "specialty_quickdraw" );
// movement == specialty_stalker
self _unsetPerk( "specialty_stalker" );
// throwing grenades == specialty_fastoffhand
self _unsetPerk( "specialty_fastoffhand" );
// sprint recovery == specialty_fastsprintrecovery
self _unsetPerk( "specialty_fastsprintrecovery" );
// NOTE: deprecated with new mantling
// mantling == specialty_fastmantle
//self _unsetPerk( "specialty_fastmantle" );
// switching weapons == specialty_quickswap
self _unsetPerk( "specialty_quickswap" );
// give them back their loadout perks
//// TODO: once we do a more complicated perk system, this will need to be updated
//if( self.loadoutPerk1 != "specialty_null" )
// self givePerk( self.loadoutPerk1, false );
//if( self.loadoutPerk2 != "specialty_null" )
// self givePerk( self.loadoutPerk2, false );
//if( self.loadoutPerk3 != "specialty_null" )
// self givePerk( self.loadoutPerk3, false );
// 2013-25-04 wsh - commenting out the give*perks functions
// since we've moved away from the point based ability sys
/*
self maps\mp\perks\_abilities::giveSpeedPerks( self.speedAbility );
self maps\mp\perks\_abilities::giveHandlingPerks( self.handlingAbility );
self maps\mp\perks\_abilities::giveStealthPerks( self.stealthAbility );
self maps\mp\perks\_abilities::giveAwarenessPerks( self.awarenessAbility );
self maps\mp\perks\_abilities::giveResistancePerks( self.resistanceAbility );
self maps\mp\perks\_abilities::giveEquipmentPerks( self.equipmentAbility );
*/
// restore the new iw6 perks system
if ( IsDefined( self.pers[ "loadoutPerks" ] ) )
{
self maps\mp\perks\_abilities::givePerksFromKnownLoadout( self.pers[ "loadoutPerks" ] );
}
self.isJuiced = undefined;
if ( !IsAI( self ) )
{
self SetClientDvar( "ui_juiced_end_milliseconds", 0 );
}
self notify( "unset_juiced" );
}
unsetJuicedOnRide()
{
self endon ( "disconnect" );
self endon ( "unset_juiced" );
while( true )
{
wait( 0.05 );
if( self isUsingRemote() )
{
self thread unsetJuiced();
break;
}
}
}
unsetJuicedOnDeath()
{
self endon ( "disconnect" );
self endon ( "unset_juiced" );
self waittill_any( "death", "faux_spawn" );
self thread unsetJuiced( true );
}
unsetJuicedOnMatchEnd()
{
self endon ( "disconnect" );
self endon ( "unset_juiced" );
level waittill_any( "round_end_finished", "game_ended" );
self thread unsetJuiced();
}
hasJuiced() // self == player
{
return ( IsDefined( self.isJuiced ) );
}
// END JUICED
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// COMBAT HIGH: painkiller, give a health boost for a set time
setCombatHigh()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "unset_combathigh" );
level endon( "end_game" );
self.damageBlockedTotal = 0;
//self visionSetNakedForPlayer( "end_game", 1 );
if ( level.splitscreen )
{
yOffset = 56;
iconSize = 21; // 32/1.5
}
else
{
yOffset = 112;
iconSize = 32;
}
// since we can have more than one deathstreak, juiced might have an overlay and timer up, so delete them
//if( IsDefined( self.juicedOverlay ) )
// self.juicedOverlay Destroy();
if( IsDefined( self.juicedTimer ) )
self.juicedTimer Destroy();
if( IsDefined( self.juicedIcon ) )
self.juicedIcon Destroy();
self.combatHighOverlay = newClientHudElem( self );
self.combatHighOverlay.x = 0;
self.combatHighOverlay.y = 0;
self.combatHighOverlay.alignX = "left";
self.combatHighOverlay.alignY = "top";
self.combatHighOverlay.horzAlign = "fullscreen";
self.combatHighOverlay.vertAlign = "fullscreen";
self.combatHighOverlay setshader ( "combathigh_overlay", 640, 480 );
self.combatHighOverlay.sort = -10;
self.combatHighOverlay.archived = true;
self.combatHighTimer = createTimer( "hudsmall", 1.0 );
self.combatHighTimer setPoint( "CENTER", "CENTER", 0, yOffset );
self.combatHighTimer setTimer( 10.0 );
self.combatHighTimer.color = (.8,.8,0);
self.combatHighTimer.archived = false;
self.combatHighTimer.foreground = true;
self.combatHighIcon = self createIcon( "specialty_painkiller", iconSize, iconSize );
self.combatHighIcon.alpha = 0;
self.combatHighIcon setParent( self.combatHighTimer );
self.combatHighIcon setPoint( "BOTTOM", "TOP" );
self.combatHighIcon.archived = true;
self.combatHighIcon.sort = 1;
self.combatHighIcon.foreground = true;
self.combatHighOverlay.alpha = 0.0;
self.combatHighOverlay fadeOverTime( 1.0 );
self.combatHighIcon fadeOverTime( 1.0 );
self.combatHighOverlay.alpha = 1.0;
self.combatHighIcon.alpha = 0.85;
self thread unsetCombatHighOnDeath();
self thread unsetCombatHighOnRide();
wait( 8 );
self.combatHighIcon fadeOverTime( 2.0 );
self.combatHighIcon.alpha = 0.0;
self.combatHighOverlay fadeOverTime( 2.0 );
self.combatHighOverlay.alpha = 0.0;
self.combatHighTimer fadeOverTime( 2.0 );
self.combatHighTimer.alpha = 0.0;
wait( 2 );
self.damageBlockedTotal = undefined;
self _unsetPerk( "specialty_combathigh" );
}
unsetCombatHighOnDeath()
{
self endon ( "disconnect" );
self endon ( "unset_combathigh" );
self waittill ( "death" );
self thread _unsetPerk( "specialty_combathigh" );
}
unsetCombatHighOnRide()
{
self endon ( "disconnect" );
self endon ( "unset_combathigh" );
for ( ;; )
{
wait( 0.05 );
if ( self isUsingRemote() )
{
self thread _unsetPerk( "specialty_combathigh" );
break;
}
}
}
unsetCombatHigh()
{
self notify ( "unset_combathigh" );
self.combatHighOverlay destroy();
self.combatHighIcon destroy();
self.combatHighTimer destroy();
}
// END COMBAT HIGH
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// ARMOR: give a health boost
setLightArmor( optionalArmorValue )
{
self notify( "give_light_armor" );
if( IsDefined( self.lightArmorHP ) )
unsetLightArmor();
self thread removeLightArmorOnDeath();
self thread removeLightArmorOnMatchEnd();
self.lightArmorHP = 150;
if( IsDefined(optionalArmorValue) )
self.lightArmorHP = optionalArmorValue;
if ( IsPlayer(self) )
{
self SetClientOmnvar( "ui_light_armor", true );
self _setNameplateMaterial( "player_name_bg_green_vest", "player_name_bg_red_vest" );
}
}
removeLightArmorOnDeath()
{
self endon ( "disconnect" );
self endon( "give_light_armor" );
self endon( "remove_light_armor" );
self waittill ( "death" );
unsetLightArmor();
}
unsetLightArmor()
{
self.lightArmorHP = undefined;
if ( IsPlayer(self) )
{
self SetClientOmnvar( "ui_light_armor", false );
self _restorePreviousNameplateMaterial();
}
self notify( "remove_light_armor" );
}
removeLightArmorOnMatchEnd()
{
self endon ( "disconnect" );
self endon ( "remove_light_armor" );
level waittill_any( "round_end_finished", "game_ended" );
self thread unsetLightArmor();
}
hasLightArmor()
{
return ( IsDefined( self.lightArmorHP ) && self.lightArmorHP > 0 );
}
hasHeavyArmor( player )
{
return ( IsDefined( player.heavyArmorHP ) && (player.heavyArmorHP > 0) );
}
setHeavyArmor( armorValue )
{
if( IsDefined(armorValue) )
{
self.heavyArmorHP = armorValue;
}
}
// END ARMOR
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// REVENGE: show the last player who killed you, on your mini-map or in the world with a head icon
setRevenge() // this version does the head icon
{
self notify( "stopRevenge" );
wait( 0.05 ); // let all of the already running threads stop and clean up
if( !IsDefined( self.lastKilledBy ) )
return;
if( level.teamBased && self.team == self.lastKilledBy.team )
return;
revengeParams = SpawnStruct();
revengeParams.showTo = self;
revengeParams.icon = "compassping_revenge";
revengeParams.offset = ( 0, 0, 64 );
revengeParams.width = 10;
revengeParams.height = 10;
revengeParams.archived = false;
revengeParams.delay = 1.5;
revengeParams.constantSize = false;
revengeParams.pinToScreenEdge = true;
revengeParams.fadeOutPinnedIcon = false;
revengeParams.is3D = false;
self.revengeParams = revengeParams;
self.lastKilledBy maps\mp\_entityheadIcons::setHeadIcon(
revengeParams.showTo,
revengeParams.icon,
revengeParams.offset,
revengeParams.width,
revengeParams.height,
revengeParams.archived,
revengeParams.delay,
revengeParams.constantSize,
revengeParams.pinToScreenEdge,
revengeParams.fadeOutPinnedIcon,
revengeParams.is3D );
self thread watchRevengeDeath();
self thread watchRevengeKill();
self thread watchRevengeDisconnected();
self thread watchRevengeVictimDisconnected();
self thread watchStopRevenge();
}
//setRevenge() // this version does the mini-map objective
//{
// self notify( "stopRevenge" );
// wait( 0.05 ); // let all of the already running threads stop and clean up
//
// if( !IsDefined( self.lastKilledBy ) )
// return;
//
// // show objective only to a single player, not the whole team
// curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
// Objective_Add( curObjID, "invisible", (0,0,0) );
// Objective_OnEntity( curObjID, self.lastKilledBy );
// Objective_State( curObjID, "active" );
// Objective_Icon( curObjID, "compassping_revenge" );
// Objective_Player( curObjID, self GetEntityNumber() );
// self.objIdFriendly = curObjID;
//
// self thread watchRevengeKill();
// self thread watchRevengeDisconnected();
// self thread watchRevengeVictimDisconnected();
// self thread watchStopRevenge();
//}
watchRevengeDeath() // self == player with the deathstreak
{
self endon( "stopRevenge" );
self endon( "disconnect" );
lastKilledBy = self.lastKilledBy;
// since head icons get deleted on death, we need to keep giving this player a head icon until stop revenge
while( true )
{
lastKilledBy waittill( "spawned_player" );
lastKilledBy maps\mp\_entityheadIcons::setHeadIcon(
self.revengeParams.showTo,
self.revengeParams.icon,
self.revengeParams.offset,
self.revengeParams.width,
self.revengeParams.height,
self.revengeParams.archived,
self.revengeParams.delay,
self.revengeParams.constantSize,
self.revengeParams.pinToScreenEdge,
self.revengeParams.fadeOutPinnedIcon,
self.revengeParams.is3D );
}
}
watchRevengeKill()
{
self endon( "stopRevenge" );
self waittill( "killed_enemy" );
self notify( "stopRevenge" );
}
watchRevengeDisconnected()
{
self endon( "stopRevenge" );
self.lastKilledBy waittill( "disconnect" );
self notify( "stopRevenge" );
}
watchStopRevenge() // self == player with the deathstreak
{
lastKilledBy = self.lastKilledBy;
// if the player gets any kill, then stop the revenge on the last killed by player
// if the player dies again without getting any kills, have the new killer show and the old not
self waittill( "stopRevenge" );
if( !IsDefined( lastKilledBy ) )
return;
foreach( key, headIcon in lastKilledBy.entityHeadIcons )
{
if( !IsDefined( headIcon ) )
continue;
headIcon destroy();
}
//if( IsDefined( self.objIdFriendly ) )
// _objective_delete( self.objIdFriendly );
}
watchRevengeVictimDisconnected()
{
// if the player with revenge gets disconnected then clean up
objID = self.objIdFriendly;
lastKilledBy = self.lastKilledBy;
lastKilledBy endon( "disconnect" );
level endon( "game_ended" );
self endon( "stopRevenge" );
self waittill( "disconnect" );
if( !IsDefined( lastKilledBy ) )
return;
foreach( key, headIcon in lastKilledBy.entityHeadIcons )
{
if( !IsDefined( headIcon ) )
continue;
headIcon destroy();
}
//if( IsDefined( objID ) )
// _objective_delete( objID );
}
unsetRevenge()
{
self notify( "stopRevenge" );
}
// END REVENGE
/////////////////////////////////////////////////////////////////
/***************************************************************************************************************
* END DEATH STREAKS
***************************************************************************************************************/