2525 lines
76 KiB
Plaintext
2525 lines
76 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
#include common_scripts\utility;
|
|
|
|
// killstreak table
|
|
KILLSTREAK_NAME_COLUMN = 1;
|
|
KILLSTREAK_EARNED_HINT_COLUMN = 5;
|
|
KILLSTREAK_EARN_DIALOG_COLUMN = 7;
|
|
KILLSTREAK_ENEMY_USE_DIALOG_COLUMN = 10;
|
|
KILLSTREAK_ICON_COLUMN = 13;
|
|
KILLSTREAK_OVERHEAD_ICON_COLUMN = 14;
|
|
KILLSTREAK_OVERHEAD_ICON_PLUS_1_COLUMN = 15;
|
|
KILLSTREAK_OVERHEAD_ICON_PLUS_2_COLUMN = 16;
|
|
KILLSTREAK_OVERHEAD_ICON_PLUS_3_COLUMN = 17;
|
|
|
|
onPlayerConnect()
|
|
{
|
|
for ( ;; )
|
|
{
|
|
level waittill( "connected", player );
|
|
|
|
if( !IsDefined ( player.pers[ "killstreaks" ] ) )
|
|
player.pers[ "killstreaks" ] = [];
|
|
|
|
if( !IsDefined ( player.pers[ "kID" ] ) )
|
|
player.pers[ "kID" ] = 10;
|
|
|
|
player.lifeId = 0;
|
|
player.curDefValue = 0;
|
|
|
|
if ( IsDefined( player.pers["deaths"] ) )
|
|
player.lifeId = player.pers["deaths"];
|
|
|
|
player.spUpdateTotal = 0;
|
|
|
|
if (GetDvarInt("virtualLobbyActive",0))
|
|
return; // don't start any threads if in vl
|
|
|
|
player thread onPlayerSpawned();
|
|
}
|
|
}
|
|
|
|
onPlayerSpawned()
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill_any( "spawned_player", "faux_spawn" );
|
|
|
|
self thread killstreakUseWaiter();
|
|
self thread streakNotifyTracker();
|
|
self thread waitForChangeTeam();
|
|
|
|
self thread streakSelectUpTracker();
|
|
self thread streakSelectDownTracker();
|
|
//self thread aerialKillstreakMarker();
|
|
|
|
// pc needs to watch for addition key presses
|
|
if( !level.console )
|
|
self thread pc_watchStreakUse();
|
|
|
|
if ( !IsDefined( self.pers["killstreaks"][0] ) )
|
|
self initPlayerKillstreaks();
|
|
|
|
if ( !IsDefined( self.earnedStreakLevel ) )
|
|
self.earnedStreakLevel = 0;
|
|
|
|
// we reset the adrenaline on first connect in playerlogic
|
|
// we want to restore the killstreak score back to what it was for round based games
|
|
if( !IsDefined( self.adrenaline ) || self.adrenaline == 0 )
|
|
{
|
|
self.adrenaline = self.pers[ "ks_totalPoints" ];
|
|
self.adrenalineSupport = self.pers[ "ks_totalPointsSupport" ];
|
|
self updateStreakCount();
|
|
|
|
// turn on HUD elements
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
streakName = self.pers[ "killstreaks" ][ i ].streakName;
|
|
available = self.pers[ "killstreaks" ][ i ].available;
|
|
|
|
if( IsDefined(streakName) )
|
|
{
|
|
if( (i == level.KILLSTREAK_GIMME_SLOT) && (!IsDefined(available) || !available) )
|
|
continue;
|
|
|
|
streakIndex = getKillstreakIndex( self.pers[ "killstreaks" ][ i ].streakName );
|
|
killstreak_iconName = "ks_icon" + toString(i);
|
|
self SetClientOmnvar( killstreak_iconName, streakIndex );
|
|
}
|
|
}
|
|
|
|
self updateStreakIcons( false );
|
|
}
|
|
|
|
self updateStreakSlots();
|
|
self giveOwnedKillstreakItem();
|
|
self updateStreakCount();
|
|
}
|
|
}
|
|
|
|
|
|
updateStreakIcons( isInit )
|
|
{
|
|
// init all of the icons to 0 in case the player hasn't selected all 3 streaks
|
|
// also init the hasStreak to false
|
|
assert( level.KILLSTREAK_STACKING_START_SLOT <= 16 ); // if it gets bigger, we overflow an int
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
// don't reset the gimme slot on update
|
|
if ( !isInit && i == level.KILLSTREAK_GIMME_SLOT )
|
|
continue;
|
|
|
|
killstreak_iconName = "ks_icon" + toString(i);
|
|
self SetClientOmnvar( killstreak_iconName, 0 );
|
|
|
|
// set ks_hasStreak to false at the index i
|
|
previousHasStreak = self GetClientOmnvar( "ks_hasStreak" );
|
|
newHasStreak = previousHasStreak & (~(1<<i)) & (~(1<<(i+level.KILLSTREAK_STACKING_START_SLOT))); // i is hasStreak, i+level.KILLSTREAK_STACKING_START_SLOT is supportStreak
|
|
self SetClientOmnvar( "ks_hasStreak", newHasStreak );
|
|
}
|
|
|
|
index = 1;
|
|
|
|
if( IsDefined( self.killstreaks ) )
|
|
{
|
|
foreach ( streakName in self.killstreaks )
|
|
{
|
|
self_pers_killstreaks_index = self.pers["killstreaks"][index];
|
|
self_pers_killstreaks_index.streakName = streakName;
|
|
|
|
killstreakIndexName = self_pers_killstreaks_index.streakName;
|
|
killstreak_iconName = "ks_icon" + toString(index);
|
|
self SetClientOmnvar( killstreak_iconName, getKillstreakIndex( killstreakIndexName ) );
|
|
|
|
// if we try to insert something at this point, we'll overwrite valid supportStreak data
|
|
assert( index < level.KILLSTREAK_STACKING_START_SLOT );
|
|
|
|
// set ks_hasStreak to false at the index index
|
|
previousHasStreak = self GetClientOmnvar( "ks_hasStreak" );
|
|
newHasStreak = previousHasStreak & (~(1<<index));
|
|
|
|
// mark each killstreak as support or not
|
|
if( isSupportStreak( self, streakName ) )
|
|
newHasStreak = newHasStreak | (1<<(index+level.KILLSTREAK_STACKING_START_SLOT));
|
|
else
|
|
newHasStreak = newHasStreak & (~(1<<(index+level.KILLSTREAK_STACKING_START_SLOT)));
|
|
self SetClientOmnvar( "ks_hasStreak", newHasStreak );
|
|
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
initPlayerKillstreaks()
|
|
{
|
|
// gimme slot is where care package items and special given items go
|
|
// we want the gimme slot to be stackable so we don't lose killstreaks when we pick another up
|
|
// so we'll make index 0 be a pointer of sorts to show where the next usable killstreak is in the killstreak array
|
|
self_pers_killstreaks_gimme_slot = spawnStruct();
|
|
self_pers_killstreaks_gimme_slot.available = false;
|
|
self_pers_killstreaks_gimme_slot.streakName = undefined;
|
|
self_pers_killstreaks_gimme_slot.earned = false;
|
|
self_pers_killstreaks_gimme_slot.awardxp = undefined;
|
|
self_pers_killstreaks_gimme_slot.owner = undefined;
|
|
self_pers_killstreaks_gimme_slot.kID = undefined;
|
|
self_pers_killstreaks_gimme_slot.lifeId = undefined;
|
|
self_pers_killstreaks_gimme_slot.isGimme = true;
|
|
self_pers_killstreaks_gimme_slot.nextSlot = undefined;
|
|
self.pers["killstreaks"][ level.KILLSTREAK_GIMME_SLOT ] = self_pers_killstreaks_gimme_slot;
|
|
|
|
// reserved for each killstreak whether they have them or not
|
|
for( i = level.KILLSTREAK_SLOT_1; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
self_pers_killstreaks_i = spawnStruct();
|
|
|
|
self_pers_killstreaks_i.available = false;
|
|
self_pers_killstreaks_i.streakName = undefined;
|
|
self_pers_killstreaks_i.earned = true;
|
|
self_pers_killstreaks_i.awardxp = 1;
|
|
self_pers_killstreaks_i.owner = undefined;
|
|
self_pers_killstreaks_i.kID = undefined;
|
|
self_pers_killstreaks_i.lifeId = -1;
|
|
self_pers_killstreaks_i.isGimme = false;
|
|
self.pers["killstreaks"][ i ] = self_pers_killstreaks_i;
|
|
}
|
|
|
|
self updateStreakIcons( true );
|
|
|
|
self SetClientOmnvar( "ks_selectedIndex", -1 );
|
|
|
|
// set ks_hasStreak to false at the index level.KILLSTREAK_STACKING_START_SLOT
|
|
previousHasStreak = self GetClientOmnvar( "ks_hasStreak" );
|
|
newHasStreak = previousHasStreak & (~(1<<level.KILLSTREAK_STACKING_START_SLOT));
|
|
self SetClientOmnvar( "ks_hasStreak", newHasStreak );
|
|
}
|
|
|
|
isSupportStreak( player, streakName )
|
|
{
|
|
moduleRefs = GetArrayKeys( self.killStreakModules );
|
|
|
|
foreach ( moduleName in moduleRefs )
|
|
{
|
|
baseStreakName = getStreakModuleBaseKillstreak( moduleName );
|
|
|
|
if ( baseStreakName == streakName )
|
|
{
|
|
supportColumn = TableLookup( level.KS_MODULES_TABLE, level.KS_MODULE_REF_COLUMN, moduleName, level.KS_MODULE_SUPPORT_COLUMN );
|
|
|
|
if ( IsDefined( supportColumn ) && supportColumn != "" && supportcolumn != "0" )
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
updateStreakCount()
|
|
{
|
|
if( !IsDefined( self.pers["killstreaks"] ) )
|
|
{
|
|
for( i = level.KILLSTREAK_SLOT_1; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
self SetClientOmnvar( "ks_count" + toString(i), 0 );
|
|
}
|
|
self SetClientOmnvar( "ks_count_updated", 1 );
|
|
return;
|
|
}
|
|
|
|
for( i = level.KILLSTREAK_SLOT_1; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
streakName = self.pers[ "killstreaks" ][ i ].streakName;
|
|
ksBarName = "ks_count" + toString(i);
|
|
ksPointsName = "ks_points" + toString(i);
|
|
|
|
if ( !IsDefined( streakName ) )
|
|
{
|
|
self SetClientOmnvar( ksBarName, 0 );
|
|
continue;
|
|
}
|
|
|
|
streakVal = self getStreakCost( self.pers[ "killstreaks" ][ i ].streakName );
|
|
if ( isSupportStreak( self, streakName ) )
|
|
{
|
|
barFillPercent = self.adrenalineSupport / streakVal;
|
|
score_remaining = streakVal - self.adrenalineSupport;
|
|
}
|
|
else
|
|
{
|
|
barFillPercent = self.adrenaline / streakVal;
|
|
score_remaining = streakVal - self.adrenaline;
|
|
}
|
|
|
|
if( barFillPercent >= 1 )
|
|
{
|
|
barFillPercent = 0;
|
|
score_remaining = streakVal;
|
|
}
|
|
|
|
self SetClientOmnvar( ksPointsName, score_remaining );
|
|
self SetClientOmnvar( ksBarName, barFillPercent );
|
|
}
|
|
|
|
self SetClientOmnvar( "ks_count_updated", 1 );
|
|
}
|
|
|
|
getMaxStreakCost( isSupport )
|
|
{
|
|
if( !IsDefined(self.killstreaks) )
|
|
return 0;
|
|
|
|
maxCost = 0;
|
|
|
|
foreach ( streakName in self.killstreaks )
|
|
{
|
|
supportStreak = isSupportStreak( self, streakName );
|
|
if ( ( isSupport && !supportStreak ) || ( !isSupport && supportStreak ) )
|
|
continue;
|
|
|
|
streakVal = self getStreakCost( streakName );
|
|
|
|
if ( streakVal > maxCost )
|
|
{
|
|
maxCost = streakVal;
|
|
}
|
|
}
|
|
return maxCost;
|
|
}
|
|
|
|
updateStreakSlots()
|
|
{
|
|
if ( !isReallyAlive(self) )
|
|
return;
|
|
|
|
self_pers_killstreaks = self.pers["killstreaks"];
|
|
|
|
// what's available?
|
|
numStreaks = 0;
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
if( IsDefined( self_pers_killstreaks[i] ) && IsDefined( self_pers_killstreaks[i].streakName ) )
|
|
{
|
|
// update ks_hasStreak
|
|
previousHasStreak = self GetClientOmnvar( "ks_hasStreak" );
|
|
if( self_pers_killstreaks[i].available == true )
|
|
{
|
|
newHasStreak = previousHasStreak | (1<<i);
|
|
}
|
|
else
|
|
{
|
|
newHasStreak = previousHasStreak & (~(1<<i));
|
|
}
|
|
self SetClientOmnvar( "ks_hasStreak", newHasStreak );
|
|
|
|
if ( self_pers_killstreaks[i].available == true )
|
|
numStreaks++;
|
|
}
|
|
}
|
|
|
|
// selected index
|
|
if ( IsDefined( self.killstreakIndexWeapon ) )
|
|
{
|
|
self SetClientOmnvar( "ks_selectedIndex", self.killstreakIndexWeapon );
|
|
}
|
|
else
|
|
{
|
|
self SetClientOmnvar( "ks_selectedIndex", -1 );
|
|
}
|
|
}
|
|
|
|
|
|
waitForChangeTeam()
|
|
{
|
|
self endon ( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
|
|
self notify ( "waitForChangeTeam" );
|
|
self endon ( "waitForChangeTeam" );
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill ( "joined_team" );
|
|
clearKillstreaks( true );
|
|
}
|
|
}
|
|
|
|
|
|
killstreakUsePressed()
|
|
{
|
|
self_pers_killstreaks = self.pers["killstreaks"];
|
|
|
|
streakName = self_pers_killstreaks[self.killstreakIndexWeapon].streakName;
|
|
lifeId = self_pers_killstreaks[self.killstreakIndexWeapon].lifeId;
|
|
isEarned = self_pers_killstreaks[self.killstreakIndexWeapon].earned;
|
|
awardXp = self_pers_killstreaks[self.killstreakIndexWeapon].awardXp;
|
|
kID = self_pers_killstreaks[self.killstreakIndexWeapon].kID;
|
|
isGimme = self_pers_killstreaks[self.killstreakIndexWeapon].isGimme;
|
|
modules = self_pers_killstreaks[self.killstreakIndexWeapon].modules;
|
|
|
|
PrintLn( "Killstreak " + streakName + " activated by player " + self GetEntityNumber() );
|
|
|
|
// track where the scorestreak is in the gimme stack in case another scorestreak is put on top of it
|
|
clearSlotNumber = undefined;
|
|
stackedSlotNumber = undefined;
|
|
keepCurrentKillstreak = undefined;
|
|
if ( self.killstreakIndexWeapon == level.KILLSTREAK_GIMME_SLOT )
|
|
stackedSlotNumber = self_pers_killstreaks[ level.KILLSTREAK_GIMME_SLOT ].nextSlot;
|
|
|
|
if ( !validateUseStreak( streakName ) )
|
|
return false;
|
|
|
|
// Balance for anyone using the explosive ammo killstreak, remove it when they activate the next killstreak
|
|
removeExplosiveAmmo = false;
|
|
if ( self _hasPerk( "specialty_explosivebullets" ) && !issubstr( streakName, "explosive_ammo" ) )
|
|
removeExplosiveAmmo = true;
|
|
|
|
if( IsSubStr( streakName, "airdrop" ) )
|
|
{
|
|
if ( !self [[ level.killstreakFuncs[ streakName ] ]]( lifeId, kID, modules ) )
|
|
return ( false );
|
|
}
|
|
else
|
|
{
|
|
if ( !self [[ level.killstreakFuncs[ streakName ] ]]( lifeId, modules ) )
|
|
return ( false );
|
|
}
|
|
|
|
/#
|
|
// let test client bots (not AI bots) use the full functionality of the killstreak usage
|
|
if( IsTestClient(self) )
|
|
return true;
|
|
#/
|
|
|
|
// Balance for anyone using the explosive ammo killstreak, remove it when they activate the next killstreak
|
|
if ( removeExplosiveAmmo )
|
|
self _unsetPerk( "specialty_explosivebullets" );
|
|
|
|
if ( IsDefined( stackedSlotNumber ) && streakName != self_pers_killstreaks[self.killstreakIndexWeapon].streakName )
|
|
{
|
|
keepCurrentKillstreak = true;
|
|
clearSlotNumber = stackedSlotNumber;
|
|
}
|
|
|
|
self thread updateKillstreaks( keepCurrentKillstreak, clearSlotNumber );
|
|
self usedKillstreak( streakName, modules, awardXp );
|
|
|
|
return ( true );
|
|
}
|
|
|
|
|
|
usedKillstreak( streakName, modules, awardXp )
|
|
{
|
|
// self playLocalSound( "weap_c4detpack_trigger_plr" );
|
|
self incPlayerStat( "killStreaksUsed", 1 );
|
|
|
|
if ( awardXp )
|
|
self thread maps\mp\gametypes\_missions::useHardpoint( streakName );
|
|
|
|
team = self.team;
|
|
friendlyLine = team + "_friendly_" + streakName + "_inbound";
|
|
enemyLine = team + "_enemy_" + streakName + "_inbound";
|
|
|
|
// last minute add to change VO based on modules for EMP
|
|
if( streakName == "emp" )
|
|
{
|
|
moduleLine = maps\mp\killstreaks\_emp::getModuleLineEMP( modules );
|
|
friendlyLine += moduleLine;
|
|
enemyLine += moduleLine;
|
|
}
|
|
|
|
// play killstreak dialog
|
|
if ( level.teamBased )
|
|
{
|
|
thread leaderDialog( friendlyLine, team );
|
|
|
|
if ( getKillstreakInformEnemy( streakName ) )
|
|
thread leaderDialog( enemyLine, level.otherTeam[ team ] );
|
|
}
|
|
else
|
|
{
|
|
self thread leaderDialogOnPlayer( friendlyLine );
|
|
|
|
if ( getKillstreakInformEnemy( streakName ) )
|
|
{
|
|
excludeList[0] = self;
|
|
thread leaderDialog( enemyLine, undefined, undefined, excludeList );
|
|
}
|
|
}
|
|
|
|
if( isDefined( level.mapKillStreak ) )
|
|
{
|
|
if( streakName == level.mapKillStreak )
|
|
{
|
|
mapStreaksUsed = getMatchData( "players", self.clientId, "numberOfMapstreaksUsed" );
|
|
mapStreaksUsed++;
|
|
setMatchData( "players", self.clientId, "numberOfMapstreaksUsed", clampToByte( mapStreaksUsed ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
updateKillstreaks( keepCurrent, clearSlotNumber )
|
|
{
|
|
if ( !IsDefined( keepCurrent ) )
|
|
{
|
|
self.pers["killstreaks"][self.killstreakIndexWeapon].available = false;
|
|
|
|
// if this is the gimme slot and we still have some stacked then leave available and set the new icon
|
|
if( self.killstreakIndexWeapon == level.KILLSTREAK_GIMME_SLOT )
|
|
{
|
|
// if this is the gimme slot then clear the last used stacked killstreak before updating killstreaks
|
|
self.pers["killstreaks"][ self.pers["killstreaks"][ level.KILLSTREAK_GIMME_SLOT ].nextSlot ] = undefined;
|
|
|
|
// loop through the stacked killstreaks and find the next available one
|
|
streakName = undefined;
|
|
modules = undefined;
|
|
self_pers_killstreaks = self.pers["killstreaks"];
|
|
for( i = level.KILLSTREAK_STACKING_START_SLOT; i < self_pers_killstreaks.size; i++ )
|
|
{
|
|
if( !IsDefined( self_pers_killstreaks[i] ) || !IsDefined( self_pers_killstreaks[i].streakName ) )
|
|
continue;
|
|
|
|
streakName = self_pers_killstreaks[i].streakName;
|
|
if ( IsDefined( self_pers_killstreaks[i].modules ) )
|
|
modules = self_pers_killstreaks[i].modules;
|
|
self_pers_killstreaks[ level.KILLSTREAK_GIMME_SLOT ].nextSlot = i;
|
|
}
|
|
|
|
if( IsDefined( streakName ) )
|
|
{
|
|
self_pers_killstreaks[ level.KILLSTREAK_GIMME_SLOT ].available = true;
|
|
self_pers_killstreaks[ level.KILLSTREAK_GIMME_SLOT ].streakName = streakName;
|
|
if ( IsDefined( modules ) )
|
|
self_pers_killstreaks[ level.KILLSTREAK_GIMME_SLOT ].modules = modules;
|
|
|
|
streakIndex = getKillstreakIndex( streakName );
|
|
killstreak_iconName = "ks_icon" + toString(level.KILLSTREAK_GIMME_SLOT);
|
|
self SetClientOmnvar( killstreak_iconName, streakIndex );
|
|
|
|
// pc need to put this new one in the actionslot for use
|
|
if( !level.console && !self is_player_gamepad_enabled() )
|
|
{
|
|
killstreakWeapon = getKillstreakWeapon( streakName, modules );
|
|
_setActionSlot( 4, "weapon", killstreakWeapon );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
killstreak_iconName = "ks_icon" + toString(level.KILLSTREAK_GIMME_SLOT);
|
|
self SetClientOmnvar( killstreak_iconName, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( clearSlotNumber ) )
|
|
self.pers["killstreaks"][clearSlotNumber] = undefined;
|
|
|
|
// find the highest remaining streak and select it
|
|
highestStreakIndex = undefined;
|
|
|
|
for ( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
self_pers_killstreaks_i = self.pers["killstreaks"][i];
|
|
if( IsDefined( self_pers_killstreaks_i ) &&
|
|
IsDefined( self_pers_killstreaks_i.streakName ) &&
|
|
self_pers_killstreaks_i.available )
|
|
{
|
|
highestStreakIndex = i;
|
|
}
|
|
}
|
|
|
|
|
|
if ( IsDefined( highestStreakIndex ) )
|
|
{
|
|
if( level.console || self is_player_gamepad_enabled() )
|
|
{
|
|
self.killstreakIndexWeapon = highestStreakIndex;
|
|
self.pers["lastEarnedStreak"] = self.pers["killstreaks"][highestStreakIndex].streakName;
|
|
|
|
self giveSelectedKillstreakItem();
|
|
}
|
|
// pc doesn't select killstreaks
|
|
else
|
|
{
|
|
// make sure we still have all of the available killstreak weapons, things like the airdrop will get taken if you have more than one
|
|
for ( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
self_pers_killstreaks_i = self.pers["killstreaks"][i];
|
|
if( IsDefined( self_pers_killstreaks_i ) &&
|
|
IsDefined( self_pers_killstreaks_i.streakName ) &&
|
|
self_pers_killstreaks_i.available )
|
|
{
|
|
killstreakWeapon = getKillstreakWeapon( self_pers_killstreaks_i.streakName, self_pers_killstreaks_i.modules );
|
|
weaponsListItems = self GetWeaponsListItems();
|
|
hasKillstreakWeapon = false;
|
|
for( j = 0; j < weaponsListItems.size; j++ )
|
|
{
|
|
if( killstreakWeapon == weaponsListItems[j] )
|
|
{
|
|
hasKillstreakWeapon = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !hasKillstreakWeapon )
|
|
{
|
|
self _giveWeapon( killstreakWeapon );
|
|
}
|
|
else
|
|
{
|
|
// if we have more than one airdrop type weapon the ammo gets set to 0 because we give the next airdrop weapon before we take the last one
|
|
// this is a quicker fix than trying to figure out how to take and give at the right times
|
|
if( IsSubStr( killstreakWeapon, "airdrop_" ) )
|
|
self SetWeaponAmmoClip( killstreakWeapon, 1 );
|
|
}
|
|
|
|
// we should re-set the action slot just to make sure everything is correct (juggernaut needs this or they won't be able to use their killstreaks once obtained because we clear the action slots in giveLoadout())
|
|
self _setActionSlot( i + 4, "weapon", killstreakWeapon );
|
|
}
|
|
}
|
|
|
|
self.killstreakIndexWeapon = undefined;
|
|
self.pers["lastEarnedStreak"] = self.pers["killstreaks"][highestStreakIndex].streakName;
|
|
self updateStreakSlots();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.killstreakIndexWeapon = undefined;
|
|
self.pers["lastEarnedStreak"] = undefined;
|
|
self updateStreakSlots();
|
|
|
|
// NOTE: we used to take item weapons from the player here but that stopped killstreak weapon animations from playing if it was the only killstreak
|
|
// since we take the item weapons when we give a killstreak weapon anyways, no need to do that here
|
|
// we've also added the waitTakeKillstreakWeapon() function to take them when appropriate
|
|
// VERY IMPORTANT: with the current system, we NEVER want to loop and take all weapon list items
|
|
}
|
|
|
|
self SetClientOmnvar( "ks_used", 1 );
|
|
}
|
|
|
|
clearKillstreaks( clearSupportStreaks )
|
|
{
|
|
if ( !IsDefined( clearSupportStreaks ) )
|
|
clearSupportStreaks = true;
|
|
|
|
self_pers_killstreaks = self.pers["killstreaks"];
|
|
if( !IsDefined(self_pers_killstreaks) )
|
|
return;
|
|
|
|
for( i = self_pers_killstreaks.size - 1; i > -1; i-- )
|
|
{
|
|
self.pers["killstreaks"][i] = undefined;
|
|
}
|
|
|
|
initPlayerKillstreaks();
|
|
|
|
self resetAdrenaline( clearSupportStreaks );
|
|
self.killstreakIndexWeapon = undefined;
|
|
self updateStreakSlots();
|
|
}
|
|
|
|
getFirstPrimaryWeapon()
|
|
{
|
|
weaponsList = self getWeaponsListPrimaries();
|
|
|
|
assert ( IsDefined( weaponsList[0] ) );
|
|
assertEx( !isKillstreakWeapon( weaponsList[0] ), "Killstreak weapon: " + weaponsList[0] );
|
|
|
|
return weaponsList[0];
|
|
}
|
|
|
|
isTryingToUseKillstreakSlot()
|
|
{
|
|
return IsDefined( self.tryingToUseKS ) && self.tryingToUseKS && IsDefined( self.killstreakIndexWeapon );
|
|
}
|
|
|
|
waitForKillstreakWeaponSwitchStarted()
|
|
{
|
|
self endon( "weapon_switch_invalid" );
|
|
|
|
self waittill( "weapon_switch_started", newWeapon );
|
|
self notify( "killstreak_weapon_change", "switch_started", newWeapon );
|
|
}
|
|
|
|
waitForKillstreakWeaponSwitchInvalid()
|
|
{
|
|
self endon( "weapon_switch_started" );
|
|
|
|
self waittill( "weapon_switch_invalid", invalidWeapon );
|
|
self notify( "killstreak_weapon_change", "switch_invalid", invalidWeapon );
|
|
}
|
|
|
|
waitForKillstreakWeaponChange()
|
|
{
|
|
self childthread waitForKillstreakWeaponSwitchStarted();
|
|
self childthread waitForKillstreakWeaponSwitchInvalid();
|
|
|
|
self waittill( "killstreak_weapon_change", result, weapon );
|
|
|
|
if ( result == "switch_started" )
|
|
return weapon;
|
|
|
|
// caused by client server mistmatch where the client selects a killstreak that is no longer in his inventory
|
|
assert( result == "switch_invalid" );
|
|
assert( isTryingToUseKillstreakSlot() );
|
|
|
|
killstreakWeapon = getKillstreakWeapon( self.pers["killstreaks"][self.killstreakIndexWeapon].streakName, self.pers["killstreaks"][self.killstreakIndexWeapon].modules );
|
|
|
|
PrintLn( "Invalid killstreak weapon switch: " + weapon + ". Forcing switch to " + killstreakWeapon + " instead." );
|
|
|
|
self SwitchToWeapon( killstreakWeapon );
|
|
|
|
self waittill( "weapon_switch_started", newWeapon );
|
|
|
|
// player changed weapons while waiting for switch.
|
|
if ( newWeapon != killstreakWeapon )
|
|
{
|
|
PrintLn( "Player switched weapons after script forced killstreak weapon. Skipping killstreak weapon change. " + newWeapon + " != " + killstreakWeapon );
|
|
return undefined;
|
|
}
|
|
|
|
return killstreakWeapon;
|
|
}
|
|
|
|
updateAerialKillStreakMarker()
|
|
{
|
|
foreach( player in level.players )
|
|
player notify( "updateKillStreakMarker" );
|
|
}
|
|
|
|
aerialKillstreakMarker()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "finish_death" );
|
|
self endon( "joined_team" );
|
|
self endon( "faux_spawn" );
|
|
level endon( "game_ended" );
|
|
|
|
enemyTeam = maps\mp\gametypes\_gameobjects::getEnemyTeam( self.team );
|
|
|
|
while( true )
|
|
{
|
|
self waittill_any( "weapon_change", "updateKillStreakMarker" );
|
|
|
|
playerWeapon = self GetCurrentWeapon();
|
|
sWeaponClass = weaponClass( playerWeapon );
|
|
|
|
if( sWeaponClass != "rocketlauncher" )
|
|
continue;
|
|
|
|
targetList = [];
|
|
targetList = getAerialKillstreakArray( enemyTeam );
|
|
|
|
if( targetList.size == 0 )
|
|
continue;
|
|
|
|
foreach( target in targetList )
|
|
{
|
|
createThreatIcon( target, self );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
getAerialKillstreakArray( team )
|
|
{
|
|
entityList = [];
|
|
UAVModels = [];
|
|
|
|
if ( inVirtualLobby() )
|
|
return entityList;
|
|
|
|
if( level.teamBased )
|
|
{
|
|
UAVModels = level.uavmodels[team];
|
|
}
|
|
else
|
|
{
|
|
UAVModels = level.UAVModels;
|
|
}
|
|
|
|
foreach( uav in UAVModels )
|
|
{
|
|
if( IsDefined(uav.isLeaving) && uav.isLeaving )
|
|
continue;
|
|
|
|
if( IsDefined(uav.orbit) && uav.orbit )
|
|
continue;
|
|
|
|
entityList[entityList.size] = uav;
|
|
}
|
|
|
|
foreach ( plane in level.planes )
|
|
{
|
|
if ( !level.teamBased || plane.team == team )
|
|
entityList[entityList.size] = plane;
|
|
}
|
|
|
|
if( level.orbitalsupportInUse && IsDefined( level.orbitalsupport_planemodel ) && IsDefined(level.orbitalsupport_planemodel.owner) && IsDefined(level.orbitalsupport_planemodel.showThreatMarker) && level.orbitalsupport_planemodel.showThreatMarker )
|
|
{
|
|
if( level.teamBased && (level.orbitalsupport_planemodel.owner.team == team) )
|
|
entityList[entityList.size] = level.orbitalsupport_planemodel;
|
|
|
|
if( !level.teamBased )
|
|
entityList[entityList.size] = level.orbitalsupport_planemodel;
|
|
}
|
|
|
|
if ( IsDefined( level.getAerialKillstreakArray ) )
|
|
{
|
|
levelAerialKillstreak = [[level.getAerialKillstreakArray]](team);
|
|
foreach( killstreak in levelAerialKillstreak )
|
|
entityList[entityList.size] = killstreak;
|
|
}
|
|
|
|
return entityList;
|
|
}
|
|
|
|
|
|
createThreatIcon( target, player )
|
|
{
|
|
if( !IsDefined(target.wayPoint) )
|
|
target.wayPoint = [];
|
|
|
|
id = player.guid;
|
|
|
|
if ( IsDefined( target.wayPoint[ id ] ) )
|
|
return;
|
|
|
|
target.wayPoint[ id ] = newHudElem();
|
|
target.wayPoint[ id ] SetShader( "waypoint_threat_hostile", 1, 1 );
|
|
target.wayPoint[ id ].alpha = .75;
|
|
target.wayPoint[ id ].color = ( 1, 1, 1 );
|
|
target.wayPoint[ id ].x = target.origin[0];
|
|
target.wayPoint[ id ].y = target.origin[ 1 ];
|
|
target.wayPoint[ id ].z = target.origin[ 2 ];
|
|
target.wayPoint[ id ] SetWayPoint( true, true, true );
|
|
target.wayPoint[ id ] SetTargetEnt( target );
|
|
target.wayPoint[ id ].showinkillcam = 0;
|
|
target.wayPoint[ id ].archived = 0;
|
|
|
|
level thread removeThreatIcon( self, target, target.wayPoint[ id ] );
|
|
}
|
|
|
|
|
|
removeThreatIcon( player, target, wayPoint )
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
player waittill_any_ents( player, "death", target, "death", player, "weapon_change", player, "disconnect", target, "leaving" );
|
|
wayPoint Destroy();
|
|
}
|
|
|
|
|
|
killstreakUseWaiter()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "finish_death" );
|
|
self endon( "joined_team" );
|
|
self endon( "faux_spawn" );
|
|
level endon( "game_ended" );
|
|
|
|
self notify( "killstreakUseWaiter" );
|
|
self endon( "killstreakUseWaiter" );
|
|
|
|
self.lastKillStreak = 0;
|
|
if ( !IsDefined( self.pers["lastEarnedStreak"] ) )
|
|
self.pers["lastEarnedStreak"] = undefined;
|
|
|
|
self thread finishDeathWaiter();
|
|
|
|
for ( ;; )
|
|
{
|
|
if ( !IsDefined( self.justSwitchedToKillstreakWeapon ) )
|
|
{
|
|
self waittill ( "weapon_change", newWeapon );
|
|
}
|
|
else
|
|
{
|
|
newWeapon = self.justSwitchedToKillstreakWeapon;
|
|
self.justSwitchedToKillstreakWeapon = undefined;
|
|
}
|
|
|
|
// Note: isKillstreakWeap is being used to figure out an issue
|
|
isKillstreakWeap = isKillstreakWeapon( newWeapon );
|
|
|
|
if ( !isAlive( self ) )
|
|
continue;
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 0 activated by player " + self GetEntityNumber() );
|
|
|
|
if ( IsDefined( self.ball_carried ) )
|
|
continue;
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 1 activated by player " + self GetEntityNumber() );
|
|
|
|
if ( !IsDefined( self.killstreakIndexWeapon ) )
|
|
continue;
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 2 activated by player " + self GetEntityNumber() );
|
|
|
|
// holding X to remote join a kill streak that has already been deployed
|
|
if( IsDefined(self.manuallyJoiningKillStreak) && self.manuallyJoiningKillStreak )
|
|
continue;
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 3 activated by player " + self GetEntityNumber() );
|
|
|
|
// don't activate a scorestreak while carrying another one
|
|
if ( IsDefined( self.isCarrying ) && self.isCarrying )
|
|
continue;
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 4 activated by player " + self GetEntityNumber() );
|
|
|
|
if ( !IsDefined( self.pers["killstreaks"][self.killstreakIndexWeapon] ) || !IsDefined( self.pers["killstreaks"][self.killstreakIndexWeapon].streakName ) )
|
|
continue;
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 5 activated by player " + self GetEntityNumber() );
|
|
|
|
killstreakWeapon = getKillstreakWeapon( self.pers["killstreaks"][self.killstreakIndexWeapon].streakName, self.pers["killstreaks"][self.killstreakIndexWeapon].modules );
|
|
if ( newWeapon != killstreakWeapon )
|
|
{
|
|
// since this weapon is not the killstreak we have selected, go back to the last weapon if we're holding an airdrop canister
|
|
if( isStrStart( newWeapon, "airdrop_" ) )
|
|
{
|
|
self TakeWeapon( newWeapon );
|
|
self SwitchToWeapon( self.lastdroppableweapon );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if ( isKillstreakWeap )
|
|
PrintLn( "killstreakUseWaiter 6 activated by player " + self GetEntityNumber() );
|
|
|
|
waittillframeend;
|
|
|
|
// get this stuff now because self.killstreakIndexWeapon will change after killstreakUsePressed()
|
|
streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName;
|
|
isGimme = self.pers["killstreaks"][self.killstreakIndexWeapon].isGimme;
|
|
modules = self.pers["killstreaks"][self.killstreakIndexWeapon].modules;
|
|
|
|
assert( IsDefined( streakName ) );
|
|
assert( IsDefined( level.killstreakFuncs[ streakName ] ) );
|
|
|
|
lastWeapon = self playerGetKillstreakLastWeapon();
|
|
slotNumber = self.killstreakIndexWeapon;
|
|
|
|
if ( shouldSwitchWeaponAfterRaiseAnimation( killstreakWeapon ) )
|
|
self childthread switchWeaponAfterRaiseAnimation( killstreakWeapon, lastWeapon );
|
|
|
|
startUsePressed = GetTime();
|
|
result = self killstreakUsePressed();
|
|
endUsePressed = GetTime();
|
|
elapsedSec = ( endUsePressed - startUsePressed ) / 1000;
|
|
|
|
|
|
if ( !result && !isAlive( self ) && !self hasWeapon( self getLastWeapon() ) )
|
|
{
|
|
// on death your weapon is dropped, if a private match default class was created with no secondary
|
|
// then getFirstPrimaryWeapon() in the 'else if' below will assert because you have no weapons left
|
|
lastWeapon = self playerGetKillstreakLastWeapon( result );
|
|
self _giveWeapon( lastWeapon );
|
|
}
|
|
|
|
// we need to take the killstreak weapon away once we've switched back to our last weapon
|
|
// this fixes an issue where you can call in a killstreak and then press right again to pull the killstreak weapon out
|
|
if( result )
|
|
self thread waitTakeKillstreakWeapon( killstreakWeapon, lastWeapon );
|
|
|
|
//no force switching weapon for ridable killstreaks
|
|
if ( shouldSwitchWeaponPostKillstreak( result, killstreakWeapon, streakName, modules ) && !IsDefined( self.justSwitchedToKillstreakWeapon ) )
|
|
{
|
|
// Allow time for the killstreak weapon to finish the raise anim (drop anim time should be set to 0)
|
|
switch( killstreakWeapon )
|
|
{
|
|
case "killstreak_predator_missile_mp":
|
|
if ( !result && ( 1.2 - elapsedSec ) > 0 )
|
|
wait( 1.2 - elapsedSec ); // Raise time
|
|
break;
|
|
}
|
|
|
|
if ( !IsDefined( self.underWater ) )
|
|
{
|
|
//in co-op don't switch me back to my previous weapon if weaponsJammed has been triggered
|
|
if ( !isdefined ( level.isHorde ) || ( ( isdefined ( level.isHorde ) && level.isHorde ) && !(level.hordeWeaponsJammed && issubstr ( killstreakWeapon, "turrethead" ) ) ) )
|
|
self switch_to_last_weapon( lastWeapon );
|
|
}
|
|
else
|
|
self.water_last_weapon = lastWeapon;
|
|
}
|
|
|
|
// give time to switch to the near weapon; when the weapon is none (such as during a "disableWeapon()" period
|
|
// re-enabling the weapon immediately does a "weapon_change" to the killstreak weapon we just used. In the case that
|
|
// we have two of that killstreak, it immediately uses the second one
|
|
if ( self GetCurrentWeapon() == "none" )
|
|
{
|
|
while ( self GetCurrentWeapon() == "none" )
|
|
wait ( 0.05 );
|
|
|
|
waittillframeend;
|
|
}
|
|
|
|
if( IsDefined( level.cb_usedKillstreak ) && result )
|
|
{
|
|
[[level.cb_usedKillstreak]]( streakName, isGimme, slotNumber );
|
|
}
|
|
}
|
|
}
|
|
|
|
switchWeaponAfterRaiseAnimation( weapon, lastWeapon )
|
|
{
|
|
switch( weapon )
|
|
{
|
|
case "killstreak_uav_mp":
|
|
wait 0.75; // Raise time (minus a little)
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
self switch_to_last_weapon( lastWeapon );
|
|
}
|
|
|
|
playerGetKillstreakLastWeapon( result )
|
|
{
|
|
if ( ( !IsDefined( result ) || ( IsDefined( result ) && !result ) ) && !isAlive( self ) && !self hasWeapon( self getLastWeapon() ) )
|
|
{
|
|
// on death your weapon is dropped, if a private match default class was created with no secondary
|
|
// then getFirstPrimaryWeapon() in the 'else if' below will assert because you have no weapons left
|
|
return self getLastWeapon();
|
|
}
|
|
else if( !self hasWeapon( self getLastWeapon() ) )
|
|
{
|
|
return self getFirstPrimaryWeapon();
|
|
}
|
|
else
|
|
{
|
|
return self getLastWeapon();
|
|
}
|
|
}
|
|
|
|
waitTakeKillstreakWeapon( killstreakWeapon, lastWeapon )
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "finish_death" );
|
|
self endon( "joined_team" );
|
|
level endon( "game_ended" );
|
|
self endon( "faux_spawn" );
|
|
|
|
self notify( "waitTakeKillstreakWeapon" );
|
|
self endon( "waitTakeKillstreakWeapon" );
|
|
|
|
// planted killstreaks like the sam, sentry, remote turret, and ims, will come in here with none as the current weapon sometimes because we _disableWeapons() while you carry them
|
|
// we need to know this so we can take the weapon correctly in these cases
|
|
wasNone = ( self GetCurrentWeapon() == "none" );
|
|
|
|
// this lets the killstreak weapon animation play and then take it once we switch away from it
|
|
self waittill( "weapon_change", newWeapon );
|
|
|
|
if( newWeapon == lastWeapon )
|
|
{
|
|
takeKillstreakWeaponIfNoDupe( killstreakWeapon );
|
|
// pc needs to reset the killstreakIndexWeapon because we set this when they press the use button and we don't want the value lingering
|
|
if( !level.console && !self is_player_gamepad_enabled() )
|
|
self.killstreakIndexWeapon = undefined;
|
|
}
|
|
// this could happen with ridden killstreaks like the ac130
|
|
else if( newWeapon != killstreakWeapon )
|
|
{
|
|
self thread waitTakeKillstreakWeapon( killstreakWeapon, lastWeapon );
|
|
}
|
|
// this could happen with planted killstreaks like the sam, sentry, remote turret, and ims
|
|
// they come into this function with current weapon as none and then the weapon change fires off immediately because we call _enableWeapons()
|
|
// that gives us back the killstreak weapon and it plays an animation before switching back to your normal weapon
|
|
else if( wasNone && self GetCurrentWeapon() == killstreakWeapon )
|
|
{
|
|
self thread waitTakeKillstreakWeapon( killstreakWeapon, lastWeapon );
|
|
}
|
|
}
|
|
|
|
takeKillstreakWeaponIfNoDupe( killstreakWeapon )
|
|
{
|
|
// only take the killstreak weapon if they don't have anymore
|
|
// the player could have two of the same killstreak and if we take the weapon then they can't use the second one
|
|
hasKillstreak = false;
|
|
self_pers_killstreaks = self.pers["killstreaks"];
|
|
for( i = 0; i < self_pers_killstreaks.size; i++ )
|
|
{
|
|
if( IsDefined( self_pers_killstreaks[i] ) && IsDefined( self_pers_killstreaks[i].streakName ) && self_pers_killstreaks[i].available )
|
|
{
|
|
// this fixes a bug where you earn a uav, change classes to specialist and earn the first streak, use the uav and the killstreak weapon doesn't get taken because it thinks you still have one
|
|
if( killstreakWeapon == getKillstreakWeapon( self_pers_killstreaks[i].streakName, self_pers_killstreaks[i].modules ) )
|
|
{
|
|
hasKillstreak = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if they have the killstreak then check to see if the currently selected killstreak is the same killstreak, if not take the weapon because it'll be given to them when they select it
|
|
if( hasKillstreak )
|
|
{
|
|
if( level.console || self is_player_gamepad_enabled() )
|
|
{
|
|
if( IsDefined( self.killstreakIndexWeapon ) && killstreakWeapon != getKillstreakWeapon( self_pers_killstreaks[self.killstreakIndexWeapon].streakName, self_pers_killstreaks[self.killstreakIndexWeapon].modules ) )
|
|
{
|
|
// take the weapon because it's currently not the selected killstreak
|
|
self TakeWeapon( killstreakWeapon );
|
|
}
|
|
else if( IsDefined( self.killstreakIndexWeapon ) && killstreakWeapon == getKillstreakWeapon( self_pers_killstreaks[self.killstreakIndexWeapon].streakName, self_pers_killstreaks[self.killstreakIndexWeapon].modules ) )
|
|
{
|
|
// take and give it right back, this fixes an issue where you could have two of the same weapons and after using the first then you couldn't use the second
|
|
// this was reproduced by doing predator, precision airstrike, strafe run, where airstrike and strafe run use the same weapon
|
|
// so if you called in the predator, then called in the strafe, you couldn't use the airstrike because you no longer have the weapon
|
|
// script isn't taking the weapon from you but code was saying clear that slot because the weapons were 'clip only', they shouldn't be
|
|
self TakeWeapon( killstreakWeapon );
|
|
self _giveWeapon( killstreakWeapon, 0 );
|
|
self _setActionSlot( 4, "weapon", killstreakWeapon );
|
|
}
|
|
}
|
|
// pc doesn't have selected killstreaks
|
|
else
|
|
{
|
|
// we still want to take and give to make sure they have the weapon
|
|
self TakeWeapon( killstreakWeapon );
|
|
self _giveWeapon( killstreakWeapon, 0 );
|
|
}
|
|
}
|
|
else
|
|
self TakeWeapon( killstreakWeapon );
|
|
}
|
|
|
|
shouldSwitchWeaponPostKillstreak( result, killstreakWeapon, streakName, modules )
|
|
{
|
|
if ( shouldSwitchWeaponAfterRaiseAnimation( killstreakWeapon ) )
|
|
return false;
|
|
|
|
if ( !result )
|
|
return true;
|
|
|
|
// certain killstreaks handle the weapon switching
|
|
switch( streakName )
|
|
{
|
|
case "warbird":
|
|
return ( array_contains( modules, "warbird_ai_attack" ) || array_contains( modules, "warbird_ai_follow" ) );
|
|
case "assault_ugv":
|
|
return ( array_contains( modules, "assault_ugv_ai" ) );
|
|
}
|
|
if( isRideKillstreak( streakName ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
shouldSwitchWeaponAfterRaiseAnimation( weapon )
|
|
{
|
|
switch( weapon )
|
|
{
|
|
case "killstreak_uav_mp":
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
finishDeathWaiter()
|
|
{
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
self endon( "faux_spawn" );
|
|
|
|
self notify ( "finishDeathWaiter" );
|
|
self endon ( "finishDeathWaiter" );
|
|
|
|
self waittill ( "death" );
|
|
wait ( 0.05 );
|
|
self notify ( "finish_death" );
|
|
self.pers["lastEarnedStreak"] = undefined;
|
|
}
|
|
|
|
checkStreakReward()
|
|
{
|
|
foreach( streakName in self.killstreaks )
|
|
{
|
|
streakVal = getStreakCost( streakName );
|
|
|
|
adrenaline = self.adrenaline;
|
|
previousAdrenaline = self.previousAdrenaline;
|
|
if ( isSupportStreak( self, streakName ) )
|
|
{
|
|
adrenaline = self.adrenalineSupport;
|
|
previousAdrenaline = self.previousAdrenalineSupport;
|
|
}
|
|
|
|
if( streakVal > adrenaline && adrenaline > previousAdrenaline )
|
|
continue;
|
|
|
|
if( previousAdrenaline < streakVal && ( adrenaline >= streakVal || adrenaline <= previousAdrenaline ) )
|
|
self earnKillstreak( streakName, streakVal );
|
|
}
|
|
}
|
|
|
|
killstreakEarned( streakName )
|
|
{
|
|
if( IsDefined( self.class_num ) )
|
|
{
|
|
class_num = self.class_num;
|
|
if ( class_num == -1 )
|
|
{
|
|
actual_class_name = self.pers["copyCatLoadout"]["className"];
|
|
class_num = getClassIndex( actual_class_name );
|
|
if ( IsSubStr( actual_class_name, "practice" ) )
|
|
{
|
|
class_num = self.pers["copyCatLoadout"]["practiceClassNum"];
|
|
}
|
|
}
|
|
|
|
if ( isSubstr( self.class, "custom" ) )
|
|
{
|
|
if ( self getCacPlayerData( class_num, "assaultStreaks", 0, "streak" ) == streakName )
|
|
{
|
|
self.firstKillstreakEarned = getTime();
|
|
}
|
|
else if ( self getCaCPlayerData( class_num, "assaultStreaks", 2, "streak" ) == streakName && IsDefined( self.firstKillstreakEarned ) )
|
|
{
|
|
if ( getTime() - self.firstKillstreakEarned < 20000 )
|
|
self thread maps\mp\gametypes\_missions::genericChallenge( "wargasm" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
earnKillstreak( streakName, streakVal )
|
|
{
|
|
self.earnedStreakLevel = streakVal;
|
|
|
|
modules = getKillstreakModules( self, streakName );
|
|
|
|
// called before giveKillstreak to see what slot this will end up in
|
|
slotIndex = self maps\mp\killstreaks\_killstreaks::getNextKillstreakSlotIndex( streakName, true );
|
|
|
|
self thread maps\mp\_events::earnedKillStreakEvent( streakName, streakVal, modules, slotIndex );
|
|
self thread killstreakEarned( streakName );
|
|
self.pers["lastEarnedStreak"] = streakName;
|
|
|
|
self giveKillstreak( streakName, true, true, self, modules );
|
|
|
|
//Hardline Perk Challenge
|
|
if( self _hasPerk( "specialty_class_hardline" ) )
|
|
self maps\mp\gametypes\_missions::processChallenge( "ch_perk_hardline" );
|
|
|
|
}
|
|
|
|
getKillstreakModules( owner, streakName )
|
|
{
|
|
Assert( IsPlayer( owner ) && IsDefined( owner.killStreakModules ) );
|
|
|
|
modules = [];
|
|
|
|
moduleRefs = GetArrayKeys( self.killStreakModules );
|
|
|
|
foreach ( module in moduleRefs )
|
|
{
|
|
baseKillstreakRef = getStreakModuleBaseKillstreak( module );
|
|
if ( baseKillstreakRef == streakName )
|
|
modules[modules.size] = module;
|
|
}
|
|
|
|
return modules;
|
|
}
|
|
|
|
/*getModulesForDefaultStreak( streakName )
|
|
{
|
|
combinations = [];
|
|
|
|
for ( i = 0; true; i++ )
|
|
{
|
|
tableStreakRef = TableLookupByRow( level.KS_COMBINATIONS_TABLE, i, level.KS_COMBINATIONS_REF_COLUMN );
|
|
|
|
if ( !IsDefined( tableStreakRef ) || tableStreakRef == "" )
|
|
break;
|
|
|
|
if ( tableStreakRef != streakName )
|
|
continue;
|
|
|
|
valid = TableLookupByRow( level.KS_COMBINATIONS_TABLE, i, level.KS_COMBINATIONS_VALID_COLUMN );
|
|
|
|
if ( !IsDefined( valid ) || valid == "" || valid == "0" )
|
|
continue;
|
|
|
|
combinationIndex = combinations.size;
|
|
combinations[combinationIndex] = [];
|
|
|
|
module1Ref = TableLookupByRow( level.KS_COMBINATIONS_TABLE, i, level.KS_COMBINATIONS_MOD1_COLUMN );
|
|
if ( IsDefined( module1Ref ) && module1Ref != "" )
|
|
{
|
|
index = combinations[combinationIndex].size;
|
|
combinations[combinationIndex][index] = module1Ref;
|
|
}
|
|
|
|
module2Ref = TableLookupByRow( level.KS_COMBINATIONS_TABLE, i, level.KS_COMBINATIONS_MOD2_COLUMN );
|
|
if ( IsDefined( module2Ref ) && module2Ref != "" )
|
|
{
|
|
index = combinations[combinationIndex].size;
|
|
combinations[combinationIndex][index] = module2Ref;
|
|
}
|
|
|
|
module3Ref = TableLookupByRow( level.KS_COMBINATIONS_TABLE, i, level.KS_COMBINATIONS_MOD3_COLUMN );
|
|
if ( IsDefined( module3Ref ) && module3Ref != "" )
|
|
{
|
|
index = combinations[combinationIndex].size;
|
|
combinations[combinationIndex][index] = module3Ref;
|
|
}
|
|
}
|
|
|
|
|
|
if ( combinations.size == 0 )
|
|
{
|
|
PrintLn( "WARNING: No default modules found in the 'killstreaksCombination' table for killstreak: " + streakName );
|
|
return combinations;
|
|
}
|
|
|
|
randIndex = RandomInt( combinations.size );
|
|
return combinations[randIndex];
|
|
}*/
|
|
|
|
getNextHordeKillStreakSlotIndex( slotNumber )
|
|
{
|
|
if( !IsDefined(slotNumber) )
|
|
slotNumber = level.KILLSTREAK_GIMME_SLOT;
|
|
|
|
return slotNumber;
|
|
}
|
|
|
|
giveHordeKillStreak( streakName, owner, modules, slotNumber, available )
|
|
{
|
|
self endon( "givingLoadout" );
|
|
|
|
if ( !IsDefined( level.killstreakFuncs[streakName] ) || tableLookup( level.KILLSTREAK_STRING_TABLE, 1, streakName, 0 ) == "" )
|
|
{
|
|
AssertMsg( "giveKillstreak() called with invalid killstreak: " + streakName );
|
|
return;
|
|
}
|
|
// for devmenu give with spectators in match
|
|
if( !IsDefined( self.pers["killstreaks"] ) )
|
|
return;
|
|
|
|
self endon ( "disconnect" );
|
|
|
|
// streaks given from crates go in the gimme
|
|
index = undefined;
|
|
|
|
// put this killstreak in the next available position
|
|
// 0 - gimme slot (that will index stacked killstreaks)
|
|
// 1-3 - cac selected killstreaks
|
|
// 4 or more - stacked killstreaks
|
|
|
|
// MW3 way so it will stack in the gimme slot
|
|
nextSlot = self.pers[ "killstreaks" ].size;
|
|
|
|
if( IsDefined(slotNumber) )
|
|
nextSlot = slotNumber;
|
|
|
|
if( !IsDefined( self.pers[ "killstreaks" ][ nextSlot ] ) )
|
|
self.pers[ "killstreaks" ][ nextSlot ] = spawnStruct();
|
|
|
|
self_pers_killstreak_nextSlot = self.pers[ "killstreaks" ][ nextSlot ];
|
|
|
|
self_pers_killstreak_nextSlot.available = false;
|
|
self_pers_killstreak_nextSlot.streakName = streakName;
|
|
self_pers_killstreak_nextSlot.earned = false;
|
|
self_pers_killstreak_nextSlot.awardxp = false;
|
|
self_pers_killstreak_nextSlot.owner = owner;
|
|
self_pers_killstreak_nextSlot.kID = self.pers["kID"];
|
|
self_pers_killstreak_nextSlot.lifeId = -1;
|
|
self_pers_killstreak_nextSlot.isGimme = true;
|
|
|
|
index = getNextHordeKillStreakSlotIndex( slotNumber );
|
|
|
|
if ( !IsDefined( modules ) || !IsArray( modules ) )
|
|
modules = getKillstreakModules( self, streakName );
|
|
self_pers_killstreak_nextSlot.modules = modules;
|
|
|
|
self.pers[ "killstreaks" ][ index ].nextSlot = nextSlot;
|
|
self.pers[ "killstreaks" ][ index ].streakName = streakName;
|
|
|
|
streakIndex = getKillstreakIndex( streakName );
|
|
killstreak_iconName = "ks_icon" + toString( index );
|
|
self SetClientOmnvar( killstreak_iconName, streakIndex );
|
|
|
|
if ( !available )
|
|
{
|
|
self updateStreakSlots();
|
|
|
|
if ( IsDefined( level.killstreakSetupFuncs[ streakName ] ) )
|
|
self [[ level.killstreakSetupFuncs[ streakName ] ]]();
|
|
|
|
self SetClientOmnvar( "ks_acquired", 1 );
|
|
|
|
return;
|
|
}
|
|
|
|
self_pers_killstreak_index = self.pers["killstreaks"][index];
|
|
self_pers_killstreak_index.available = true;
|
|
self_pers_killstreak_index.earned = false;
|
|
self_pers_killstreak_index.awardxp = false;
|
|
self_pers_killstreak_index.owner = owner;
|
|
self_pers_killstreak_index.kID = self.pers["kID"];
|
|
if ( IsDefined( modules ) && IsArray( modules ) )
|
|
self_pers_killstreak_index.modules = modules;
|
|
else
|
|
self_pers_killstreak_index.modules = getKillstreakModules( self, streakName );
|
|
self.pers["kID"]++;
|
|
|
|
self_pers_killstreak_index.lifeId = -1;
|
|
|
|
if( level.console || self is_player_gamepad_enabled() )
|
|
{
|
|
weapon = getKillstreakWeapon( streakName, modules );
|
|
self giveKillstreakWeapon( weapon );
|
|
|
|
// NOTE_A (also see NOTE_B): before we change the killstreakIndexWeapon, let's make sure it's not the one we're holding
|
|
// if we're currently holding something like an airdrop marker and we earned a killstreak while holding it then we want that to remain the weapon index
|
|
// because if it's not, then when you throw it, it'll think we're using a different killstreak and not take it away but it'll take away the other one
|
|
if( IsDefined( self.killstreakIndexWeapon ) )
|
|
{
|
|
streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName;
|
|
killstreakWeapon = getKillstreakWeapon( streakName, modules );
|
|
currentWeapon = self GetCurrentWeapon();
|
|
if( currentWeapon != killstreakWeapon && !IsSubStr( currentWeapon, "turrethead" ) )
|
|
{
|
|
self.killstreakIndexWeapon = index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.killstreakIndexWeapon = index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for pc, we need to give you the killstreak weapon in the right action slot
|
|
|
|
// if this is the gimme slot then take away the weapon for what is in there right now and just give them this new one
|
|
// we don't want to keep giving weapons every time they get something in the gimme slot because there is a cap eventually
|
|
if( level.KILLSTREAK_GIMME_SLOT == index && self.pers[ "killstreaks" ][ level.KILLSTREAK_GIMME_SLOT ].nextSlot > level.KILLSTREAK_STACKING_START_SLOT )
|
|
{
|
|
// since nextSlot has already been incremented, get the next lowest and take the weapon
|
|
slotToTake = self.pers[ "killstreaks" ][ level.KILLSTREAK_GIMME_SLOT ].nextSlot - 1;
|
|
killstreakWeaponToTake = getKillstreakWeapon( self.pers["killstreaks"][ slotToTake ].streakName, self.pers["killstreaks"][ slotToTake ].modules );
|
|
self TakeWeapon( killstreakWeaponToTake );
|
|
}
|
|
|
|
killstreakWeapon = getKillstreakWeapon( streakName, modules );
|
|
self _giveWeapon( killstreakWeapon, 0 );
|
|
self _setActionSlot( index + 4, "weapon", killstreakWeapon );
|
|
}
|
|
|
|
self updateStreakSlots();
|
|
|
|
if ( IsDefined( level.killstreakSetupFuncs[ streakName ] ) )
|
|
self [[ level.killstreakSetupFuncs[ streakName ] ]]();
|
|
|
|
self SetClientOmnvar( "ks_acquired", 1 );
|
|
}
|
|
|
|
getNextKillstreakSlotIndex( streakName, isEarned, slotNumber )
|
|
{
|
|
nextSlotIndex = undefined;
|
|
|
|
// 0 - gimme slot (that will index stacked killstreaks)
|
|
// 1-4 - cac selected killstreaks
|
|
|
|
if ( !IsDefined( isEarned ) || isEarned == false )
|
|
{
|
|
if( !IsDefined(slotNumber) )
|
|
nextSlotIndex = level.KILLSTREAK_GIMME_SLOT;
|
|
else
|
|
nextSlotIndex = slotNumber;
|
|
}
|
|
else
|
|
{
|
|
for( i = level.KILLSTREAK_SLOT_1; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
self_pers_killstreak_i = self.pers["killstreaks"][i];
|
|
if( IsDefined( self_pers_killstreak_i ) && IsDefined( self_pers_killstreak_i.streakName ) && streakName == self_pers_killstreak_i.streakName )
|
|
{
|
|
nextSlotIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nextSlotIndex;
|
|
}
|
|
|
|
giveKillstreak( streakName, isEarned, awardXp, owner, modules, slotNumber )
|
|
{
|
|
self endon( "givingLoadout" );
|
|
|
|
if ( !IsDefined( level.killstreakFuncs[streakName] ) || tableLookup( level.KILLSTREAK_STRING_TABLE, 1, streakName, 0 ) == "" )
|
|
{
|
|
AssertMsg( "giveKillstreak() called with invalid killstreak: " + streakName );
|
|
return;
|
|
}
|
|
// for devmenu give with spectators in match
|
|
if( !IsDefined( self.pers["killstreaks"] ) )
|
|
return;
|
|
|
|
self endon ( "disconnect" );
|
|
|
|
// streaks given from crates go in the gimme
|
|
index = undefined;
|
|
if ( !IsDefined( isEarned ) || isEarned == false )
|
|
{
|
|
// put this killstreak in the next available position
|
|
// 0 - gimme slot (that will index stacked killstreaks)
|
|
// 1-4 - cac selected killstreaks
|
|
// 5 or more - stacked killstreaks
|
|
|
|
// MW3 way so it will stack in the gimme slot
|
|
nextSlot = self.pers[ "killstreaks" ].size;
|
|
|
|
if( IsDefined(slotNumber) )
|
|
nextSlot = slotNumber;
|
|
|
|
if( !IsDefined( self.pers[ "killstreaks" ][ nextSlot ] ) )
|
|
self.pers[ "killstreaks" ][ nextSlot ] = spawnStruct();
|
|
|
|
self_pers_killstreak_nextSlot = self.pers[ "killstreaks" ][ nextSlot ];
|
|
|
|
self_pers_killstreak_nextSlot.available = false;
|
|
self_pers_killstreak_nextSlot.streakName = streakName;
|
|
self_pers_killstreak_nextSlot.earned = false;
|
|
self_pers_killstreak_nextSlot.awardxp = IsDefined( awardXp ) && awardXp;
|
|
self_pers_killstreak_nextSlot.owner = owner;
|
|
self_pers_killstreak_nextSlot.kID = self.pers["kID"];
|
|
self_pers_killstreak_nextSlot.lifeId = -1;
|
|
self_pers_killstreak_nextSlot.isGimme = true;
|
|
|
|
index = getNextKillstreakSlotIndex( streakName, isEarned, slotNumber );
|
|
|
|
if ( !IsDefined( modules ) || !IsArray( modules ) )
|
|
modules = getKillstreakModules( self, streakName );
|
|
self_pers_killstreak_nextSlot.modules = modules;
|
|
|
|
self.pers[ "killstreaks" ][ index ].nextSlot = nextSlot;
|
|
self.pers[ "killstreaks" ][ index ].streakName = streakName;
|
|
|
|
streakIndex = getKillstreakIndex( streakName );
|
|
killstreak_iconName = "ks_icon" + toString( index );
|
|
self SetClientOmnvar( killstreak_iconName, streakIndex );
|
|
}
|
|
else
|
|
{
|
|
index = getNextKillstreakSlotIndex( streakName, isEarned, slotNumber );
|
|
|
|
if ( !IsDefined( index ) )
|
|
{
|
|
/#
|
|
println( "self.killstreaks" );
|
|
keys = getArrayKeys( self.killstreaks );
|
|
for ( i = 0; i < keys.size; i++ )
|
|
println( " self.killstreaks[\"" + keys[ i ] + "\"] = ", self.killstreaks[ keys[ i ] ] );
|
|
|
|
println( "self.pers[\"killstreaks\"]" );
|
|
for ( i = 0; i < self.pers["killstreaks"].size; i++ )
|
|
{
|
|
killstreak_struct = self.pers["killstreaks"][i];
|
|
if ( IsDefined(killstreak_struct.streakname) )
|
|
println( " self.pers[\"killstreaks\"][\"" + i + "\"] = ", killstreak_struct.streakname );
|
|
}
|
|
AssertMsg( "earnKillstreak() trying to give unearnable killstreak with giveKillstreak(): " + streakName + ". See log for details" );
|
|
#/
|
|
return;
|
|
}
|
|
}
|
|
|
|
self_pers_killstreak_index = self.pers["killstreaks"][index];
|
|
self_pers_killstreak_index.available = true;
|
|
self_pers_killstreak_index.earned = IsDefined( isEarned ) && isEarned;
|
|
self_pers_killstreak_index.awardxp = IsDefined( awardXp ) && awardXp;
|
|
self_pers_killstreak_index.owner = owner;
|
|
self_pers_killstreak_index.kID = self.pers["kID"];
|
|
if ( IsDefined( modules ) && IsArray( modules ) )
|
|
self_pers_killstreak_index.modules = modules;
|
|
else
|
|
self_pers_killstreak_index.modules = getKillstreakModules( self, streakName );
|
|
//self.pers["kIDs_valid"][self.pers["kID"]] = true;
|
|
self.pers["kID"]++;
|
|
|
|
if ( !self_pers_killstreak_index.earned )
|
|
self_pers_killstreak_index.lifeId = -1;
|
|
else
|
|
self_pers_killstreak_index.lifeId = self.pers["deaths"];
|
|
|
|
if( level.console || self is_player_gamepad_enabled() )
|
|
{
|
|
weapon = getKillstreakWeapon( streakName, modules );
|
|
self giveKillstreakWeapon( weapon );
|
|
|
|
// NOTE_A (also see NOTE_B): before we change the killstreakIndexWeapon, let's make sure it's not the one we're holding
|
|
// if we're currently holding something like an airdrop marker and we earned a killstreak while holding it then we want that to remain the weapon index
|
|
// because if it's not, then when you throw it, it'll think we're using a different killstreak and not take it away but it'll take away the other one
|
|
if( IsDefined( self.killstreakIndexWeapon ) )
|
|
{
|
|
streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName;
|
|
killstreakWeapon = getKillstreakWeapon( streakName, modules );
|
|
currentWeapon = self GetCurrentWeapon();
|
|
if( currentWeapon != killstreakWeapon && !IsSubStr( currentWeapon, "turrethead" ) )
|
|
{
|
|
self.killstreakIndexWeapon = index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.killstreakIndexWeapon = index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for pc, we need to give you the killstreak weapon in the right action slot
|
|
|
|
// if this is the gimme slot then take away the weapon for what is in there right now and just give them this new one
|
|
// we don't want to keep giving weapons every time they get something in the gimme slot because there is a cap eventually
|
|
if( level.KILLSTREAK_GIMME_SLOT == index && self.pers[ "killstreaks" ][ level.KILLSTREAK_GIMME_SLOT ].nextSlot > level.KILLSTREAK_STACKING_START_SLOT )
|
|
{
|
|
// since nextSlot has already been incremented, get the next lowest and take the weapon
|
|
slotToTake = self.pers[ "killstreaks" ][ level.KILLSTREAK_GIMME_SLOT ].nextSlot - 1;
|
|
killstreakWeaponToTake = getKillstreakWeapon( self.pers["killstreaks"][ slotToTake ].streakName, self.pers["killstreaks"][ slotToTake ].modules );
|
|
self TakeWeapon( killstreakWeaponToTake );
|
|
}
|
|
|
|
killstreakWeapon = getKillstreakWeapon( streakName, modules );
|
|
self _giveWeapon( killstreakWeapon, 0 );
|
|
self _setActionSlot( index + 4, "weapon", killstreakWeapon );
|
|
}
|
|
|
|
|
|
self updateStreakSlots();
|
|
|
|
if ( IsDefined( level.killstreakSetupFuncs[ streakName ] ) )
|
|
self [[ level.killstreakSetupFuncs[ streakName ] ]]();
|
|
|
|
if ( IsDefined( isEarned ) && isEarned && IsDefined( awardXp ) && awardXp )
|
|
self notify( "received_earned_killstreak" );
|
|
|
|
self SetClientOmnvar( "ks_acquired", 1 );
|
|
}
|
|
|
|
|
|
giveKillstreakWeapon( weapon )
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
// pc doesn't need to give the weapon because you use on a single button press (unless using gamepad)
|
|
if( !level.console && !self is_player_gamepad_enabled() )
|
|
return;
|
|
|
|
weaponList = self GetWeaponsListItems();
|
|
|
|
foreach( item in weaponList )
|
|
{
|
|
if( !isStrStart( item, "killstreak_" ) && !isStrStart( item, "airdrop_" ) && !isStrStart( item, "deployable_" ) )
|
|
continue;
|
|
|
|
if( self GetCurrentWeapon() == item )
|
|
continue;
|
|
|
|
while( self isChangingWeapon() )
|
|
wait ( 0.05 );
|
|
|
|
self TakeWeapon( item );
|
|
}
|
|
|
|
// NOTE_B (also see NOTE_A) : before we giving the killstreak weapon, let's make sure it's not the one we're holding
|
|
// if we're currently holding something like an airdrop marker and we earned a killstreak while holding it then we want that to remain the killstreak weapon
|
|
// because if it's not, then when we earn the new killstreak, we won't be able to put this one away because it thinks it's something else
|
|
if( IsDefined( self.killstreakIndexWeapon ) )
|
|
{
|
|
streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName;
|
|
modules = self.pers["killstreaks"][self.killstreakIndexWeapon].modules;
|
|
killstreakWeapon = getKillstreakWeapon( streakName, modules );
|
|
if( self GetCurrentWeapon() != killstreakWeapon )
|
|
{
|
|
self _giveWeapon( weapon, 0 );
|
|
self _setActionSlot( 4, "weapon", weapon );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self _giveWeapon( weapon, 0 );
|
|
self _setActionSlot( 4, "weapon", weapon );
|
|
}
|
|
}
|
|
|
|
|
|
getStreakModuleCost( moduleName ) // self == level
|
|
{
|
|
return int( TableLookup( level.KS_MODULES_TABLE, level.KS_MODULE_REF_COLUMN, moduleName, level.KS_MODULE_ADDED_POINTS_COLUMN ) );
|
|
}
|
|
|
|
|
|
getStreakModuleBaseKillstreak( moduleName ) // self == level
|
|
{
|
|
return TableLookup( level.KS_MODULES_TABLE, level.KS_MODULE_REF_COLUMN, moduleName, level.KS_MODULE_KILLSTREAK_REF_COLUMN );
|
|
}
|
|
|
|
|
|
getAllStreakModulesCost( streakName ) // self == player
|
|
{
|
|
Assert( IsPlayer( self ) && IsDefined( self.killStreakModules ) );
|
|
|
|
cost = 0;
|
|
|
|
moduleRefs = GetArrayKeys( self.killStreakModules );
|
|
|
|
foreach ( module in moduleRefs )
|
|
{
|
|
baseKillstreakRef = getStreakModuleBaseKillstreak( module );
|
|
if ( baseKillstreakRef == streakName )
|
|
cost += self.killStreakModules[module];
|
|
}
|
|
|
|
return cost;
|
|
}
|
|
|
|
|
|
getStreakCost( streakName )
|
|
{
|
|
cost = int( getKillstreakKills( streakName ) );
|
|
|
|
if ( IsPlayer( self ) )
|
|
cost += getAllStreakModulesCost( streakName );
|
|
|
|
if( IsDefined( self ) && IsPlayer( self ) )
|
|
{
|
|
if ( cost > 100 && self _hasPerk( "specialty_hardline" ) )
|
|
{
|
|
cost -= 100;
|
|
}
|
|
}
|
|
|
|
return cost;
|
|
}
|
|
|
|
|
|
|
|
getKillstreakHint( streakName )
|
|
{
|
|
return tableLookupIString( level.KILLSTREAK_STRING_TABLE, KILLSTREAK_NAME_COLUMN, streakName, KILLSTREAK_EARNED_HINT_COLUMN );
|
|
}
|
|
|
|
|
|
getKillstreakInformEnemy( streakName )
|
|
{
|
|
return int( tableLookup( level.KILLSTREAK_STRING_TABLE, KILLSTREAK_NAME_COLUMN, streakName, KILLSTREAK_ENEMY_USE_DIALOG_COLUMN ) );
|
|
}
|
|
|
|
|
|
getKillstreakDialog( streakName )
|
|
{
|
|
return tableLookup( level.KILLSTREAK_STRING_TABLE, KILLSTREAK_NAME_COLUMN, streakName, KILLSTREAK_EARN_DIALOG_COLUMN );
|
|
}
|
|
|
|
|
|
getKillstreakCrateIcon( streakName, modules )
|
|
{
|
|
column = KILLSTREAK_OVERHEAD_ICON_COLUMN;
|
|
if ( IsDefined( modules ) && modules.size > 0 )
|
|
{
|
|
switch( modules.size )
|
|
{
|
|
case 1: column = KILLSTREAK_OVERHEAD_ICON_PLUS_1_COLUMN; break;
|
|
case 2: column = KILLSTREAK_OVERHEAD_ICON_PLUS_2_COLUMN; break;
|
|
case 3: column = KILLSTREAK_OVERHEAD_ICON_PLUS_3_COLUMN; break;
|
|
default:
|
|
AssertMsg( "Too many modules for func getKillstreakCrateIcon" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return tableLookup(level.KILLSTREAK_STRING_TABLE, KILLSTREAK_NAME_COLUMN, streakName, column );
|
|
}
|
|
|
|
|
|
|
|
giveOwnedKillstreakItem( skipDialog )
|
|
{
|
|
self_pers_killstreaks = self.pers["killstreaks"];
|
|
|
|
if( level.console || self is_player_gamepad_enabled() )
|
|
{
|
|
// find the highest costing streak
|
|
keepIndex = -1;
|
|
highestCost = -1;
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
if( IsDefined( self_pers_killstreaks[i] ) &&
|
|
IsDefined( self_pers_killstreaks[i].streakName ) &&
|
|
self_pers_killstreaks[i].available &&
|
|
getStreakCost( self_pers_killstreaks[i].streakName ) > highestCost )
|
|
{
|
|
// make sure the gimme slot is the lowest regardless of the cost of the killstreak in it
|
|
highestCost = 0;
|
|
if( !self_pers_killstreaks[i].isGimme )
|
|
highestCost = getStreakCost( self_pers_killstreaks[i].streakName );
|
|
keepIndex = i;
|
|
}
|
|
}
|
|
|
|
if ( keepIndex != -1 )
|
|
{
|
|
// select it
|
|
self.killstreakIndexWeapon = keepIndex;
|
|
|
|
// give the weapon
|
|
streakName = self_pers_killstreaks[self.killstreakIndexWeapon].streakName;
|
|
modules = self.pers["killstreaks"][self.killstreakIndexWeapon].modules;
|
|
weapon = getKillstreakWeapon( streakName, modules );
|
|
self giveKillstreakWeapon( weapon );
|
|
}
|
|
else
|
|
self.killstreakIndexWeapon = undefined;
|
|
}
|
|
// pc doesn't select killstreaks
|
|
else
|
|
{
|
|
keepIndex = -1;
|
|
highestCost = -1;
|
|
// make sure we still have all of the available killstreak weapons
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
if( IsDefined( self_pers_killstreaks[i] ) &&
|
|
IsDefined( self_pers_killstreaks[i].streakName ) &&
|
|
self_pers_killstreaks[i].available )
|
|
{
|
|
killstreakWeapon = getKillstreakWeapon( self_pers_killstreaks[i].streakName, self_pers_killstreaks[i].modules );
|
|
weaponsListItems = self GetWeaponsListItems();
|
|
hasKillstreakWeapon = false;
|
|
for( j = 0; j < weaponsListItems.size; j++ )
|
|
{
|
|
if( killstreakWeapon == weaponsListItems[j] )
|
|
{
|
|
hasKillstreakWeapon = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !hasKillstreakWeapon )
|
|
{
|
|
self _giveWeapon( killstreakWeapon );
|
|
}
|
|
else
|
|
{
|
|
// if we have more than one airdrop type weapon the ammo gets set to 0 because we give the next airdrop weapon before we take the last one
|
|
// this is a quicker fix than trying to figure out how to take and give at the right times
|
|
if( IsSubStr( killstreakWeapon, "airdrop_" ) )
|
|
self SetWeaponAmmoClip( killstreakWeapon, 1 );
|
|
}
|
|
|
|
// since the killstreak is available, make sure the actionslot is set correctly
|
|
// this fixes a bug where you could have, for example, a uav in your gimme slot and earned a uav before you died, when you respawned the earned uav actionslot wasn't set and you couldn't use it
|
|
self _setActionSlot( i + 4, "weapon", killstreakWeapon );
|
|
|
|
// get the highest value killstreak so we can show hint text for it on spawn
|
|
// make sure the gimme slot is the lowest regardless of the cost of the killstreak in it
|
|
if( getStreakCost( self_pers_killstreaks[i].streakName ) > highestCost )
|
|
{
|
|
highestCost = 0;
|
|
if( !self_pers_killstreaks[i].isGimme )
|
|
highestCost = getStreakCost( self_pers_killstreaks[i].streakName );
|
|
keepIndex = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( keepIndex != -1 )
|
|
{
|
|
streakName = self_pers_killstreaks[ keepIndex ].streakName;
|
|
}
|
|
|
|
self.killstreakIndexWeapon = undefined;
|
|
}
|
|
|
|
updateStreakSlots();
|
|
}
|
|
|
|
|
|
playerWaittillRideKillstreakComplete()
|
|
{
|
|
if ( !IsDefined( self.remoteRideTransition ) )
|
|
return;
|
|
|
|
self endon( "rideKillstreakComplete" );
|
|
|
|
self waittill( "rideKillstreakFailed" );
|
|
}
|
|
|
|
|
|
playerWaittillRideKillstreakBlack()
|
|
{
|
|
if ( !IsDefined( self.remoteRideTransition ) )
|
|
return;
|
|
|
|
self endon( "rideKillstreakBlack" );
|
|
|
|
self waittill( "rideKillstreakFailed" );
|
|
}
|
|
|
|
|
|
initRideKillstreak( streak, bSkipScreenFade, blackoutTimeOverride, fullBlackoutDelayOverride )
|
|
{
|
|
if( !IsDefined(bSkipScreenFade) )
|
|
bSkipScreenFade = false;
|
|
|
|
self playerDestroyGlassBelow();
|
|
self _disableUsability();
|
|
self freezeControlsWrapper( true );
|
|
self.remoteRideTransition = true;
|
|
result = self initRideKillstreak_internal( streak, bSkipScreenFade, blackoutTimeOverride, fullBlackoutDelayOverride );
|
|
|
|
if ( IsDefined( self ) )
|
|
{
|
|
self freezeControlsWrapper( false );
|
|
self _enableUsability();
|
|
self.remoteRideTransition = undefined;
|
|
|
|
if ( result == "success" )
|
|
{
|
|
self notify( "rideKillstreakBlack" );
|
|
}
|
|
else
|
|
{
|
|
self playerRemoteKillstreakShowHud();
|
|
self notify( "rideKillstreakFailed" );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
initRideKillstreak_internal( streak, bSkipScreenFade, blackoutTimeOverride, fullBlackoutDelayOverride )
|
|
{
|
|
self thread resetPlayerOnTeamChange();
|
|
|
|
laptopWait = "none";
|
|
laptopWaitTime = 0.75;
|
|
if ( IsDefined( streak ) && streak == "coop" )
|
|
laptopWaitTime = 0.05;
|
|
|
|
laptopWait = self waittill_any_timeout( laptopWaitTime, "disconnect", "death", "weapon_switch_started" );
|
|
|
|
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
|
|
|
|
if ( laptopWait == "disconnect" )
|
|
return "disconnect";
|
|
|
|
if ( laptopWait == "death" )
|
|
return "fail";
|
|
|
|
if ( laptopWait == "weapon_switch_started" )
|
|
return "fail";
|
|
|
|
if ( !IsDefined( self ) || !isAlive( self ) )
|
|
return "fail";
|
|
|
|
if ( !self IsOnGround() && !self IsLinked() )
|
|
return "fail";
|
|
|
|
if ( IsDefined( self.underWater ) && self.underWater )
|
|
return "fail";
|
|
|
|
if ( level.gameEnded )
|
|
return "fail";
|
|
|
|
if ( self isEMPed() || self isAirDenied() )
|
|
return "fail";
|
|
|
|
self playerRemoteKillstreakHideHud();
|
|
self playerDestroyGlassBelow();
|
|
|
|
if( bSkipScreenFade )
|
|
{
|
|
if ( !IsDefined( blackoutTimeOverride ) )
|
|
blackoutTimeOverride = 1.0;
|
|
}
|
|
else
|
|
{
|
|
if ( !IsDefined( blackoutTimeOverride ) )
|
|
blackoutTimeOverride = 0.80;
|
|
|
|
self SetClientOmnvar( "ui_killstreak_blackout", 1 );
|
|
self SetClientOmnvar( "ui_killstreak_blackout_fade_end", GetTime() + int(blackoutTimeOverride*1000) );
|
|
self thread clearRideIntroOnTeamChange();
|
|
self thread clearRideIntroOnRoundTransition();
|
|
}
|
|
|
|
laptopWait = self waittill_any_timeout( blackoutTimeOverride, "disconnect", "death" );
|
|
|
|
if ( laptopWait == "disconnect" || !IsDefined( self ) )
|
|
return "disconnect";
|
|
|
|
if ( !IsDefined( fullBlackoutDelayOverride ) )
|
|
fullBlackoutDelayOverride = 0.6;
|
|
|
|
if ( bSkipScreenFade )
|
|
self notify( "intro_cleared" );
|
|
else
|
|
self thread clearRideIntro( fullBlackoutDelayOverride );
|
|
|
|
|
|
if ( laptopWait == "death" )
|
|
return "fail";
|
|
|
|
if ( !IsDefined( self ) || !isAlive( self ) )
|
|
return "fail";
|
|
|
|
if ( !self IsOnGround() && !self IsLinked() )
|
|
return "fail";
|
|
|
|
if ( IsDefined( self.underWater ) && self.underWater )
|
|
return "fail";
|
|
|
|
if ( level.gameEnded )
|
|
return "fail";
|
|
|
|
if ( self isEMPed() || self isAirDenied() )
|
|
return "fail";
|
|
|
|
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
|
|
|
|
return "success";
|
|
}
|
|
|
|
|
|
clearRideIntro( delay )
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "joined_team" );
|
|
|
|
if ( IsDefined( delay ) )
|
|
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( delay );
|
|
|
|
transitionFade = 0.5;
|
|
|
|
self SetClientOmnvar( "ui_killstreak_blackout", 0 );
|
|
self SetClientOmnvar( "ui_killstreak_blackout_fade_end", GetTime() + int(transitionFade*1000) );
|
|
|
|
wait transitionFade;
|
|
|
|
if ( !IsDefined( self ) )
|
|
return;
|
|
|
|
self notify( "rideKillstreakComplete" );
|
|
}
|
|
|
|
|
|
resetPlayerOnTeamChange()
|
|
{
|
|
self endon( "rideKillstreakComplete" );
|
|
self endon( "rideKillstreakFailed" );
|
|
|
|
self waittill( "joined_team" );
|
|
|
|
self freezeControlsWrapper( false );
|
|
self.remoteRideTransition = undefined;
|
|
if ( self.disabledUsability )
|
|
self _enableUsability();
|
|
if ( self isUsingRemote() )
|
|
self clearUsingRemote();
|
|
}
|
|
|
|
|
|
clearRideIntroOnTeamChange()
|
|
{
|
|
self endon( "rideKillstreakComplete" );
|
|
self endon( "rideKillstreakFailed" );
|
|
|
|
self waittill( "joined_team" );
|
|
|
|
self SetClientOmnvar( "ui_killstreak_blackout", 0 );
|
|
self SetClientOmnvar( "ui_killstreak_blackout_fade_end", 0 );
|
|
self playerRemoteKillstreakShowHud();
|
|
|
|
self notify( "rideKillstreakComplete" );
|
|
}
|
|
|
|
|
|
clearRideIntroOnRoundTransition()
|
|
{
|
|
self endon( "rideKillstreakComplete" );
|
|
self endon( "rideKillstreakFailed" );
|
|
|
|
level waittill( "game_ended" );
|
|
|
|
self SetClientOmnvar( "ui_killstreak_blackout", 0 );
|
|
self SetClientOmnvar( "ui_killstreak_blackout_fade_end", 0 );
|
|
self playerRemoteKillstreakShowHud();
|
|
|
|
self notify( "rideKillstreakComplete" );
|
|
}
|
|
|
|
|
|
playerDestroyGlassBelow()
|
|
{
|
|
if ( self IsOnGround() )
|
|
{
|
|
trace = BulletTrace( self.origin + ( 0, 0, 5 ) , self.origin + ( 0, 0, -5 ), false );
|
|
if ( IsDefined( trace["glass"] ) )
|
|
DestroyGlass( trace["glass"] );
|
|
}
|
|
}
|
|
|
|
|
|
giveSelectedKillstreakItem()
|
|
{
|
|
streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName;
|
|
modules = self.pers["killstreaks"][self.killstreakIndexWeapon].modules;
|
|
|
|
weapon = getKillstreakWeapon( streakName, modules );
|
|
self giveKillstreakWeapon( weapon );
|
|
|
|
self updateStreakSlots();
|
|
}
|
|
|
|
getKillstreakCount()
|
|
{
|
|
numAvailable = 0;
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
if( IsDefined( self.pers["killstreaks"][i] ) &&
|
|
IsDefined( self.pers["killstreaks"][i].streakName ) &&
|
|
self.pers["killstreaks"][i].available )
|
|
{
|
|
numAvailable++;
|
|
}
|
|
}
|
|
return numAvailable;
|
|
}
|
|
|
|
shuffleKillstreaksUp()
|
|
{
|
|
if ( getKillstreakCount() > 1 )
|
|
{
|
|
while ( true )
|
|
{
|
|
self.killstreakIndexWeapon++;
|
|
if ( self.killstreakIndexWeapon >= level.KILLSTREAK_STACKING_START_SLOT )
|
|
self.killstreakIndexWeapon = 0;
|
|
if ( self.pers["killstreaks"][self.killstreakIndexWeapon].available == true )
|
|
break;
|
|
}
|
|
|
|
giveSelectedKillstreakItem();
|
|
}
|
|
}
|
|
|
|
shuffleKillstreaksDown()
|
|
{
|
|
if ( getKillstreakCount() > 1 )
|
|
{
|
|
while ( true )
|
|
{
|
|
self.killstreakIndexWeapon--;
|
|
if ( self.killstreakIndexWeapon < 0 )
|
|
self.killstreakIndexWeapon = level.KILLSTREAK_STACKING_START_SLOT - 1;
|
|
if ( self.pers["killstreaks"][self.killstreakIndexWeapon].available == true )
|
|
break;
|
|
}
|
|
|
|
giveSelectedKillstreakItem();
|
|
}
|
|
}
|
|
|
|
streakSelectUpTracker()
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
self endon ( "faux_spawn" );
|
|
level endon ( "game_ended" );
|
|
|
|
if ( IsDefined( level.isHorde ) && level.isHorde )
|
|
self endon ( "horde_end_spectate" );
|
|
|
|
for (;;)
|
|
{
|
|
self waittill( "toggled_up" );
|
|
|
|
if ( !level.Console && !self is_player_gamepad_enabled() )
|
|
continue;
|
|
|
|
if( canShuffleKillstreaks() )
|
|
{
|
|
self shuffleKillstreaksUp();
|
|
}
|
|
wait( .12 );
|
|
}
|
|
}
|
|
|
|
streakSelectDownTracker()
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
self endon ( "faux_spawn" );
|
|
level endon ( "game_ended" );
|
|
|
|
if ( IsDefined( level.isHorde ) && level.isHorde )
|
|
self endon ( "horde_end_spectate" );
|
|
|
|
for (;;)
|
|
{
|
|
self waittill( "toggled_down" );
|
|
|
|
if ( !level.Console && !self is_player_gamepad_enabled() )
|
|
continue;
|
|
|
|
if( canShuffleKillstreaks() )
|
|
{
|
|
self shuffleKillstreaksDown();
|
|
}
|
|
wait( .12 );
|
|
}
|
|
}
|
|
|
|
canShuffleKillstreaks()
|
|
{
|
|
return ( !self isMantling() &&
|
|
( !IsDefined( self.changingWeapon ) || ( IsDefined( self.changingWeapon ) && self.changingWeapon == "none" ) ) &&
|
|
( canShuffleWithKillstreakWeapon() ) &&
|
|
( !IsDefined( self.isCarrying ) || ( IsDefined( self.isCarrying ) && self.isCarrying == false ) ) );
|
|
}
|
|
|
|
canShuffleWithKillstreakWeapon()
|
|
{
|
|
curWeapon = self GetCurrentWeapon();
|
|
return ( !isKillstreakWeapon( curWeapon ) ||
|
|
( isKillstreakWeapon( curWeapon ) && self isJuggernaut() ) );
|
|
}
|
|
|
|
streakNotifyTracker()
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
self endon( "faux_spawn" );
|
|
|
|
if ( IsBot(self) )
|
|
return; // Bots handle killstreaks internally
|
|
|
|
gameFlagWait( "prematch_done" );
|
|
|
|
self notifyOnPlayerCommand( "toggled_up", "+actionslot 1" );
|
|
self notifyOnPlayerCommand( "toggled_down", "+actionslot 2" );
|
|
|
|
if( !level.console )
|
|
{
|
|
self notifyOnPlayerCommand( "streakUsed1", "+actionslot 4" );
|
|
self notifyOnPlayerCommand( "streakUsed2", "+actionslot 5" );
|
|
self notifyOnPlayerCommand( "streakUsed3", "+actionslot 6" );
|
|
self notifyOnPlayerCommand( "streakUsed4", "+actionslot 7" );
|
|
self notifyOnPlayerCommand( "streakUsed5", "+actionslot 8" );
|
|
}
|
|
}
|
|
|
|
giveAdrenalineDirect( value )
|
|
{
|
|
if ( !value )
|
|
return;
|
|
|
|
// give regular adrenaline
|
|
totalKillStreakScore = self.adrenaline + value;
|
|
maxStreakCost = self getMaxStreakCost( false );
|
|
|
|
// do not let the kill streak score exceed the max kill streak cost
|
|
if( totalKillStreakScore >= maxStreakCost )
|
|
totalKillStreakScore = totalKillStreakScore - maxStreakCost;
|
|
|
|
self setAdrenaline( totalKillStreakScore );
|
|
|
|
// give support adrenaline
|
|
totalKillStreakScore = self.adrenalineSupport + value;
|
|
maxStreakCost = self getMaxStreakCost( true );
|
|
|
|
// do not let the kill streak score exceed the max kill streak cost
|
|
if( totalKillStreakScore >= maxStreakCost )
|
|
totalKillStreakScore = totalKillStreakScore - maxStreakCost;
|
|
|
|
self setAdrenalineSupport( totalKillStreakScore );
|
|
|
|
self updateStreakCount();
|
|
self checkStreakReward();
|
|
}
|
|
|
|
roundUp( floatVal )
|
|
{
|
|
if ( int( floatVal ) != floatVal )
|
|
return int( floatVal + 1 );
|
|
else
|
|
return int( floatVal );
|
|
}
|
|
|
|
giveAdrenaline( event )
|
|
{
|
|
scoreReward = maps\mp\gametypes\_rank::getScoreInfoValue( event );
|
|
|
|
if ( isReallyAlive( self ) )
|
|
self giveAdrenalineDirect( scoreReward );
|
|
|
|
self displayKillStreakPoints( event, scoreReward );
|
|
}
|
|
|
|
|
|
displayKillStreakPoints( event, scoreReward )
|
|
{
|
|
// show points earned
|
|
if( !level.hardcoreMode )
|
|
{
|
|
self thread maps\mp\gametypes\_rank::xpPointsPopup( event, scoreReward );
|
|
}
|
|
}
|
|
|
|
|
|
resetAdrenaline( clearSupportStreaks )
|
|
{
|
|
self.earnedStreakLevel = 0;
|
|
self setAdrenaline(0);
|
|
if ( clearSupportStreaks )
|
|
{
|
|
self setAdrenalineSupport( 0 );
|
|
self.pers["ks_totalPointsSupport"] = 0;
|
|
}
|
|
self updateStreakCount();
|
|
self.pers["ks_totalPoints"] = 0;
|
|
self.pers["lastEarnedStreak"] = undefined;
|
|
}
|
|
|
|
|
|
setAdrenaline( value )
|
|
{
|
|
if ( value < 0 )
|
|
value = 0;
|
|
|
|
if ( IsDefined( self.adrenaline ) && self.adrenaline != 0 )
|
|
self.previousAdrenaline = self.adrenaline;
|
|
else
|
|
self.previousAdrenaline = 0;
|
|
|
|
self.adrenaline = value;
|
|
self.pers["ks_totalPoints"] = self.adrenaline;
|
|
}
|
|
|
|
setAdrenalineSupport( value )
|
|
{
|
|
if ( value < 0 )
|
|
value = 0;
|
|
|
|
if ( IsDefined( self.adrenalineSupport ) && self.adrenalineSupport != 0 )
|
|
self.previousAdrenalineSupport = self.adrenalineSupport;
|
|
else
|
|
self.previousAdrenalineSupport = 0;
|
|
|
|
self.adrenalineSupport = value;
|
|
self.pers["ks_totalPointsSupport"] = self.adrenalineSupport;
|
|
}
|
|
|
|
pc_watchControlsChanged()
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
|
|
usingController = self is_player_gamepad_enabled();
|
|
|
|
while ( true )
|
|
{
|
|
// if any of these are true then .killstreakIndexWeapon may not be valid so wait until a frame after they are complete
|
|
if ( self isInRemoteTransition() || self isUsingRemote() || self isChangingWeapon() )
|
|
{
|
|
while ( self isInRemoteTransition() || self isUsingRemote() || self isChangingWeapon() )
|
|
waitframe();
|
|
waitframe();
|
|
}
|
|
|
|
if ( usingController != self is_player_gamepad_enabled() )
|
|
{
|
|
self thread updateKillstreaks( true );
|
|
usingController = self is_player_gamepad_enabled();
|
|
}
|
|
|
|
waitframe();
|
|
}
|
|
}
|
|
|
|
pc_watchStreakUse() // self == player
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
self endon( "faux_spawn" );
|
|
|
|
self.actionSlotEnabled = [];
|
|
self.actionSlotEnabled[ level.KILLSTREAK_GIMME_SLOT ] = true;
|
|
self.actionSlotEnabled[ level.KILLSTREAK_SLOT_1 ] = true;
|
|
self.actionSlotEnabled[ level.KILLSTREAK_SLOT_2 ] = true;
|
|
self.actionSlotEnabled[ level.KILLSTREAK_SLOT_3 ] = true;
|
|
self.actionSlotEnabled[ level.KILLSTREAK_SLOT_4 ] = true;
|
|
|
|
if ( !IsBot( self ) )
|
|
self thread pc_watchControlsChanged();
|
|
|
|
while( true )
|
|
{
|
|
result = self waittill_any_return( "streakUsed1", "streakUsed2", "streakUsed3", "streakUsed4", "streakUsed5" );
|
|
|
|
if( self is_player_gamepad_enabled() )
|
|
continue;
|
|
|
|
if( !IsDefined( result ) )
|
|
continue;
|
|
|
|
// don't let the killstreakIndexWeapon change while we are at none weapon because that could mean we're carrying something like sentry or ims
|
|
if( IsDefined( self.changingWeapon ) && self.changingWeapon == "none" )
|
|
continue;
|
|
|
|
switch( result )
|
|
{
|
|
case "streakUsed1":
|
|
if( self.pers["killstreaks"][ level.KILLSTREAK_GIMME_SLOT ].available && self.actionSlotEnabled[ level.KILLSTREAK_GIMME_SLOT ] )
|
|
self.killstreakIndexWeapon = level.KILLSTREAK_GIMME_SLOT;
|
|
break;
|
|
case "streakUsed2":
|
|
if( self.pers["killstreaks"][ level.KILLSTREAK_SLOT_1 ].available && self.actionSlotEnabled[ level.KILLSTREAK_SLOT_1 ] )
|
|
self.killstreakIndexWeapon = level.KILLSTREAK_SLOT_1;
|
|
break;
|
|
case "streakUsed3":
|
|
if( self.pers["killstreaks"][ level.KILLSTREAK_SLOT_2 ].available && self.actionSlotEnabled[ level.KILLSTREAK_SLOT_2 ] )
|
|
self.killstreakIndexWeapon = level.KILLSTREAK_SLOT_2;
|
|
break;
|
|
case "streakUsed4":
|
|
if( self.pers["killstreaks"][ level.KILLSTREAK_SLOT_3 ].available && self.actionSlotEnabled[ level.KILLSTREAK_SLOT_3 ] )
|
|
self.killstreakIndexWeapon = level.KILLSTREAK_SLOT_3;
|
|
break;
|
|
case "streakUsed5":
|
|
if( self.pers["killstreaks"][ level.KILLSTREAK_SLOT_4 ].available && self.actionSlotEnabled[ level.KILLSTREAK_SLOT_4 ] )
|
|
self.killstreakIndexWeapon = level.KILLSTREAK_SLOT_4;
|
|
break;
|
|
}
|
|
|
|
// just a sanity check to make sure we reset the killstreakIndexWeapon
|
|
if( IsDefined( self.killstreakIndexWeapon ) && !self.pers["killstreaks"][ self.killstreakIndexWeapon ].available )
|
|
self.killstreakIndexWeapon = undefined;
|
|
|
|
if( IsDefined( self.killstreakIndexWeapon ) )
|
|
{
|
|
if ( !IsBot( self ) )
|
|
self disableKillstreakActionSlots();
|
|
while( true )
|
|
{
|
|
self waittill( "weapon_change", newWeapon );
|
|
if( IsDefined( self.killstreakIndexWeapon ) )
|
|
{
|
|
killstreakWeapon = getKillstreakWeapon( self.pers["killstreaks"][ self.killstreakIndexWeapon ].streakName, self.pers["killstreaks"][ self.killstreakIndexWeapon ].modules );
|
|
// if this is the killstreak weapon or none then continue and wait for the next weapon change
|
|
// remote uav gives you a different weapon than the killstreak weapon from the killstreaktable.csv, so we need to also check for that
|
|
if( newWeapon == killstreakWeapon ||
|
|
newWeapon == "none" ||
|
|
( killstreakWeapon == "killstreak_uav_mp" && newWeapon == "uav_remote_mp" ) ||
|
|
( killstreakWeapon == "killstreak_recreation_mp" && newWeapon == "uav_remote_mp" ) )
|
|
continue;
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
// they either used the killstreak or cancelled it
|
|
if ( !IsBot( self ) )
|
|
self enableKillstreakActionSlots();
|
|
self.killstreakIndexWeapon = undefined;
|
|
}
|
|
}
|
|
}
|
|
|
|
disableKillstreakActionSlots() // self == player
|
|
{
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
if( !IsDefined( self.killstreakIndexWeapon ) )
|
|
break;
|
|
|
|
if( self.killstreakIndexWeapon == i )
|
|
continue;
|
|
|
|
// clear all other killstreak slots while we are using a killstreak so they can't try to use another one
|
|
self _setActionSlot( i + 4, "" );
|
|
self.actionSlotEnabled[ i ] = false;
|
|
}
|
|
}
|
|
|
|
enableKillstreakActionSlots() // self == player
|
|
{
|
|
for( i = 0; i < level.KILLSTREAK_STACKING_START_SLOT; i++ )
|
|
{
|
|
// turn all of the action slots back on
|
|
if( self.pers["killstreaks"][ i ].available )
|
|
{
|
|
killstreakWeapon = getKillstreakWeapon( self.pers["killstreaks"][ i ].streakName, self.pers["killstreaks"][ i ].modules );
|
|
self _setActionSlot( i + 4, "weapon", killstreakWeapon );
|
|
}
|
|
else
|
|
{
|
|
// since this killstreak isn't available, clear the action slot so they can't pull an empty weapon out
|
|
self _setActionSlot( i + 4, "" );
|
|
}
|
|
|
|
// even if they don't have a killstreak in this slot we need to switch this flag for later uses
|
|
// if we don't, then once they earn it they won't be able to use it because this flag is off
|
|
self.actionSlotEnabled[ i ] = true;
|
|
}
|
|
}
|
|
|
|
|
|
killstreakHit( attacker, weapon, vehicle )
|
|
{
|
|
if( IsDefined( weapon ) && isPlayer( attacker ) && IsDefined( vehicle.owner ) && IsDefined( vehicle.owner.team ) )
|
|
{
|
|
if ( ( (level.teamBased && vehicle.owner.team != attacker.team) || !level.teamBased ) && attacker != vehicle.owner )
|
|
{
|
|
if( isKillstreakWeapon( weapon ) )
|
|
return;
|
|
|
|
if ( !isDefined( attacker.lastHitTime[ weapon ] ) )
|
|
attacker.lastHitTime[ weapon ] = 0;
|
|
|
|
// already hit with this weapon on this frame
|
|
if ( attacker.lastHitTime[ weapon ] == getTime() )
|
|
return;
|
|
|
|
attacker.lastHitTime[ weapon ] = getTime();
|
|
|
|
attacker thread maps\mp\gametypes\_gamelogic::threadedSetWeaponStatByName( weapon, 1, "hits" );
|
|
|
|
totalShots = attacker maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" );
|
|
hits = attacker maps\mp\gametypes\_persistence::statGetBuffered( "hits" ) + 1;
|
|
|
|
if ( hits <= totalShots )
|
|
{
|
|
attacker maps\mp\gametypes\_persistence::statSetBuffered( "hits", hits );
|
|
attacker maps\mp\gametypes\_persistence::statSetBuffered( "misses", int(totalShots - hits) );
|
|
|
|
accuracy = Clamp( float( hits ) / float( totalShots ), 0.0, 1.0 ) * 10000.0;
|
|
attacker maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int(accuracy) );
|
|
}
|
|
}
|
|
}
|
|
}
|