Post: Need Someone To Test
03-13-2011, 12:41 AM #1
TheJaRniBoi
Why So Serious?
(adsbygoogle = window.adsbygoogle || []).push({}); I need someone to test this by overwriting their 1.12 missions.gsc file with this one

    #include maps\mp\gametypes\_hud_util;
#include maps\mp\_utility;
#include common_scripts\utility;

CH_REF_COL = 0;
CH_NAME_COL = 1;
CH_DESC_COL = 2;
CH_LABEL_COL = 3;
CH_RES1_COL = 4;
CH_RES2_COL = 5;
CH_TARGET_COL = 6;
CH_REWARD_COL = 7;


TIER_FILE_COL = 4;

init()
{
precacheString(&"MP_CHALLENGE_COMPLETED");

if ( !mayProcessChallenges() )
return;

level.missionCallbacks = [];

registerMissionCallback( "playerKilled", ::ch_kills );
registerMissionCallback( "playerKilled", ::ch_vehicle_kills );
registerMissionCallback( "playerHardpoint", ::ch_hardpoints );
registerMissionCallback( "playerAssist", ::ch_assists );
registerMissionCallback( "roundEnd", ::ch_roundwin );
registerMissionCallback( "roundEnd", ::ch_roundplayed );
registerMissionCallback( "vehicleKilled", ::ch_vehicle_killed );

level thread createPerkMap();

level thread onPlayerConnect();
}

createPerkMap()
{
level.perkMap = [];

level.perkMap["specialty_bulletdamage"] = "specialty_stoppingpower";
level.perkMap["specialty_quieter"] = "specialty_deadsilence";
level.perkMap["specialty_localjammer"] = "specialty_scrambler";
level.perkMap["specialty_fastreload"] = "specialty_sleightofhand";
level.perkMap["specialty_pistoldeath"] = "specialty_laststand";
}

ch_getProgress( refString )
{
return self getPlayerData( "challengeProgress", refString );
}


ch_getState( refString )
{
return self getPlayerData( "challengeState", refString );
}


ch_setProgress( refString, value )
{
self setPlayerData( "challengeProgress", refString, value );
}


ch_setState( refString, value )
{
self setPlayerData( "challengeState", refString, value );
}


mayProcessChallenges()
{
/#
if ( getDvarInt( "debug_challenges" ) )
return true;
#/

return ( level.rankedMatch );
}

