1695 lines
56 KiB
Plaintext
1695 lines
56 KiB
Plaintext
#using scripts\codescripts\struct;
|
|
|
|
#using scripts\shared\callbacks_shared;
|
|
#using scripts\shared\challenges_shared;
|
|
#using scripts\shared\killstreaks_shared;
|
|
#using scripts\shared\rank_shared;
|
|
#using scripts\shared\scoreevents_shared;
|
|
#using scripts\shared\system_shared;
|
|
#using scripts\shared\util_shared;
|
|
#using scripts\shared\abilities\_ability_player;
|
|
#using scripts\shared\weapons\_weapon_utils;
|
|
|
|
|
|
|
|
|
|
#using scripts\mp\gametypes\_globallogic_score;
|
|
|
|
#using scripts\mp\_challenges;
|
|
#using scripts\mp\_util;
|
|
#using scripts\mp\killstreaks\_killstreaks;
|
|
#using scripts\mp\_teamops;
|
|
|
|
|
|
|
|
#namespace scoreevents;
|
|
|
|
function autoexec __init__sytem__() { system::register("scoreevents",&__init__,undefined,undefined); }
|
|
|
|
function __init__()
|
|
{
|
|
callback::on_start_gametype( &init );
|
|
}
|
|
|
|
function init()
|
|
{
|
|
level.scoreEventCallbacks = [];
|
|
level.scoreEventGameEndCallback =&onGameEnd;
|
|
|
|
registerScoreEventCallback( "playerKilled", &scoreevents::scoreEventPlayerKill );
|
|
}
|
|
function scoreEventTableLookupInt( index, scoreEventColumn )
|
|
{
|
|
return int( tableLookup( getScoreEventTableName(), 0, index, scoreEventColumn ) );
|
|
}
|
|
|
|
function scoreEventTableLookup( index, scoreEventColumn )
|
|
{
|
|
return tableLookup( getScoreEventTableName(), 0, index, scoreEventColumn );
|
|
}
|
|
|
|
function registerScoreEventCallback( callback, func )
|
|
{
|
|
if ( !isdefined( level.scoreEventCallbacks[callback] ) )
|
|
{
|
|
level.scoreEventCallbacks[callback] = [];
|
|
}
|
|
level.scoreEventCallbacks[callback][level.scoreEventCallbacks[callback].size] = func;
|
|
}
|
|
|
|
function scoreEventPlayerKill( data, time )
|
|
{
|
|
victim = data.victim;
|
|
attacker = data.attacker;
|
|
time = data.time;
|
|
level.numKills++;
|
|
attacker.lastKilledPlayer = victim;
|
|
wasDefusing = data.wasDefusing;
|
|
wasPlanting = data.wasPlanting;
|
|
victimWasOnGround = data.victimOnGround;
|
|
attackerWasOnGround = data.attackerOnGround;
|
|
meansOfDeath = data.sMeansOfDeath;
|
|
attackerTraversing = data.attackerTraversing;
|
|
attackerWallRunning = data.attackerWallRunning;
|
|
attackerDoubleJumping = data.attackerDoubleJumping;
|
|
attackerSliding = data.attackerSliding;
|
|
victimWasWallRunning = data.victimWasWallRunning;
|
|
victimWasDoubleJumping = data.victimWasDoubleJumping;
|
|
attackerSpeedburst = data.attackerSpeedburst;
|
|
victimSpeedburst = data.victimSpeedburst;
|
|
victimCombatEfficieny = data.victimCombatEfficieny;
|
|
attackerflashbackTime = data.attackerflashbackTime;
|
|
victimflashbackTime = data.victimflashbackTime;
|
|
victimSpeedburstLastOnTime = data.victimSpeedburstLastOnTime;
|
|
victimCombatEfficiencyLastOnTime = data.victimCombatEfficiencyLastOnTime;
|
|
victimVisionPulseActivateTime = data.victimVisionPulseActivateTime;
|
|
attackerVisionPulseActivateTime = data.attackerVisionPulseActivateTime;
|
|
victimVisionPulseActivateTime = data.victimVisionPulseActivateTime;
|
|
attackerVisionPulseArray = data.attackerVisionPulseArray;
|
|
victimVisionPulseArray = data.victimVisionPulseArray;
|
|
attackerVisionPulseOriginArray = data.attackerVisionPulseOriginArray;
|
|
victimVisionPulseOriginArray = data.victimVisionPulseOriginArray;
|
|
attackerVisionPulseOrigin = data.attackerVisionPulseOrigin;
|
|
victimVisionPulseOrigin = data.victimVisionPulseOrigin;
|
|
attackerWasFlashed = data.attackerWasFlashed;
|
|
attackerWasConcussed = data.attackerWasConcussed;
|
|
victimWasUnderwater = data.wasUnderwater;
|
|
victimHeroAbilityActive = data.victimHeroAbilityActive;
|
|
victimHeroAbility = data.victimHeroAbility;
|
|
attackerHeroAbilityActive = data.attackerHeroAbilityActive;
|
|
attackerHeroAbility = data.attackerHeroAbility;
|
|
attackerWasHeatWaveStunned = data.attackerWasHeatWaveStunned;
|
|
victimWasHeatWaveStunned = data.victimWasHeatWaveStunned;
|
|
victimElectrifiedBy = data.victimElectrifiedBy;
|
|
victimWasInSlamState = data.victimWasInSlamState;
|
|
victimBledOut = data.bledOut;
|
|
victimWasLungingWithArmBlades = data.victimWasLungingWithArmBlades;
|
|
victimPowerArmorLastTookDamageTime = data.victimPowerArmorLastTookDamageTime;
|
|
victimHeroWeaponKillsThisActivation = data.victimHeroWeaponKillsThisActivation;
|
|
victimGadgetPower = data.victimGadgetPower;
|
|
victimGadgetWasActiveLastDamage = ( data.victimGadgetWasActiveLastDamage === true );
|
|
victimIsThiefOrRoulette = data.victimIsThiefOrRoulette;
|
|
attackerIsRoulette = data.attackerIsRoulette;
|
|
victimHeroAbilityName = data.victimHeroAbilityName; // note that victim hero ability name cannot be reliably taken from victimHeroAbility, so this is done instead
|
|
attackerInVehicleArchetype = data.attackerInVehicleArchetype;
|
|
if ( isdefined( victimHeroAbilityName ) )
|
|
victimHeroAbilityEquipped = GetWeapon( victimHeroAbilityName );
|
|
|
|
if ( victimBledOut == true ) // do not process player killed score events if the player bled out
|
|
return;
|
|
|
|
exlosiveDamage = false;
|
|
attackerShotVictim = ( meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_RIFLE_BULLET" || meansOfDeath == "MOD_HEAD_SHOT" );
|
|
|
|
weapon = level.weaponNone;
|
|
inflictor = data.eInflictor;
|
|
isGrenade = false;
|
|
if ( isdefined( data.weapon ) )
|
|
{
|
|
weapon = data.weapon;
|
|
weaponClass = util::getWeaponClass( data.weapon );
|
|
isGrenade = weapon.isGrenadeWeapon;
|
|
killstreak = killstreaks::get_from_weapon( data.weapon );
|
|
}
|
|
|
|
victim.anglesOnDeath = victim getPlayerAngles();
|
|
|
|
if ( meansOfDeath == "MOD_GRENADE" || meansOfDeath == "MOD_GRENADE_SPLASH" || meansOfDeath == "MOD_EXPLOSIVE" || meansOfDeath == "MOD_EXPLOSIVE_SPLASH" || meansOfDeath == "MOD_PROJECTILE" || meansOfDeath == "MOD_PROJECTILE_SPLASH" )
|
|
{
|
|
if ( weapon == level.weaponNone && isdefined( data.victim.explosiveInfo["weapon"] ) )
|
|
weapon = data.victim.explosiveInfo["weapon"];
|
|
|
|
exlosiveDamage = true;
|
|
}
|
|
|
|
|
|
if ( !isdefined( killstreak ) )
|
|
{
|
|
if ( level.teamBased )
|
|
{
|
|
if ( isdefined( victim.lastKillTime ) && ( victim.lastKillTime > time - 3000 ) )
|
|
{
|
|
if ( isdefined( victim.lastkilledplayer ) && victim.lastkilledplayer util::IsEnemyPlayer( attacker ) == false && attacker != victim.lastkilledplayer )
|
|
{
|
|
processScoreEvent( "kill_enemy_who_killed_teammate", attacker, victim, weapon );
|
|
victim RecordKillModifier("avenger");
|
|
}
|
|
}
|
|
|
|
if ( isdefined( victim.damagedPlayers ) )
|
|
{
|
|
keys = getarraykeys(victim.damagedPlayers);
|
|
|
|
for ( i = 0; i < keys.size; i++ )
|
|
{
|
|
key = keys[i];
|
|
if ( key == attacker.clientid )
|
|
continue;
|
|
|
|
if ( !isdefined( victim.damagedPlayers[key].entity ) )
|
|
continue;
|
|
|
|
if ( attacker util::IsEnemyPlayer( victim.damagedPlayers[key].entity ) )
|
|
continue;
|
|
|
|
if ( ( time - victim.damagedPlayers[key].time ) < 1000 )
|
|
{
|
|
processScoreEvent( "kill_enemy_injuring_teammate", attacker, victim, weapon );
|
|
if ( isdefined( victim.damagedPlayers[key].entity ) )
|
|
{
|
|
victim.damagedPlayers[key].entity.lastRescuedBy = attacker;
|
|
victim.damagedPlayers[key].entity.lastRescuedTime = time;
|
|
}
|
|
victim RecordKillModifier("defender");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( isGrenade == false || ( weapon.name == "hero_gravityspikes" ) )
|
|
{
|
|
if ( victimWasDoubleJumping == true )
|
|
{
|
|
if ( attackerDoubleJumping == true )
|
|
{
|
|
processScoreEvent( "kill_enemy_while_both_in_air", attacker, victim, weapon );
|
|
}
|
|
|
|
processScoreEvent( "kill_enemy_that_is_in_air", attacker, victim, weapon );
|
|
attacker addPlayerStat( "kill_enemy_that_in_air", 1 );
|
|
}
|
|
|
|
if ( attackerDoubleJumping == true )
|
|
{
|
|
processScoreEvent( "kill_enemy_while_in_air", attacker, victim, weapon );
|
|
attacker addPlayerStat( "kill_while_in_air", 1 );
|
|
}
|
|
|
|
if ( victimWasWallRunning == true )
|
|
{
|
|
processScoreEvent( "kill_enemy_that_is_wallrunning", attacker, victim, weapon );
|
|
attacker addPlayerStat( "kill_enemy_thats_wallrunning", 1 );
|
|
}
|
|
|
|
if ( attackerWallRunning == true )
|
|
{
|
|
processScoreEvent( "kill_enemy_while_wallrunning", attacker, victim, weapon );
|
|
attacker addPlayerStat( "kill_while_wallrunning", 1 );
|
|
}
|
|
|
|
if ( attackerSliding == true )
|
|
{
|
|
processScoreEvent( "kill_enemy_while_sliding", attacker, victim, weapon );
|
|
attacker addPlayerStat( "kill_while_sliding", 1 );
|
|
}
|
|
|
|
if ( attackerTraversing == true )
|
|
{
|
|
processScoreEvent( "traversal_kill", attacker, victim, weapon );
|
|
attacker addPlayerStat( "kill_while_mantling", 1 );
|
|
}
|
|
|
|
if ( attackerWasFlashed )
|
|
{
|
|
processScoreEvent( "kill_enemy_while_flashbanged", attacker, victim, weapon );
|
|
}
|
|
|
|
if ( attackerWasConcussed )
|
|
{
|
|
processScoreEvent( "kill_enemy_while_stunned", attacker, victim, weapon );
|
|
}
|
|
|
|
if ( attackerWasHeatWaveStunned )
|
|
{
|
|
processScoreEvent( "kill_enemy_that_heatwaved_you", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
}
|
|
|
|
if ( victimWasHeatWaveStunned )
|
|
{
|
|
if ( isdefined( victim._heat_wave_stunned_by ) &&
|
|
isdefined( victim._heat_wave_stunned_by[attacker.clientid] ) &&
|
|
victim._heat_wave_stunned_by[attacker.clientid] >= time )
|
|
{
|
|
processScoreEvent( "heatwave_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( getWeapon( "gadget_heat_wave" ), get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
}
|
|
|
|
if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_heat_wave" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( attackerSpeedburst == true )
|
|
{
|
|
processScoreEvent( "speed_burst_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( GetWeapon( "gadget_speed_burst" ), get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
|
|
if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_speed_burst" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
|
|
}
|
|
}
|
|
|
|
if ( victimSpeedburstLastOnTime > time - 50 )
|
|
{
|
|
processScoreEvent( "kill_enemy_who_is_speedbursting", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
}
|
|
|
|
if ( victimCombatEfficiencyLastOnTime > time - 50 )
|
|
{
|
|
processScoreEvent( "kill_enemy_who_is_using_focus", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
}
|
|
|
|
if ( attackerflashbackTime != 0 && attackerflashbackTime > time - 4000 )
|
|
{
|
|
processScoreEvent( "flashback_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( GetWeapon( "gadget_flashback" ), get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
|
|
if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_flashback" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
|
|
}
|
|
}
|
|
|
|
if ( victimflashbackTime != 0 && victimflashbackTime > time - 4000 )
|
|
{
|
|
processScoreEvent( "kill_enemy_who_has_flashbacked", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
}
|
|
|
|
if ( victimWasInSlamState )
|
|
{
|
|
processScoreEvent( "end_enemy_gravity_spike_attack", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_weapon_enemy" );
|
|
}
|
|
|
|
if ( challenges::isHighestScoringPlayer( victim ) )
|
|
{
|
|
processScoreEvent( "kill_enemy_who_has_high_score", attacker, victim, weapon );
|
|
}
|
|
|
|
if ( victimWasUnderwater && exlosiveDamage )
|
|
{
|
|
processScoreEvent( "kill_underwater_enemy_explosive", attacker, victim, weapon );
|
|
}
|
|
|
|
if ( isdefined ( victimElectrifiedBy ) && victimElectrifiedBy != attacker )
|
|
{
|
|
processScoreEvent( "electrified", victimElectrifiedBy, victim, weapon );
|
|
}
|
|
|
|
if ( victimVisionPulseActivateTime != 0 && victimVisionPulseActivateTime > time - 4000 )
|
|
{
|
|
gadgetWeapon = getWeapon("gadget_vision_pulse");
|
|
for ( i = 0; i < victimVisionPulseArray.size; i++ )
|
|
{
|
|
player = victimVisionPulseArray[i];
|
|
if ( player == attacker )
|
|
{
|
|
gadget = GetWeapon( "gadget_vision_pulse" );
|
|
|
|
if ( victimVisionPulseActivateTime + 300 > time - gadgetWeapon.gadget_pulse_duration )
|
|
{
|
|
distanceToPulse = distance( victimVisionPulseOriginArray[i], victimVisionPulseOrigin );
|
|
|
|
ratio = distanceToPulse / gadgetWeapon.gadget_pulse_max_range;
|
|
timing = ratio * gadgetWeapon.gadget_pulse_duration;
|
|
if ( victimVisionPulseActivateTime + 300 > time - timing )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
processScoreEvent( "kill_enemy_that_pulsed_you", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( isdefined( victimHeroAbility ) )
|
|
{
|
|
attacker notify( "hero_shutdown", victimHeroAbility );
|
|
attacker notify( "hero_shutdown_gadget", victimHeroAbility, victim );
|
|
}
|
|
}
|
|
|
|
if ( attackerVisionPulseActivateTime != 0 && attackerVisionPulseActivateTime > time - ( 2000 + 4000 + 500 ) )
|
|
{
|
|
gadgetWeapon = getWeapon("gadget_vision_pulse");
|
|
for ( i = 0; i < attackerVisionPulseArray.size; i++ )
|
|
{
|
|
player = attackerVisionPulseArray[i];
|
|
if ( player == victim )
|
|
{
|
|
gadget = GetWeapon( "gadget_vision_pulse" );
|
|
|
|
if ( attackerVisionPulseActivateTime > time - gadgetWeapon.gadget_pulse_duration )
|
|
{
|
|
distanceToPulse = distance( attackerVisionPulseOriginArray[i], attackerVisionPulseOrigin );
|
|
|
|
ratio = distanceToPulse / gadgetWeapon.gadget_pulse_max_range;
|
|
timing = ratio * gadgetWeapon.gadget_pulse_duration;
|
|
if ( attackerVisionPulseActivateTime > time - timing )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
processScoreEvent( "vision_pulse_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( gadgetWeapon, get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
|
|
if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_vision_pulse" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( victimHeroAbilityActive && isdefined ( victimHeroAbility ) )
|
|
{
|
|
attacker notify( "hero_shutdown", victimHeroAbility );
|
|
attacker notify( "hero_shutdown_gadget", victimHeroAbility, victim );
|
|
|
|
switch( victimHeroAbility.name )
|
|
{
|
|
case "gadget_armor":
|
|
processScoreEvent( "kill_enemy_who_has_powerarmor", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
break;
|
|
case "gadget_resurrect":
|
|
processScoreEvent( "kill_enemy_that_used_resurrect", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
break;
|
|
case "gadget_camo":
|
|
processScoreEvent( "kill_enemy_that_is_using_optic_camo", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
break;
|
|
case "gadget_clone":
|
|
processScoreEvent( "end_enemy_psychosis", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( isdefined( victimPowerArmorLastTookDamageTime ) && ( time - victimPowerArmorLastTookDamageTime <= 3000 ) )
|
|
{
|
|
attacker notify( "hero_shutdown", victimHeroAbility );
|
|
attacker notify( "hero_shutdown_gadget", victimHeroAbility, victim );
|
|
processScoreEvent( "kill_enemy_who_has_powerarmor", attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_ability_enemy" );
|
|
}
|
|
}
|
|
|
|
|
|
if ( isdefined( data.victimWeapon ) && isdefined( data.victimWeapon.isHeroWeapon ) && data.victimWeapon.isHeroWeapon == true )
|
|
{
|
|
attacker notify( "hero_shutdown", data.victimWeapon );
|
|
attacker notify( "hero_shutdown_gadget", data.victimWeapon, victim );
|
|
}
|
|
else if ( isdefined( victim.heroWeapon ) && victimGadgetWasActiveLastDamage && victimGadgetPower < 100 )
|
|
{
|
|
// need to do this for some hero weapons like armblades
|
|
attacker notify( "hero_shutdown", victim.heroWeapon );
|
|
attacker notify( "hero_shutdown_gadget", victim.heroWeapon, victim );
|
|
}
|
|
|
|
if ( attackerHeroAbilityActive && isdefined ( attackerHeroAbility ) )
|
|
{
|
|
abilityToCheck = undefined;
|
|
|
|
switch( attackerHeroAbility.name )
|
|
{
|
|
case "gadget_armor":
|
|
{
|
|
processScoreEvent( "power_armor_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( attackerHeroAbility, get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
abilityToCheck = attackerHeroAbility.name;
|
|
}
|
|
break;
|
|
case "gadget_resurrect":
|
|
{
|
|
processScoreEvent( "resurrect_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( attackerHeroAbility, get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
abilityToCheck = attackerHeroAbility.name;
|
|
}
|
|
break;
|
|
case "gadget_camo":
|
|
{
|
|
processScoreEvent( "optic_camo_kill", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( attackerHeroAbility, get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
abilityToCheck = attackerHeroAbility.name;
|
|
}
|
|
break;
|
|
case "gadget_clone":
|
|
{
|
|
processScoreEvent( "kill_enemy_while_using_psychosis", attacker, victim, weapon );
|
|
attacker hero_ability_kill_event( attackerHeroAbility, get_equipped_hero_ability( victimHeroAbilityName ) );
|
|
attacker specialistMedalAchievement();
|
|
attacker thread specialistStatAbilityUsage( 4, false );
|
|
abilityToCheck = attackerHeroAbility.name;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( attackerIsRoulette && !victimIsThiefOrRoulette && isdefined( abilityToCheck ) && victimHeroAbilityName === abilityToCheck )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
|
|
}
|
|
}
|
|
|
|
if ( victimWasLungingWithArmBlades )
|
|
{
|
|
processScoreEvent( "end_enemy_armblades_attack", attacker, victim, weapon );
|
|
}
|
|
|
|
if ( isdefined( data.victimWeapon ) )
|
|
{
|
|
killedHeroWeaponEnemy( attacker, victim, weapon, data.victimWeapon, victimGadgetPower, victimGadgetWasActiveLastDamage );
|
|
|
|
if ( data.victimWeapon.name == "minigun" )
|
|
{
|
|
processScoreEvent( "killed_death_machine_enemy", attacker, victim, weapon );
|
|
}
|
|
else if ( data.victimWeapon.name == "m32" )
|
|
{
|
|
processScoreEvent( "killed_multiple_grenade_launcher_enemy", attacker, victim, weapon );
|
|
}
|
|
|
|
// armblade is special case since the victimWeapon can be a primary or secondary weapon
|
|
is_hero_armblade_and_active = ( isdefined( victim.heroweapon ) && victim.heroweapon.name == "hero_armblade" && victimGadgetWasActiveLastDamage );
|
|
|
|
if ( ( data.victimWeapon.inventorytype == "hero" || is_hero_armblade_and_active ) && victimGadgetPower < 100 )
|
|
{
|
|
if ( victimHeroWeaponKillsThisActivation == 0 )
|
|
{
|
|
attacker AddPlayerStat( "kill_before_specialist_weapon_use", 1 );
|
|
}
|
|
|
|
if ( weapon.inventorytype == "hero" )
|
|
{
|
|
attacker AddPlayerStat( "kill_specialist_with_specialist", 1 );
|
|
}
|
|
|
|
// add here
|
|
attacker_is_thief = ( isdefined( attacker.heroweapon ) && attacker.heroweapon.name == "gadget_thief" );
|
|
if ( !attacker_is_thief )
|
|
{
|
|
processScoreEvent( "end_enemy_specialist_weapon", attacker, victim, weapon );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( weapon.rootweapon.name == "frag_grenade" )
|
|
{
|
|
attacker thread updateSingleFragMultiKill( victim, weapon, weaponClass, killstreak );
|
|
}
|
|
|
|
attacker thread updateMultiKills( weapon, weaponClass, killstreak, victim );
|
|
|
|
if ( level.numKills == 1 )
|
|
{
|
|
victim RecordKillModifier("firstblood");
|
|
processScoreEvent( "first_kill", attacker, victim, weapon );
|
|
}
|
|
else
|
|
{
|
|
if ( isdefined( attacker.lastKilledBy ) )
|
|
{
|
|
if ( attacker.lastKilledBy == victim )
|
|
{
|
|
level.globalPaybacks++;
|
|
processScoreEvent( "revenge_kill", attacker, victim, weapon );
|
|
attacker AddWeaponStat( weapon, "revenge_kill", 1 );
|
|
victim RecordKillModifier("revenge");
|
|
attacker.lastKilledBy = undefined;
|
|
}
|
|
}
|
|
if ( victim killstreaks::is_an_a_killstreak() )
|
|
{
|
|
level.globalBuzzKills++;
|
|
processScoreEvent( "stop_enemy_killstreak", attacker, victim, weapon );
|
|
victim RecordKillModifier("buzzkill");
|
|
}
|
|
if ( isdefined( victim.lastManSD ) && victim.lastManSD == true )
|
|
{
|
|
processScoreEvent( "final_kill_elimination", attacker, victim, weapon );
|
|
if ( isdefined( attacker.lastManSD ) && attacker.lastManSD == true )
|
|
{
|
|
processScoreEvent( "elimination_and_last_player_alive", attacker, victim, weapon );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( is_weapon_valid( meansOfDeath, weapon, weaponClass, killstreak ) )
|
|
{
|
|
if ( isdefined( victim.vAttackerOrigin ) )
|
|
attackerOrigin = victim.vAttackerOrigin;
|
|
else
|
|
attackerOrigin = attacker.origin;
|
|
distToVictim = distanceSquared( victim.origin, attackerOrigin );
|
|
weap_min_dmg_range = get_distance_for_weapon( weapon, weaponClass );
|
|
if ( distToVictim > weap_min_dmg_range )
|
|
{
|
|
attacker challenges::longDistanceKillMP( weapon );
|
|
if ( weapon.rootweapon.name == "hatchet" )
|
|
{
|
|
attacker challenges::longDistanceHatchetKill();
|
|
}
|
|
processScoreEvent( "longshot_kill", attacker, victim, weapon );
|
|
attacker.pers["longshots"]++;
|
|
attacker.longshots = attacker.pers["longshots"];
|
|
victim RecordKillModifier("longshot");
|
|
}
|
|
|
|
// Record kill distances and num of entries
|
|
killdistance = distance( victim.origin, attackerOrigin );
|
|
attacker.pers["kill_distances"] += killdistance;
|
|
attacker.pers["num_kill_distance_entries"]++;
|
|
}
|
|
|
|
if ( isAlive( attacker ) )
|
|
{
|
|
if ( attacker.health < ( attacker.maxHealth * 0.35 ) )
|
|
{
|
|
attacker.lastKillWhenInjured = time;
|
|
processScoreEvent( "kill_enemy_when_injured", attacker, victim, weapon );
|
|
|
|
attacker AddWeaponStat( weapon, "kill_enemy_when_injured", 1 );
|
|
if ( attacker util::has_toughness_perk_purchased_and_equipped() )
|
|
{
|
|
attacker AddPlayerStat( "perk_bulletflinch_kills", 1 );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( isdefined( attacker.deathtime ) && ( ( attacker.deathtime + 800 ) < time ) && !attacker IsInVehicle() )
|
|
{
|
|
level.globalAfterlifes++;
|
|
processScoreEvent( "kill_enemy_after_death", attacker, victim, weapon );
|
|
victim RecordKillModifier("posthumous");
|
|
}
|
|
}
|
|
|
|
if( attacker.cur_death_streak >= 3 )
|
|
{
|
|
level.globalComebacks++;
|
|
processScoreEvent( "comeback_from_deathstreak", attacker, victim, weapon );
|
|
victim RecordKillModifier("comeback");
|
|
}
|
|
|
|
if ( isdefined( victim.lastMicrowavedBy ) )
|
|
{
|
|
foreach( beingMicrowavedBy in victim.beingMicrowavedBy )
|
|
{
|
|
if ( isdefined( beingMicrowavedBy ) && ( attacker util::IsEnemyPlayer( beingMicrowavedBy ) == false ) )
|
|
{
|
|
if ( beingMicrowavedBy != attacker )
|
|
{
|
|
scoreGiven = processScoreEvent( "microwave_turret_assist", beingMicrowavedBy, victim, weapon );
|
|
if ( isdefined ( scoreGiven ) )
|
|
{
|
|
beingMicrowavedBy challenges::earnedMicrowaveAssistScore( scoreGiven );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
attackerMicrowavedVictim = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( attackerMicrowavedVictim === true && weapon.name != "microwave_turret" )
|
|
{
|
|
attacker challenges::killWhileDamagingWithHPM();
|
|
}
|
|
}
|
|
|
|
if ( weapon_utils::isMeleeMOD( meansOfDeath ) && !weapon.isRiotShield )
|
|
{
|
|
// "stabs" are now "melees"
|
|
attacker.pers["stabs"]++;
|
|
attacker.stabs = attacker.pers["stabs"];
|
|
|
|
if ( meansOfDeath == "MOD_MELEE_WEAPON_BUTT" && weapon.name != "ball" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_gunbutt", attacker, victim, weapon );
|
|
}
|
|
else if ( weapon_utils::isPunch( weapon ) )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_fists", attacker, victim, weapon );
|
|
}
|
|
else if ( weapon_utils::isNonBareHandsMelee( weapon ) )
|
|
{
|
|
vAngles = victim.anglesOnDeath[1];
|
|
pAngles = attacker.anglesOnKill[1];
|
|
angleDiff = AngleClamp180( vAngles - pAngles );
|
|
|
|
if ( angleDiff > -30 && angleDiff < 70 )
|
|
{
|
|
level.globalBackstabs++;
|
|
processScoreEvent( "backstabber_kill", attacker, victim, weapon );
|
|
|
|
weaponPickedUp = false;
|
|
if( isdefined( attacker.pickedUpWeapons ) && isdefined( attacker.pickedUpWeapons[weapon] ) )
|
|
{
|
|
weaponPickedUp = true;
|
|
}
|
|
|
|
attacker AddWeaponStat( weapon, "backstabber_kill", 1, attacker.class_num, weaponPickedUp, undefined, attacker.primaryLoadoutGunSmithVariantIndex, attacker.secondaryLoadoutGunSmithVariantIndex );
|
|
attacker.pers["backstabs"]++;
|
|
attacker.backstabs = attacker.pers["backstabs"];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( isdefined ( victim.firstTimeDamaged ) && victim.firstTimeDamaged == time && !( isdefined( weapon.isHeroWeapon ) && weapon.isHeroWeapon ) )
|
|
{
|
|
if ( attackerShotVictim )
|
|
{
|
|
attacker thread updateOneShotMultiKills( victim, weapon, victim.firstTimeDamaged );
|
|
attacker AddWeaponStat( weapon, "kill_enemy_one_bullet", 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( isdefined( attacker.tookWeaponFrom ) && isdefined( attacker.tookWeaponFrom[ weapon ] ) && isdefined( attacker.tookWeaponFrom[ weapon ].previousOwner ) )
|
|
{
|
|
pickedUpWeapon = attacker.tookWeaponFrom[ weapon ];
|
|
if ( pickedUpWeapon.previousOwner == victim )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_their_weapon", attacker, victim, weapon );
|
|
attacker AddWeaponStat( weapon, "kill_enemy_with_their_weapon", 1 );
|
|
if ( isdefined( pickedUpWeapon.sWeapon ) && isdefined( pickedUpWeapon.sMeansOfDeath ) && weapon_utils::isMeleeMOD( pickedUpWeapon.sMeansOfDeath ) )
|
|
{
|
|
foreach( meleeWeapon in level.meleeWeapons )
|
|
{
|
|
if ( weapon != meleeWeapon && pickedUpWeapon.sWeapon.rootweapon == meleeWeapon )
|
|
{
|
|
attacker AddWeaponStat( meleeWeapon, "kill_enemy_with_their_weapon", 1 );
|
|
break; // once found and handled, no need to continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( wasDefusing )
|
|
{
|
|
processScoreEvent( "killed_bomb_defuser", attacker, victim, weapon );
|
|
}
|
|
else if ( wasPlanting )
|
|
{
|
|
processScoreEvent( "killed_bomb_planter", attacker, victim, weapon );
|
|
}
|
|
|
|
heroWeaponKill( attacker, victim, weapon );
|
|
|
|
} // end if ( !isdefined( killstreak ) )
|
|
|
|
specificWeaponKill( attacker, victim, weapon, killstreak, inflictor );
|
|
|
|
if( isdefined( level.vtol ) && isdefined( level.vtol.owner ) && ( weapon.name == "helicopter_gunner_turret_secondary" || weapon.name == "helicopter_gunner_turret_tertiary" ) )
|
|
{
|
|
attacker addplayerstat( "kill_as_support_gunner", 1 );
|
|
|
|
processScoreEvent( "mothership_assist_kill", level.vtol.owner, victim, weapon );
|
|
}
|
|
|
|
if ( isdefined( attackerInVehicleArchetype ) )
|
|
{
|
|
if ( attackerInVehicleArchetype == "siegebot" )
|
|
{
|
|
if ( meansOfDeath == "MOD_CRUSH" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_siegebot_crush", attacker, victim, weapon );
|
|
}
|
|
|
|
if(!isdefined(attacker.siegebot_kills))attacker.siegebot_kills=0;
|
|
|
|
attacker.siegebot_kills++;
|
|
|
|
if ( attacker.siegebot_kills % 5 == 0 )
|
|
{
|
|
processScoreEvent( "siegebot_killstreak_5", attacker, victim, weapon );
|
|
}
|
|
}
|
|
}
|
|
|
|
switch ( weapon.rootweapon.name )
|
|
{
|
|
case "hatchet":
|
|
{
|
|
attacker.pers["tomahawks"]++;
|
|
attacker.tomahawks = attacker.pers["tomahawks"];
|
|
|
|
processScoreEvent( "hatchet_kill", attacker, victim, weapon );
|
|
|
|
if ( isdefined( data.victim.explosiveInfo["projectile_bounced"] ) && data.victim.explosiveInfo["projectile_bounced"] == true )
|
|
{
|
|
level.globalBankshots++;
|
|
|
|
processScoreEvent( "bounce_hatchet_kill", attacker, victim, weapon );
|
|
}
|
|
}
|
|
break;
|
|
case "supplydrop":
|
|
case "inventory_supplydrop":
|
|
case "supplydrop_marker":
|
|
case "inventory_supplydrop_marker":
|
|
{
|
|
if ( meansOfDeath == "MOD_HIT_BY_OBJECT" || meansOfDeath == "MOD_CRUSH" )
|
|
{
|
|
processScoreEvent( "kill_enemy_with_care_package_crush", attacker, victim, weapon );
|
|
}
|
|
else
|
|
{
|
|
processScoreEvent( "kill_enemy_with_hacked_care_package", attacker, victim, weapon );
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
if( isdefined( killstreak ) )
|
|
{
|
|
attacker thread updateMultiKills( weapon, weaponClass, killstreak, victim );
|
|
|
|
victim RecordKillModifier("killstreak");
|
|
}
|
|
|
|
attacker.cur_death_streak = 0;
|
|
attacker disabledeathstreak();
|
|
}
|
|
|
|
function get_equipped_hero_ability( ability_name )
|
|
{
|
|
if ( !isdefined( ability_name ) )
|
|
return undefined;
|
|
|
|
return GetWeapon( ability_name );
|
|
}
|
|
|
|
function heroWeaponKill( attacker, victim, weapon )
|
|
{
|
|
if ( !isdefined( weapon ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( isdefined( weapon.isHeroWeapon ) && !weapon.isHeroWeapon )
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch( weapon.name )
|
|
{
|
|
case "hero_minigun":
|
|
case "hero_minigun_body3":
|
|
event = "minigun_kill";
|
|
break;
|
|
case "hero_flamethrower":
|
|
event = "flamethrower_kill";
|
|
break;
|
|
case "hero_lightninggun":
|
|
case "hero_lightninggun_arc":
|
|
event = "lightninggun_kill";
|
|
break;
|
|
case "hero_chemicalgelgun":
|
|
case "hero_firefly_swarm":
|
|
event = "gelgun_kill";
|
|
break;
|
|
case "hero_pineapplegun":
|
|
case "hero_pineapple_grenade":
|
|
event = "pineapple_kill";
|
|
break;
|
|
case "hero_armblade":
|
|
event = "armblades_kill";
|
|
break;
|
|
case "hero_bowlauncher":
|
|
case "hero_bowlauncher2":
|
|
case "hero_bowlauncher3":
|
|
case "hero_bowlauncher4":
|
|
event = "bowlauncher_kill";
|
|
break;
|
|
case "hero_gravityspikes":
|
|
event = "gravityspikes_kill";
|
|
break;
|
|
case "hero_annihilator":
|
|
event = "annihilator_kill";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
processScoreEvent( event, attacker, victim, weapon );
|
|
}
|
|
|
|
function killedHeroWeaponEnemy( attacker, victim, weapon, victim_weapon, victim_gadget_power, victimGadgetWasActiveLastDamage )
|
|
{
|
|
if ( !isdefined( victim_weapon ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( victim_gadget_power >= 100 )
|
|
return;
|
|
|
|
switch( victim_weapon.name )
|
|
{
|
|
case "hero_minigun":
|
|
case "hero_minigun_body3":
|
|
event = "killed_minigun_enemy";
|
|
break;
|
|
case "hero_flamethrower":
|
|
event = "killed_flamethrower_enemy";
|
|
break;
|
|
case "hero_lightninggun":
|
|
case "hero_lightninggun_arc":
|
|
event = "killed_lightninggun_enemy";
|
|
break;
|
|
case "hero_chemicalgelgun":
|
|
event = "killed_gelgun_enemy";
|
|
break;
|
|
case "hero_pineapplegun":
|
|
event = "killed_pineapple_enemy";
|
|
break;
|
|
case "hero_bowlauncher":
|
|
case "hero_bowlauncher2":
|
|
case "hero_bowlauncher3":
|
|
case "hero_bowlauncher4":
|
|
event = "killed_bowlauncher_enemy";
|
|
break;
|
|
case "hero_gravityspikes":
|
|
event = "killed_gravityspikes_enemy";
|
|
break;
|
|
case "hero_annihilator":
|
|
event = "killed_annihilator_enemy";
|
|
break;
|
|
|
|
default:
|
|
if ( isdefined( victim.heroWeapon ) && victim.heroWeapon.name == "hero_armblade" && victimGadgetWasActiveLastDamage )
|
|
{
|
|
event = "killed_armblades_enemy";
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
processScoreEvent( event, attacker, victim, weapon );
|
|
attacker util::player_contract_event( "killed_hero_weapon_enemy" );
|
|
}
|
|
|
|
function specificWeaponKill( attacker, victim, weapon, killstreak, inflictor )
|
|
{
|
|
switchWeapon = weapon.name;
|
|
|
|
if( isdefined( killstreak ) )
|
|
{
|
|
switchWeapon = killstreak;
|
|
}
|
|
switch( switchWeapon )
|
|
{
|
|
case "remote_missile":
|
|
case "inventory_remote_missile":
|
|
event = "remote_missile_kill";
|
|
break;
|
|
case "autoturret":
|
|
case "inventory_autoturret":
|
|
event = "sentry_gun_kill";
|
|
break;
|
|
case "planemortar":
|
|
case "inventory_planemortar":
|
|
event = "plane_mortar_kill";
|
|
break;
|
|
case "ai_tank_drop":
|
|
case "inventory_ai_tank_drop":
|
|
event = "aitank_kill";
|
|
if ( isdefined( inflictor ) && isdefined( inflictor.controlled ) )
|
|
{
|
|
if ( inflictor.controlled == true )
|
|
{
|
|
attacker addPlayerStat( "kill_with_controlled_ai_tank", 1 );
|
|
}
|
|
}
|
|
break;
|
|
case "microwave_turret":
|
|
case "inventory_microwave_turret":
|
|
case "microwaveturret":
|
|
case "inventory_microwaveturret":
|
|
event = "microwave_turret_kill";
|
|
break;
|
|
case "raps":
|
|
case "inventory_raps":
|
|
event = "raps_kill";
|
|
break;
|
|
case "sentinel":
|
|
case "inventory_sentinel":
|
|
{
|
|
event = "sentinel_kill";
|
|
if ( isdefined( inflictor ) && isdefined( inflictor.controlled ) )
|
|
{
|
|
if ( inflictor.controlled == true )
|
|
{
|
|
attacker addPlayerStat( "kill_with_controlled_sentinel", 1 );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "combat_robot":
|
|
case "inventory_combat_robot":
|
|
event = "combat_robot_kill";
|
|
break;
|
|
case "rcbomb":
|
|
case "inventory_rcbomb":
|
|
event = "hover_rcxd_kill";
|
|
break;
|
|
case "helicopter_gunner":
|
|
case "helicopter_gunner_assistant":
|
|
case "inventory_helicopter_gunner":
|
|
case "inventory_helicopter_gunner_assistant":
|
|
event = "vtol_mothership_kill";
|
|
break;
|
|
case "helicopter_comlink":
|
|
case "inventory_helicopter_comlink":
|
|
event = "helicopter_comlink_kill";
|
|
break;
|
|
case "drone_strike":
|
|
case "inventory_drone_strike":
|
|
event = "drone_strike_kill";
|
|
break;
|
|
case "dart":
|
|
case "inventory_dart":
|
|
case "dart_turret":
|
|
event = "dart_kill";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if ( isdefined( inflictor ) )
|
|
{
|
|
if ( isdefined( inflictor.killstreak_id ) && isdefined( level.matchRecorderKillstreakKills[inflictor.killstreak_id] ) )
|
|
{
|
|
level.matchRecorderKillstreakKills[inflictor.killstreak_id]++;
|
|
}
|
|
else if ( isdefined( inflictor.killcament ) && isdefined( inflictor.killcament.killstreak_id ) && isdefined( level.matchRecorderKillstreakKills[inflictor.killcament.killstreak_id] ) )
|
|
{
|
|
level.matchRecorderKillstreakKills[inflictor.killcament.killstreak_id]++;
|
|
}
|
|
}
|
|
|
|
processScoreEvent( event, attacker, victim, weapon );
|
|
}
|
|
|
|
function multiKill( killCount, weapon )
|
|
{
|
|
assert( killCount > 1 );
|
|
|
|
self challenges::multiKill( killCount, weapon );
|
|
|
|
if ( killCount > 8 )
|
|
{
|
|
processScoreEvent( "multikill_more_than_8", self, undefined, weapon );
|
|
}
|
|
else
|
|
{
|
|
processScoreEvent( "multikill_" + killCount, self, undefined, weapon );
|
|
}
|
|
|
|
if ( killCount > 2 )
|
|
{
|
|
if ( isdefined( self.challenge_objectiveDefensiveKillcount ) && self.challenge_objectiveDefensiveKillcount > 0 )
|
|
{
|
|
self.challenge_objectiveDefensiveTripleKillMedalOrBetterEarned = true;
|
|
}
|
|
}
|
|
|
|
self RecordMultiKill( killCount );
|
|
}
|
|
|
|
function multiHeroAbilityKill( killCount, weapon )
|
|
{
|
|
if ( killcount > 1 )
|
|
{
|
|
self addPlayerStat( "multikill_2_with_heroability", int( killCount / 2 ) );
|
|
self AddWeaponStat( weapon, "heroability_doublekill", int( killCount / 2 ) );
|
|
self addPlayerStat( "multikill_3_with_heroability", int( killCount / 3 ) );
|
|
self AddWeaponStat( weapon, "heroability_triplekill", int( killCount / 3 ) );
|
|
}
|
|
}
|
|
|
|
function is_weapon_valid( meansOfDeath, weapon, weaponClass, killstreak )
|
|
{
|
|
valid_weapon = false;
|
|
|
|
if ( isdefined( killstreak ) )
|
|
valid_weapon = false;
|
|
else if ( get_distance_for_weapon( weapon, weaponClass ) == 0 )
|
|
valid_weapon = false;
|
|
else if ( meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_RIFLE_BULLET" )
|
|
valid_weapon = true;
|
|
else if ( meansOfDeath == "MOD_HEAD_SHOT" )
|
|
valid_weapon = true;
|
|
else if ( weapon.rootweapon.name == "hatchet" && meansOfDeath == "MOD_IMPACT" )
|
|
valid_weapon = true;
|
|
else
|
|
{
|
|
baseWeapon = challenges::getBaseWeapon( weapon );
|
|
if ( baseWeapon == level.weaponSpecialCrossbow && meansOfDeath == "MOD_IMPACT" )
|
|
valid_weapon = true;
|
|
else if ( baseWeapon == level.weaponBallisticKnife && meansOfDeath == "MOD_IMPACT" )
|
|
valid_weapon = true;
|
|
else if ( ( baseWeapon.forceDamageHitLocation || baseWeapon == level.weaponShotgunEnergy || baseWeapon == level.weaponSpecialDiscGun ) && meansofDeath == "MOD_PROJECTILE" )
|
|
valid_weapon = true;
|
|
}
|
|
|
|
return valid_weapon;
|
|
}
|
|
|
|
|
|
function updateSingleFragMultiKill( victim, weapon, weaponClass, killstreak )
|
|
{
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
|
|
self notify ( "updateSingleFragMultiKill" );
|
|
self endon ( "updateSingleFragMultiKill" );
|
|
|
|
if ( !isdefined (self.recent_SingleFragMultiKill) || self.recent_SingleFragMultiKillID != victim.explosiveinfo["damageid"] )
|
|
self.recent_SingleFragMultiKill = 0;
|
|
|
|
self.recent_SingleFragMultiKillID = victim.explosiveinfo["damageid"];
|
|
self.recent_SingleFragMultiKill++;
|
|
|
|
self waitTillTimeoutOrDeath( 0.05 );
|
|
|
|
if ( self.recent_SingleFragMultiKill >= 2 )
|
|
{
|
|
processScoreEvent( "frag_multikill", self, victim, weapon );
|
|
}
|
|
|
|
self.recent_SingleFragMultiKill = 0;
|
|
}
|
|
|
|
function updatemultikills( weapon, weaponClass, killstreak, victim )
|
|
{
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
|
|
self notify ( "updateRecentKills" );
|
|
self endon ( "updateRecentKills" );
|
|
|
|
baseWeaponParam = [[ level.get_base_weapon_param ]]( weapon );
|
|
baseWeapon = GetWeapon( GetRefFromItemIndex( GetBaseWeaponItemIndex( baseWeaponParam ) ) );
|
|
|
|
if ( !isdefined( self.recentKillVariables ) )
|
|
{
|
|
self resetRecentKillVariables();
|
|
}
|
|
|
|
if ( !isdefined( self.recentKillCountWeapon ) || self.recentKillCountWeapon != baseWeapon )
|
|
{
|
|
self.recentKillCountSameWeapon = 0;
|
|
self.recentKillCountWeapon = baseWeapon;
|
|
}
|
|
|
|
if (!isdefined(killstreak))
|
|
{
|
|
self.recentKillCountSameWeapon++;
|
|
self.recentKillCount++;
|
|
}
|
|
|
|
if ( isdefined( weaponClass ) )
|
|
{
|
|
if ( weaponClass == "weapon_lmg" || weaponClass == "weapon_smg" )
|
|
{
|
|
if ( self PlayerAds() < 1.0 )
|
|
{
|
|
self.recent_LMG_SMG_KillCount++;
|
|
}
|
|
}
|
|
if ( weaponClass == "weapon_grenade" )
|
|
{
|
|
self.recentLethalCount++;
|
|
}
|
|
}
|
|
|
|
if ( weapon.name == "satchel_charge" )
|
|
{
|
|
self.recentC4KillCount++;
|
|
}
|
|
|
|
if ( isdefined( level.killstreakWeapons ) && isdefined( level.killstreakWeapons[weapon] ) )
|
|
{
|
|
switch( level.killstreakWeapons[weapon] )
|
|
{
|
|
case "remote_missile":
|
|
case "inventory_remote_missile":
|
|
{
|
|
self.recentRemoteMissileCount++;
|
|
}
|
|
break;
|
|
case "rcbomb":
|
|
case "inventory_rcbomb":
|
|
{
|
|
self.recentRCBombCount++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if ( isdefined( weapon.isHeroWeapon ) && weapon.isHeroWeapon == true )
|
|
{
|
|
self.recentHeroKill = getTime();
|
|
self.recentHeroWeaponKillCount++;
|
|
if ( isdefined( victim ) )
|
|
{
|
|
self.recentHeroWeaponVictims[ victim GetEntityNumber() ] = victim;
|
|
}
|
|
switch( weapon.name )
|
|
{
|
|
case "hero_annihilator":
|
|
self.recentAnihilatorCount++;
|
|
break;
|
|
case "hero_minigun":
|
|
case "hero_minigun_body3":
|
|
self.recentMiniGunCount++;
|
|
break;
|
|
case "hero_bowlauncher":
|
|
case "hero_bowlauncher2":
|
|
case "hero_bowlauncher3":
|
|
case "hero_bowlauncher4":
|
|
self.recentBowLauncherCount++;
|
|
break;
|
|
case "hero_flamethrower":
|
|
self.recentFlameThrowerCount++;
|
|
break;
|
|
case "hero_gravityspikes":
|
|
self.recentGravitySpikesCount++;
|
|
break;
|
|
case "hero_lightninggun":
|
|
case "hero_lightninggun_arc":
|
|
self.recentLightningGunCount++;
|
|
break;
|
|
case "hero_pineapplegun":
|
|
case "hero_pineapple_grenade":
|
|
self.recentPineappleGunCount++;
|
|
break;
|
|
case "hero_chemicalgun":
|
|
case "hero_firefly_swarm":
|
|
self.recentGelGunCount++;
|
|
break;
|
|
case "hero_armblade":
|
|
self.recentArmBladeCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( isdefined( self.heroAbility ) && isdefined( victim ) )
|
|
{
|
|
if ( victim ability_player::gadget_CheckHeroAbilityKill( self ) )
|
|
{
|
|
if ( isdefined( self.recentHeroAbilityKillWeapon ) && self.recentHeroAbilityKillWeapon != self.heroAbility )
|
|
{
|
|
self.recentHeroAbilityKillCount = 0;
|
|
}
|
|
self.recentHeroAbilityKillWeapon = self.heroAbility;
|
|
self.recentHeroAbilityKillCount++;
|
|
}
|
|
}
|
|
|
|
if ( isdefined ( killstreak ) )
|
|
{
|
|
switch( killstreak )
|
|
{
|
|
case "remote_missile":
|
|
self.recentRemoteMissileKillCount++;
|
|
break;
|
|
case "rcbomb":
|
|
self.recentRCBombKillCount++;
|
|
break;
|
|
case "inventory_m32":
|
|
case "m32":
|
|
self.recentMGLKillCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( self.recentKillCountSameWeapon == 2 )
|
|
{
|
|
self AddWeaponStat( weapon, "multikill_2", 1 );
|
|
}
|
|
else if ( self.recentKillCountSameWeapon == 3 )
|
|
{
|
|
self AddWeaponStat( weapon, "multikill_3", 1 );
|
|
}
|
|
|
|
self waitTillTimeoutOrDeath( 4.0 );
|
|
|
|
if ( self.recent_LMG_SMG_KillCount >= 3 )
|
|
self challenges::multi_LMG_SMG_Kill();
|
|
|
|
if ( self.recentRCBombKillCount >= 2 )
|
|
self challenges::multi_RCBomb_Kill();
|
|
|
|
if ( self.recentMGLKillCount >= 3 )
|
|
self challenges::multi_MGL_Kill();
|
|
|
|
if ( self.recentRemoteMissileKillCount >= 3 )
|
|
self challenges::multi_RemoteMissile_Kill();
|
|
|
|
|
|
if ( self.recentHeroWeaponKillCount > 1 )
|
|
{
|
|
self scoreevents::hero_weapon_multikill_event( self.recentHeroWeaponKillCount, weapon );
|
|
}
|
|
|
|
if ( self.recentHeroWeaponKillCount > 5 )
|
|
{
|
|
ArrayRemoveValue( self.recentHeroWeaponVictims, undefined );
|
|
if ( self.recentHeroWeaponVictims.size > 5 )
|
|
{
|
|
self addPlayerStat( "kill_entire_team_with_specialist_weapon", 1 );
|
|
}
|
|
}
|
|
|
|
if ( self.recentAnihilatorCount >= 3 )
|
|
{
|
|
processScoreEvent( "annihilator_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentAnihilatorCount == 2 )
|
|
{
|
|
processScoreEvent( "annihilator_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentMiniGunCount >= 3 )
|
|
{
|
|
processScoreEvent( "minigun_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentMiniGunCount == 2 )
|
|
{
|
|
processScoreEvent( "minigun_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentBowLauncherCount >= 3 )
|
|
{
|
|
processScoreEvent( "bowlauncher_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentBowLauncherCount == 2 )
|
|
{
|
|
processScoreEvent( "bowlauncher_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentFlameThrowerCount >= 3 )
|
|
{
|
|
processScoreEvent( "flamethrower_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentFlameThrowerCount == 2 )
|
|
{
|
|
processScoreEvent( "flamethrower_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentGravitySpikesCount >= 3 )
|
|
{
|
|
processScoreEvent( "gravityspikes_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentGravitySpikesCount == 2 )
|
|
{
|
|
processScoreEvent( "gravityspikes_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentLightningGunCount >= 3 )
|
|
{
|
|
processScoreEvent( "lightninggun_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentLightningGunCount == 2 )
|
|
{
|
|
processScoreEvent( "lightninggun_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentPineappleGunCount >= 3 )
|
|
{
|
|
processScoreEvent( "pineapple_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentPineappleGunCount == 2 )
|
|
{
|
|
processScoreEvent( "pineapple_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentGelGunCount >= 3 )
|
|
{
|
|
processScoreEvent( "gelgun_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentGelGunCount == 2 )
|
|
{
|
|
processScoreEvent( "gelgun_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
if ( self.recentArmBladeCount >= 3 )
|
|
{
|
|
processScoreEvent( "armblades_multikill", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
else if ( self.recentArmBladeCount == 2 )
|
|
{
|
|
processScoreEvent( "armblades_multikill_2", self, undefined, weapon );
|
|
self multikillMedalAchievement();
|
|
}
|
|
|
|
if ( self.recentC4KillCount >= 2 )
|
|
{
|
|
processScoreEvent( "c4_multikill", self, undefined, weapon );
|
|
}
|
|
if ( self.recentRemoteMissileCount >= 3 )
|
|
{
|
|
self addPlayerStat( "multikill_3_remote_missile", 1 );
|
|
}
|
|
if ( self.recentRCBombCount >= 2 )
|
|
{
|
|
self addPlayerStat( "multikill_2_rcbomb", 1 );
|
|
}
|
|
if ( self.recentLethalCount >= 2 )
|
|
{
|
|
if ( !isdefined( self.pers["challenge_kills_double_kill_lethal"] ) )
|
|
{
|
|
self.pers["challenge_kills_double_kill_lethal"] = 0;
|
|
}
|
|
|
|
self.pers["challenge_kills_double_kill_lethal"]++;
|
|
if ( self.pers["challenge_kills_double_kill_lethal"] >= 3 )
|
|
{
|
|
self addPlayerStat( "kills_double_kill_3_lethal", 1 );
|
|
}
|
|
}
|
|
|
|
if ( self.recentKillCount > 1 )
|
|
self multiKill( self.recentKillCount, weapon );
|
|
|
|
if ( self.recentHeroAbilityKillCount > 1 )
|
|
{
|
|
self multiHeroAbilityKill( self.recentHeroAbilityKillCount, self.recentHeroAbilityKillWeapon );
|
|
self scoreevents::hero_ability_multikill_event( self.recentHeroAbilityKillCount, self.recentHeroAbilityKillWeapon );
|
|
}
|
|
|
|
self resetRecentKillVariables();
|
|
}
|
|
|
|
function resetRecentKillVariables()
|
|
{
|
|
self.recent_LMG_SMG_KillCount = 0;
|
|
self.recentAnihilatorCount = 0;
|
|
self.recentArmBladeCount = 0;
|
|
self.recentBowLauncherCount = 0;
|
|
self.recentC4KillCount = 0;
|
|
self.recentFlameThrowerCount = 0;
|
|
self.recentGelGunCount = 0;
|
|
self.recentGravitySpikesCount = 0;
|
|
self.recentHeroAbilityKillCount = 0;
|
|
self.recentHeroWeaponKillCount = 0;
|
|
self.recentHeroWeaponVictims = [];
|
|
self.recentKillCount = 0;
|
|
self.recentKillCountSameWeapon = 0;
|
|
self.recentKillCountWeapon = undefined;
|
|
self.recentLethalCount = 0;
|
|
self.recentLightningGunCount = 0;
|
|
self.recentMGLKillCount = 0;
|
|
self.recentMiniGunCount = 0;
|
|
self.recentPineappleGunCount = 0;
|
|
self.recentRCBombCount = 0;
|
|
self.recentRCBombKillCount = 0;
|
|
self.recentRemoteMissileCount = 0;
|
|
self.recentRemoteMissileKillCount = 0;
|
|
|
|
self.recentKillVariables = true;
|
|
}
|
|
|
|
function waitTillTimeoutOrDeath( timeout )
|
|
{
|
|
self endon( "death" );
|
|
wait( timeout );
|
|
}
|
|
|
|
function updateoneshotmultikills( victim, weapon, firstTimeDamaged )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self notify( "updateoneshotmultikills" + firstTimeDamaged );
|
|
self endon( "updateoneshotmultikills" + firstTimeDamaged );
|
|
if ( !isdefined( self.oneshotmultikills ) || firstTimeDamaged > (isdefined(self.oneshotmultikillsdamagetime)?self.oneshotmultikillsdamagetime:0) )
|
|
{
|
|
self.oneshotmultikills = 0;
|
|
}
|
|
|
|
self.oneshotmultikills++;
|
|
self.oneshotmultikillsdamagetime = firstTimeDamaged;
|
|
|
|
wait( 1.0 );
|
|
if ( self.oneshotmultikills > 1 )
|
|
{
|
|
processScoreEvent( "kill_enemies_one_bullet", self, victim, weapon );
|
|
}
|
|
else
|
|
{
|
|
processScoreEvent( "kill_enemy_one_bullet", self, victim, weapon );
|
|
}
|
|
self.oneshotmultikills = 0;
|
|
}
|
|
|
|
function get_distance_for_weapon( weapon, weaponClass )
|
|
{
|
|
// this is special for the long shot medal
|
|
// need to do this on a per weapon category basis, to better control it
|
|
|
|
distance = 0;
|
|
|
|
if( !isdefined( weaponClass ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// special case weapons
|
|
if ( weapon.rootweapon.name == "pistol_shotgun" )
|
|
{
|
|
weaponClass = "weapon_cqb"; // per design
|
|
}
|
|
|
|
|
|
switch ( weaponClass )
|
|
{
|
|
case "weapon_smg":
|
|
distance = 1500 * 1500;
|
|
break;
|
|
|
|
case "weapon_assault":
|
|
distance = 1750 * 1750;
|
|
break;
|
|
|
|
case "weapon_lmg":
|
|
distance = 1750 * 1750;
|
|
break;
|
|
|
|
case "weapon_sniper":
|
|
distance = 2000 * 2000;
|
|
break;
|
|
|
|
case "weapon_pistol":
|
|
distance = 1000 * 1000;
|
|
break;
|
|
|
|
case "weapon_cqb":
|
|
distance = 550 * 550;
|
|
break;
|
|
|
|
|
|
case "weapon_special":
|
|
{
|
|
baseWeapon = challenges::getBaseWeapon( weapon );
|
|
if ( baseWeapon == level.weaponBallisticKnife || baseWeapon == level.weaponSpecialCrossbow || baseWeapon == level.weaponSpecialDiscGun )
|
|
{
|
|
distance = 1500 * 1500;
|
|
}
|
|
}
|
|
break;
|
|
case "weapon_grenade":
|
|
if ( weapon.rootweapon.name == "hatchet" )
|
|
{
|
|
distance = 1500 * 1500;
|
|
}
|
|
break;
|
|
default:
|
|
distance = 0;
|
|
break;
|
|
}
|
|
|
|
return distance;
|
|
}
|
|
|
|
|
|
function onGameEnd( data )
|
|
{
|
|
player = data.player;
|
|
winner = data.winner;
|
|
|
|
if ( isdefined( winner ) )
|
|
{
|
|
if ( level.teambased )
|
|
{
|
|
if ( winner != "tie" && player.team == winner )
|
|
{
|
|
processScoreEvent( "won_match", player );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
placement = level.placement["all"];
|
|
topThreePlayers = min( 3, placement.size );
|
|
|
|
for ( index = 0; index < topThreePlayers; index++ )
|
|
{
|
|
if ( level.placement["all"][index] == player )
|
|
{
|
|
processScoreEvent( "won_match", player );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
processScoreEvent( "completed_match", player );
|
|
}
|
|
|
|
|
|
function specialistMedalAchievement()
|
|
{
|
|
if( level.rankedMatch )
|
|
{
|
|
if ( !isdefined( self.pers["specialistMedalAchievement"] ) )
|
|
{
|
|
self.pers["specialistMedalAchievement"] = 0;
|
|
}
|
|
self.pers["specialistMedalAchievement"]++;
|
|
if ( self.pers["specialistMedalAchievement"] == 5 )
|
|
{
|
|
self GiveAchievement( "MP_SPECIALIST_MEDALS" ); // Get 5 Medals based on a Specialist Ability in a single game.
|
|
}
|
|
|
|
self util::player_contract_event( "earned_specialist_ability_medal" );
|
|
}
|
|
}
|
|
|
|
function specialistStatAbilityUsage( usageSingleGame, multiTrackPerLife )
|
|
{
|
|
self endon ( "disconnect" );
|
|
level endon ( "game_ended" );
|
|
|
|
self notify ( "updatethread specialistStatAbilityUsage" );
|
|
self endon ( "updatethread specialistStatAbilityUsage" );
|
|
|
|
isRoulette = ( self.isRoulette === true );
|
|
if ( isdefined( self.heroAbility ) && !isRoulette )
|
|
{
|
|
self addWeaponStat( self.heroAbility, "combatRecordStat", 1 );
|
|
}
|
|
|
|
self challenges::processSpecialistChallenge( "kills_ability" );
|
|
if ( !isdefined( self.pers["specialistUsagePerGame"] ) )
|
|
{
|
|
self.pers["specialistUsagePerGame"] = 0;
|
|
}
|
|
self.pers["specialistUsagePerGame"]++;
|
|
if ( self.pers["specialistUsagePerGame"] >= usageSingleGame )
|
|
{
|
|
self challenges::processSpecialistChallenge( "kill_one_game_ability" );
|
|
self.pers["specialistUsagePerGame"] = 0;
|
|
}
|
|
|
|
if ( multiTrackPerLife )
|
|
{
|
|
self.pers["specialistStatAbilityUsage"]++;
|
|
if ( self.pers["specialistStatAbilityUsage"] >= 2 )
|
|
{
|
|
self challenges::processSpecialistChallenge( "multikill_ability" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !isdefined( self.specialistStatAbilityUsage ) )
|
|
{
|
|
self.specialistStatAbilityUsage = 0;
|
|
}
|
|
|
|
self.specialistStatAbilityUsage++;
|
|
self waitTillTimeoutOrDeath( 4.0 );
|
|
if ( self.specialistStatAbilityUsage >= 2 )
|
|
{
|
|
self challenges::processSpecialistChallenge( "multikill_ability" );
|
|
}
|
|
self.specialistStatAbilityUsage = 0;
|
|
}
|
|
}
|
|
|
|
function multikillMedalAchievement()
|
|
{
|
|
if ( level.rankedMatch )
|
|
{
|
|
self GiveAchievement( "MP_MULTI_KILL_MEDALS" ); // Get a Specialist-based medal that requires 3 or more rapid kills while using any Specialist Weapon.
|
|
self challenges::processSpecialistChallenge( "multikill_weapon" );
|
|
}
|
|
}
|
|
|