boiii-scripts/mp/_challenges.gsc
2023-04-13 17:30:38 +02:00

1953 lines
61 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\drown;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\weapons\_weapon_utils;
#using scripts\mp\gametypes\_loadout;
#using scripts\mp\_util;
#using scripts\mp\killstreaks\_counteruav;
#using scripts\mp\killstreaks\_emp;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\killstreaks\_satellite;
#using scripts\mp\killstreaks\_uav;
#namespace challenges;
function autoexec __init__sytem__() { system::register("challenges",&__init__,undefined,undefined); }
function __init__()
{
callback::on_start_gametype( &start_gametype );
callback::on_spawned( &on_player_spawn );
level.heroAbilityActivateNearDeath = &heroAbilityActivateNearDeath;
level.callbackEndHeroSpecialistEMP = &callbackEndHeroSpecialistEMP;
level.capturedObjectiveFunction = &capturedObjectiveFunction;
}
function start_gametype()
{
if ( !isdefined( level.ChallengesCallbacks ) )
{
level.ChallengesCallbacks = [];
}
waittillframeend;
if ( isdefined ( level.scoreEventGameEndCallback ) )
{
challenges::registerChallengesCallback( "gameEnd",level.scoreEventGameEndCallback );
}
if ( canProcessChallenges() )
{
challenges::registerChallengesCallback( "playerKilled",&challengeKills );
challenges::registerChallengesCallback( "gameEnd",&challengeGameEndMP );
}
callback::on_connect( &on_player_connect );
}
function on_player_connect()
{
initChallengeData();
self addSpecialistUsedStatOnConnect();
self thread spawnWatcher();
self thread monitorReloads();
self thread monitorGrenadeFire();
}
function initChallengeData()
{
self.pers["bulletStreak"] = 0;
self.pers["lastBulletKillTime"] = 0;
self.pers["stickExplosiveKill"] = 0;
self.pers["carepackagesCalled"] = 0;
self.pers["challenge_destroyed_air"] = 0;
self.pers["challenge_destroyed_ground"] = 0;
self.pers["challenge_anteup_earn"] = 0;
self.pers["specialistStatAbilityUsage"] = 0;
self.pers["canSetSpecialistStat"] = self isSpecialistUnlocked();
self.pers["activeKillstreaks"] = [];
}
function addSpecialistUsedStatOnConnect()
{
if ( !isdefined(self.pers["challenge_heroweaponkills"]) )
{
// intentionally using "used" hero weapon on connect to determine frequency of specialist usage
// which is the sum of "specialist ability" usage and "specialist weapon" usage.
heroWeaponName = self GetLoadoutItemRef( 0, "heroWeapon" );
heroWeapon = GetWeapon( heroWeaponName );
if ( heroWeapon == level.weaponNone )
{
heroAbilityName = self GetHeroAbilityName();
heroWeapon = GetWeapon( heroAbilityName );
}
if ( heroWeapon != level.weaponNone )
{
self addweaponstat( heroWeapon, "used", 1 );
}
self.pers["challenge_heroweaponkills"] = 0;
}
}
function spawnWatcher()
{
self endon( "disconnect" );
self.pers["killNemesis"] = 0;
self.pers["killsFastMagExt"] = 0;
self.pers["longshotsPerLife"] = 0;
self.pers["specialistStatAbilityUsage"] = 0;
self.challenge_defenderkillcount = 0;
self.challenge_offenderkillcount = 0;
self.challenge_offenderProjectileMultiKillcount = 0;
self.challenge_offenderComlinkKillcount = 0;
self.challenge_offenderSentryTurretKillCount = 0;
self.challenge_objectiveDefensiveKillcount = 0;
self.challenge_objectiveOffensiveKillcount = 0;
self.challenge_scavengedCount = 0;
self.challenge_resuppliedNameKills = 0;
self.challenge_objectiveDefensive = undefined;
self.challenge_objectiveOffensive = undefined;
self.challenge_lastsurvivewithflakfrom = undefined;
self.explosiveInfo = [];
for(;;)
{
self waittill("spawned_player");
self.weaponKillsThisSpawn = [];
self.attachmentKillsThisSpawn = [];
self.challenge_hatchetTossCount = 0;
self.challenge_hatchetkills = 0;
self.retreivedBlades = 0;
self.challenge_combatRobotAttackClientID = [];
self thread watchDoubleJump();
self thread watchJump();
self thread watchSwimming();
self thread watchWallrun();
self thread watchSlide();
self thread watchSprint();
self thread watchScavengeLethal();
self thread watchWallRunTwoOppositeWallsNoGround();
self thread watchWeaponChangeComplete();
}
}
function watchScavengeLethal()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_scavengedCount = 0;
for(;;)
{
self waittill( "scavenged_primary_grenade" );
self.challenge_scavengedCount++;
}
}
function watchDoublejump()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_doublejump_begin = 0;
self.challenge_doublejump_end = 0;
for(;;)
{
ret = util::waittill_any_return( "doublejump_begin", "doublejump_end", "disconnect" );
switch( ret )
{
case "doublejump_begin":
self.challenge_doublejump_begin = gettime();
break;
case "doublejump_end":
self.challenge_doublejump_end = gettime();
break;
}
}
}
function watchJump()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_jump_begin = 0;
self.challenge_jump_end = 0;
for(;;)
{
ret = util::waittill_any_return( "jump_begin", "jump_end", "disconnect" );
switch( ret )
{
case "jump_begin":
self.challenge_jump_begin = gettime();
break;
case "jump_end":
self.challenge_jump_end = gettime();
break;
}
}
}
function watchSwimming()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_swimming_begin = 0;
self.challenge_swimming_end = 0;
for(;;)
{
ret = util::waittill_any_return( "swimming_begin", "swimming_end", "disconnect" );
switch( ret )
{
case "swimming_begin":
self.challenge_swimming_begin = gettime();
break;
case "swimming_end":
self.challenge_swimming_end = gettime();
break;
}
}
}
function watchWallrun()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_wallrun_begin = 0;
self.challenge_wallrun_end = 0;
for(;;)
{
ret = util::waittill_any_return( "wallrun_begin", "wallrun_end", "disconnect" );
switch( ret )
{
case "wallrun_begin":
self.challenge_wallrun_begin = gettime();
break;
case "wallrun_end":
self.challenge_wallrun_end = gettime();
break;
}
}
}
function watchSlide()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_slide_begin = 0;
self.challenge_slide_end = 0;
for(;;)
{
ret = util::waittill_any_return( "slide_begin", "slide_end", "disconnect" );
switch( ret )
{
case "slide_begin":
self.challenge_slide_begin = gettime();
break;
case "slide_end":
self.challenge_slide_end = gettime();
break;
}
}
}
function watchSprint()
{
self endon( "death" );
self endon( "disconnect" );
self.challenge_sprint_begin = 0;
self.challenge_sprint_end = 0;
for(;;)
{
ret = util::waittill_any_return( "sprint_begin", "sprint_end", "disconnect" );
switch( ret )
{
case "sprint_begin":
self.challenge_sprint_begin = gettime();
break;
case "sprint_end":
self.challenge_sprint_end = gettime();
break;
}
}
}
function challengeKills( data )
{
victim = data.victim;
attacker = data.attacker;
time = data.time;
level.numKills++;
attacker.lastKilledPlayer = victim;
attackerDoubleJumping = data.attackerDoubleJumping;
attackerflashbackTime = data.attackerflashbackTime;
attackerHeroAbility = data.attackerHeroAbility;
attackerHeroAbilityActive = data.attackerHeroAbilityActive;
attackerSliding = data.attackerSliding;
attackerSpeedburst = data.attackerSpeedburst;
attackerTraversing = data.attackerTraversing;
attackerVisionPulseActivateTime = data.attackerVisionPulseActivateTime;
attackerVisionPulseArray = data.attackerVisionPulseArray;
attackerVisionPulseOrigin = data.attackerVisionPulseOrigin;
attackerVisionPulseOriginArray = data.attackerVisionPulseOriginArray;
attackerWallRunning = data.attackerWallRunning;
attackerWasConcussed = data.attackerWasConcussed;
attackerWasFlashed = data.attackerWasFlashed;
attackerWasHeatWaveStunned = data.attackerWasHeatWaveStunned;
attackerWasOnGround = data.attackerOnGround;
attackerWasUnderwater = data.attackerWasUnderwater;
attackerLastFastReloadTime = data.attackerLastFastReloadTime;
lastWeaponBeforeToss = data.lastWeaponBeforeToss;
meansOfDeath = data.sMeansOfDeath;
ownerWeaponAtLaunch = data.ownerWeaponAtLaunch;
victimBedOut = data.bledOut;
victimOrigin = data.victimOrigin;
victimCombatEfficiencyLastOnTime = data.victimCombatEfficiencyLastOnTime;
victimCombatEfficieny = data.victimCombatEfficieny;
victimElectrifiedBy = data.victimElectrifiedBy;
victimflashbackTime = data.victimflashbackTime;
victimHeroAbility = data.victimHeroAbility;
victimHeroAbilityActive = data.victimHeroAbilityActive;
victimSpeedburst = data.victimSpeedburst;
victimSpeedburstLastOnTime = data.victimSpeedburstLastOnTime;
victimVisionPulseActivateTime = data.victimVisionPulseActivateTime;
victimVisionPulseActivateTime = data.victimVisionPulseActivateTime;
victimVisionPulseArray = data.victimVisionPulseArray;
victimVisionPulseOrigin = data.victimVisionPulseOrigin;
victimVisionPulseOriginArray = data.victimVisionPulseOriginArray;
victimAttackersThisSpawn = data.victimAttackersThisSpawn;
victimWasDoubleJumping = data.victimWasDoubleJumping;
victimWasInSlamState = data.victimWasInSlamState;
victimWasLungingWithArmBlades = data.victimWasLungingWithArmBlades;
victimWasOnGround = data.victimOnGround;
victimWasUnderwater = data.wasUnderwater;
victimWasWallRunning = data.victimWasWallRunning;
victimLastStunnedBy = data.victimLastStunnedBy;
victimActiveProximityGrenades = data.victim.activeProximityGrenades;
victimActiveBouncingBetties = data.victim.activeBouncingBetties;
attackerLastFlashedBy = data.attackerLastFlashedBy;
attackerLastStunnedBy = data.attackerLastStunnedBy;
attackerLastStunnedTime = data.attackerLastStunnedTime;
attackerWasSliding = data.attackerWasSliding;
attackerWasSprinting = data.attackerWasSprinting;
wasDefusing = data.wasDefusing;
wasPlanting = data.wasPlanting;
inflictorOwnerWasSprinting = data.inflictorOwnerWasSprinting;
player = data.attacker;
playerOrigin = data.attackerOrigin;
weapon = data.weapon;
victim_doublejump_begin = data.victim_doublejump_begin;
victim_doublejump_end = data.victim_doublejump_end;
victim_jump_begin = data.victim_jump_begin;
victim_jump_end = data.victim_jump_end;
victim_swimming_begin = data.victim_swimming_begin;
victim_swimming_end = data.victim_swimming_end;
victim_slide_begin = data.victim_slide_begin;
victim_slide_end = data.victim_slide_end;
victim_wallrun_begin = data.victim_wallrun_begin;
victim_wallrun_end = data.victim_wallrun_end;
victim_was_drowning = data.victim_was_drowning;
attacker_doublejump_begin = data.attacker_doublejump_begin;
attacker_doublejump_end = data.attacker_doublejump_end;
attacker_jump_begin = data.attacker_jump_begin;
attacker_jump_end = data.attacker_jump_end;
attacker_swimming_begin = data.attacker_swimming_begin;
attacker_swimming_end = data.attacker_swimming_end;
attacker_slide_begin = data.attacker_slide_begin;
attacker_slide_end = data.attacker_slide_end;
attacker_wallrun_begin = data.attacker_wallrun_begin;
attacker_wallrun_end = data.attacker_wallrun_end;
attacker_was_drowning = data.attacker_was_drowning;
attacker_sprint_end = data.attacker_sprint_end;
attacker_sprint_begin = data.attacker_sprint_begin;
attacker_wallRanTwoOppositeWallsNoGround = data.attacker_wallRanTwoOppositeWallsNoGround;
inflictorIsCooked = data.inflictorIsCooked;
inflictorChallenge_hatchetTossCount = data.inflictorChallenge_hatchetTossCount;
inflictorOwnerWasSprinting = data.inflictorOwnerWasSprinting;
inflictorPlayerHasEngineerPerk = data.inflictorPlayerHasEngineerPerk;
inflictor = data.eInflictor; // MAY ALREADY BE REMOVED
if ( !isdefined( data.weapon ) )
{
return;
}
if ( !isdefined( player ) || !isplayer( player ) || ( weapon == level.weaponNone ) )
{
return;
}
// getting the altweapon name is not ideal, but acceptable for BO3's current weapons in MP;
// TODO: add code-based accessor to parentWeaponName ("Stat Name" in APE)
weaponClass = util::getWeaponClass( weapon );
baseWeapon = getBaseWeapon( weapon );
baseWeaponItemIndex = GetBaseWeaponItemIndex( baseWeapon );
weaponPurchased = player isItemPurchased( baseWeaponItemIndex );
victimSupportIndex = victim.team;
playerSupportIndex = player.team;
if ( !level.teambased )
{
playerSupportIndex = player.entnum;
victimSupportIndex = victim.entnum;
}
if ( meansOfDeath == "MOD_HEAD_SHOT" || meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_RIFLE_BULLET" )
{
bulletKill = true;
}
else
{
bulletKill = false;
}
if ( level.teambased )
{
if ( player.team == victim.team )
{
return;
}
}
else
{
if ( player == victim )
{
return;
}
}
killstreak = killstreaks::get_from_weapon( data.weapon );
if ( !isdefined( killstreak ) )
{
player processSpecialistChallenge( "kills" );
if ( weapon.isheroWeapon == true )
{
player processSpecialistChallenge( "kills_weapon" );
player.heroWeaponKillsThisActivation++;
player.pers["challenge_heroweaponkills"]++;
if ( player.pers["challenge_heroweaponkills"] >= 6 )
{
player processSpecialistChallenge( "kill_one_game_weapon" );
player.pers["challenge_heroweaponkills"] = 0;
}
}
}
if ( bulletKill )
{
if ( weaponPurchased )
{
if ( weaponclass == "weapon_sniper" )
{
if ( isdefined ( victim.firstTimeDamaged ) && victim.firstTimeDamaged == time )
{
player AddPlayerStat( "kill_enemy_one_bullet_sniper", 1 );
player AddWeaponStat( weapon, "kill_enemy_one_bullet_sniper", 1 );
}
}
else if ( weaponclass == "weapon_cqb" )
{
if ( isdefined ( victim.firstTimeDamaged ) && victim.firstTimeDamaged == time )
{
player AddPlayerStat( "kill_enemy_one_bullet_shotgun", 1 );
player AddWeaponStat( weapon, "kill_enemy_one_bullet_shotgun", 1 );
}
}
}
if ( GetDvarInt( "ui_enablePromoTracking", 0 ) && meansOfDeath == "MOD_HEAD_SHOT" )
{
util::increment_zmhd_thermometer( 1 );
}
if ( ( time - data.attacker_swimming_end <= 2000 ) && ( time - data.attacker_doublejump_begin <= 2000 ) )
{
player AddPlayerStat( "kill_after_doublejump_out_of_water", 1 );
}
if ( attackerWasSliding )
{
if ( attacker_doublejump_end == attacker_slide_begin )
{
player AddPlayerStat( "kill_while_sliding_from_doublejump", 1 );
}
}
if ( ( player IsBonusCardActive( 2, player.class_num ) ) && player IsItemPurchased( GetItemIndexFromRef( "bonuscard_primary_gunfighter_3" ) ) )
{
if ( isdefined( weapon.attachments ) && weapon.attachments.size == 6 )
{
player AddPlayerStat( "kill_with_gunfighter", 1 );
}
}
//Check for the killstreak 5 challenge completion
checkkillstreak5( baseWeapon, player );
if ( weapon.isDualWield && weaponPurchased )
{
checkDualWield( baseWeapon, player, attacker, time, attackerwassprinting, attacker_sprint_end );
}
if ( isdefined( weapon.attachments ) && weapon.attachments.size > 0 )
{
attachmentName = player GetWeaponOptic( weapon );
if ( isdefined( attachmentName ) && attachmentName != "" && player WeaponHasAttachmentAndUnlocked( weapon, attachmentName ) )
{
if ( weapon.attachments.size > 5 && player AllWeaponAttachmentsUnlocked( weapon ) && !isdefined( attacker.tookWeaponFrom[ weapon ] ) )
{
player AddPlayerStat( "kill_optic_5_attachments", 1 );
}
if ( isdefined( player.attachmentKillsThisSpawn[ attachmentName ] ) )
{
player.attachmentKillsThisSpawn[ attachmentName ]++;
if ( player.attachmentKillsThisSpawn[ attachmentName ] == 5 )
{
player AddWeaponStat( weapon, "killstreak_5_attachment", 1 );
}
}
else
{
player.attachmentKillsThisSpawn[ attachmentName ] = 1;
}
if ( weapon_utils::isPistol( weapon.rootweapon ) )
{
if ( player weaponHasAttachmentAndUnlocked( weapon, "suppressed", "extbarrel" ) )
{
player AddPlayerStat( "kills_pistol_lasersight_suppressor_longbarrel", 1 );
}
}
}
if ( player weaponHasAttachmentAndUnlocked( weapon, "suppressed" ) )
{
if ( attacker util::has_hard_wired_perk_purchased_and_equipped() // hardwired
&& attacker util::has_ghost_perk_purchased_and_equipped() // ghost
&& attacker util::has_jetquiet_perk_purchased_and_equipped() ) // blast suppressor
{
player AddPlayerStat( "kills_suppressor_ghost_hardwired_blastsuppressor", 1 );
}
}
if ( player PlayerAds() == 1 )
{
if ( isdefined( player.smokeGrenadeTime ) && isdefined( player.smokeGrenadePosition ) )
{
if ( player.smokeGrenadeTime + 14000 > time )
{
if ( player util::is_looking_at( player.smokeGrenadePosition ) || ( distancesquared( player.origin, player.smokeGrenadePosition ) < 200 * 200 ))
{
if ( player weaponHasAttachmentAndUnlocked( weapon, "ir" ) )
{
player AddPlayerStat( "kill_with_thermal_and_smoke_ads", 1 );
player AddWeaponStat( weapon, "kill_thermal_through_smoke", 1 );
}
}
}
}
}
if ( weapon.attachments.size > 1 )
{
if ( player PlayerAds() == 1 )
{
if ( player weaponHasAttachmentAndUnlocked( weapon, "grip", "quickdraw" ) )
{
player AddPlayerStat( "kills_ads_quickdraw_and_grip", 1 );
}
if ( player weaponHasAttachmentAndUnlocked( weapon, "swayreduc", "stalker" ) )
{
player AddPlayerStat( "kills_ads_stock_and_cpu", 1 );
}
}
else
{
if ( player weaponHasAttachmentAndUnlocked( weapon, "rf", "steadyaim" ) )
{
if ( attacker util::has_fast_hands_perk_purchased_and_equipped() )
{
player AddPlayerStat( "kills_hipfire_rapidfire_lasersights_fasthands", 1 );
}
}
}
if ( player weaponHasAttachmentAndUnlocked( weapon, "fastreload", "extclip" ) )
{
player.pers["killsFastMagExt"]++;
if ( player.pers["killsFastMagExt"] > 4 )
{
player AddPlayerStat( "kills_one_life_fastmags_and_extclip", 1 );
player.pers["killsFastMagExt"] = 0;
}
}
}
if ( weapon.attachments.size > 2 )
{
if ( meansOfDeath == "MOD_HEAD_SHOT" )
{
if ( player weaponHasAttachmentAndUnlocked( weapon, "fmj", "damage", "extbarrel" ) )
{
player AddPlayerStat( "headshot_fmj_highcaliber_longbarrel", 1 );
}
}
}
if ( weapon.attachments.size > 4 )
{
if ( player weaponHasAttachmentAndUnlocked( weapon, "extclip", "grip", "fastreload", "quickdraw", "stalker" ) )
{
player AddPlayerStat( "kills_extclip_grip_fastmag_quickdraw_stock", 1 );
}
}
}
if ( victim_was_drowning && attacker_was_drowning )
{
player AddPlayerStat( "dr_lung", 1 );
}
if ( isdefined( attackerLastFastReloadTime ) && ( time - attackerLastFastReloadTime <= 5000 ) && player WeaponHasAttachmentAndUnlocked( weapon, "fastreload" ) )
{
player AddPlayerStat( "kills_after_reload_fastreload", 1 );
}
if ( victim.iDFlagsTime == time )
{
if ( victim.iDFlags & 8 )
{
player AddPlayerStat( "kill_enemy_through_wall", 1 );
if ( player weaponHasAttachmentAndUnlocked( weapon, "fmj" ) )
{
player AddPlayerStat( "kill_enemy_through_wall_with_fmj", 1 );
}
}
}
if ( attacker_wallRanTwoOppositeWallsNoGround === true )
{
player AddPlayerStat( "kill_while_wallrunning_2_walls", 1 );
}
// end if ( bulletkill )
}
else if ( weapon_utils::isMeleeMOD( meansOfDeath ) && !isdefined( killstreak ) )
{
player AddPlayerStat( "melee", 1 );
if ( weapon_utils::isPunch( weapon ) )
{
player AddPlayerStat( "kill_enemy_with_fists", 1 );
}
//Check for the killstreak 5 challenge completion
checkkillstreak5( baseWeapon, player );
}
else
{
if ( weaponPurchased )
{
if ( weapon == player.grenadeTypePrimary )
{
if ( player.challenge_scavengedCount > 0 )
{
player.challenge_resuppliedNameKills++;
if ( player.challenge_resuppliedNameKills >= 3 )
{
player AddPlayerStat( "kills_3_resupplied_nade_one_life", 1 );
player.challenge_resuppliedNameKills = 0;
}
player.challenge_scavengedCount--;
}
}
if ( isdefined( inflictorIsCooked ) )
{
if ( inflictorIsCooked == true && weapon.rootweapon.name != "hatchet" )
{
player AddPlayerStat( "kill_with_cooked_grenade", 1 );
}
}
if ( victimLastStunnedBy === player )
{
if ( weaponclass == "weapon_grenade" )
{
player AddPlayerStat( "kill_stun_lethal", 1 );
}
}
if ( baseWeapon == level.weaponSpecialCrossbow )
{
if ( weapon.isDualWield ) // determined purchased
{
checkDualWield( baseWeapon, player, attacker, time, attackerwassprinting, attacker_sprint_end );
}
}
// for "energy" shotgun
if ( baseWeapon == level.weaponShotgunEnergy )
{
if ( isdefined ( victim.firstTimeDamaged ) && victim.firstTimeDamaged == time )
{
player AddPlayerStat( "kill_enemy_one_bullet_shotgun", 1 );
player AddWeaponStat( weapon, "kill_enemy_one_bullet_shotgun", 1 );
}
}
}
if ( baseWeapon.forceDamageHitLocation || baseWeapon == level.weaponSpecialCrossbow || baseWeapon == level.weaponShotgunEnergy || baseWeapon == level.weaponSpecialDiscGun || baseWeapon == level.weaponBallisticKnife || baseWeapon == level.weaponLauncherEx41 )
{
//Check for the killstreak 5 challenge completion
checkkillstreak5( baseWeapon, player );
}
}
if ( isdefined( attacker.tookWeaponFrom[ weapon ] ) && isdefined( attacker.tookWeaponFrom[ weapon ].previousOwner ) )
{
if ( !isdefined( attacker.tookWeaponFrom[ weapon ].previousOwner.team ) || attacker.tookWeaponFrom[ weapon ].previousOwner.team != player.team )
{
player AddPlayerStat( "kill_with_pickup", 1 );
}
}
awarded_kill_enemy_that_blinded_you = false;
playerHasTacticalMask = loadout::hasTacticalMask( player );
if ( attackerWasFlashed )
{
if ( attackerLastFlashedBy === victim && !playerHasTacticalMask )
{
player AddPlayerStat( "kill_enemy_that_blinded_you", 1 );
awarded_kill_enemy_that_blinded_you = true;
}
}
if ( !awarded_kill_enemy_that_blinded_you && isdefined( attackerLastStunnedTime ) && attackerLastStunnedTime + 5000 > time )
{
if ( attackerLastStunnedBy === victim && !playerHasTacticalMask )
{
player AddPlayerStat( "kill_enemy_that_blinded_you", 1 );
awarded_kill_enemy_that_blinded_you = true;
}
}
killedStunnedVictim = false;
if ( isdefined( victim.lastConcussedBy ) && victim.lastConcussedBy == attacker )
{
if ( victim.concussionEndTime > time )
{
if ( player util::is_item_purchased( "concussion_grenade" ) )
{
player AddPlayerStat( "kill_concussed_enemy", 1 );
}
killedStunnedVictim = true;
player AddWeaponStat( GetWeapon( "concussion_grenade" ), "CombatRecordStat", 1 );
}
}
if ( isdefined( victim.lastShockedBy ) && victim.lastShockedBy == attacker )
{
if ( victim.shockEndTime > time )
{
if ( player util::is_item_purchased( "proximity_grenade" ) )
{
player AddPlayerStat( "kill_shocked_enemy", 1 );
}
player AddWeaponStat( GetWeapon( "proximity_grenade" ), "CombatRecordStat", 1 );
killedStunnedVictim = true;
if ( weapon.rootweapon.name == "bouncingbetty" )
{
player AddPlayerStat( "kill_trip_mine_shocked", 1 );
}
}
}
if ( victim util::isFlashbanged() )
{
if ( isdefined( victim.lastFlashedBy ) && victim.lastFlashedBy == player )
{
killedStunnedVictim = true;
if ( player util::is_item_purchased( "flash_grenade" ) )
{
player AddPlayerStat( "kill_flashed_enemy", 1 );
}
player AddWeaponStat( GetWeapon( "flash_grenade" ), "CombatRecordStat", 1 );
}
}
if ( level.teamBased )
{
if ( ( !isDefined( player.pers["kill_every_enemy_with_specialist"] ) ) && ( level.playerCount[victim.pers["team"]] > 3 && player.pers["killed_players_with_specialist"].size >= level.playerCount[victim.pers["team"]] ) )
{
player AddPlayerStat( "kill_every_enemy", 1 );
player.pers["kill_every_enemy_with_specialist"] = true;
}
if ( isdefined( victimAttackersThisSpawn ) && IsArray( victimAttackersThisSpawn ) )
{
if ( victimAttackersThisSpawn.size > 5 )
{
attackerCount = 0;
foreach( attacking_player in victimAttackersThisSpawn )
{
if ( !isdefined( attacking_player ) )
continue;
if ( attacking_player == attacker )
continue;
if ( attacking_player.team != attacker.team )
continue;
attackerCount++;
}
if ( attackerCount > 4 )
{
// note: "kill_enemy_5_teammates_assists" should be awarded withing on life, not just assist
player AddPlayerStat( "kill_enemy_5_teammates_assists", 1 );
}
}
}
}
if ( isdefined( killstreak ) )
{
if ( killstreak == "rcbomb" || killstreak == "inventory_rcbomb" )
{
if ( !victimWasOnGround || victimWasWallRunning )
{
player AddPlayerStat( "kill_wallrunner_or_air_with_rcbomb", 1 );
}
}
if ( killstreak == "autoturret" || killstreak == "inventory_autoturret" )
{
if ( isdefined( inflictor ) && player util::is_item_purchased( "killstreak_auto_turret" ) )
{
if ( !isdefined( inflictor.challenge_killcount ) )
{
inflictor.challenge_killcount = 0;
}
inflictor.challenge_killcount++;
if ( inflictor.challenge_killcount == 5 )
{
player AddPlayerStat( "kills_auto_turret_5", 1 );
}
}
}
}
if ( isdefined( victim.challenge_combatRobotAttackClientID[player.clientid] ) )
{
if ( !isdefined( inflictor ) || !isdefined( inflictor.killstreakType ) || !IsString( inflictor.killstreakType ) || ( inflictor.killstreakType != "combat_robot" ) )
{
player AddPlayerStat( "kill_enemy_who_damaged_robot", 1 );
}
}
if ( player IsBonusCardActive( 8, player.class_num ) && player util::is_item_purchased( "bonuscard_danger_close" ) )
{
if ( weaponclass == "weapon_grenade" )
{
player AddBonusCardStat( 8, "kills", 1, player.class_num );
}
if ( weapon.rootweapon.name == "hatchet" && inflictorChallenge_hatchetTossCount <= 2 )
{
player.challenge_hatchetkills++;
if ( player.challenge_hatchetkills == 2 )
{
player AddPlayerStat( "kills_first_throw_both_hatchets", 1 );
}
}
}
player trackKillstreakSupportKills( victim );
// PERKS
if ( !isdefined( killstreak ) )
{
if ( attackerWasUnderwater )
{
player AddPlayerStat( "kill_while_underwater", 1 );
}
if ( player util::has_purchased_perk_equipped( "specialty_jetcharger" ) ) // afterburner
{
if ( ( attacker_doublejump_begin > attacker_doublejump_end || attacker_doublejump_end + 3000 > time )
|| ( attacker_slide_begin > attacker_slide_end || attacker_slide_end + 3000 > time ) )
{
player AddPlayerStat( "kills_after_jumping_or_sliding", 1 );
if ( player util::has_purchased_perk_equipped( "specialty_overcharge" ) )
{
{
player AddPlayerStat( "kill_overclock_afterburner_specialist_weapon_after_thrust", 1 );
}
}
}
}
trackedPlayer = false;
if ( player util::has_purchased_perk_equipped( "specialty_tracker" ) )
{
if ( !victim hasPerk ( "specialty_trackerjammer" ) ) // hardwired
{
player AddPlayerStat( "kill_detect_tracker", 1 );
trackedPlayer = true;
}
}
if ( player util::has_purchased_perk_equipped( "specialty_detectnearbyenemies" ) ) // sixth sense
{
if ( !victim hasPerk ( "specialty_sixthsensejammer" ) )
{
player AddPlayerStat( "kill_enemy_sixth_sense", 1 );
if ( player util::has_purchased_perk_equipped( "specialty_loudenemies" ) ) // awareness
{
if ( !victim hasPerk ( "specialty_quieter" ) ) // dead silence
{
player AddPlayerStat( "kill_sixthsense_awareness", 1 );
}
}
}
if ( trackedPlayer )
{
player AddPlayerStat( "kill_tracker_sixthsense", 1 );
}
}
if ( weapon.isheroWeapon == true || attackerHeroAbilityActive )
{
if ( player util::has_purchased_perk_equipped( "specialty_overcharge" ) ) // overclock
{
player AddPlayerStat( "kill_with_specialist_overclock", 1 );
}
}
if ( player util::has_purchased_perk_equipped( "specialty_gpsjammer" ) ) // ghost
{
if ( uav::HasUAV( victimSupportIndex ) )
{
player AddPlayerStat( "kill_uav_enemy_with_ghost", 1 );
}
if ( player util::has_blind_eye_perk_purchased_and_equipped() ) // blindeye
{
activeKillstreaks = victim killstreaks::getActiveKillstreaks();
awarded_kill_blindeye_ghost_aircraft = false;
foreach( activeStreak in activeKillstreaks )
{
if ( awarded_kill_blindeye_ghost_aircraft )
break;
switch( activeStreak.killstreakType )
{
case "sentinel":
case "helicopter_comlink":
case "drone_striked":
case "uav":
player AddPlayerStat( "kill_blindeye_ghost_aircraft", 1 );
awarded_kill_blindeye_ghost_aircraft = true;
break;
}
}
}
}
if ( player util::has_purchased_perk_equipped( "specialty_flakjacket" ) )
{
if ( isdefined ( player.challenge_lastsurvivewithflakfrom ) && player.challenge_lastsurvivewithflakfrom == victim )
{
player AddPlayerStat( "kill_enemy_survive_flak", 1 );
}
if ( player util::has_tactical_mask_purchased_and_equipped() )
{
recentlySurvivedFlak = false;
if ( isdefined ( player.challenge_lastsurvivewithflaktime ) )
{
if ( ( player.challenge_lastsurvivewithflaktime + 3000 ) > time )
{
recentlySurvivedFlak = true;
}
}
recentlyStunned = false;
if ( isdefined( player.lastStunnedTime ) )
{
if ( player.lastStunnedTime + 2000 > time )
{
recentlyStunned = true;
}
}
if ( recentlySurvivedFlak
|| ( player util::isFlashbanged() )
|| recentlyStunned )
{
player AddPlayerStat( "kill_flak_tac_while_stunned", 1 );
}
}
}
if ( player util::has_hard_wired_perk_purchased_and_equipped() ) // hard wired
{
if ( victim counteruav::HasIndexActiveCounterUAV( victimSupportIndex ) || victim emp::hasactiveemp() )
{
player AddPlayerStat( "kills_counteruav_emp_hardline", 1 );
}
}
if ( player util::has_scavenger_perk_purchased_and_equipped() )
{
if ( player.scavenged )
{
player AddPlayerStat( "kill_after_resupply", 1 );
if ( trackedPlayer )
{
player AddPlayerStat( "kill_scavenger_tracker_resupply", 1 );
}
}
}
if ( player util::has_fast_hands_perk_purchased_and_equipped() ) // fasthands
{
if ( bulletKill )
{
if ( attackerWasSprinting || attacker_sprint_end + 3000 > time )
{
player AddPlayerStat( "kills_after_sprint_fasthands", 1 );
if ( player util::has_gung_ho_perk_purchased_and_equipped() ) // gungho
{
player AddPlayerStat( "kill_fasthands_gungho_sprint", 1 );
}
}
}
}
if ( player util::has_hard_wired_perk_purchased_and_equipped() ) // hardwired
{
if ( player util::has_cold_blooded_perk_purchased_and_equipped() ) // cold blooded
{
player AddPlayerStat( "kill_hardwired_coldblooded", 1 );
}
}
killedPlayerWithGungHo = false;
if ( player util::has_gung_ho_perk_purchased_and_equipped() ) // gung ho
{
if ( bulletKill )
{
killedPlayerWithGungHo = true;
if ( attackerWasSprinting && player PlayerAds() != 1 )
{
player AddPlayerStat( "kill_hip_gung_ho", 1 );
}
}
if ( weaponclass == "weapon_grenade" )
{
if ( isdefined( inflictorOwnerWasSprinting ) && inflictorOwnerWasSprinting == true )
{
killedPlayerWithGungHo = true;
player AddPlayerStat( "kill_hip_gung_ho", 1 );
}
}
}
if ( player util::has_jetquiet_perk_purchased_and_equipped() ) // blast surpressor
{
if ( attackerDoubleJumping || ( attacker_doublejump_end + 3000 > time ) )
{
player AddPlayerStat( "kill_blast_doublejump", 1 );
if ( player util::has_ghost_perk_purchased_and_equipped() ) // ghost
{
if ( uav::HasUAV( victimSupportIndex ) )
{
player AddPlayerStat( "kill_doublejump_uav_engineer_hardwired", 1 );
}
}
}
}
if ( player util::has_awareness_perk_purchased_and_equipped() ) // awareness
{
player AddPlayerStat( "kill_awareness", 1 );
}
if ( killedStunnedVictim )
{
if ( player util::has_tactical_mask_purchased_and_equipped() ) // tacmask
{
player AddPlayerStat( "kill_stunned_tacmask", 1 );
if ( killedPlayerWithGungHo == true )
{
player AddPlayerStat( "kill_sprint_stunned_gungho_tac", 1 );
}
}
}
if ( player util::has_ninja_perk_purchased_and_equipped() ) // dead silence
{
player AddPlayerStat( "kill_dead_silence", 1 );
if ( distanceSquared( playerOrigin, victimOrigin ) < 120 * 120 )
{
if ( player util::has_awareness_perk_purchased_and_equipped() ) // awareness
{
player AddPlayerStat( "kill_close_deadsilence_awareness", 1 );
}
if ( player util::has_jetquiet_perk_purchased_and_equipped() ) // blast suppressr
{
player AddPlayerStat( "kill_close_blast_deadsilence", 1 );
}
}
}
greedCardsActive = 0;
if ( player IsBonusCardActive( 5, player.class_num ) && player util::is_item_purchased( "bonuscard_perk_1_greed" ) )
{
greedCardsActive++;
}
if ( player IsBonusCardActive( 6, player.class_num ) && player util::is_item_purchased( "bonuscard_perk_2_greed" ) )
{
greedCardsActive++;
}
if ( player IsBonusCardActive( 7, player.class_num ) && player util::is_item_purchased( "bonuscard_perk_3_greed" ) )
{
greedCardsActive++;
}
if ( greedCardsActive >= 2 )
{
player AddPlayerStat( "kill_2_greed_2_perks_each", 1 );
}
if ( player BonusCardActiveCount( player.class_num ) >= 2 )
{
player AddPlayerStat( "kill_2_wildcards", 1 );
}
gunfighterOverkillActive = false;
if ( player IsBonusCardActive( 4, player.class_num ) && player util::is_item_purchased( "bonuscard_overkill" ) )
{
primaryAttachmentsTotal = 0;
if ( isdefined( player.primaryLoadoutWeapon ) )
primaryAttachmentsTotal = player.primaryLoadoutWeapon.attachments.size;
secondaryAttachmentsTotal = 0;
if ( isdefined( player.secondaryLoadoutWeapon ) )
secondaryAttachmentsTotal = player.secondaryLoadoutWeapon.attachments.size;
if ( primaryAttachmentsTotal + secondaryAttachmentsTotal >= 5 )
{
gunfighterOverkillActive = true;
}
}
if ( ( isdefined (player.primaryLoadoutWeapon ) && weapon == player.primaryLoadoutWeapon )
|| ( isdefined (player.primaryLoadoutAltWeapon ) && weapon == player.primaryLoadoutAltWeapon ) )
{
if ( player IsBonusCardActive( 0, player.class_num ) && player util::is_item_purchased( "bonuscard_primary_gunfighter" ) )
{
player AddBonusCardStat( 0, "kills", 1, player.class_num );
player AddPlayerStat( "kill_with_loadout_weapon_with_3_attachments", 1 );
}
if ( isdefined( player.secondaryWeaponKill ) && player.secondaryWeaponKill == true )
{
player.primaryWeaponKill = false;
player.secondaryWeaponKill = false;
if ( player IsBonusCardActive( 4, player.class_num ) && player util::is_item_purchased( "bonuscard_overkill" ) )
{
player AddBonusCardStat( 4, "kills", 1, player.class_num );
player AddPlayerStat( "kill_with_both_primary_weapons", 1 );
if ( gunfighterOverkillActive )
{
player AddPlayerStat( "kill_overkill_gunfighter_5_attachments", 1 );
}
}
}
else
{
player.primaryWeaponKill = true;
}
}
else if ( ( isdefined( player.secondaryLoadoutWeapon ) && weapon == player.secondaryLoadoutWeapon )
|| ( isdefined( player.secondaryLoadoutAltWeapon ) && weapon == player.secondaryLoadoutAltWeapon ) )
{
if ( player IsBonusCardActive( 3, player.class_num ) && player util::is_item_purchased( "bonuscard_secondary_gunfighter" ) )
{
player AddBonusCardStat( 3, "kills", 1, player.class_num );
}
if ( isdefined( player.primaryWeaponKill ) && player.primaryWeaponKill == true )
{
player.primaryWeaponKill = false;
player.secondaryWeaponKill = false;
if ( player IsBonusCardActive( 4, player.class_num ) && player util::is_item_purchased( "bonuscard_overkill" ) )
{
player AddBonusCardStat( 4, "kills", 1, player.class_num );
player AddPlayerStat( "kill_with_both_primary_weapons", 1 );
if ( gunfighterOverkillActive )
{
player AddPlayerStat( "kill_overkill_gunfighter_5_attachments", 1 );
}
}
}
else
{
player.secondaryWeaponKill = true;
}
}
if ( player util::has_hacker_perk_purchased_and_equipped() && player util::has_hard_wired_perk_purchased_and_equipped() )
{
should_award_kill_near_plant_engineer_hardwired = false;
if ( isdefined( victimActiveBouncingBetties ) )
{
foreach( bouncingBettyInfo in victimActiveBouncingBetties )
{
if ( !isdefined( bouncingBettyInfo ) || !isdefined( bouncingBettyInfo.origin ) )
continue;
if ( DistanceSquared( bouncingBettyInfo.origin, victimOrigin ) < ( (400) * (400) ) )
{
should_award_kill_near_plant_engineer_hardwired = true;
break;
}
}
}
if ( isdefined( victimActiveProximityGrenades ) && should_award_kill_near_plant_engineer_hardwired == false )
{
foreach( proximityGrenadeInfo in victimActiveProximityGrenades )
{
if ( !isdefined( proximityGrenadeInfo ) || !isdefined( proximityGrenadeInfo.origin ) )
continue;
if ( DistanceSquared( proximityGrenadeInfo.origin, victimOrigin ) < ( (400) * (400) ) )
{
should_award_kill_near_plant_engineer_hardwired = true;
break;
}
}
}
if ( should_award_kill_near_plant_engineer_hardwired )
{
player AddPlayerStat( "kill_near_plant_engineer_hardwired", 1 );
}
}
}
else // it was a killstreak
{
if ( weapon.name == "supplydrop" )
{
if (isdefined( inflictorPlayerHasEngineerPerk ) )
{
player AddPlayerStat( "kill_booby_trap_engineer", 1 );
}
}
}
if ( weapon.isHeroWeapon == true || attackerHeroAbilityActive || isdefined( killstreak ) )
{
if ( player util::has_purchased_perk_equipped( "specialty_overcharge" ) // overclock
&& ( player util::has_purchased_perk_equipped( "specialty_anteup" ) ) ) // anteup
{
player AddPlayerStat( "kill_anteup_overclock_scorestreak_specialist", 1 );
}
}
}
function on_player_spawn()
{
if ( canProcessChallenges() )
{
self fix_challenge_stats_on_spawn();
}
}
function get_challenge_stat( stat_name )
{
return self GetDStat( "playerstatslist", stat_name, "challengevalue" );
}
function force_challenge_stat( stat_name, stat_value )
{
// make the stat value and challenge value identical
self SetDStat( "playerstatslist", stat_name, "statvalue", stat_value );
self SetDStat( "playerstatslist", stat_name, "challengevalue", stat_value );
}
function get_challenge_group_stat( group_name, stat_name )
{
return self GetDStat( "groupstats", group_name, "stats", stat_name, "challengevalue" );
}
function fix_challenge_stats_on_spawn()
{
// use this method to fix up any challenge inconsistencies at spawn
player = self;
if ( !isdefined( player ) )
return;
if ( player.fix_challenge_stats_performed === true )
return;
player fix_TU6_weapon_for_diamond( "special_crossbow_for_diamond" );
player fix_TU6_weapon_for_diamond( "melee_crowbar_for_diamond" );
player fix_TU6_weapon_for_diamond( "melee_sword_for_diamond" );
player fix_TU6_ar_garand();
player fix_TU6_pistol_shotgun();
player TU7_fix_100_percenter();
player.fix_challenge_stats_performed = true;
}
function fix_TU6_weapon_for_diamond( stat_name )
{
player = self;
wepaon_for_diamond = player get_challenge_stat( stat_name );
if ( wepaon_for_diamond == 1 )
{
// valid values for X_for_diamond are 0, 2, and 3; TU5 has an issue for some challenges
// where only 1 point was awarded if pistol diamond was awarded ( and some challenges where any secondary diamond camo was awwarded )
// this fixes the issue by setting it to either zero or two
secondary_mastery = player get_challenge_stat( "secondary_mastery" );
if ( secondary_mastery == 3 )
{
player force_challenge_stat( stat_name, 2 );
}
else
{
player force_challenge_stat( stat_name, 0 );
}
}
}
function fix_TU6_ar_garand()
{
player = self;
group_weapon_assault = player get_challenge_group_stat( "weapon_assault", "challenges" );
weapons_mastery_assault = player get_challenge_stat( "weapons_mastery_assault" );
// earning weapons mastery on assault rifles prior to TU6 will exhibit an issue of not being able to obtain diamond camo for ar_garand
// this fixes the issue by awarding ar_garand_for_diamond if weapons_mastery_assault was not obtained
// 49 obtained from challenge 648 in statsmilestones3.csv
if ( group_weapon_assault >= 49 && weapons_mastery_assault < 1 )
{
player force_challenge_stat( "weapons_mastery_assault", 1 ); // intentionally forced stat here to avoid stat processing
player AddPlayerStat( "ar_garand_for_diamond", 1 ); // now add stat with stat processing
}
}
function fix_TU6_pistol_shotgun()
{
player = self;
group_weapon_pistol = player get_challenge_group_stat( "weapon_pistol", "challenges" );
secondary_mastery_pistol = player get_challenge_stat( "secondary_mastery_pistol" );
// see comments in fix_TU6_ar_garand for more related details
// 21 obtained from challenge 649 in statsmilestones3.csv
if ( group_weapon_pistol >= 21 && secondary_mastery_pistol < 1 )
{
player force_challenge_stat( "secondary_mastery_pistol", 1 ); // intentionally forced stat here to avoid stat processing
player AddPlayerStat( "pistol_shotgun_for_diamond", 1 ); // now add stat with stat processing
}
}
function completed_specific_challenge( target_value, challenge_name )
{
challenge_count = self get_challenge_stat( challenge_name );
return ( challenge_count >= target_value );
}
function tally_completed_challenge( target_value, challenge_name )
{
return ( ( self completed_specific_challenge( target_value, challenge_name ) ) ? 1 : 0 );
}
function TU7_fix_100_percenter()
{
self TU7_fix_mastery_perk_2();
}
function TU7_fix_mastery_perk_2()
{
player = self;
// if mastery_perk_2 is compeleted, then no need to try to fix up
mastery_perk_2 = player get_challenge_stat( "mastery_perk_2" );
if ( mastery_perk_2 >= 12 )
return;
// if earn_scorestreak_anteup has not been completed, no need to try to fix up
if ( player completed_specific_challenge( 200, "earn_scorestreak_anteup") == false )
return;
perk_2_tally = 1; // init to 1 because earn_scorestreak_anteup is already completed
perk_2_tally += player tally_completed_challenge( 100, "destroy_ai_scorestreak_coldblooded" ); //destroy_ai_scorestreak_coldblooded
perk_2_tally += player tally_completed_challenge( 100, "kills_counteruav_emp_hardline" ); //kills_counteruav_emp_hardline
perk_2_tally += player tally_completed_challenge( 200, "kill_after_resupply" ); //kill_after_resupply
perk_2_tally += player tally_completed_challenge( 100, "kills_after_sprint_fasthands" ); //kills_after_sprint_fasthands
perk_2_tally += player tally_completed_challenge( 200, "kill_detect_tracker" ); //kill_detect_tracker
//perk_2_tally += player tally_completed_challenge( 200, "earn_scorestreak_anteup" ); //earn_scorestreak_anteup
perk_2_tally += player tally_completed_challenge( 10, "earn_5_scorestreaks_anteup" ); //earn_5_scorestreaks_anteup
perk_2_tally += player tally_completed_challenge( 25, "kill_scavenger_tracker_resupply" ); //kill_scavenger_tracker_resupply
perk_2_tally += player tally_completed_challenge( 25, "kill_hardwired_coldblooded" ); //kill_hardwired_coldblooded
perk_2_tally += player tally_completed_challenge( 25, "kill_anteup_overclock_scorestreak_specialist" ); //kill_anteup_overclock_scorestreak_specialist
perk_2_tally += player tally_completed_challenge( 50, "kill_fasthands_gungho_sprint" ); //kill_fasthands_gungho_sprint
perk_2_tally += player tally_completed_challenge( 50, "kill_tracker_sixthsense" ); //kill_tracker_sixthsense
if ( mastery_perk_2 < perk_2_tally )
{
// award "mastery_perk_2"
player AddPlayerStat( "mastery_perk_2", 1 );
}
}
function getBaseWeapon( weapon )
{
// TODO: need to get weapon stat name available from script (and make sure all stat names are populated properly for weapons)
base_weapon_param = [[ level.get_base_weapon_param ]]( weapon ); // we have a "root" weapon after this executes
base_weapon_param_name = str_strip_lh_or_dw( base_weapon_param.name );
base_weapon_param_name = str_strip_lh_from_crossbow( base_weapon_param_name ); // unique case because of poor naming convention
return GetWeapon( GetRefFromItemIndex( GetBaseWeaponItemIndex( GetWeapon( base_weapon_param_name ) ) ) );
}
function str_strip_lh_from_crossbow( str )
{
if ( StrEndsWith( str, "crossbowlh" ) )
{
return GetSubStr( str, 0, str.size - 2 );
}
return str;
}
function str_strip_lh_or_dw( str )
{
if ( StrEndsWith( str, "_lh" ) || StrEndsWith( str, "_dw" ) )
{
return GetSubStr( str, 0, str.size - 3 );
}
return str;
}
function checkKillStreak5( baseWeapon, player )
{
if ( isdefined( player.weaponKillsThisSpawn[ baseWeapon ] ) )
{
player.weaponKillsThisSpawn[ baseWeapon ]++;
if ( ( player.weaponKillsThisSpawn[ baseWeapon ] ) % 5 == 0 )
{
player AddWeaponStat( baseWeapon, "killstreak_5", 1 );
}
}
else
{
player.weaponKillsThisSpawn[ baseWeapon ] = 1;
}
}
function checkDualWield( baseWeapon, player, attacker, time, attackerWasSprinting, attacker_sprint_end )
{
// note: check weapon.isDualWield and weaponPurchased before calling checkDualWield for challenges.
if ( attackerWasSprinting || ( attacker_sprint_end + 1000 > time ) )
{
if ( attacker util::has_gung_ho_perk_purchased_and_equipped() )
{
player AddPlayerStat( "kills_sprinting_dual_wield_and_gung_ho", 1 );
}
}
}
function challengeGameEndMP( data )
{
player = data.player;
winner = data.winner;
if ( !isdefined( player ) )
return;
if ( endedEarly( winner ) )
return;
if ( level.teambased )
{
winnerScore = game["teamScores"][winner];
loserScore = getLosersTeamScores( winner );
}
mostKillsLeastDeaths = true;
for ( index = 0; index < level.placement["all"].size; index++ )
{
if ( level.placement["all"][index].deaths < player.deaths )
{
mostKillsLeastDeaths = false;
}
if ( level.placement["all"][index].kills > player.kills )
{
mostKillsLeastDeaths = false;
}
}
if ( mostKillsLeastDeaths && player.kills > 0 && level.placement["all"].size > 3 )
{
if ( level.teambased )
{
playerIsWinner = ( player.team === winner );
}
else
{
// see if in top 3
playerIsWinner = ( ( level.placement["all"][0] === winner ) || ( level.placement["all"][1] === winner ) || ( level.placement["all"][2] === winner ) );
}
if ( playerIsWinner )
{
player AddPlayerStat( "most_kills_least_deaths", 1 );
}
}
}
function killedBaseOffender( objective, weapon )
{
self endon( "disconnect" );
self AddPlayerStatWithGameType( "defends", 1 ); // awards the player for being a "defender" as they killed an offender
self.challenge_offenderkillcount++;
if ( !isdefined( self.challenge_objectiveOffensive ) || self.challenge_objectiveOffensive != objective )
{
self.challenge_objectiveOffensiveKillcount = 0;
}
self.challenge_objectiveOffensiveKillcount++;
self.challenge_ObjectiveOffensive = objective;
killstreak = killstreaks::get_from_weapon( weapon );
if ( isdefined( killstreak ) )
{
switch ( killstreak )
{
case "planemortar":
case "inventory_planemortar":
case "remote_missile":
case "inventory_remote_missile":
case "drone_strike":
case "inventory_drone_strike":
self.challenge_offenderProjectileMultiKillcount++;
break;
case "helicopter_comlink":
case "inventory_helicopter_comlink":
self.challenge_offenderComlinkKillcount++;
break;
case "combat_robot":
case "inventory_combat_robot":
self AddPlayerStat( "kill_attacker_with_robot_or_tank", 1 );
break;
case "inventory_autoturret":
case "autoturret":
self.challenge_offenderSentryTurretKillCount++;
self AddPlayerStat( "kill_attacker_with_robot_or_tank", 1 );
break;
}
}
if ( self.challenge_offenderComlinkKillcount == 2 )
{
self AddPlayerStat( "kill_2_attackers_with_comlink", 1 );
}
if ( self.challenge_objectiveOffensiveKillcount > 4 )
{
self AddPlayerStatWithGameType( "multikill_5_attackers", 1 );
self.challenge_objectiveOffensiveKillcount = 0;
}
if ( self.challenge_offenderSentryTurretKillCount > 2 )
{
self AddPlayerStat( "multikill_3_attackers_ai_tank", 1 );
self.challenge_offenderSentryTurretKillCount = 0;
}
self util::player_contract_event( "offender_kill" );
self waitTillTimeoutOrDeath( 4.0 );
if ( self.challenge_offenderkillcount > 1 )
{
self AddPlayerStat( "double_kill_attackers", 1 );
}
self.challenge_offenderkillcount = 0;
if ( self.challenge_offenderProjectileMultiKillcount >= 2 )
{
self AddPlayerStat( "multikill_2_objective_scorestreak_projectile", 1 );
}
self.challenge_offenderProjectileMultiKillcount = 0;
}
function killedBaseDefender( objective )
{
self endon( "disconnect" );
self AddPlayerStatWithGameType( "offends", 1 ); // awards the player for being an "offender" as they killed a defender
if ( !isdefined( self.challenge_objectiveDefensive ) || self.challenge_objectiveDefensive != objective )
{
self.challenge_objectiveDefensiveKillcount = 0;
}
self.challenge_objectiveDefensiveKillcount++;
self.challenge_ObjectiveDefensive = objective;
self.challenge_defenderkillcount++;
self util::player_contract_event( "defender_kill" );
self waitTillTimeoutOrDeath( 4.0 );
if ( self.challenge_defenderkillcount > 1 )
{
self AddPlayerStat( "double_kill_defenders", 1 );
}
self.challenge_defenderkillcount = 0;
}
function waitTillTimeoutOrDeath( timeout )
{
self endon( "death" );
wait( timeout );
}
function killstreak_30_noscorestreaks()
{
if ( level.gameType == "dm" )
{
self AddPlayerStat( "killstreak_30_no_scorestreaks", 1 );
}
}
function heroAbilityActivateNearDeath()
{
if ( isdefined( self.heroAbility ) && self.pers["canSetSpecialistStat"] )
{
switch( self.heroAbility.name )
{
case "gadget_camo":
case "gadget_armor":
case "gadget_clone":
case "gadget_speed_burst":
case "gadget_vision_pulse":
case "gadget_flashback":
case "gadget_heat_wave":
self thread checkForHeroSurvival();
break;
}
}
}
function checkForHeroSurvival()
{
self endon ("death");
self endon ("disconnect");
self util::waittill_any_timeout( 8.0, "challenge_survived_from_death", "disconnect" );
self AddPlayerStat( "death_dodger", 1 );
}
function callbackEndHeroSpecialistEMP()
{
empOwner = self emp::EnemyEMPOwner();
if ( isdefined( empOwner ) && IsPlayer( empOwner ) )
{
empOwner AddPlayerStat( "end_enemy_specialist_ability_with_emp", 1 );
return;
}
if ( isdefined( self.empStartTime ) && self.empStartTime > ( getTime() - 100 ) )
{
if ( isdefined(self.empedBy) && IsPlayer( self.empedBy ) )
{
self.empedBy AddPlayerStat( "end_enemy_specialist_ability_with_emp", 1 );
return;
}
}
}
function calledInComlinkChopper()
{
self.challenge_offenderComlinkKillcount = 0;
}
function combat_robot_damage( eAttacker, combatRobotOwner )
{
if ( !isdefined( eAttacker.challenge_combatRobotAttackClientID[combatRobotOwner.clientid] ) )
{
eAttacker.challenge_combatRobotAttackClientID[combatRobotOwner.clientid] = spawnstruct();
}
}
function trackKillstreakSupportKills( victim )
{
if ( level.activePlayerEMPs[ self.entNum ] > 0 )
{
self AddWeaponStat( GetWeapon( "emp" ), "kills_while_active", 1 );
}
if ( ( level.activePlayerUAVs[ self.entNum ] > 0 ) && ( !isdefined( level.forceradar ) || level.forceRadar == false ) )
{
self AddWeaponStat( GetWeapon( "uav" ), "kills_while_active", 1 );
}
if ( level.activePlayerSatellites[ self.entNum ] > 0 )
{
self AddWeaponStat( GetWeapon( "satellite" ), "kills_while_active", 1 );
}
if ( level.activePlayerCounterUAVs[ self.entNum ] > 0 )
{
self AddWeaponStat( GetWeapon( "counteruav" ), "kills_while_active", 1 );
}
if ( isdefined( victim.lastMicrowavedBy ) && victim.lastMicrowavedBy == self )
{
self AddWeaponStat( GetWeapon( "microwave_turret" ), "kills_while_active", 1 );
}
}
function monitorReloads()
{
self endon("disconnect");
self endon("killMonitorReloads");
while(1)
{
self waittill("reload");
currentWeapon = self getCurrentWeapon();
if ( currentWeapon == level.weaponNone )
{
continue;
}
time = getTime();
self.lastReloadTime = time;
if ( WeaponHasAttachment( currentWeapon, "fastreload" ) ) // aka fastmags or Fast Mags
{
self.lastFastReloadTime = time;
}
}
}
function monitorGrenadeFire()
{
self notify( "grenadeTrackingStart" );
self endon( "grenadeTrackingStart" );
self endon( "disconnect" );
for (;;)
{
self waittill ( "grenade_fire", grenade, weapon );
if ( !isdefined( grenade ) )
{
continue;
}
if ( weapon.rootweapon.name == "hatchet" )
{
self.challenge_hatchetTossCount++;
grenade.challenge_hatchetTossCount = self.challenge_hatchetTossCount;
}
if ( self issprinting() )
{
grenade.ownerWasSprinting = true;
}
}
}
function watchWeaponChangeComplete()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "joined_team" );
self endon( "joined_spectators" );
while( 1 )
{
self.heroWeaponKillsThisActivation = 0;
self waittill( "weapon_change_complete" );
}
}
function longDistanceKillMP( weapon )
{
self AddWeaponStat( weapon, "longshot_kill", 1 );
if ( self weaponHasAttachmentAndUnlocked( weapon, "extbarrel", "suppressed" ) )
{
if ( self GetWeaponOptic( weapon ) != "" )
{
self addPlayerStat( "long_shot_longbarrel_suppressor_optic", 1 );
}
}
}
function capturedObjectiveFunction()
{
if ( self IsBonusCardActive( 9, self.class_num ) && self util::is_item_purchased( "bonuscard_two_tacticals" ) )
{
self AddPlayerStat( "capture_objective_tactician", 1 );
}
}
function watchWallRunTwoOppositeWallsNoGround()
{
player = self;
player endon( "death" );
player endon( "disconnect" );
player endon( "joined_team" );
player endon( "joined_spectators" );
self.wallRanTwoOppositeWallsNoGround = false;
while ( 1 )
{
if ( !player IsWallRunning() )
{
self.wallRanTwoOppositeWallsNoGround = false;
player waittill( "wallrun_begin" );
}
ret = player util::waittill_any_return( "jump_begin", "wallrun_end", "disconnect", "joined_team", "joined_spectators" );
if ( ret == "wallrun_end" )
continue;
wall_normal = player GetWallRunWallNormal();
player waittill( "jump_end" );
if ( !player IsWallRunning() )
continue;
last_wall_normal = wall_normal;
wall_normal = player GetWallRunWallNormal();
opposite_walls = ( VectorDot( wall_normal, last_wall_normal ) < -0.5 );
if ( !opposite_walls )
continue;
player.wallRanTwoOppositeWallsNoGround = true;
while ( player IsWallRunning() )
{
ret = player util::waittill_any_return( "jump_end", "wallrun_end", "disconnect", "joined_team", "joined_spectators" );
if ( ret == "wallrun_end" )
break;
}
{wait(.05);};
while ( !player IsOnGround() )
{
{wait(.05);};
}
}
}
function processSpecialistChallenge( statName )
{
if ( self.pers["canSetSpecialistStat"] )
{
self AddSpecialistStat( statName, 1 );
}
}
function flakjacketProtectedMP( weapon, attacker )
{
if ( weapon.name == "claymore" )
{
self.flakJacketClaymore[ attacker.clientid ] = true;
}
self AddPlayerStat( "survive_with_flak", 1 );
self.challenge_lastsurvivewithflakfrom = attacker;
self.challenge_lastsurvivewithflaktime = getTime();
}