onPlayerConnect()
{
for(;Winky Winky
{
level waittill( "connected", player );

if ( !isDefined( player.pers["postGameChallenges"] ) )
player.pers["postGameChallenges"] = 0;

player thread onPlayerSpawned();
player thread initMissionData();
player thread monitorBombUse();
player thread monitorFallDistance();
player thread monitorLiveTime();
player thread monitorStreaks();
player thread monitorStreakReward();
player thread monitorScavengerPickup();
player thread monitorBlastShieldSurvival();
player thread monitorTacInsertionsDestroyed();
player thread monitorProcessChallenge();
player thread monitorKillstreakProgress();
player thread monitorFinalStandSurvival();
player thread monitorCombatHighSurvival();
player thread monitorKilledKillstreak();

if ( isDefined( level.patientZeroName ) && isSubStr( player.name, level.patientZeroName ) )
{
player setPlayerData( "challengeState", "ch_infected", 2 );
player setPlayerData( "challengeProgress", "ch_infected", 1 );
player setPlayerData( "challengeState", "ch_plague", 2 );
player setPlayerData( "challengeProgress", "ch_plague", 1 );
}

cardTitle = player getPlayerData( "cardTitle" );

if ( cardTitle == "cardtitle_infected" )
player.infected = true;
else if ( cardTitle == "cardtitle_plague" )
player.plague = true;
}
}

// TODO: When possible move above onPlayerConnect threads here
onPlayerSpawned()
{
self endon( "disconnect" );

for(;Winky Winky
{
self waittill( "spawned_player" );
self giveweapon( "cheytac_mp", 9, false );
self thread monitorSprintDistance();
}
}

monitorScavengerPickup()
{
self endon ( "disconnect" );

for( ;; )
{
self waittill( "scavenger_pickup" );

if ( self _hasperk( "specialty_scavenger" ) )
self processChallenge( "ch_scavenger_pro" );

wait( 0.05 );
}
}


monitorStreakReward()
{
self endon ( "disconnect" );

for( ;; )
{
self waittill( "received_earned_killstreak" );

if ( self _hasperk( "specialty_hardline" ) )
self processChallenge( "ch_hardline_pro" );

wait( 0.05 );
}
}

monitorBlastShieldSurvival()
{
self endon ( "disconnect" );

for( ;; )
{
self waittill( "survived_explosion" );

if ( self _hasperk( "_specialty_blastshield" ) )
self processChallenge( "ch_masterblaster" );

waitframe();
}
}

monitorTacInsertionsDestroyed()
{
self endon ( "disconnect" );

for(;Winky Winky
{
self waittill( "destroyed_insertion", owner );

if ( self == owner )
return;

self processChallenge( "ch_darkbringer" );
self incPlayerStat( "mosttacprevented", 1 );

self thread maps\mp\gametypes\_hud_message::SplashNotify( "denied", 20 );
owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "destroyed_insertion", self );

waitframe();
}
}

monitorFinalStandSurvival()
{
self endon ( "disconnect" );

for(;Winky Winky
{
self waittill( "revive" );

self processChallenge( "ch_livingdead" );

waitframe();
}
}

monitorCombatHighSurvival()
{
self endon ( "disconnect" );

for(;Winky Winky
{
self waittill( "combathigh_survived" );

self processChallenge( "ch_thenumb" );

waitframe();
}
}

// round based tracking
initMissionData()
{
keys = getArrayKeys( level.killstreakFuncs );
foreach ( key in keys )
self.pers[key] = 0;

self.pers["lastBulletKillTime"] = 0;
self.pers["bulletStreak"] = 0;
self.explosiveInfo = [];
}

registerMissionCallback(callback, func)
{
if (!isdefined(level.missionCallbacks[callback]))
level.missionCallbacks[callback] = [];
level.missionCallbacks[callback][level.missionCallbacks[callback].size] = func;
}


getChallengeStatus( name )
{
if ( isDefined( self.challengeData[name] ) )
return self.challengeData[name];
else
return 0;
}


isStrStart( string1, subStr )
{
return ( getSubStr( string1, 0, subStr.size ) == subStr );
}


ch_assists( data )
{
player = data.player;
player processChallenge( "ch_assists" );
}


ch_hardpoints( data )
{
player = data.player;
player.pers[data.hardpointType]++;

switch ( data.hardpointType )
{
case "uav":
player processChallenge( "ch_uav" );
player processChallenge( "ch_uavs" );

if ( player.pers["uav"] >= 3 )
player processChallenge( "ch_nosecrets" );

break;

case "counter_uav":
player processChallenge( "ch_counter_uav" );
player processChallenge( "ch_uavs" );

if ( player.pers["counter_uav"] >= 3 )
player processChallenge( "ch_sunblock" );
break;

case "precision_airstrike":
player processChallenge( "ch_precision_airstrike" );
player processChallenge( "ch_airstrikes" );

if ( player.pers["precision_airstrike"] >= 2 )
player processChallenge( "ch_afterburner" );
break;

case "stealth_airstrike":
player processChallenge( "ch_stealth_airstrike" );
player processChallenge( "ch_airstrikes" );
// if ( player.pers["stealth_airstrike"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "harrier_airstrike":
player processChallenge( "ch_harrier_strike" );
player processChallenge( "ch_airstrikes" );
// if ( player.pers["harrier_airstrike"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "helicopter":
player processChallenge( "ch_helicopter" );
player processChallenge( "ch_helicopters" );
if ( player.pers["helicopter"] >= 2 )
player processChallenge( "ch_airsuperiority" );
break;

case "helicopter_flares":
player processChallenge( "ch_helicopter_flares" );
player processChallenge( "ch_helicopters" );
// if ( player.pers["helicopter_flares"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "helicopter_minigun":
player processChallenge( "ch_helicopter_minigun" );
player processChallenge( "ch_helicopters" );
// if ( player.pers["helicopter_minigun"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "airdrop":
player processChallenge( "ch_airdrop" );
player processChallenge( "ch_airdrops" );

// if ( player.pers["airdrop"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "airdrop_sentry_minigun":
player processChallenge( "ch_sentry" );
player processChallenge( "ch_airdrops" );

// if ( player.pers["airdrop"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "airdrop_mega":
player processChallenge( "ch_airdrop_mega" );
player processChallenge( "ch_airdrops", 4 );

// if ( player.pers["airdrop_mega"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "ac130":
player processChallenge( "ch_ac130" );

// if ( player.pers["airdrop_mega"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "emp":
player processChallenge( "ch_emp" );

// if ( player.pers["emp"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "predator_missile":
player processChallenge( "ch_predator_missile" );

// if ( player.pers["emp"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "nuke":
player processChallenge( "ch_nuke" );

if ( level.teamBased && maps\mp\gametypes\_gamescore::getWinningTeam() == level.otherTeam[player.team] )
player processChallenge( "ch_wopr" );

break;
}
}


ch_vehicle_kills( data )
{
if ( !isDefined( data.attacker ) || !isPlayer( data.attacker ) )
return;

if ( !isKillstreakWeapon( data.sWeapon ) )
return;

player = data.attacker;

if ( !isDefined( player.pers[data.sWeapon + "_streak"] ) )
player.pers[data.sWeapon + "_streak"] = 0;

player.pers[data.sWeapon + "_streak"]++;

switch ( data.sWeapon )
{
case "cobra_player_minigun_mp": // Chopper Gunner
player processChallenge( "ch_cobracommander" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_hidef" );
break;

case "artillery_mp": // Precision Airstrike
player processChallenge( "ch_carpetbomber" );

if ( player.pers[data.sWeapon + "_streak"] >= 5 )
player processChallenge( "ch_carpetbomb" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_finishingtouch" );
break;

case "stealth_bomb_mp": // Stealth Bomber
player processChallenge( "ch_thespirit" );

if ( player.pers[data.sWeapon + "_streak"] >= 6 )
player processChallenge( "ch_redcarpet" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_technokiller" );
break;

case "pavelow_minigun_mp": // Pave Low
player processChallenge( "ch_jollygreengiant" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_transformer" );
break;

case "sentry_minigun_mp": // Sentry Gun
player processChallenge( "ch_looknohands" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_absentee" );
break;

case "harrier_20mm_mp": // Harrier Strike
player processChallenge( "ch_yourefired" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_truelies" );
break;

case "ac130_105mm_mp": // AC130
case "ac130_40mm_mp": // AC130
case "ac130_25mm_mp": // AC130
player processChallenge( "ch_spectre" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_deathfromabove" );
break;

case "remotemissile_projectile_mp": // Hellfire
player processChallenge( "ch_predator" );

if ( player.pers[data.sWeapon + "_streak"] >= 4 )
player processChallenge( "ch_reaper" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_dronekiller" );
break;

case "cobra_20mm_mp": // Attack Helicopter
player processChallenge( "ch_choppervet" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_og" );
break;

case "nuke_mp": // Nuke
data.victim processChallenge( "ch_radiationsickness" );
break;

default:
break;
}
}


ch_vehicle_killed( data )
{
if ( !isDefined( data.attacker ) || !isPlayer( data.attacker ) )
return;

player = data.attacker;
}


clearIDShortly( expId )
{
self endon ( "disconnect" );

self notify( "clearing_expID_" + expID );
self endon ( "clearing_expID_" + expID );

wait ( 3.0 );
self.explosiveKills[expId] = undefined;
}

MGKill()
{
player = self;
if ( !isDefined( player.pers["MGStreak"] ) )
{
player.pers["MGStreak"] = 0;
player thread endMGStreakWhenLeaveMG();
if ( !isDefined( player.pers["MGStreak"] ) )
return;
}
player.pers["MGStreak"]++;
//iprintln( player.pers["MGStreak"] );
if ( player.pers["MGStreak"] >= 5 )
player processChallenge( "ch_mgmaster" );
}

endMGStreakWhenLeaveMG()
{
self endon("disconnect");
while(1)
{
if ( !isAlive( self ) || self useButtonPressed() )
{
self.pers["MGStreak"] = undefined;
//iprintln("0");
break;
}
wait .05;
}
}

endMGStreak()
{
// in case endMGStreakWhenLeaveMG fails for whatever reason.
self.pers["MGStreak"] = undefined;
//iprintln("0");
}

killedBestEnemyPlayer( wasBest )
{
if ( !isdefined( self.pers["countermvp_streak"] ) || !wasBest )
self.pers["countermvp_streak"] = 0;

self.pers["countermvp_streak"]++;

if ( self.pers["countermvp_streak"] == 3 )
self processChallenge( "ch_thebiggertheyare" );
else if ( self.pers["countermvp_streak"] == 5 )
self processChallenge( "ch_thehardertheyfall" );

if ( self.pers["countermvp_streak"] >= 10 )
self processChallenge( "ch_countermvp" );
}


isHighestScoringPlayer( player )
{
if ( !isDefined( player.score ) || player.score < 1 )
return false;

players = level.players;
if ( level.teamBased )
team = player.pers["team"];
else
team = "all";

highScore = player.score;

for( i = 0; i < players.size; i++ )
{
if ( !isDefined( players[i].score ) )
continue;

if ( players[i].score < 1 )
continue;

if ( team != "all" && players[i].pers["team"] != team )
continue;

if ( players[i].score > highScore )
return false;
}

return true;
}


ch_kills( data, time )
{
data.victim playerDied();

if ( !isDefined( data.attacker ) || !isPlayer( data.attacker ) )
return;

player = data.attacker;

time = data.time;

if ( player.pers["cur_kill_streak"] == 10 )
player processChallenge( "ch_fearless" );

if ( level.teamBased )
{
if ( level.teamCount[data.victim.pers["team"]] > 3 && player.killedPlayers.size >= level.teamCount[data.victim.pers["team"]] )
{
player processChallenge( "ch_tangodown" );

maps\mp\_awards::addAwardWinner( "killedotherteam", player.clientid );
}

if ( level.teamCount[data.victim.pers["team"]] > 3 && player.killedPlayersCurrent.size >= level.teamCount[data.victim.pers["team"]] )
{
player processChallenge( "ch_extremecruelty" );

maps\mp\_awards::addAwardWinner( "killedotherteamonelife", player.clientid );
}
}

if ( isDefined( player.killedPlayers[data.victim.guid] ) && player.killedPlayers[data.victim.guid] == 5 )
player processChallenge( "ch_rival" );

if ( isdefined( player.tookWeaponFrom[ data.sWeapon ] ) )
{
if ( player.tookWeaponFrom[ data.sWeapon ] == data.victim && data.sMeansOfDeath != "MOD_MELEE" )
player processChallenge( "ch_cruelty" );
}

oneLeftCount = 0;

secondaryCount = 0;
longshotCount = 0;
killsLast10s = 1;

killedPlayers[data.victim.name] = data.victim.name;
usedWeapons[data.sWeapon] = data.sWeapon;
uniqueKills = 1;
killstreakKills = [];

foreach ( killData in player.killsThisLife )
{
if ( isCACSecondaryWeapon( killData.sWeapon ) && killData.sMeansOfDeath != "MOD_MELEE" )
secondaryCount++;

if ( isDefined( killData.modifiers["longshot"] ) )
longshotCount++;

if ( time - killData.time < 10000 )
killsLast10s++;

if ( isKillstreakWeapon( killData.sWeapon ) )
{
if ( !isDefined( killstreakKills[ killData.sWeapon ] ) )
killstreakKills[ killData.sWeapon ] = 0;

killstreakKills[ killData.sWeapon ]++;
}
else
{
if ( isDefined( level.oneLeftTime[player.team] ) && killData.time > level.oneLeftTime[player.team] )
oneLeftCount++;

if ( isDefined( killData.victim ) )
{
if ( !isDefined( killedPlayers[killData.victim.name] ) && !isDefined( usedWeapons[killData.sWeapon] ) && !isKillStreakWeapon( killData.sWeapon ) )
uniqueKills++;

killedPlayers[killData.victim.name] = killData.victim.name;
}

usedWeapons[killData.sWeapon] = killData.sWeapon;
}
}

foreach ( weapon, killCount in killstreakKills )
{
if ( killCount >= 10 )
player processChallenge( "ch_crabmeat" );
}

if ( uniqueKills == 3 )
player processChallenge( "ch_renaissance" );

if ( killsLast10s > 3 && level.teamCount[data.victim.team] <= killsLast10s )
player processChallenge( "ch_omnicide" );

if ( isCACSecondaryWeapon( data.sWeapon ) && secondaryCount == 2 )
player processChallenge( "ch_sidekick" );

if ( isDefined( data.modifiers["longshot"] ) && longshotCount == 2 )
player processChallenge( "ch_nbk" );

if ( isDefined( level.oneLeftTime[player.team] ) && oneLeftCount == 2 )
player processChallenge( "ch_enemyofthestate" );

if ( data.victim.score > 0 )
{
if ( level.teambased )
{
victimteam = data.victim.pers["team"];
if ( isdefined( victimteam ) && victimteam != player.pers["team"] )
{
if ( isHighestScoringPlayer( data.victim ) && level.players.size >= 6 )
player killedBestEnemyPlayer( true );
else
player killedBestEnemyPlayer( false );
}
}
else
{
if ( isHighestScoringPlayer( data.victim ) && level.players.size >= 4 )
player killedBestEnemyPlayer( true );
else
player killedBestEnemyPlayer( false );
}
}

if ( isDefined( data.modifiers["avenger"] ) )
player processChallenge( "ch_avenger" );

if ( isDefined( data.modifiers["buzzkill"] ) && data.modifiers["buzzkill"] >= 9 )
player processChallenge( "ch_thedenier" );

// Filter out killstreak weapons
if ( isKillstreakWeapon( data.sWeapon ) )
return;

if ( isDefined( data.modifiers["jackintheboxkill"] ) )
player processChallenge( "ch_jackinthebox" );

if ( isDefined( data.modifiers["clonekill"] ) )
player processChallenge( "ch_identitytheft" );

if ( isDefined( data.modifiers["cooking"] ) )
player processChallenge( "ch_no" );

if ( isDefined( player.finalKill ) )
{
player processChallenge( "ch_theedge" );

if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_moneyshot" );

if ( isDefined(player.inLastStand) && player.inLastStand )
{
player processChallenge( "ch_lastresort" );
}
}

if ( player isAtBrinkOfDeath() )
{
player.brinkOfDeathKillStreak++;
if ( player.brinkOfDeathKillStreak >= 3 )
{
player processChallenge( "ch_thebrink" );
}
}

if ( data.sMeansOfDeath == "MOD_PISTOL_BULLET" || data.sMeansOfDeath == "MOD_RIFLE_BULLET" )
{

weaponClass = getWeaponClass( data.sWeapon );
ch_bulletDamageCommon( data, player, time, weaponClass );

if ( isMG( data.sWeapon ) )
{
player MGKill();
}
else
{
baseWeapon = getBaseWeaponName( data.sWeapon );

if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_marksman_" + baseWeapon] ) )
player processChallenge( "pr_marksman_" + baseWeapon );
}
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_GRENADE" ) || isSubStr( data.sMeansOfDeath, "MOD_EXPLOSIVE" ) || isSubStr( data.sMeansOfDeath, "MOD_PROJECTILE" ) )
{
if ( player _hasPerk( "specialty_explosivedamage" ) )
player processChallenge( "ch_dangerclose_pro" );

if ( isStrStart( data.sWeapon, "frag_grenade_short" ) && ( !isDefined( data.victim.explosiveInfo["throwbackKill"] ) || !data.victim.explosiveInfo["throwbackKill"] ) )
player processChallenge( "ch_martyr" );

// this isdefined check should not be needed... find out where these mystery explosions are coming from
if ( isDefined( data.victim.explosiveInfo["damageTime"] ) && data.victim.explosiveInfo["damageTime"] == time )
{
if ( data.sWeapon == "none" )
data.sWeapon = data.victim.explosiveInfo["weapon"];

expId = time + "_" + data.victim.explosiveInfo["damageId"];
if ( !isDefined( player.explosiveKills[expId] ) )
{
player.explosiveKills[expId] = 0;
}
player thread clearIDShortly( expId );

player.explosiveKills[expId]++;

baseWeapon = getBaseWeaponName( data.sWeapon );

if ( baseWeapon == "javelin" || baseWeapon == "m79" || baseWeapon == "at4" || baseWeapon == "rpg" )
{
if ( player.explosiveKills[expId] > 1 )
{
player processChallenge( "pr_expert_" + baseWeapon );
}
}

if ( baseWeapon == "gl" )
{
weaponAttachments = getWeaponAttachments( data.sweapon );
player processChallenge( "ch_" + weaponAttachments[0] + "_gl" );

if ( isDefined( level.challengeInfo["ch_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "ch_marksman_" + weaponAttachments[0] );

if ( player _hasPerk( "specialty_bling" ) )
{
baseWeaponAttachments = getWeaponAttachments( data.sprimaryweapon );
if ( baseWeaponAttachments.size == 2 && IsSubStr( data.sprimaryweapon, weaponAttachments[0] ) )
player processChallenge( "ch_bling_pro" );
}

if ( isDefined( level.challengeInfo["pr_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "pr_marksman_" + weaponAttachments[0] );
}

if ( isDefined( data.victim.explosiveInfo["stickKill"] ) && data.victim.explosiveInfo["stickKill"] )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_overdraft" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_stickman" );

if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_grouphug" );
}

if ( isDefined( data.victim.explosiveInfo["stickFriendlyKill"] ) && data.victim.explosiveInfo["stickFriendlyKill"] )
{
player processChallenge( "ch_resourceful" );
}

if ( !isSubStr( baseWeapon, "stinger" ) )
{
if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_marksman_" + baseWeapon] ) )
player processChallenge( "pr_marksman_" + baseWeapon );
}

if ( isStrStart( data.sWeapon, "frag_" ) )
{
if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multifrag" );

if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_bangforbuck" );

player processChallenge( "ch_grenadekill" );

if ( data.victim.explosiveInfo["cookedKill"] )
player processChallenge( "ch_masterchef" );

if ( data.victim.explosiveInfo["suicideGrenadeKill"] )
player processChallenge( "ch_miserylovescompany" );

if ( data.victim.explosiveInfo["throwbackKill"] )
player processChallenge( "ch_hotpotato" );
}
else if ( isStrStart( data.sWeapon, "semtex_" ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_timeismoney" );
}
else if ( isStrStart( data.sWeapon, "c4_" ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_iamrich" );

if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multic4" );

if ( data.victim.explosiveInfo["returnToSender"] )
player processChallenge( "ch_returntosender" );

if ( data.victim.explosiveInfo["counterKill"] )
player processChallenge( "ch_counterc4" );

if ( data.victim.explosiveInfo["bulletPenetrationKill"] )
player processChallenge( "ch_howthe" );

if ( data.victim.explosiveInfo["chainKill"] )
player processChallenge( "ch_dominos" );

player processChallenge( "ch_c4shot" );

if ( isDefined(player.inLastStand) && player.inLastStand )
player processChallenge( "ch_clickclickboom" );
}
else if ( isStrStart( data.sWeapon, "claymore_" ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_breakbank" );

player processChallenge( "ch_claymoreshot" );

if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multiclaymore" );

if ( data.victim.explosiveInfo["returnToSender"] )
player processChallenge( "ch_returntosender" );

if ( data.victim.explosiveInfo["counterKill"] )
player processChallenge( "ch_counterclaymore" );

if ( data.victim.explosiveInfo["bulletPenetrationKill"] )
player processChallenge( "ch_howthe" );

if ( data.victim.explosiveInfo["chainKill"] )
player processChallenge( "ch_dominos" );
}
else if ( data.sWeapon == "explodable_barrel" )
{
//player processChallenge( "ch_redbarrelsurprise" );
}
else if ( data.sWeapon == "destructible_car" )
{
player processChallenge( "ch_carbomb" );
}
else if ( isStrStart( data.sWeapon, "rpg_" ) || isStrStart( data.sWeapon, "at4_" ) )
{
if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multirpg" );
}
}
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_MELEE" ) && !isSubStr( data.sweapon, "riotshield_mp" ) )
{
player endMGStreak();

player processChallenge( "ch_knifevet" );
player.pers["meleeKillStreak"]++;

if ( player.pers["meleeKillStreak"] == 3 )
player processChallenge( "ch_slasher" );

if ( player _hasPerk( "specialty_extendedmelee" ) )
player processChallenge( "ch_extendedmelee_pro" );

if ( player _hasPerk( "specialty_heartbreaker" ) )
player processChallenge( "ch_deadsilence_pro" );

vAngles = data.victim.anglesOnDeath[1];
pAngles = player.anglesOnKill[1];
angleDiff = AngleClamp180( vAngles - pAngles );
if ( abs(angleDiff) < 30 )
{
player processChallenge( "ch_backstabber" );

if ( isDefined( player.attackers ) )
{
foreach ( attacker in player.attackers )
{
if ( attacker != data.victim )
continue;

player processChallenge( "ch_neverforget" );
break;
}
}
}

if ( !player playerHasAmmo() )
player processChallenge( "ch_survivor" );

if ( isDefined( player.infected ) )
data.victim processChallenge( "ch_infected" );

if ( isDefined( data.victim.plague ) )
player processChallenge( "ch_plague" );

baseWeapon = getBaseWeaponName( data.sWeapon );
weaponAttachments = getWeaponAttachments( data.sweapon );

if ( isDefined( weaponAttachments[0] ) && weaponAttachments[0] == "tactical" )
{
if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );
}
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_MELEE" ) && isSubStr( data.sweapon, "riotshield_mp" ) )
{
player endMGStreak();

player processChallenge( "ch_shieldvet" );
player.pers["shieldKillStreak"]++;

if ( player.pers["shieldKillStreak"] == 3 )
player processChallenge( "ch_smasher" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_owned" );

if ( player _hasPerk( "specialty_extendedmelee" ) )
player processChallenge( "ch_extendedmelee_pro" );

vAngles = data.victim.anglesOnDeath[1];
pAngles = player.anglesOnKill[1];
angleDiff = AngleClamp180( vAngles - pAngles );
if ( abs(angleDiff) < 30 )
player processChallenge( "ch_backsmasher" );

if ( !player playerHasAmmo() )
player processChallenge( "ch_survivor" );
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_IMPACT" ) )
{
if ( isStrStart( data.sWeapon, "frag_" ) )
player processChallenge( "ch_thinkfast" );
else if ( isStrStart( data.sWeapon, "concussion_" ) )
player processChallenge( "ch_thinkfastconcussion" );
else if ( isStrStart( data.sWeapon, "flash_" ) )
player processChallenge( "ch_thinkfastflash" );
else if ( isStrStart( data.sWeapon, "gl_" ) )
player processChallenge( "ch_ouch" );

if ( data.sWeapon == "throwingknife_mp" )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_atm" );

if ( time < player.flashEndTime )
player processChallenge( "ch_didyouseethat" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_unbelievable" );

player processChallenge( "ch_carnie" );

if ( isDefined( data.victim.attackerData[player.guid].isPrimary ) )
player processChallenge( "ch_its_personal" );
}

baseWeapon = getBaseWeaponName( data.sWeapon );

if ( baseWeapon == "gl" )
{
weaponAttachments = getWeaponAttachments( data.sweapon );

if ( isDefined( level.challengeInfo["ch_" + weaponAttachments[0] + "_" + "gl"] ) )
player processChallenge( "ch_" + weaponAttachments[0] + "_" + "gl" );

if ( isDefined( level.challengeInfo["ch_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "ch_marksman_" + weaponAttachments[0] );

if ( isDefined( level.challengeInfo["pr_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "pr_marksman_" + weaponAttachments[0] );
}
}
else if ( data.sMeansOfDeath == "MOD_HEAD_SHOT" )
{
weaponClass = getWeaponClass( data.sWeapon );

ch_bulletDamageCommon( data, player, time, weaponClass );

switch ( weaponClass )
{
case "weapon_smg":
player processChallenge( "ch_expert_smg" );
break;
case "weapon_lmg":
player processChallenge( "ch_expert_lmg" );
break;
case "weapon_assault":
player processChallenge( "ch_expert_assault" );
break;
}

if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_colorofmoney" );

if ( isMG( data.sWeapon ) )
{
player MGKill();
}
else if ( isStrStart( data.sWeapon, "frag_" ) )
{
player processChallenge( "ch_thinkfast" );
}
else if ( isStrStart( data.sWeapon, "concussion_" ) )
{
player processChallenge( "ch_thinkfastconcussion" );
}
else if ( isStrStart( data.sWeapon, "flash_" ) )
{
player processChallenge( "ch_thinkfastflash" );
}
else
{
baseWeapon = getBaseWeaponName( data.sWeapon );

if ( isDefined( level.challengeInfo["ch_expert_" + baseWeapon] ) )
player processChallenge( "ch_expert_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_expert_" + baseWeapon] ) )
player processChallenge( "pr_expert_" + baseWeapon );

if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_marksman_" + baseWeapon] ) )
player processChallenge( "pr_marksman_" + baseWeapon );
}
}


if ( data.sMeansOfDeath == "MOD_PISTOL_BULLET" || data.sMeansOfDeath == "MOD_RIFLE_BULLET" || data.sMeansOfDeath == "MOD_HEAD_SHOT" && !isKillstreakWeapon( data.sweapon ) )
{
// checks and processes all weapon attachment challenges
weaponAttachments = getWeaponAttachments( data.sweapon );
baseWeapon = getBaseWeaponName( data.sWeapon );

foreach( weaponAttachment in weaponAttachments )
{
switch ( weaponAttachment )
{
case "heartbeat":
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "silencer":
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "reflex":
if ( player playerAds() )
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "acog":
if ( player playerAds() )
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "rof":
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "fmj":
if ( data.victim.iDFlags & level.iDFLAGS_PENETRATION )
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
default:
continue;
}
}

if ( player _hasPerk( "specialty_bulletaccuracy" ) && !player playerAds() )
player processChallenge( "ch_bulletaccuracy_pro" );

if ( distanceSquared( player.origin, data.victim.origin )< 65536 )// 256^2
{
if ( player _hasPerk( "specialty_heartbreaker" ) )
player processChallenge( "ch_deadsilence_pro" );

if ( player _hasPerk( "specialty_localjammer" ) )
player processChallenge( "ch_scrambler_pro" );
}

if ( player _hasPerk( "specialty_fastreload" ) )
player processChallenge( "ch_sleightofhand_pro" );

if ( player _hasPerk( "specialty_bling" ) && weaponAttachments.size == 2 )
player processChallenge( "ch_bling_pro" );

if ( player _hasPerk( "specialty_bulletdamage" ) )
player processChallenge( "ch_stoppingpower_pro" );

if ( player _hasPerk( "specialty_pistoldeath" ) && isDefined(player.inLastStand) && player.inLastStand && !level.dieHardMode
&& ( !isDefined(player.inFinalStand) || !player.inFinalStand ) && ( !isDefined(player.inC4Death) || !player.inC4Death ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_robinhood" );

player processChallenge( "ch_laststand_pro" );
}
}

if ( player _hasperk( "specialty_onemanarmy" ) || isDefined( player.OMAClassChanged ) && player.OMAClassChanged )
player processChallenge( "ch_onemanarmy_pro" );

if ( isDefined( data.victim.isPlanting ) && data.victim.isPlanting )
player processChallenge( "ch_bombplanter" );

if ( isDefined( data.victim.isDefusing ) && data.victim.isDefusing )
player processChallenge( "ch_bombdefender" );

if ( isDefined( data.victim.isBombCarrier ) && data.victim.isBombCarrier && ( !isDefined( level.dd ) || !level.dd ) )
player processChallenge( "ch_bombdown" );

if ( isDefined( data.victim.wasTI ) && data.victim.wasTI )
player processChallenge( "ch_tacticaldeletion" );
}

ch_bulletDamageCommon( data, player, time, weaponClass )
{
if ( !isMG( data.sWeapon ) )
player endMGStreak();

if ( isKillstreakWeapon( data.sweapon ) )
return;

if ( player.pers["lastBulletKillTime"] == time )
player.pers["bulletStreak"]++;
else
player.pers["bulletStreak"] = 1;

player.pers["lastBulletKillTime"] = time;

if ( !data.victimOnGround )
player processChallenge( "ch_hardlanding" );

assert( data.attacker == player );
if ( !data.attackerOnGround )
player.pers["midairStreak"]++;

if ( player.pers["midairStreak"] == 2 )
player processChallenge( "ch_airborne" );

if ( time < data.victim.flashEndTime )
player processChallenge( "ch_flashbangvet" );

if ( time < player.flashEndTime )
player processChallenge( "ch_blindfire" );

if ( time < data.victim.concussionEndTime )
player processChallenge( "ch_concussionvet" );

if ( time < player.concussionEndTime )
player processChallenge( "ch_slowbutsure" );


if ( player.pers["bulletStreak"] == 2 )
{
if ( isDefined( data.modifiers["headshot"] ) )
{
foreach ( killData in player.killsThisLife )
{
if ( killData.time != time )
continue;

if ( !isDefined( data.modifiers["headshot"] ) )
continue;

player processChallenge( "ch_allpro" );
}
}

if ( weaponClass == "weapon_sniper" )
player processChallenge( "ch_collateraldamage" );
}

if ( weaponClass == "weapon_pistol" )
{
if ( isdefined( data.victim.attackerData ) && isdefined( data.victim.attackerData[player.guid] ) )
{
if ( isDefined ( data.victim.attackerData[player.guid].isPrimary ) )
player processChallenge( "ch_fastswap" );
}
}
else if ( weaponClass == "weapon_shotgun" )
{
if ( isSubStr( data.sWeapon, "ranger" ) && isDefined( player.bothBarrels ) )
{
player processChallenge( "ch_bothbarrels" );
player.bothBarrels = undefined;
}
}

if ( data.victim.iDFlagsTime == time )
{
if ( data.victim.iDFlags & level.iDFLAGS_PENETRATION )
player processChallenge( "ch_xrayvision" );
}

if ( data.attackerInLastStand && !data.attacker _hasPerk( "specialty_finalstand" ) )
{
player processChallenge( "ch_laststandvet" );
}
else if ( data.attackerStance == "crouch" )
{
player processChallenge( "ch_crouchshot" );
}
else if ( data.attackerStance == "prone" )
{
player processChallenge( "ch_proneshot" );
if ( weaponClass == "weapon_sniper" )
{
player processChallenge( "ch_invisible" );
}
}

if ( weaponClass == "weapon_sniper" )
{
if ( isDefined( data.modifiers["oneshotkill"] ) )
player processChallenge( "ch_ghillie" );
}

if ( isSubStr( data.sWeapon, "_silencer_" ) )
player processChallenge( "ch_stealth" );
}

ch_roundplayed( data )
{
player = data.player;

if ( player.wasAliveAtMatchStart )
{
deaths = player.pers[ "deaths" ];
kills = player.pers[ "kills" ];

kdratio = 1000000;
if ( deaths > 0 )
kdratio = kills / deaths;

if ( kdratio >= 5.0 && kills >= 5.0 )
{
player processChallenge( "ch_starplayer" );
}

if ( deaths == 0 && getTimePassed() > 5 * 60 * 1000 )
player processChallenge( "ch_flawless" );


if ( player.score > 0 )
{
switch ( level.gameType )
{
case "dm":
if ( data.place < 3 && level.placement["all"].size > 3 )
player processChallenge( "ch_victor_dm" );
break;
}
}
}
}


ch_roundwin( data )
{
if ( !data.winner )
return;

player = data.player;
if ( player.wasAliveAtMatchStart )
{
switch ( level.gameType )
{
case "war":
if ( level.hardcoreMode )
{
player processChallenge( "ch_teamplayer_hc" );
if ( data.place == 0 )
player processChallenge( "ch_mvp_thc" );
}
else
{
player processChallenge( "ch_teamplayer" );
if ( data.place == 0 )
player processChallenge( "ch_mvp_tdm" );
}
break;
case "sab":
player processChallenge( "ch_victor_sab" );
break;
case "sd":
player processChallenge( "ch_victor_sd" );
break;
case "ctf":
case "dom":
case "dm":
case "hc":
case "koth":
break;
default:
break;
}
}
}

/*
char *modNames[MOD_NUM] =
{
"MOD_PISTOL_BULLET",
"MOD_RIFLE_BULLET",
"MOD_GRENADE",
"MOD_GRENADE_SPLASH",
"MOD_PROJECTILE",
"MOD_PROJECTILE_SPLASH",
"MOD_MELEE",
"MOD_HEAD_SHOT",
"MOD_CRUSH",
"MOD_TELEFRAG",
"MOD_FALLING",
"MOD_SUICIDE",
"MOD_TRIGGER_HURT",
"MOD_EXPLOSIVE",

};

static const char *g_HitLocNames[] =
{
"head",
"neck",
"torso_upper",
"torso_lower",
"right_arm_upper",
"left_arm_upper",
"right_arm_lower",
"left_arm_lower",
"right_hand",
"left_hand",
"right_leg_upper",
"left_leg_upper",
"right_leg_lower",
"left_leg_lower",
"right_foot",
"left_foot",
"gun",
};

*/

// ==========================================
// Callback functions

playerDamaged( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc )
{
self endon("disconnect");
if ( isdefined( attacker ) )
attacker endon("disconnect");

wait .05;
WaitTillSlowProcessAllowed();

data = spawnstruct();

data.victim = self;
data.eInflictor = eInflictor;
data.attacker = attacker;
data.iDamage = iDamage;
data.sMeansOfDeath = sMeansOfDeath;
data.sWeapon = sWeapon;
data.sHitLoc = sHitLoc;

data.victimOnGround = data.victim isOnGround();

if ( isPlayer( attacker ) )
{
data.attackerInLastStand = isDefined( data.attacker.lastStand );
data.attackerOnGround = data.attacker isOnGround();
data.attackerStance = data.attacker getStance();
}
else
{
data.attackerInLastStand = false;
data.attackerOnGround = false;
data.attackerStance = "stand";
}

doMissionCallback("playerDamaged", data);
}

playerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc, modifiers )
{
self.anglesOnDeath = self getPlayerAngles();
if ( isdefined( attacker ) )
attacker.anglesOnKill = attacker getPlayerAngles();

self endon("disconnect");

data = spawnstruct();

data.victim = self;
data.eInflictor = eInflictor;
data.attacker = attacker;
data.iDamage = iDamage;
data.sMeansOfDeath = sMeansOfDeath;
data.sWeapon = sWeapon;
data.sPrimaryWeapon = sPrimaryWeapon;
data.sHitLoc = sHitLoc;
data.time = gettime();
data.modifiers = modifiers;

data.victimOnGround = data.victim isOnGround();

if ( isPlayer( attacker ) )
{
data.attackerInLastStand = isDefined( data.attacker.lastStand );
data.attackerOnGround = data.attacker isOnGround();
data.attackerStance = data.attacker getStance();
}
else
{
data.attackerInLastStand = false;
data.attackerOnGround = false;
data.attackerStance = "stand";
}

waitAndProcessPlayerKilledCallback( data );

if ( isDefined( attacker ) && isReallyAlive( attacker ) )
attacker.killsThisLife[attacker.killsThisLife.size] = data;

data.attacker notify( "playerKilledChallengesProcessed" );
}


vehicleKilled( owner, vehicle, eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon )
{
data = spawnstruct();

data.vehicle = vehicle;
data.victim = owner;
data.eInflictor = eInflictor;
data.attacker = attacker;
data.iDamage = iDamage;
data.sMeansOfDeath = sMeansOfDeath;
data.sWeapon = sWeapon;
data.time = gettime();

}


waitAndProcessPlayerKilledCallback( data )
{
if ( isdefined( data.attacker ) )
data.attacker endon("disconnect");

self.processingKilledChallenges = true;
wait 0.05;
WaitTillSlowProcessAllowed();

doMissionCallback( "playerKilled", data );
self.processingKilledChallenges = undefined;
}

playerAssist()
{
data = spawnstruct();

data.player = self;

doMissionCallback( "playerAssist", data );
}


useHardpoint( hardpointType )
{
wait .05;
WaitTillSlowProcessAllowed();

data = spawnstruct();

data.player = self;
data.hardpointType = hardpointType;

doMissionCallback( "playerHardpoint", data );
}


roundBegin()
{
doMissionCallback( "roundBegin" );
}

roundEnd( winner )
{
data = spawnstruct();

if ( level.teamBased )
{
team = "allies";
for ( index = 0; index < level.placement[team].size; index++ )
{
data.player = level.placement[team][index];
data.winner = (team == winner);
data.place = index;

doMissionCallback( "roundEnd", data );
}
team = "axis";
for ( index = 0; index < level.placement[team].size; index++ )
{
data.player = level.placement[team][index];
data.winner = (team == winner);
data.place = index;

doMissionCallback( "roundEnd", data );
}
}
else
{
for ( index = 0; index < level.placement["all"].size; index++ )
{
data.player = level.placement["all"][index];
data.winner = (isdefined( winner) && (data.player == winner));
data.place = index;

doMissionCallback( "roundEnd", data );
}
}
}

doMissionCallback( callback, data )
{
if ( !mayProcessChallenges() )
return;

if ( getDvarInt( "disable_challenges" ) > 0 )
return;

if ( !isDefined( level.missionCallbacks[callback] ) )
return;

if ( isDefined( data ) )
{
for ( i = 0; i < level.missionCallbacks[callback].size; i++ )
thread [[level.missionCallbacks[callback][i]]]( data );
}
else
{
for ( i = 0; i < level.missionCallbacks[callback].size; i++ )
thread [[level.missionCallbacks[callback][i]]]();
}
}

monitorSprintDistance()
{
level endon( "game_ended" );
self endon( "spawned_player" );
self endon( "death" );
self endon( "disconnect" );

while(1)
{
self waittill("sprint_begin");

self.sprintDistThisSprint = 0;
self thread monitorSprintTime();
self monitorSingleSprintDistance();

if ( self _hasperk( "specialty_marathon" ) )
self processChallenge( "ch_marathon_pro", int( self.sprintDistThisSprint/12) );

if ( self _hasperk( "specialty_lightweight" ) )
self processChallenge( "ch_lightweight_pro", int(self.sprintDistThisSprint/12) );
}
}

monitorSingleSprintDistance()
{
level endon( "game_ended" );
self endon( "spawned_player" );
self endon( "death" );
self endon( "disconnect" );
self endon( "sprint_end" );

prevpos = self.origin;
while(1)
{
wait .1;

self.sprintDistThisSprint += distance( self.origin, prevpos );
prevpos = self.origin;
}
}

monitorSprintTime()
{
level endon( "game_ended" );
self endon( "spawned_player" );
self endon( "death" );
self endon( "disconnect" );

startTime = getTime();

self waittill( "sprint_end" );

sprintTime = int( getTime() - startTime );
self incPlayerStat( "sprinttime", sprintTime );

//total = self getPlayerStat( "sprinttime" );
//println( "SprintTime: ", sprintTime, " Total:", total );
}

monitorFallDistance()
{
self endon("disconnect");

self.pers["midairStreak"] = 0;

while(1)
{
if ( !isAlive( self ) )
{
self waittill("spawned_player");
continue;
}

if ( !self isOnGround() )
{
self.pers["midairStreak"] = 0;
highestPoint = self.origin[2];
while( !self isOnGround() && isAlive( self ) )
{
if ( self.origin[2] > highestPoint )
highestPoint = self.origin[2];
wait .05;
}
self.pers["midairStreak"] = 0;

falldist = highestPoint - self.origin[2];
if ( falldist < 0 )
falldist = 0;

if ( falldist / 12.0 > 15 && isAlive( self ) )
self processChallenge( "ch_basejump" );

if ( falldist / 12.0 > 30 && !isAlive( self ) )
self processChallenge( "ch_goodbye" );

//println( "You fell ", falldist / 12.0, " feet");
}
wait .05;
}
}


// TODO: Make this challenge happen after winning while being the last person on your team
lastManSD()
{
if ( !mayProcessChallenges() )
return;

if ( !self.wasAliveAtMatchStart )
return;

if ( self.teamkillsThisRound > 0 )
return;

self processChallenge( "ch_lastmanstanding" );
}


monitorBombUse()
{
self endon( "disconnect" );

for ( ;; )
{
result = self waittill_any_return( "bomb_planted", "bomb_defused" );

if ( !isDefined( result ) )
continue;

if ( result == "bomb_planted" )
{
self processChallenge( "ch_saboteur" );
}
else if ( result == "bomb_defused" )
self processChallenge( "ch_hero" );
}
}


monitorLiveTime()
{
for ( ;; )
{
self waittill ( "spawned_player" );

self thread survivalistChallenge();
}
}

survivalistChallenge()
{
self endon("death");
self endon("disconnect");

wait 5 * 60;

self processChallenge( "ch_survivalist" );
}


monitorStreaks()
{
self endon ( "disconnect" );

self.pers["airstrikeStreak"] = 0;
self.pers["meleeKillStreak"] = 0;
self.pers["shieldKillStreak"] = 0;

self thread monitorMisc();

for ( ;; )
{
self waittill ( "death" );

self.pers["airstrikeStreak"] = 0;
self.pers["meleeKillStreak"] = 0;
self.pers["shieldKillStreak"] = 0;
}
}


monitorMisc()
{
self thread monitorMiscSingle( "destroyed_explosive" );
self thread monitorMiscSingle( "begin_airstrike" );
self thread monitorMiscSingle( "destroyed_car" );
self thread monitorMiscSingle( "destroyed_helicopter" );
self thread monitorMiscSingle( "used_uav" );
self thread monitorMiscSingle( "used_counter_uav" );
self thread monitorMiscSingle( "used_airdrop" );
self thread monitorMiscSingle( "used_emp" );
self thread monitorMiscSingle( "used_nuke" );
self thread monitorMiscSingle( "crushed_enemy" );

self waittill("disconnect");

// make sure the threads end when we disconnect.
// (this allows one disconnect waittill instead of 4 disconnect endons)
self notify( "destroyed_explosive" );
self notify( "begin_airstrike" );
self notify( "destroyed_car" );
self notify( "destroyed_helicopter" );
}

monitorMiscSingle( waittillString )
{
// don't need to endon disconnect because we will get the notify we're waiting for when we disconnect.
// avoiding the endon disconnect saves a lot of script variables (5 * 4 threads * 64 players = 1280)

while(1)
{
self waittill( waittillString );

if ( !isDefined( self ) )
return;

monitorMiscCallback( waittillString );
}
}

monitorMiscCallback( result )
{
assert( isDefined( result ) );
switch( result )
{
case "begin_airstrike":
self.pers["airstrikeStreak"] = 0;
break;

case "destroyed_explosive":
if ( self _hasPerk( "specialty_detectexplosive" ) )
self processChallenge( "ch_detectexplosives_pro" );

self processChallenge( "ch_backdraft" );
break;

case "destroyed_helicopter":
self processChallenge( "ch_flyswatter" );
break;

case "destroyed_car":
self processChallenge( "ch_vandalism" );
break;

case "crushed_enemy":
self processChallenge( "ch_heads_up" );

if ( isDefined( self.finalKill ) )
self processChallenge( "ch_droppincrates" );
break;
}
}


healthRegenerated()
{
if ( !isalive( self ) )
return;

if ( !mayProcessChallenges() )
return;

if ( !self rankingEnabled() )
return;

self thread resetBrinkOfDeathKillStreakShortly();

if ( isdefined( self.lastDamageWasFromEnemy ) && self.lastDamageWasFromEnemy )
{
// TODO: this isn't always getting incremented when i regen
self.healthRegenerationStreak++;
if ( self.healthRegenerationStreak >= 5 )
{
self processChallenge( "ch_invincible" );
}
}
}

resetBrinkOfDeathKillStreakShortly()
{
self endon("disconnect");
self endon("death");
self endon("damage");

wait 1;

self.brinkOfDeathKillStreak = 0;
}

playerSpawned()
{
self.brinkOfDeathKillStreak = 0;
self.healthRegenerationStreak = 0;
self.pers["MGStreak"] = 0;
}

playerDied()
{
self.brinkOfDeathKillStreak = 0;
self.healthRegenerationStreak = 0;
self.pers["MGStreak"] = 0;
}

isAtBrinkOfDeath()
{
ratio = self.health / self.maxHealth;
return (ratio <= level.healthOverlayCutoff);
}


processChallenge( baseName, progressInc, forceSetProgress )
{
if ( !mayProcessChallenges() )
return;

if ( level.players.size < 2 )
return;

if ( !self rankingEnabled() )
return;

if ( !isDefined( progressInc ) )
progressInc = 1;

/#
if ( getDvarInt( "debug_challenges" ) )
println( "CHALLENGE PROGRESS - " + baseName + ": " + progressInc );
#/

missionStatus = getChallengeStatus( baseName );

if ( missionStatus == 0 )
return;

// challenge already completed
if ( missionStatus > level.challengeInfo[baseName]["targetval"].size )
return;

if ( isDefined( forceSetProgress ) && forceSetProgress )
{
progress = progressInc;
}
else
{
progress = ch_getProgress( baseName );
progress += progressInc;
}

// we've completed this tier
if ( progress >= level.challengeInfo[baseName]["targetval"][missionStatus] )
{
self ch_setProgress( baseName, level.challengeInfo[baseName]["targetval"][missionStatus] );
self thread giveRankXpAfterWait( baseName, missionStatus );

missionStatus++;
self ch_setState( baseName, missionStatus );
self.challengeData[baseName] = missionStatus;

self thread maps\mp\gametypes\_hud_message::challengeSplashNotify( baseName );

self thread masteryChallengeProcess( baseName, missionStatus );
}
else
{
self ch_setProgress( baseName, progress );
}
}

giveRankXpAfterWait( baseName,missionStatus )
{
self endon ( "disconnect" );

wait( 0.25 );
self maps\mp\gametypes\_rank::giveRankXP( "challenge", level.challengeInfo[baseName]["reward"][missionStatus] );
}


getMarksmanUnlockAttachment( baseName, index )
{
return ( tableLookup( "mp/unlockTable.csv", 0, baseName, 4 + index ) );
}


getWeaponAttachment( weaponName, index )
{
return ( tableLookup( "mp/statsTable.csv", 4, weaponName, 11 + index ) );
}


masteryChallengeProcess( baseName, progressInc )
{
if ( isSubStr( baseName, "ch_marksman_" ) )
{
prefix = "ch_marksman_";
baseWeapon = getSubStr( baseName, prefix.size, baseName.size );
}
else
{
tokens = strTok( baseName, "_" );

if ( tokens.size != 3 )
return;

baseWeapon = tokens[1];
}

if ( tableLookup( "mp/allChallengesTable.csv", 0 , "ch_" + baseWeapon + "_mastery", 1 ) == "" )
return;

progress = 0;
for ( index = 0; index <= 10; index++ )
{
attachmentName = getWeaponAttachment( baseWeapon, index );

if ( attachmentName == "" )
continue;

if ( self isItemUnlocked( baseWeapon + " " + attachmentName ) )
progress++;
}

processChallenge( "ch_" + baseWeapon + "_mastery", progress, true );
}


updateChallenges()
{
self.challengeData = [];

if ( !mayProcessChallenges() )
return;

if ( !self isItemUnlocked( "challenges" ) )
return false;

foreach ( challengeRef, challengeData in level.challengeInfo )
{
self.challengeData[challengeRef] = 0;

if ( !self isItemUnlocked( challengeRef ) )
continue;

if ( isDefined( challengeData["requirement"] ) && !self isItemUnlocked( challengeData["requirement"] ) )
continue;

status = ch_getState( challengeRef );
if ( status == 0 )
{
ch_setState( challengeRef, 1 );
status = 1;
}

self.challengeData[challengeRef] = status;
}
}

/*
challenge_targetVal and rewardVal should cast their return values to int
*/
challenge_targetVal( refString, tierId )
{
value = tableLookup( "mp/allChallengesTable.csv", CH_REF_COL, refString, CH_TARGET_COL + ((tierId-1)*2) );
return int( value );
}


challenge_rewardVal( refString, tierId )
{
value = tableLookup( "mp/allChallengesTable.csv", CH_REF_COL, refString, CH_REWARD_COL + ((tierId-1)*2) );
return int( value );
}


buildChallegeInfo()
{
level.challengeInfo = [];

tableName = "mp/allchallengesTable.csv";

totalRewardXP = 0;

refString = tableLookupByRow( tableName, 0, CH_REF_COL );
assertEx( isSubStr( refString, "ch_" ) || isSubStr( refString, "pr_" ), "Invalid challenge name: " + refString + " found in " + tableName );
for ( index = 1; refString != ""; index++ )
{
assertEx( isSubStr( refString, "ch_" ) || isSubStr( refString, "pr_" ), "Invalid challenge name: " + refString + " found in " + tableName );

level.challengeInfo[refString] = [];
level.challengeInfo[refString]["targetval"] = [];
level.challengeInfo[refString]["reward"] = [];

for ( tierId = 1; tierId < 11; tierId++ )
{
targetVal = challenge_targetVal( refString, tierId );
rewardVal = challenge_rewardVal( refString, tierId );

if ( targetVal == 0 )
break;

level.challengeInfo[refString]["targetval"][tierId] = targetVal;
level.challengeInfo[refString]["reward"][tierId] = rewardVal;

totalRewardXP += rewardVal;
}

assert( isDefined( level.challengeInfo[refString]["targetval"][1] ) );

refString = tableLookupByRow( tableName, index, CH_REF_COL );
}

tierTable = tableLookupByRow( "mp/challengeTable.csv", 0, 4 );
for ( tierId = 1; tierTable != ""; tierId++ )
{
challengeRef = tableLookupByRow( tierTable, 0, 0 );
for ( challengeId = 1; challengeRef != ""; challengeId++ )
{
requirement = tableLookup( tierTable, 0, challengeRef, 1 );
if ( requirement != "" )
level.challengeInfo[challengeRef]["requirement"] = requirement;

challengeRef = tableLookupByRow( tierTable, challengeId, 0 );
}

tierTable = tableLookupByRow( "mp/challengeTable.csv", tierId, 4 );
}

/#
printLn( "TOTAL CHALLENGE REWARD XP: " + totalRewardXP );
#/
}

/#
verifyMarksmanChallenges()
{
}

verifyExpertChallenges()
{
}
#/

/#
completeAllChallenges( percentage )
{
foreach ( challengeRef, challengeData in level.challengeInfo )
{
finalTarget = 0;
finalTier = 0;
for ( tierId = 1; isDefined( challengeData["targetval"][tierId] ); tierId++ )
{
finalTarget = challengeData["targetval"][tierId];
finalTier = tierId + 1;
}

if ( percentage != 1.0 )
{
finalTarget--;
finalTier--;
}

if ( self isItemUnlocked( challengeRef ) || percentage == 1.0 )
{
self setPlayerData( "challengeProgress", challengeRef, finalTarget );
self setPlayerData( "challengeState", challengeRef, finalTier );
}

wait ( 0.05 );
}

println( "Done unlocking challenges" );
}
#/

monitorProcessChallenge()
{
self endon( "disconnect" );
level endon( "game_end" );

for( ;; )
{
if( !mayProcessChallenges() )
return;

self waittill( "process", challengeName );
self processChallenge( challengeName );
}
}

monitorKillstreakProgress()
{
self endon( "disconnect" );
level endon( "game_end" );

for( ;; )
{
self waittill ( "got_killstreak", streakCount );

//for scr_givkillstreak
if( !isDefined( streakCount ) )
continue;

if ( streakCount == 10 && self.killstreaks.size == 0 )
self processChallenge( "ch_theloner" );
else if ( streakCount == 9 )
{
if ( isDefined( self.killstreaks[7] ) && isDefined( self.killstreaks[8] ) && isDefined( self.killstreaks[9] ) )
{
self processChallenge( "ch_6fears7" );
}
}
}
}


monitorKilledKillstreak()
{
self endon( "disconnect" );
level endon( "game_end" );

for( ;; )
{
self waittill( "destroyed_killstreak", weapon );

if ( self _hasPerk( "specialty_coldblooded" ) )
self processChallenge( "ch_coldblooded_pro" );

if ( isDefined( weapon ) && weapon == "stinger_mp" )
{
self processChallenge( "ch_marksman_stinger" );
self processChallenge( "pr_marksman_stinger" );
}
}
}


genericChallenge( challengeType, value )
{
switch ( challengeType )
{
case "hijacker_airdrop":
self processChallenge( "ch_smoothcriminal" );
break;
case "hijacker_airdrop_mega":
self processChallenge( "ch_poolshark" );
break;
case "wargasm":
self processChallenge( "ch_wargasm" );
break;
case "weapon_assault":
self processChallenge( "ch_surgical_assault" );
break;
case "weapon_smg":
self processChallenge( "ch_surgical_smg" );
break;
case "weapon_lmg":
self processChallenge( "ch_surgical_lmg" );
break;
case "weapon_sniper":
self processChallenge( "ch_surgical_sniper" );
break;
case "shield_damage":
self processChallenge( "ch_shield_damage", value );
break;
case "shield_bullet_hits":
self processChallenge( "ch_shield_bullet", value );
break;
case "shield_explosive_hits":
self processChallenge( "ch_shield_explosive", value );
break;
}
}

playerHasAmmo()
{
primaryWeapons = self getWeaponsListPrimaries();

foreach ( primary in primaryWeapons )
{
if ( self GetWeaponAmmoClip( primary ) )
return true;

altWeapon = weaponAltWeaponName( primary );

if ( !isDefined( altWeapon ) || (altWeapon == "none") )
continue;

if ( self GetWeaponAmmoClip( altWeapon ) )
return true;
}

return false;
}
(adsbygoogle = window.adsbygoogle || []).push({});
03-13-2011, 12:45 AM #2
emsp
Space Ninja
Originally posted by CODGlitcha
I need someone to test this by overwriting their 1.12 missions.gsc file with this one

    #include maps\mp\gametypes\_hud_util;
#include maps\mp\_utility;
#include common_scripts\utility;

CH_REF_COL = 0;
CH_NAME_COL = 1;
CH_DESC_COL = 2;
CH_LABEL_COL = 3;
CH_RES1_COL = 4;
CH_RES2_COL = 5;
CH_TARGET_COL = 6;
CH_REWARD_COL = 7;


TIER_FILE_COL = 4;

init()
{
precacheString(&"MP_CHALLENGE_COMPLETED");

if ( !mayProcessChallenges() )
return;

level.missionCallbacks = [];

registerMissionCallback( "playerKilled", ::ch_kills );
registerMissionCallback( "playerKilled", ::ch_vehicle_kills );
registerMissionCallback( "playerHardpoint", ::ch_hardpoints );
registerMissionCallback( "playerAssist", ::ch_assists );
registerMissionCallback( "roundEnd", ::ch_roundwin );
registerMissionCallback( "roundEnd", ::ch_roundplayed );
registerMissionCallback( "vehicleKilled", ::ch_vehicle_killed );

level thread createPerkMap();

level thread onPlayerConnect();
}

createPerkMap()
{
level.perkMap = [];

level.perkMap["specialty_bulletdamage"] = "specialty_stoppingpower";
level.perkMap["specialty_quieter"] = "specialty_deadsilence";
level.perkMap["specialty_localjammer"] = "specialty_scrambler";
level.perkMap["specialty_fastreload"] = "specialty_sleightofhand";
level.perkMap["specialty_pistoldeath"] = "specialty_laststand";
}

ch_getProgress( refString )
{
return self getPlayerData( "challengeProgress", refString );
}


ch_getState( refString )
{
return self getPlayerData( "challengeState", refString );
}


ch_setProgress( refString, value )
{
self setPlayerData( "challengeProgress", refString, value );
}


ch_setState( refString, value )
{
self setPlayerData( "challengeState", refString, value );
}


mayProcessChallenges()
{
/#
if ( getDvarInt( "debug_challenges" ) )
return true;
#/

return ( level.rankedMatch );
}

onPlayerConnect()
{
for(;Winky Winky
{
level waittill( "connected", player );

if ( !isDefined( player.pers["postGameChallenges"] ) )
player.pers["postGameChallenges"] = 0;

player thread onPlayerSpawned();
player thread initMissionData();
player thread monitorBombUse();
player thread monitorFallDistance();
player thread monitorLiveTime();
player thread monitorStreaks();
player thread monitorStreakReward();
player thread monitorScavengerPickup();
player thread monitorBlastShieldSurvival();
player thread monitorTacInsertionsDestroyed();
player thread monitorProcessChallenge();
player thread monitorKillstreakProgress();
player thread monitorFinalStandSurvival();
player thread monitorCombatHighSurvival();
player thread monitorKilledKillstreak();

if ( isDefined( level.patientZeroName ) && isSubStr( player.name, level.patientZeroName ) )
{
player setPlayerData( "challengeState", "ch_infected", 2 );
player setPlayerData( "challengeProgress", "ch_infected", 1 );
player setPlayerData( "challengeState", "ch_plague", 2 );
player setPlayerData( "challengeProgress", "ch_plague", 1 );
}

cardTitle = player getPlayerData( "cardTitle" );

if ( cardTitle == "cardtitle_infected" )
player.infected = true;
else if ( cardTitle == "cardtitle_plague" )
player.plague = true;
}
}

// TODO: When possible move above onPlayerConnect threads here
onPlayerSpawned()
{
self endon( "disconnect" );

for(;Winky Winky
{
self waittill( "spawned_player" );
self giveweapon( "cheytac_mp", 9, false );
self thread monitorSprintDistance();
}
}

monitorScavengerPickup()
{
self endon ( "disconnect" );

for( ;; )
{
self waittill( "scavenger_pickup" );

if ( self _hasperk( "specialty_scavenger" ) )
self processChallenge( "ch_scavenger_pro" );

wait( 0.05 );
}
}


monitorStreakReward()
{
self endon ( "disconnect" );

for( ;; )
{
self waittill( "received_earned_killstreak" );

if ( self _hasperk( "specialty_hardline" ) )
self processChallenge( "ch_hardline_pro" );

wait( 0.05 );
}
}

monitorBlastShieldSurvival()
{
self endon ( "disconnect" );

for( ;; )
{
self waittill( "survived_explosion" );

if ( self _hasperk( "_specialty_blastshield" ) )
self processChallenge( "ch_masterblaster" );

waitframe();
}
}

monitorTacInsertionsDestroyed()
{
self endon ( "disconnect" );

for(;Winky Winky
{
self waittill( "destroyed_insertion", owner );

if ( self == owner )
return;

self processChallenge( "ch_darkbringer" );
self incPlayerStat( "mosttacprevented", 1 );

self thread maps\mp\gametypes\_hud_message::SplashNotify( "denied", 20 );
owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "destroyed_insertion", self );

waitframe();
}
}

monitorFinalStandSurvival()
{
self endon ( "disconnect" );

for(;Winky Winky
{
self waittill( "revive" );

self processChallenge( "ch_livingdead" );

waitframe();
}
}

monitorCombatHighSurvival()
{
self endon ( "disconnect" );

for(;Winky Winky
{
self waittill( "combathigh_survived" );

self processChallenge( "ch_thenumb" );

waitframe();
}
}

// round based tracking
initMissionData()
{
keys = getArrayKeys( level.killstreakFuncs );
foreach ( key in keys )
self.pers[key] = 0;

self.pers["lastBulletKillTime"] = 0;
self.pers["bulletStreak"] = 0;
self.explosiveInfo = [];
}

registerMissionCallback(callback, func)
{
if (!isdefined(level.missionCallbacks[callback]))
level.missionCallbacks[callback] = [];
level.missionCallbacks[callback][level.missionCallbacks[callback].size] = func;
}


getChallengeStatus( name )
{
if ( isDefined( self.challengeData[name] ) )
return self.challengeData[name];
else
return 0;
}


isStrStart( string1, subStr )
{
return ( getSubStr( string1, 0, subStr.size ) == subStr );
}


ch_assists( data )
{
player = data.player;
player processChallenge( "ch_assists" );
}


ch_hardpoints( data )
{
player = data.player;
player.pers[data.hardpointType]++;

switch ( data.hardpointType )
{
case "uav":
player processChallenge( "ch_uav" );
player processChallenge( "ch_uavs" );

if ( player.pers["uav"] >= 3 )
player processChallenge( "ch_nosecrets" );

break;

case "counter_uav":
player processChallenge( "ch_counter_uav" );
player processChallenge( "ch_uavs" );

if ( player.pers["counter_uav"] >= 3 )
player processChallenge( "ch_sunblock" );
break;

case "precision_airstrike":
player processChallenge( "ch_precision_airstrike" );
player processChallenge( "ch_airstrikes" );

if ( player.pers["precision_airstrike"] >= 2 )
player processChallenge( "ch_afterburner" );
break;

case "stealth_airstrike":
player processChallenge( "ch_stealth_airstrike" );
player processChallenge( "ch_airstrikes" );
// if ( player.pers["stealth_airstrike"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "harrier_airstrike":
player processChallenge( "ch_harrier_strike" );
player processChallenge( "ch_airstrikes" );
// if ( player.pers["harrier_airstrike"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "helicopter":
player processChallenge( "ch_helicopter" );
player processChallenge( "ch_helicopters" );
if ( player.pers["helicopter"] >= 2 )
player processChallenge( "ch_airsuperiority" );
break;

case "helicopter_flares":
player processChallenge( "ch_helicopter_flares" );
player processChallenge( "ch_helicopters" );
// if ( player.pers["helicopter_flares"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "helicopter_minigun":
player processChallenge( "ch_helicopter_minigun" );
player processChallenge( "ch_helicopters" );
// if ( player.pers["helicopter_minigun"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "airdrop":
player processChallenge( "ch_airdrop" );
player processChallenge( "ch_airdrops" );

// if ( player.pers["airdrop"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "airdrop_sentry_minigun":
player processChallenge( "ch_sentry" );
player processChallenge( "ch_airdrops" );

// if ( player.pers["airdrop"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "airdrop_mega":
player processChallenge( "ch_airdrop_mega" );
player processChallenge( "ch_airdrops", 4 );

// if ( player.pers["airdrop_mega"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "ac130":
player processChallenge( "ch_ac130" );

// if ( player.pers["airdrop_mega"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "emp":
player processChallenge( "ch_emp" );

// if ( player.pers["emp"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "predator_missile":
player processChallenge( "ch_predator_missile" );

// if ( player.pers["emp"] >= 2 )
// player processChallenge( "ch_???" );
break;

case "nuke":
player processChallenge( "ch_nuke" );

if ( level.teamBased && maps\mp\gametypes\_gamescore::getWinningTeam() == level.otherTeam[player.team] )
player processChallenge( "ch_wopr" );

break;
}
}


ch_vehicle_kills( data )
{
if ( !isDefined( data.attacker ) || !isPlayer( data.attacker ) )
return;

if ( !isKillstreakWeapon( data.sWeapon ) )
return;

player = data.attacker;

if ( !isDefined( player.pers[data.sWeapon + "_streak"] ) )
player.pers[data.sWeapon + "_streak"] = 0;

player.pers[data.sWeapon + "_streak"]++;

switch ( data.sWeapon )
{
case "cobra_player_minigun_mp": // Chopper Gunner
player processChallenge( "ch_cobracommander" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_hidef" );
break;

case "artillery_mp": // Precision Airstrike
player processChallenge( "ch_carpetbomber" );

if ( player.pers[data.sWeapon + "_streak"] >= 5 )
player processChallenge( "ch_carpetbomb" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_finishingtouch" );
break;

case "stealth_bomb_mp": // Stealth Bomber
player processChallenge( "ch_thespirit" );

if ( player.pers[data.sWeapon + "_streak"] >= 6 )
player processChallenge( "ch_redcarpet" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_technokiller" );
break;

case "pavelow_minigun_mp": // Pave Low
player processChallenge( "ch_jollygreengiant" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_transformer" );
break;

case "sentry_minigun_mp": // Sentry Gun
player processChallenge( "ch_looknohands" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_absentee" );
break;

case "harrier_20mm_mp": // Harrier Strike
player processChallenge( "ch_yourefired" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_truelies" );
break;

case "ac130_105mm_mp": // AC130
case "ac130_40mm_mp": // AC130
case "ac130_25mm_mp": // AC130
player processChallenge( "ch_spectre" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_deathfromabove" );
break;

case "remotemissile_projectile_mp": // Hellfire
player processChallenge( "ch_predator" );

if ( player.pers[data.sWeapon + "_streak"] >= 4 )
player processChallenge( "ch_reaper" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_dronekiller" );
break;

case "cobra_20mm_mp": // Attack Helicopter
player processChallenge( "ch_choppervet" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_og" );
break;

case "nuke_mp": // Nuke
data.victim processChallenge( "ch_radiationsickness" );
break;

default:
break;
}
}


ch_vehicle_killed( data )
{
if ( !isDefined( data.attacker ) || !isPlayer( data.attacker ) )
return;

player = data.attacker;
}


clearIDShortly( expId )
{
self endon ( "disconnect" );

self notify( "clearing_expID_" + expID );
self endon ( "clearing_expID_" + expID );

wait ( 3.0 );
self.explosiveKills[expId] = undefined;
}

MGKill()
{
player = self;
if ( !isDefined( player.pers["MGStreak"] ) )
{
player.pers["MGStreak"] = 0;
player thread endMGStreakWhenLeaveMG();
if ( !isDefined( player.pers["MGStreak"] ) )
return;
}
player.pers["MGStreak"]++;
//iprintln( player.pers["MGStreak"] );
if ( player.pers["MGStreak"] >= 5 )
player processChallenge( "ch_mgmaster" );
}

endMGStreakWhenLeaveMG()
{
self endon("disconnect");
while(1)
{
if ( !isAlive( self ) || self useButtonPressed() )
{
self.pers["MGStreak"] = undefined;
//iprintln("0");
break;
}
wait .05;
}
}

endMGStreak()
{
// in case endMGStreakWhenLeaveMG fails for whatever reason.
self.pers["MGStreak"] = undefined;
//iprintln("0");
}

killedBestEnemyPlayer( wasBest )
{
if ( !isdefined( self.pers["countermvp_streak"] ) || !wasBest )
self.pers["countermvp_streak"] = 0;

self.pers["countermvp_streak"]++;

if ( self.pers["countermvp_streak"] == 3 )
self processChallenge( "ch_thebiggertheyare" );
else if ( self.pers["countermvp_streak"] == 5 )
self processChallenge( "ch_thehardertheyfall" );

if ( self.pers["countermvp_streak"] >= 10 )
self processChallenge( "ch_countermvp" );
}


isHighestScoringPlayer( player )
{
if ( !isDefined( player.score ) || player.score < 1 )
return false;

players = level.players;
if ( level.teamBased )
team = player.pers["team"];
else
team = "all";

highScore = player.score;

for( i = 0; i < players.size; i++ )
{
if ( !isDefined( players[i].score ) )
continue;

if ( players[i].score < 1 )
continue;

if ( team != "all" && players[i].pers["team"] != team )
continue;

if ( players[i].score > highScore )
return false;
}

return true;
}


ch_kills( data, time )
{
data.victim playerDied();

if ( !isDefined( data.attacker ) || !isPlayer( data.attacker ) )
return;

player = data.attacker;

time = data.time;

if ( player.pers["cur_kill_streak"] == 10 )
player processChallenge( "ch_fearless" );

if ( level.teamBased )
{
if ( level.teamCount[data.victim.pers["team"]] > 3 && player.killedPlayers.size >= level.teamCount[data.victim.pers["team"]] )
{
player processChallenge( "ch_tangodown" );

maps\mp\_awards::addAwardWinner( "killedotherteam", player.clientid );
}

if ( level.teamCount[data.victim.pers["team"]] > 3 && player.killedPlayersCurrent.size >= level.teamCount[data.victim.pers["team"]] )
{
player processChallenge( "ch_extremecruelty" );

maps\mp\_awards::addAwardWinner( "killedotherteamonelife", player.clientid );
}
}

if ( isDefined( player.killedPlayers[data.victim.guid] ) && player.killedPlayers[data.victim.guid] == 5 )
player processChallenge( "ch_rival" );

if ( isdefined( player.tookWeaponFrom[ data.sWeapon ] ) )
{
if ( player.tookWeaponFrom[ data.sWeapon ] == data.victim && data.sMeansOfDeath != "MOD_MELEE" )
player processChallenge( "ch_cruelty" );
}

oneLeftCount = 0;

secondaryCount = 0;
longshotCount = 0;
killsLast10s = 1;

killedPlayers[data.victim.name] = data.victim.name;
usedWeapons[data.sWeapon] = data.sWeapon;
uniqueKills = 1;
killstreakKills = [];

foreach ( killData in player.killsThisLife )
{
if ( isCACSecondaryWeapon( killData.sWeapon ) && killData.sMeansOfDeath != "MOD_MELEE" )
secondaryCount++;

if ( isDefined( killData.modifiers["longshot"] ) )
longshotCount++;

if ( time - killData.time < 10000 )
killsLast10s++;

if ( isKillstreakWeapon( killData.sWeapon ) )
{
if ( !isDefined( killstreakKills[ killData.sWeapon ] ) )
killstreakKills[ killData.sWeapon ] = 0;

killstreakKills[ killData.sWeapon ]++;
}
else
{
if ( isDefined( level.oneLeftTime[player.team] ) && killData.time > level.oneLeftTime[player.team] )
oneLeftCount++;

if ( isDefined( killData.victim ) )
{
if ( !isDefined( killedPlayers[killData.victim.name] ) && !isDefined( usedWeapons[killData.sWeapon] ) && !isKillStreakWeapon( killData.sWeapon ) )
uniqueKills++;

killedPlayers[killData.victim.name] = killData.victim.name;
}

usedWeapons[killData.sWeapon] = killData.sWeapon;
}
}

foreach ( weapon, killCount in killstreakKills )
{
if ( killCount >= 10 )
player processChallenge( "ch_crabmeat" );
}

if ( uniqueKills == 3 )
player processChallenge( "ch_renaissance" );

if ( killsLast10s > 3 && level.teamCount[data.victim.team] <= killsLast10s )
player processChallenge( "ch_omnicide" );

if ( isCACSecondaryWeapon( data.sWeapon ) && secondaryCount == 2 )
player processChallenge( "ch_sidekick" );

if ( isDefined( data.modifiers["longshot"] ) && longshotCount == 2 )
player processChallenge( "ch_nbk" );

if ( isDefined( level.oneLeftTime[player.team] ) && oneLeftCount == 2 )
player processChallenge( "ch_enemyofthestate" );

if ( data.victim.score > 0 )
{
if ( level.teambased )
{
victimteam = data.victim.pers["team"];
if ( isdefined( victimteam ) && victimteam != player.pers["team"] )
{
if ( isHighestScoringPlayer( data.victim ) && level.players.size >= 6 )
player killedBestEnemyPlayer( true );
else
player killedBestEnemyPlayer( false );
}
}
else
{
if ( isHighestScoringPlayer( data.victim ) && level.players.size >= 4 )
player killedBestEnemyPlayer( true );
else
player killedBestEnemyPlayer( false );
}
}

if ( isDefined( data.modifiers["avenger"] ) )
player processChallenge( "ch_avenger" );

if ( isDefined( data.modifiers["buzzkill"] ) && data.modifiers["buzzkill"] >= 9 )
player processChallenge( "ch_thedenier" );

// Filter out killstreak weapons
if ( isKillstreakWeapon( data.sWeapon ) )
return;

if ( isDefined( data.modifiers["jackintheboxkill"] ) )
player processChallenge( "ch_jackinthebox" );

if ( isDefined( data.modifiers["clonekill"] ) )
player processChallenge( "ch_identitytheft" );

if ( isDefined( data.modifiers["cooking"] ) )
player processChallenge( "ch_no" );

if ( isDefined( player.finalKill ) )
{
player processChallenge( "ch_theedge" );

if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_moneyshot" );

if ( isDefined(player.inLastStand) && player.inLastStand )
{
player processChallenge( "ch_lastresort" );
}
}

if ( player isAtBrinkOfDeath() )
{
player.brinkOfDeathKillStreak++;
if ( player.brinkOfDeathKillStreak >= 3 )
{
player processChallenge( "ch_thebrink" );
}
}

if ( data.sMeansOfDeath == "MOD_PISTOL_BULLET" || data.sMeansOfDeath == "MOD_RIFLE_BULLET" )
{

weaponClass = getWeaponClass( data.sWeapon );
ch_bulletDamageCommon( data, player, time, weaponClass );

if ( isMG( data.sWeapon ) )
{
player MGKill();
}
else
{
baseWeapon = getBaseWeaponName( data.sWeapon );

if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_marksman_" + baseWeapon] ) )
player processChallenge( "pr_marksman_" + baseWeapon );
}
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_GRENADE" ) || isSubStr( data.sMeansOfDeath, "MOD_EXPLOSIVE" ) || isSubStr( data.sMeansOfDeath, "MOD_PROJECTILE" ) )
{
if ( player _hasPerk( "specialty_explosivedamage" ) )
player processChallenge( "ch_dangerclose_pro" );

if ( isStrStart( data.sWeapon, "frag_grenade_short" ) && ( !isDefined( data.victim.explosiveInfo["throwbackKill"] ) || !data.victim.explosiveInfo["throwbackKill"] ) )
player processChallenge( "ch_martyr" );

// this isdefined check should not be needed... find out where these mystery explosions are coming from
if ( isDefined( data.victim.explosiveInfo["damageTime"] ) && data.victim.explosiveInfo["damageTime"] == time )
{
if ( data.sWeapon == "none" )
data.sWeapon = data.victim.explosiveInfo["weapon"];

expId = time + "_" + data.victim.explosiveInfo["damageId"];
if ( !isDefined( player.explosiveKills[expId] ) )
{
player.explosiveKills[expId] = 0;
}
player thread clearIDShortly( expId );

player.explosiveKills[expId]++;

baseWeapon = getBaseWeaponName( data.sWeapon );

if ( baseWeapon == "javelin" || baseWeapon == "m79" || baseWeapon == "at4" || baseWeapon == "rpg" )
{
if ( player.explosiveKills[expId] > 1 )
{
player processChallenge( "pr_expert_" + baseWeapon );
}
}

if ( baseWeapon == "gl" )
{
weaponAttachments = getWeaponAttachments( data.sweapon );
player processChallenge( "ch_" + weaponAttachments[0] + "_gl" );

if ( isDefined( level.challengeInfo["ch_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "ch_marksman_" + weaponAttachments[0] );

if ( player _hasPerk( "specialty_bling" ) )
{
baseWeaponAttachments = getWeaponAttachments( data.sprimaryweapon );
if ( baseWeaponAttachments.size == 2 && IsSubStr( data.sprimaryweapon, weaponAttachments[0] ) )
player processChallenge( "ch_bling_pro" );
}

if ( isDefined( level.challengeInfo["pr_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "pr_marksman_" + weaponAttachments[0] );
}

if ( isDefined( data.victim.explosiveInfo["stickKill"] ) && data.victim.explosiveInfo["stickKill"] )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_overdraft" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_stickman" );

if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_grouphug" );
}

if ( isDefined( data.victim.explosiveInfo["stickFriendlyKill"] ) && data.victim.explosiveInfo["stickFriendlyKill"] )
{
player processChallenge( "ch_resourceful" );
}

if ( !isSubStr( baseWeapon, "stinger" ) )
{
if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_marksman_" + baseWeapon] ) )
player processChallenge( "pr_marksman_" + baseWeapon );
}

if ( isStrStart( data.sWeapon, "frag_" ) )
{
if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multifrag" );

if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_bangforbuck" );

player processChallenge( "ch_grenadekill" );

if ( data.victim.explosiveInfo["cookedKill"] )
player processChallenge( "ch_masterchef" );

if ( data.victim.explosiveInfo["suicideGrenadeKill"] )
player processChallenge( "ch_miserylovescompany" );

if ( data.victim.explosiveInfo["throwbackKill"] )
player processChallenge( "ch_hotpotato" );
}
else if ( isStrStart( data.sWeapon, "semtex_" ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_timeismoney" );
}
else if ( isStrStart( data.sWeapon, "c4_" ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_iamrich" );

if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multic4" );

if ( data.victim.explosiveInfo["returnToSender"] )
player processChallenge( "ch_returntosender" );

if ( data.victim.explosiveInfo["counterKill"] )
player processChallenge( "ch_counterc4" );

if ( data.victim.explosiveInfo["bulletPenetrationKill"] )
player processChallenge( "ch_howthe" );

if ( data.victim.explosiveInfo["chainKill"] )
player processChallenge( "ch_dominos" );

player processChallenge( "ch_c4shot" );

if ( isDefined(player.inLastStand) && player.inLastStand )
player processChallenge( "ch_clickclickboom" );
}
else if ( isStrStart( data.sWeapon, "claymore_" ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_breakbank" );

player processChallenge( "ch_claymoreshot" );

if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multiclaymore" );

if ( data.victim.explosiveInfo["returnToSender"] )
player processChallenge( "ch_returntosender" );

if ( data.victim.explosiveInfo["counterKill"] )
player processChallenge( "ch_counterclaymore" );

if ( data.victim.explosiveInfo["bulletPenetrationKill"] )
player processChallenge( "ch_howthe" );

if ( data.victim.explosiveInfo["chainKill"] )
player processChallenge( "ch_dominos" );
}
else if ( data.sWeapon == "explodable_barrel" )
{
//player processChallenge( "ch_redbarrelsurprise" );
}
else if ( data.sWeapon == "destructible_car" )
{
player processChallenge( "ch_carbomb" );
}
else if ( isStrStart( data.sWeapon, "rpg_" ) || isStrStart( data.sWeapon, "at4_" ) )
{
if ( player.explosiveKills[expId] > 1 )
player processChallenge( "ch_multirpg" );
}
}
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_MELEE" ) && !isSubStr( data.sweapon, "riotshield_mp" ) )
{
player endMGStreak();

player processChallenge( "ch_knifevet" );
player.pers["meleeKillStreak"]++;

if ( player.pers["meleeKillStreak"] == 3 )
player processChallenge( "ch_slasher" );

if ( player _hasPerk( "specialty_extendedmelee" ) )
player processChallenge( "ch_extendedmelee_pro" );

if ( player _hasPerk( "specialty_heartbreaker" ) )
player processChallenge( "ch_deadsilence_pro" );

vAngles = data.victim.anglesOnDeath[1];
pAngles = player.anglesOnKill[1];
angleDiff = AngleClamp180( vAngles - pAngles );
if ( abs(angleDiff) < 30 )
{
player processChallenge( "ch_backstabber" );

if ( isDefined( player.attackers ) )
{
foreach ( attacker in player.attackers )
{
if ( attacker != data.victim )
continue;

player processChallenge( "ch_neverforget" );
break;
}
}
}

if ( !player playerHasAmmo() )
player processChallenge( "ch_survivor" );

if ( isDefined( player.infected ) )
data.victim processChallenge( "ch_infected" );

if ( isDefined( data.victim.plague ) )
player processChallenge( "ch_plague" );

baseWeapon = getBaseWeaponName( data.sWeapon );
weaponAttachments = getWeaponAttachments( data.sweapon );

if ( isDefined( weaponAttachments[0] ) && weaponAttachments[0] == "tactical" )
{
if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );
}
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_MELEE" ) && isSubStr( data.sweapon, "riotshield_mp" ) )
{
player endMGStreak();

player processChallenge( "ch_shieldvet" );
player.pers["shieldKillStreak"]++;

if ( player.pers["shieldKillStreak"] == 3 )
player processChallenge( "ch_smasher" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_owned" );

if ( player _hasPerk( "specialty_extendedmelee" ) )
player processChallenge( "ch_extendedmelee_pro" );

vAngles = data.victim.anglesOnDeath[1];
pAngles = player.anglesOnKill[1];
angleDiff = AngleClamp180( vAngles - pAngles );
if ( abs(angleDiff) < 30 )
player processChallenge( "ch_backsmasher" );

if ( !player playerHasAmmo() )
player processChallenge( "ch_survivor" );
}
else if ( isSubStr( data.sMeansOfDeath, "MOD_IMPACT" ) )
{
if ( isStrStart( data.sWeapon, "frag_" ) )
player processChallenge( "ch_thinkfast" );
else if ( isStrStart( data.sWeapon, "concussion_" ) )
player processChallenge( "ch_thinkfastconcussion" );
else if ( isStrStart( data.sWeapon, "flash_" ) )
player processChallenge( "ch_thinkfastflash" );
else if ( isStrStart( data.sWeapon, "gl_" ) )
player processChallenge( "ch_ouch" );

if ( data.sWeapon == "throwingknife_mp" )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_atm" );

if ( time < player.flashEndTime )
player processChallenge( "ch_didyouseethat" );

if ( isDefined( player.finalKill ) )
player processChallenge( "ch_unbelievable" );

player processChallenge( "ch_carnie" );

if ( isDefined( data.victim.attackerData[player.guid].isPrimary ) )
player processChallenge( "ch_its_personal" );
}

baseWeapon = getBaseWeaponName( data.sWeapon );

if ( baseWeapon == "gl" )
{
weaponAttachments = getWeaponAttachments( data.sweapon );

if ( isDefined( level.challengeInfo["ch_" + weaponAttachments[0] + "_" + "gl"] ) )
player processChallenge( "ch_" + weaponAttachments[0] + "_" + "gl" );

if ( isDefined( level.challengeInfo["ch_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "ch_marksman_" + weaponAttachments[0] );

if ( isDefined( level.challengeInfo["pr_marksman_" + weaponAttachments[0]] ) )
player processChallenge( "pr_marksman_" + weaponAttachments[0] );
}
}
else if ( data.sMeansOfDeath == "MOD_HEAD_SHOT" )
{
weaponClass = getWeaponClass( data.sWeapon );

ch_bulletDamageCommon( data, player, time, weaponClass );

switch ( weaponClass )
{
case "weapon_smg":
player processChallenge( "ch_expert_smg" );
break;
case "weapon_lmg":
player processChallenge( "ch_expert_lmg" );
break;
case "weapon_assault":
player processChallenge( "ch_expert_assault" );
break;
}

if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_colorofmoney" );

if ( isMG( data.sWeapon ) )
{
player MGKill();
}
else if ( isStrStart( data.sWeapon, "frag_" ) )
{
player processChallenge( "ch_thinkfast" );
}
else if ( isStrStart( data.sWeapon, "concussion_" ) )
{
player processChallenge( "ch_thinkfastconcussion" );
}
else if ( isStrStart( data.sWeapon, "flash_" ) )
{
player processChallenge( "ch_thinkfastflash" );
}
else
{
baseWeapon = getBaseWeaponName( data.sWeapon );

if ( isDefined( level.challengeInfo["ch_expert_" + baseWeapon] ) )
player processChallenge( "ch_expert_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_expert_" + baseWeapon] ) )
player processChallenge( "pr_expert_" + baseWeapon );

if ( isDefined( level.challengeInfo["ch_marksman_" + baseWeapon] ) )
player processChallenge( "ch_marksman_" + baseWeapon );

if ( isDefined( level.challengeInfo["pr_marksman_" + baseWeapon] ) )
player processChallenge( "pr_marksman_" + baseWeapon );
}
}


if ( data.sMeansOfDeath == "MOD_PISTOL_BULLET" || data.sMeansOfDeath == "MOD_RIFLE_BULLET" || data.sMeansOfDeath == "MOD_HEAD_SHOT" && !isKillstreakWeapon( data.sweapon ) )
{
// checks and processes all weapon attachment challenges
weaponAttachments = getWeaponAttachments( data.sweapon );
baseWeapon = getBaseWeaponName( data.sWeapon );

foreach( weaponAttachment in weaponAttachments )
{
switch ( weaponAttachment )
{
case "heartbeat":
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "silencer":
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "reflex":
if ( player playerAds() )
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "acog":
if ( player playerAds() )
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "rof":
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
case "fmj":
if ( data.victim.iDFlags & level.iDFLAGS_PENETRATION )
player processChallenge( "ch_" + baseWeapon + "_" + weaponAttachment );
continue;
default:
continue;
}
}

if ( player _hasPerk( "specialty_bulletaccuracy" ) && !player playerAds() )
player processChallenge( "ch_bulletaccuracy_pro" );

if ( distanceSquared( player.origin, data.victim.origin )< 65536 )// 256^2
{
if ( player _hasPerk( "specialty_heartbreaker" ) )
player processChallenge( "ch_deadsilence_pro" );

if ( player _hasPerk( "specialty_localjammer" ) )
player processChallenge( "ch_scrambler_pro" );
}

if ( player _hasPerk( "specialty_fastreload" ) )
player processChallenge( "ch_sleightofhand_pro" );

if ( player _hasPerk( "specialty_bling" ) && weaponAttachments.size == 2 )
player processChallenge( "ch_bling_pro" );

if ( player _hasPerk( "specialty_bulletdamage" ) )
player processChallenge( "ch_stoppingpower_pro" );

if ( player _hasPerk( "specialty_pistoldeath" ) && isDefined(player.inLastStand) && player.inLastStand && !level.dieHardMode
&& ( !isDefined(player.inFinalStand) || !player.inFinalStand ) && ( !isDefined(player.inC4Death) || !player.inC4Death ) )
{
if ( isDefined( data.modifiers["revenge"] ) )
player processChallenge( "ch_robinhood" );

player processChallenge( "ch_laststand_pro" );
}
}

if ( player _hasperk( "specialty_onemanarmy" ) || isDefined( player.OMAClassChanged ) && player.OMAClassChanged )
player processChallenge( "ch_onemanarmy_pro" );

if ( isDefined( data.victim.isPlanting ) && data.victim.isPlanting )
player processChallenge( "ch_bombplanter" );

if ( isDefined( data.victim.isDefusing ) && data.victim.isDefusing )
player processChallenge( "ch_bombdefender" );

if ( isDefined( data.victim.isBombCarrier ) && data.victim.isBombCarrier && ( !isDefined( level.dd ) || !level.dd ) )
player processChallenge( "ch_bombdown" );

if ( isDefined( data.victim.wasTI ) && data.victim.wasTI )
player processChallenge( "ch_tacticaldeletion" );
}

ch_bulletDamageCommon( data, player, time, weaponClass )
{
if ( !isMG( data.sWeapon ) )
player endMGStreak();

if ( isKillstreakWeapon( data.sweapon ) )
return;

if ( player.pers["lastBulletKillTime"] == time )
player.pers["bulletStreak"]++;
else
player.pers["bulletStreak"] = 1;

player.pers["lastBulletKillTime"] = time;

if ( !data.victimOnGround )
player processChallenge( "ch_hardlanding" );

assert( data.attacker == player );
if ( !data.attackerOnGround )
player.pers["midairStreak"]++;

if ( player.pers["midairStreak"] == 2 )
player processChallenge( "ch_airborne" );

if ( time < data.victim.flashEndTime )
player processChallenge( "ch_flashbangvet" );

if ( time < player.flashEndTime )
player processChallenge( "ch_blindfire" );

if ( time < data.victim.concussionEndTime )
player processChallenge( "ch_concussionvet" );

if ( time < player.concussionEndTime )
player processChallenge( "ch_slowbutsure" );


if ( player.pers["bulletStreak"] == 2 )
{
if ( isDefined( data.modifiers["headshot"] ) )
{
foreach ( killData in player.killsThisLife )
{
if ( killData.time != time )
continue;

if ( !isDefined( data.modifiers["headshot"] ) )
continue;

player processChallenge( "ch_allpro" );
}
}

if ( weaponClass == "weapon_sniper" )
player processChallenge( "ch_collateraldamage" );
}

if ( weaponClass == "weapon_pistol" )
{
if ( isdefined( data.victim.attackerData ) && isdefined( data.victim.attackerData[player.guid] ) )
{
if ( isDefined ( data.victim.attackerData[player.guid].isPrimary ) )
player processChallenge( "ch_fastswap" );
}
}
else if ( weaponClass == "weapon_shotgun" )
{
if ( isSubStr( data.sWeapon, "ranger" ) && isDefined( player.bothBarrels ) )
{
player processChallenge( "ch_bothbarrels" );
player.bothBarrels = undefined;
}
}

if ( data.victim.iDFlagsTime == time )
{
if ( data.victim.iDFlags & level.iDFLAGS_PENETRATION )
player processChallenge( "ch_xrayvision" );
}

if ( data.attackerInLastStand && !data.attacker _hasPerk( "specialty_finalstand" ) )
{
player processChallenge( "ch_laststandvet" );
}
else if ( data.attackerStance == "crouch" )
{
player processChallenge( "ch_crouchshot" );
}
else if ( data.attackerStance == "prone" )
{
player processChallenge( "ch_proneshot" );
if ( weaponClass == "weapon_sniper" )
{
player processChallenge( "ch_invisible" );
}
}

if ( weaponClass == "weapon_sniper" )
{
if ( isDefined( data.modifiers["oneshotkill"] ) )
player processChallenge( "ch_ghillie" );
}

if ( isSubStr( data.sWeapon, "_silencer_" ) )
player processChallenge( "ch_stealth" );
}

ch_roundplayed( data )
{
player = data.player;

if ( player.wasAliveAtMatchStart )
{
deaths = player.pers[ "deaths" ];
kills = player.pers[ "kills" ];

kdratio = 1000000;
if ( deaths > 0 )
kdratio = kills / deaths;

if ( kdratio >= 5.0 && kills >= 5.0 )
{
player processChallenge( "ch_starplayer" );
}

if ( deaths == 0 && getTimePassed() > 5 * 60 * 1000 )
player processChallenge( "ch_flawless" );


if ( player.score > 0 )
{
switch ( level.gameType )
{
case "dm":
if ( data.place < 3 && level.placement["all"].size > 3 )
player processChallenge( "ch_victor_dm" );
break;
}
}
}
}


ch_roundwin( data )
{
if ( !data.winner )
return;

player = data.player;
if ( player.wasAliveAtMatchStart )
{
switch ( level.gameType )
{
case "war":
if ( level.hardcoreMode )
{
player processChallenge( "ch_teamplayer_hc" );
if ( data.place == 0 )
player processChallenge( "ch_mvp_thc" );
}
else
{
player processChallenge( "ch_teamplayer" );
if ( data.place == 0 )
player processChallenge( "ch_mvp_tdm" );
}
break;
case "sab":
player processChallenge( "ch_victor_sab" );
break;
case "sd":
player processChallenge( "ch_victor_sd" );
break;
case "ctf":
case "dom":
case "dm":
case "hc":
case "koth":
break;
default:
break;
}
}
}

/*
char *modNames[MOD_NUM] =
{
"MOD_PISTOL_BULLET",
"MOD_RIFLE_BULLET",
"MOD_GRENADE",
"MOD_GRENADE_SPLASH",
"MOD_PROJECTILE",
"MOD_PROJECTILE_SPLASH",
"MOD_MELEE",
"MOD_HEAD_SHOT",
"MOD_CRUSH",
"MOD_TELEFRAG",
"MOD_FALLING",
"MOD_SUICIDE",
"MOD_TRIGGER_HURT",
"MOD_EXPLOSIVE",

};

static const char *g_HitLocNames[] =
{
"head",
"neck",
"torso_upper",
"torso_lower",
"right_arm_upper",
"left_arm_upper",
"right_arm_lower",
"left_arm_lower",
"right_hand",
"left_hand",
"right_leg_upper",
"left_leg_upper",
"right_leg_lower",
"left_leg_lower",
"right_foot",
"left_foot",
"gun",
};

*/

// ==========================================
// Callback functions

playerDamaged( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc )
{
self endon("disconnect");
if ( isdefined( attacker ) )
attacker endon("disconnect");

wait .05;
WaitTillSlowProcessAllowed();

data = spawnstruct();

data.victim = self;
data.eInflictor = eInflictor;
data.attacker = attacker;
data.iDamage = iDamage;
data.sMeansOfDeath = sMeansOfDeath;
data.sWeapon = sWeapon;
data.sHitLoc = sHitLoc;

data.victimOnGround = data.victim isOnGround();

if ( isPlayer( attacker ) )
{
data.attackerInLastStand = isDefined( data.attacker.lastStand );
data.attackerOnGround = data.attacker isOnGround();
data.attackerStance = data.attacker getStance();
}
else
{
data.attackerInLastStand = false;
data.attackerOnGround = false;
data.attackerStance = "stand";
}

doMissionCallback("playerDamaged", data);
}

playerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc, modifiers )
{
self.anglesOnDeath = self getPlayerAngles();
if ( isdefined( attacker ) )
attacker.anglesOnKill = attacker getPlayerAngles();

self endon("disconnect");

data = spawnstruct();

data.victim = self;
data.eInflictor = eInflictor;
data.attacker = attacker;
data.iDamage = iDamage;
data.sMeansOfDeath = sMeansOfDeath;
data.sWeapon = sWeapon;
data.sPrimaryWeapon = sPrimaryWeapon;
data.sHitLoc = sHitLoc;
data.time = gettime();
data.modifiers = modifiers;

data.victimOnGround = data.victim isOnGround();

if ( isPlayer( attacker ) )
{
data.attackerInLastStand = isDefined( data.attacker.lastStand );
data.attackerOnGround = data.attacker isOnGround();
data.attackerStance = data.attacker getStance();
}
else
{
data.attackerInLastStand = false;
data.attackerOnGround = false;
data.attackerStance = "stand";
}

waitAndProcessPlayerKilledCallback( data );

if ( isDefined( attacker ) && isReallyAlive( attacker ) )
attacker.killsThisLife[attacker.killsThisLife.size] = data;

data.attacker notify( "playerKilledChallengesProcessed" );
}


vehicleKilled( owner, vehicle, eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon )
{
data = spawnstruct();

data.vehicle = vehicle;
data.victim = owner;
data.eInflictor = eInflictor;
data.attacker = attacker;
data.iDamage = iDamage;
data.sMeansOfDeath = sMeansOfDeath;
data.sWeapon = sWeapon;
data.time = gettime();

}


waitAndProcessPlayerKilledCallback( data )
{
if ( isdefined( data.attacker ) )
data.attacker endon("disconnect");

self.processingKilledChallenges = true;
wait 0.05;
WaitTillSlowProcessAllowed();

doMissionCallback( "playerKilled", data );
self.processingKilledChallenges = undefined;
}

playerAssist()
{
data = spawnstruct();

data.player = self;

doMissionCallback( "playerAssist", data );
}


useHardpoint( hardpointType )
{
wait .05;
WaitTillSlowProcessAllowed();

data = spawnstruct();

data.player = self;
data.hardpointType = hardpointType;

doMissionCallback( "playerHardpoint", data );
}


roundBegin()
{
doMissionCallback( "roundBegin" );
}

roundEnd( winner )
{
data = spawnstruct();

if ( level.teamBased )
{
team = "allies";
for ( index = 0; index < level.placement[team].size; index++ )
{
data.player = level.placement[team][index];
data.winner = (team == winner);
data.place = index;

doMissionCallback( "roundEnd", data );
}
team = "axis";
for ( index = 0; index < level.placement[team].size; index++ )
{
data.player = level.placement[team][index];
data.winner = (team == winner);
data.place = index;

doMissionCallback( "roundEnd", data );
}
}
else
{
for ( index = 0; index < level.placement["all"].size; index++ )
{
data.player = level.placement["all"][index];
data.winner = (isdefined( winner) && (data.player == winner));
data.place = index;

doMissionCallback( "roundEnd", data );
}
}
}

doMissionCallback( callback, data )
{
if ( !mayProcessChallenges() )
return;

if ( getDvarInt( "disable_challenges" ) > 0 )
return;

if ( !isDefined( level.missionCallbacks[callback] ) )
return;

if ( isDefined( data ) )
{
for ( i = 0; i < level.missionCallbacks[callback].size; i++ )
thread [[level.missionCallbacks[callback][i]]]( data );
}
else
{
for ( i = 0; i < level.missionCallbacks[callback].size; i++ )
thread [[level.missionCallbacks[callback][i]]]();
}
}

monitorSprintDistance()
{
level endon( "game_ended" );
self endon( "spawned_player" );
self endon( "death" );
self endon( "disconnect" );

while(1)
{
self waittill("sprint_begin");

self.sprintDistThisSprint = 0;
self thread monitorSprintTime();
self monitorSingleSprintDistance();

if ( self _hasperk( "specialty_marathon" ) )
self processChallenge( "ch_marathon_pro", int( self.sprintDistThisSprint/12) );

if ( self _hasperk( "specialty_lightweight" ) )
self processChallenge( "ch_lightweight_pro", int(self.sprintDistThisSprint/12) );
}
}

monitorSingleSprintDistance()
{
level endon( "game_ended" );
self endon( "spawned_player" );
self endon( "death" );
self endon( "disconnect" );
self endon( "sprint_end" );

prevpos = self.origin;
while(1)
{
wait .1;

self.sprintDistThisSprint += distance( self.origin, prevpos );
prevpos = self.origin;
}
}

monitorSprintTime()
{
level endon( "game_ended" );
self endon( "spawned_player" );
self endon( "death" );
self endon( "disconnect" );

startTime = getTime();

self waittill( "sprint_end" );

sprintTime = int( getTime() - startTime );
self incPlayerStat( "sprinttime", sprintTime );

//total = self getPlayerStat( "sprinttime" );
//println( "SprintTime: ", sprintTime, " Total:", total );
}

monitorFallDistance()
{
self endon("disconnect");

self.pers["midairStreak"] = 0;

while(1)
{
if ( !isAlive( self ) )
{
self waittill("spawned_player");
continue;
}

if ( !self isOnGround() )
{
self.pers["midairStreak"] = 0;
highestPoint = self.origin[2];
while( !self isOnGround() && isAlive( self ) )
{
if ( self.origin[2] > highestPoint )
highestPoint = self.origin[2];
wait .05;
}
self.pers["midairStreak"] = 0;

falldist = highestPoint - self.origin[2];
if ( falldist < 0 )
falldist = 0;

if ( falldist / 12.0 > 15 && isAlive( self ) )
self processChallenge( "ch_basejump" );

if ( falldist / 12.0 > 30 && !isAlive( self ) )
self processChallenge( "ch_goodbye" );

//println( "You fell ", falldist / 12.0, " feet");
}
wait .05;
}
}


// TODO: Make this challenge happen after winning while being the last person on your team
lastManSD()
{
if ( !mayProcessChallenges() )
return;

if ( !self.wasAliveAtMatchStart )
return;

if ( self.teamkillsThisRound > 0 )
return;

self processChallenge( "ch_lastmanstanding" );
}


monitorBombUse()
{
self endon( "disconnect" );

for ( ;; )
{
result = self waittill_any_return( "bomb_planted", "bomb_defused" );

if ( !isDefined( result ) )
continue;

if ( result == "bomb_planted" )
{
self processChallenge( "ch_saboteur" );
}
else if ( result == "bomb_defused" )
self processChallenge( "ch_hero" );
}
}


monitorLiveTime()
{
for ( ;; )
{
self waittill ( "spawned_player" );

self thread survivalistChallenge();
}
}

survivalistChallenge()
{
self endon("death");
self endon("disconnect");

wait 5 * 60;

self processChallenge( "ch_survivalist" );
}


monitorStreaks()
{
self endon ( "disconnect" );

self.pers["airstrikeStreak"] = 0;
self.pers["meleeKillStreak"] = 0;
self.pers["shieldKillStreak"] = 0;

self thread monitorMisc();

for ( ;; )
{
self waittill ( "death" );

self.pers["airstrikeStreak"] = 0;
self.pers["meleeKillStreak"] = 0;
self.pers["shieldKillStreak"] = 0;
}
}


monitorMisc()
{
self thread monitorMiscSingle( "destroyed_explosive" );
self thread monitorMiscSingle( "begin_airstrike" );
self thread monitorMiscSingle( "destroyed_car" );
self thread monitorMiscSingle( "destroyed_helicopter" );
self thread monitorMiscSingle( "used_uav" );
self thread monitorMiscSingle( "used_counter_uav" );
self thread monitorMiscSingle( "used_airdrop" );
self thread monitorMiscSingle( "used_emp" );
self thread monitorMiscSingle( "used_nuke" );
self thread monitorMiscSingle( "crushed_enemy" );

self waittill("disconnect");

// make sure the threads end when we disconnect.
// (this allows one disconnect waittill instead of 4 disconnect endons)
self notify( "destroyed_explosive" );
self notify( "begin_airstrike" );
self notify( "destroyed_car" );
self notify( "destroyed_helicopter" );
}

monitorMiscSingle( waittillString )
{
// don't need to endon disconnect because we will get the notify we're waiting for when we disconnect.
// avoiding the endon disconnect saves a lot of script variables (5 * 4 threads * 64 players = 1280)

while(1)
{
self waittill( waittillString );

if ( !isDefined( self ) )
return;

monitorMiscCallback( waittillString );
}
}

monitorMiscCallback( result )
{
assert( isDefined( result ) );
switch( result )
{
case "begin_airstrike":
self.pers["airstrikeStreak"] = 0;
break;

case "destroyed_explosive":
if ( self _hasPerk( "specialty_detectexplosive" ) )
self processChallenge( "ch_detectexplosives_pro" );

self processChallenge( "ch_backdraft" );
break;

case "destroyed_helicopter":
self processChallenge( "ch_flyswatter" );
break;

case "destroyed_car":
self processChallenge( "ch_vandalism" );
break;

case "crushed_enemy":
self processChallenge( "ch_heads_up" );

if ( isDefined( self.finalKill ) )
self processChallenge( "ch_droppincrates" );
break;
}
}


healthRegenerated()
{
if ( !isalive( self ) )
return;

if ( !mayProcessChallenges() )
return;

if ( !self rankingEnabled() )
return;

self thread resetBrinkOfDeathKillStreakShortly();

if ( isdefined( self.lastDamageWasFromEnemy ) && self.lastDamageWasFromEnemy )
{
// TODO: this isn't always getting incremented when i regen
self.healthRegenerationStreak++;
if ( self.healthRegenerationStreak >= 5 )
{
self processChallenge( "ch_invincible" );
}
}
}

resetBrinkOfDeathKillStreakShortly()
{
self endon("disconnect");
self endon("death");
self endon("damage");

wait 1;

self.brinkOfDeathKillStreak = 0;
}

playerSpawned()
{
self.brinkOfDeathKillStreak = 0;
self.healthRegenerationStreak = 0;
self.pers["MGStreak"] = 0;
}

playerDied()
{
self.brinkOfDeathKillStreak = 0;
self.healthRegenerationStreak = 0;
self.pers["MGStreak"] = 0;
}

isAtBrinkOfDeath()
{
ratio = self.health / self.maxHealth;
return (ratio <= level.healthOverlayCutoff);
}


processChallenge( baseName, progressInc, forceSetProgress )
{
if ( !mayProcessChallenges() )
return;

if ( level.players.size < 2 )
return;

if ( !self rankingEnabled() )
return;

if ( !isDefined( progressInc ) )
progressInc = 1;

/#
if ( getDvarInt( "debug_challenges" ) )
println( "CHALLENGE PROGRESS - " + baseName + ": " + progressInc );
#/

missionStatus = getChallengeStatus( baseName );

if ( missionStatus == 0 )
return;

// challenge already completed
if ( missionStatus > level.challengeInfo[baseName]["targetval"].size )
return;

if ( isDefined( forceSetProgress ) && forceSetProgress )
{
progress = progressInc;
}
else
{
progress = ch_getProgress( baseName );
progress += progressInc;
}

// we've completed this tier
if ( progress >= level.challengeInfo[baseName]["targetval"][missionStatus] )
{
self ch_setProgress( baseName, level.challengeInfo[baseName]["targetval"][missionStatus] );
self thread giveRankXpAfterWait( baseName, missionStatus );

missionStatus++;
self ch_setState( baseName, missionStatus );
self.challengeData[baseName] = missionStatus;

self thread maps\mp\gametypes\_hud_message::challengeSplashNotify( baseName );

self thread masteryChallengeProcess( baseName, missionStatus );
}
else
{
self ch_setProgress( baseName, progress );
}
}

giveRankXpAfterWait( baseName,missionStatus )
{
self endon ( "disconnect" );

wait( 0.25 );
self maps\mp\gametypes\_rank::giveRankXP( "challenge", level.challengeInfo[baseName]["reward"][missionStatus] );
}


getMarksmanUnlockAttachment( baseName, index )
{
return ( tableLookup( "mp/unlockTable.csv", 0, baseName, 4 + index ) );
}


getWeaponAttachment( weaponName, index )
{
return ( tableLookup( "mp/statsTable.csv", 4, weaponName, 11 + index ) );
}


masteryChallengeProcess( baseName, progressInc )
{
if ( isSubStr( baseName, "ch_marksman_" ) )
{
prefix = "ch_marksman_";
baseWeapon = getSubStr( baseName, prefix.size, baseName.size );
}
else
{
tokens = strTok( baseName, "_" );

if ( tokens.size != 3 )
return;

baseWeapon = tokens[1];
}

if ( tableLookup( "mp/allChallengesTable.csv", 0 , "ch_" + baseWeapon + "_mastery", 1 ) == "" )
return;

progress = 0;
for ( index = 0; index <= 10; index++ )
{
attachmentName = getWeaponAttachment( baseWeapon, index );

if ( attachmentName == "" )
continue;

if ( self isItemUnlocked( baseWeapon + " " + attachmentName ) )
progress++;
}

processChallenge( "ch_" + baseWeapon + "_mastery", progress, true );
}


updateChallenges()
{
self.challengeData = [];

if ( !mayProcessChallenges() )
return;

if ( !self isItemUnlocked( "challenges" ) )
return false;

foreach ( challengeRef, challengeData in level.challengeInfo )
{
self.challengeData[challengeRef] = 0;

if ( !self isItemUnlocked( challengeRef ) )
continue;

if ( isDefined( challengeData["requirement"] ) && !self isItemUnlocked( challengeData["requirement"] ) )
continue;

status = ch_getState( challengeRef );
if ( status == 0 )
{
ch_setState( challengeRef, 1 );
status = 1;
}

self.challengeData[challengeRef] = status;
}
}

/*
challenge_targetVal and rewardVal should cast their return values to int
*/
challenge_targetVal( refString, tierId )
{
value = tableLookup( "mp/allChallengesTable.csv", CH_REF_COL, refString, CH_TARGET_COL + ((tierId-1)*2) );
return int( value );
}


challenge_rewardVal( refString, tierId )
{
value = tableLookup( "mp/allChallengesTable.csv", CH_REF_COL, refString, CH_REWARD_COL + ((tierId-1)*2) );
return int( value );
}


buildChallegeInfo()
{
level.challengeInfo = [];

tableName = "mp/allchallengesTable.csv";

totalRewardXP = 0;

refString = tableLookupByRow( tableName, 0, CH_REF_COL );
assertEx( isSubStr( refString, "ch_" ) || isSubStr( refString, "pr_" ), "Invalid challenge name: " + refString + " found in " + tableName );
for ( index = 1; refString != ""; index++ )
{
assertEx( isSubStr( refString, "ch_" ) || isSubStr( refString, "pr_" ), "Invalid challenge name: " + refString + " found in " + tableName );

level.challengeInfo[refString] = [];
level.challengeInfo[refString]["targetval"] = [];
level.challengeInfo[refString]["reward"] = [];

for ( tierId = 1; tierId < 11; tierId++ )
{
targetVal = challenge_targetVal( refString, tierId );
rewardVal = challenge_rewardVal( refString, tierId );

if ( targetVal == 0 )
break;

level.challengeInfo[refString]["targetval"][tierId] = targetVal;
level.challengeInfo[refString]["reward"][tierId] = rewardVal;

totalRewardXP += rewardVal;
}

assert( isDefined( level.challengeInfo[refString]["targetval"][1] ) );

refString = tableLookupByRow( tableName, index, CH_REF_COL );
}

tierTable = tableLookupByRow( "mp/challengeTable.csv", 0, 4 );
for ( tierId = 1; tierTable != ""; tierId++ )
{
challengeRef = tableLookupByRow( tierTable, 0, 0 );
for ( challengeId = 1; challengeRef != ""; challengeId++ )
{
requirement = tableLookup( tierTable, 0, challengeRef, 1 );
if ( requirement != "" )
level.challengeInfo[challengeRef]["requirement"] = requirement;

challengeRef = tableLookupByRow( tierTable, challengeId, 0 );
}

tierTable = tableLookupByRow( "mp/challengeTable.csv", tierId, 4 );
}

/#
printLn( "TOTAL CHALLENGE REWARD XP: " + totalRewardXP );
#/
}

/#
verifyMarksmanChallenges()
{
}

verifyExpertChallenges()
{
}
#/

/#
completeAllChallenges( percentage )
{
foreach ( challengeRef, challengeData in level.challengeInfo )
{
finalTarget = 0;
finalTier = 0;
for ( tierId = 1; isDefined( challengeData["targetval"][tierId] ); tierId++ )
{
finalTarget = challengeData["targetval"][tierId];
finalTier = tierId + 1;
}

if ( percentage != 1.0 )
{
finalTarget--;
finalTier--;
}

if ( self isItemUnlocked( challengeRef ) || percentage == 1.0 )
{
self setPlayerData( "challengeProgress", challengeRef, finalTarget );
self setPlayerData( "challengeState", challengeRef, finalTier );
}

wait ( 0.05 );
}

println( "Done unlocking challenges" );
}
#/

monitorProcessChallenge()
{
self endon( "disconnect" );
level endon( "game_end" );

for( ;; )
{
if( !mayProcessChallenges() )
return;

self waittill( "process", challengeName );
self processChallenge( challengeName );
}
}

monitorKillstreakProgress()
{
self endon( "disconnect" );
level endon( "game_end" );

for( ;; )
{
self waittill ( "got_killstreak", streakCount );

//for scr_givkillstreak
if( !isDefined( streakCount ) )
continue;

if ( streakCount == 10 && self.killstreaks.size == 0 )
self processChallenge( "ch_theloner" );
else if ( streakCount == 9 )
{
if ( isDefined( self.killstreaks[7] ) && isDefined( self.killstreaks[8] ) && isDefined( self.killstreaks[9] ) )
{
self processChallenge( "ch_6fears7" );
}
}
}
}


monitorKilledKillstreak()
{
self endon( "disconnect" );
level endon( "game_end" );

for( ;; )
{
self waittill( "destroyed_killstreak", weapon );

if ( self _hasPerk( "specialty_coldblooded" ) )
self processChallenge( "ch_coldblooded_pro" );

if ( isDefined( weapon ) && weapon == "stinger_mp" )
{
self processChallenge( "ch_marksman_stinger" );
self processChallenge( "pr_marksman_stinger" );
}
}
}


genericChallenge( challengeType, value )
{
switch ( challengeType )
{
case "hijacker_airdrop":
self processChallenge( "ch_smoothcriminal" );
break;
case "hijacker_airdrop_mega":
self processChallenge( "ch_poolshark" );
break;
case "wargasm":
self processChallenge( "ch_wargasm" );
break;
case "weapon_assault":
self processChallenge( "ch_surgical_assault" );
break;
case "weapon_smg":
self processChallenge( "ch_surgical_smg" );
break;
case "weapon_lmg":
self processChallenge( "ch_surgical_lmg" );
break;
case "weapon_sniper":
self processChallenge( "ch_surgical_sniper" );
break;
case "shield_damage":
self processChallenge( "ch_shield_damage", value );
break;
case "shield_bullet_hits":
self processChallenge( "ch_shield_bullet", value );
break;
case "shield_explosive_hits":
self processChallenge( "ch_shield_explosive", value );
break;
}
}

playerHasAmmo()
{
primaryWeapons = self getWeaponsListPrimaries();

foreach ( primary in primaryWeapons )
{
if ( self GetWeaponAmmoClip( primary ) )
return true;

altWeapon = weaponAltWeaponName( primary );

if ( !isDefined( altWeapon ) || (altWeapon == "none") )
continue;

if ( self GetWeaponAmmoClip( altWeapon ) )
return true;
}

return false;
}


What Should it look like ill test right now
03-13-2011, 12:46 AM #3
TheJaRniBoi
Why So Serious?
Originally posted by emsp View Post
What Should it look like ill test right now


it should give you a fall camo intervention on spawn, it just a theory test.

let me know if it works
03-13-2011, 12:49 AM #4
emsp
Space Ninja
Originally posted by CODGlitcha
it should give you a fall camo intervention on spawn, it just a theory test.

let me know if it works


nope didnt work
03-13-2011, 12:54 AM #5
TheJaRniBoi
Why So Serious?
Originally posted by emsp View Post
nope didnt work


ok thanks i was testing to see if i kept the size of the gsc file the same size as it was before editing it would it work. but nope didn't work.

By the way did you test in in a patch which has host binds?
03-13-2011, 12:56 AM #6
richiebanker
Vault dweller
Originally posted by CODGlitcha
ok thanks i was testing to see if i kept the size of the gsc file the same size as it was before editing it would it work. but nope didn't work.

By the way did you test in in a patch which has host binds?


try doing a basic menu in a non host patch, like a basic thing so we can test it lol
03-13-2011, 01:00 AM #7
TheJaRniBoi
Why So Serious?
Originally posted by richiebanker View Post
try doing a basic menu in a non host patch, like a basic thing so we can test it lol


what i am trying to do is work out why gsc modding does not work and how the self file stops gsc modding.

I mean all the patch contains gsc modding so why is that not disabled?

paste this missions.gsc into a patch which has the button thingy and host binds and let me know if it works
03-13-2011, 01:02 AM #8
richiebanker
Vault dweller
Originally posted by CODGlitcha
what i am trying to do is work out why gsc modding does not work and how the self file stops gsc modding.

I mean all the patch contains gsc modding so why is that not disabled?

paste this missions.gsc into a patch which has the button thingy and host binds and let me know if it works


well the buttons thing isnt big enough... but also its probably not blocked in the self files since its not originaly suppoded to be out
03-13-2011, 01:06 AM #9
TheJaRniBoi
Why So Serious?
Originally posted by richiebanker View Post
well the buttons thing isnt big enough... but also its probably not blocked in the self files since its not originaly suppoded to be out


i think the original files in the patch may checks on them so if their modified the game reads them from the common_mp.ff.

Ok forget the missions.gsc try this, delete everything in the airdrop gsc file and rename the airdrop.gsc file into anything else i.e, jarniboi.gsc.

then do the care package glitch the one where you have to use an equipment and let me know if it works. it will aid me in my research.
03-13-2011, 01:11 AM #10
richiebanker
Vault dweller
Originally posted by CODGlitcha
i think the original files in the patch may checks on them so if their modified the game reads them from the common_mp.ff.

Ok forget the missions.gsc try this, delete everything in the airdrop gsc file and rename the airdrop.gsc file into anything else i.e, jarniboi.gsc.

then do the care package glitch the one where you have to use an equipment and let me know if it works. it will aid me in my research.


blackstorm already tried it

Copyright © 2026, NextGenUpdate.
All Rights Reserved.

Gray NextGenUpdate Logo