Advertisement
Guest User

_damage.gsc

a guest
Oct 22nd, 2013
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 71.69 KB | None | 0 0
  1. #include maps\mp\_utility;
  2. #include maps\mp\gametypes\_hud_util;
  3. #include common_scripts\utility;
  4.  
  5.  
  6. isSwitchingTeams()
  7. {
  8.     if ( isDefined( self.switching_teams ) )
  9.         return true;
  10.  
  11.     return false;
  12. }
  13.  
  14.  
  15. isTeamSwitchBalanced()
  16. {
  17.     playerCounts = self maps\mp\gametypes\_teams::CountPlayers();
  18.     playerCounts[ self.leaving_team ] -- ;
  19.     playerCounts[ self.joining_team ]++ ;
  20.  
  21.     return( ( playerCounts[ self.joining_team ] - playerCounts[ self.leaving_team ] ) < 2 );
  22. }
  23.  
  24.  
  25. isFriendlyFire( victim, attacker )
  26. {
  27.     if ( !level.teamBased )
  28.         return false;
  29.    
  30.     if ( !isDefined( attacker ) )
  31.         return false;
  32.    
  33.     if ( !isPlayer( attacker ) && !isDefined( attacker.team ) )
  34.         return false;
  35.    
  36.     if ( victim.team != attacker.team )
  37.         return false;
  38.    
  39.     if ( victim == attacker )
  40.         return false;
  41.    
  42.     return true;
  43. }
  44.  
  45.  
  46. killedSelf( attacker )
  47. {
  48.     if ( !isPlayer( attacker ) )
  49.         return false;
  50.  
  51.     if ( attacker != self )
  52.         return false;
  53.  
  54.     return true;
  55. }
  56.  
  57.  
  58. isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker )
  59. {  
  60.     if ( isDefined( attacker ) )
  61.     {
  62.         if ( attacker.code_classname == "script_vehicle" && isDefined( attacker.owner ) )
  63.             return false;
  64.         if ( attacker.code_classname == "misc_turret" && isDefined( attacker.owner ) )
  65.             return false;
  66.         if ( attacker.code_classname == "script_model" && isDefined( attacker.owner ) )
  67.             return false;
  68.     }
  69.    
  70.     return( sHitLoc == "head" || sHitLoc == "helmet" ) && sMeansOfDeath != "MOD_MELEE" && sMeansOfDeath != "MOD_IMPACT" && !isMG( sWeapon );
  71. }
  72.  
  73.  
  74. handleTeamChangeDeath()
  75. {
  76.     if ( !level.teamBased )
  77.         return;
  78.  
  79.     // this might be able to happen now, but we should remove instances where it can
  80.     assert( self.leaving_team != self.joining_team );
  81.  
  82.     if ( self.joining_team == "spectator" || !isTeamSwitchBalanced() )
  83.     {
  84.         self thread [[ level.onXPEvent ]]( "suicide" );
  85.         self incPersStat( "suicides", 1 );
  86.         self.suicides = self getPersStat( "suicides" );
  87.     }
  88. }
  89.  
  90.  
  91. handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc )
  92. {
  93.     if ( !isDefined( attacker ) )
  94.         return;
  95.  
  96.     if ( !isDefined( attacker.team ) )
  97.     {  
  98.         handleSuicideDeath( sMeansOfDeath, sHitLoc );
  99.         return;
  100.     }
  101.    
  102.     assert( attacker.team == "axis" || attacker.team == "allies" );
  103.  
  104.     if ( level.teamBased && attacker.team != self.team )
  105.     {
  106.         if ( isDefined( level.onNormalDeath ) && isPlayer( attacker ) && attacker.team != "spectator" )
  107.             [[ level.onNormalDeath ]]( self, attacker, lifeId );
  108.     }
  109. }
  110.  
  111.  
  112. handleSuicideDeath( sMeansOfDeath, sHitLoc )
  113. {
  114.     self SetCardDisplaySlot( self, 7 );
  115.     self openMenu( "killedby_card_display" );
  116.    
  117.     if ( getDvar("g_gametype") == "gg" )
  118.     {
  119.         self thread maps\mp\gametypes\gg::gotKilled( sMeansOfDeath, true );
  120.     }
  121.    
  122.     if ( getDvar("g_gametype") == "ss" )
  123.     {
  124.         self thread maps\mp\gametypes\ss::gotKilled( sMeansOfDeath, true );
  125.     }
  126.    
  127.     if ( getDvar("g_gametype") == "oitc" )
  128.     {
  129.         self thread maps\mp\gametypes\oitc::gotKilled( sMeansOfDeath, true );
  130.     }
  131.  
  132.     self thread [[ level.onXPEvent ]]( "suicide" );
  133.     self incPersStat( "suicides", 1 );
  134.     self.suicides = self getPersStat( "suicides" );
  135.    
  136.     if ( !matchMakingGame() )
  137.         self incPlayerStat( "suicides", 1 );
  138.  
  139.     scoreSub = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "suicidepointloss" );
  140.     maps\mp\gametypes\_gamescore::_setPlayerScore( self, maps\mp\gametypes\_gamescore::_getPlayerScore( self ) - scoreSub );
  141.  
  142.     if ( sMeansOfDeath == "MOD_SUICIDE" && sHitLoc == "none" && isDefined( self.throwingGrenade ) )
  143.         self.lastGrenadeSuicideTime = gettime();
  144.  
  145.     // suicide was caused by too many team kills
  146.     if ( isDefined( self.friendlydamage ) )
  147.         self iPrintLnBold( &"MP_FRIENDLY_FIRE_WILL_NOT" );
  148. }
  149.  
  150.  
  151. handleFriendlyFireDeath( attacker )
  152. {
  153.     attacker SetCardDisplaySlot( self, 8 );
  154.     attacker openMenu( "youkilled_card_display" );
  155.  
  156.     self SetCardDisplaySlot( attacker, 7 );
  157.     self openMenu( "killedby_card_display" );
  158.  
  159.     attacker thread [[ level.onXPEvent ]]( "teamkill" );
  160.     attacker.pers[ "teamkills" ] += 1.0;
  161.  
  162.     attacker.teamkillsThisRound++ ;
  163.  
  164.     if ( maps\mp\gametypes\_tweakables::getTweakableValue( "team", "teamkillpointloss" ) )
  165.     {
  166.         scoreSub = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" );
  167.         maps\mp\gametypes\_gamescore::_setPlayerScore( attacker, maps\mp\gametypes\_gamescore::_getPlayerScore( attacker ) - scoreSub );
  168.     }
  169.  
  170.     if ( level.maxAllowedTeamkills < 0 )
  171.         return;
  172.  
  173.     if ( level.inGracePeriod )
  174.     {
  175.         teamKillDelay = 1;
  176.         attacker.pers["teamkills"] += level.maxAllowedTeamkills;
  177.     }
  178.     else if ( attacker.pers[ "teamkills" ] > 1 && getTimePassed() < ( (level.gracePeriod * 1000) + 8000 + ( attacker.pers[ "teamkills" ] * 1000 ) ) )
  179.     {
  180.         teamKillDelay = 1;
  181.         attacker.pers["teamkills"] += level.maxAllowedTeamkills;
  182.     }
  183.     else
  184.     {
  185.         teamKillDelay = attacker maps\mp\gametypes\_playerlogic::TeamKillDelay();
  186.     }
  187.  
  188.     if ( teamKillDelay > 0 )
  189.     {
  190.         attacker.pers["teamKillPunish"] = true;
  191.         attacker _suicide();
  192.     }
  193. }
  194.  
  195.  
  196. handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath )
  197. {
  198.     attacker thread maps\mp\_events::killedPlayer( lifeId, self, sWeapon, sMeansOfDeath );
  199.    
  200.     if ( getDvar("g_gametype") == "gg" )
  201.     {
  202.         attacker thread maps\mp\gametypes\gg::killedEnemy( sMeansOfDeath );
  203.         self thread maps\mp\gametypes\gg::gotKilled( sMeansOfDeath, false );
  204.     }
  205.    
  206.     if ( getDvar("g_gametype") == "ss" )
  207.     {
  208.         attacker thread maps\mp\gametypes\ss::killedEnemy( sMeansOfDeath );
  209.         self thread maps\mp\gametypes\ss::gotKilled( sMeansOfDeath, false );
  210.     }
  211.    
  212.     if ( getDvar("g_gametype") == "oitc" )
  213.     {
  214.         self thread maps\mp\gametypes\oitc::gotKilled();
  215.     }
  216.  
  217.     //if ( attacker.pers["teamkills"] <= level.maxAllowedTeamkills )
  218.     //  attacker.pers["teamkills"] = max( attacker.pers["teamkills"] - 1, 0 );
  219.  
  220.     attacker SetCardDisplaySlot( self, 8 );
  221.     attacker openMenu( "youkilled_card_display" );
  222.  
  223.     self SetCardDisplaySlot( attacker, 7 );
  224.     self openMenu( "killedby_card_display" );
  225.  
  226.     if ( sMeansOfDeath == "MOD_HEAD_SHOT" )
  227.     {
  228.         attacker incPersStat( "headshots", 1 );
  229.         attacker.headshots = attacker getPersStat( "headshots" );
  230.         attacker incPlayerStat( "headshots", 1 );
  231.  
  232.         if ( isDefined( attacker.lastStand ) )
  233.             value = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 2;
  234.         else
  235.             value = undefined;
  236.  
  237.         attacker playLocalSound( "bullet_impact_headshot_2" );
  238.     }
  239.     else
  240.     {
  241.         if ( isDefined( attacker.lastStand ) )
  242.             value = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 2;
  243.         else
  244.             value = undefined;
  245.     }
  246.  
  247.     attacker thread maps\mp\gametypes\_rank::giveRankXP( "kill", value );
  248.  
  249.     attacker incPersStat( "kills", 1 );
  250.     attacker.kills = attacker getPersStat( "kills" );
  251.     attacker updatePersRatio( "kdRatio", "kills", "deaths" );
  252.     attacker maps\mp\gametypes\_persistence::statSetChild( "round", "kills", attacker.kills );
  253.     attacker incPlayerStat( "kills", 1 );
  254.  
  255.     if ( isFlankKill( self, attacker ) )
  256.     {
  257.         attacker incPlayerStat( "flankkills", 1 );
  258.  
  259.         self incPlayerStat( "flankdeaths", 1 );
  260.     }
  261.    
  262.     lastKillStreak = attacker.pers["cur_kill_streak"];
  263.  
  264.     self.pers["copyCatLoadout"] = undefined;
  265.  
  266.     if ( self _hasPerk( "specialty_copycat" ) )
  267.         self.pers["copyCatLoadout"] = attacker maps\mp\gametypes\_class::cloneLoadout();
  268.    
  269.     if ( isAlive( attacker ) )
  270.     {
  271.         // killstreaks only advance from kills earned this life
  272.         if ( isDefined( level.killStreakSpecialCaseWeapons[sWeapon] ) ) // this is an optimization
  273.         {
  274.             switch ( sWeapon )
  275.             {
  276.                 case "ac130_105mm_mp":
  277.                 case "ac130_40mm_mp":
  278.                 case "ac130_25mm_mp":
  279.                     if ( attacker.ac130LifeId == attacker.pers["deaths"] )
  280.                         attacker.pers["cur_kill_streak"]++;
  281.                     break;
  282.                 case "cobra_player_minigun_mp":
  283.                 case "weapon_cobra_mk19_mp":
  284.                     if ( attacker.heliRideLifeId == attacker.pers["deaths"] )
  285.                         attacker.pers["cur_kill_streak"]++;
  286.                     break;
  287.                 case "cobra_20mm_mp":
  288.                 case "artillery_mp":
  289.                 case "stealth_bomb_mp":
  290.                 case "remotemissile_projectile_mp":
  291.                 case "sentry_minigun_mp":
  292.                 case "harrier_20mm_mp":
  293.                 case "pavelow_minigun_mp":
  294.                     if ( isDefined( eInflictor ) && isDefined( eInflictor.lifeId ) )
  295.                         killstreakLifeId = eInflictor.lifeId;
  296.                     else
  297.                         killstreakLifeId = attacker.lifeId;
  298.                        
  299.                     if ( killstreakLifeId == attacker.pers["deaths"] )
  300.                         attacker.pers["cur_kill_streak"]++;
  301.                     break;
  302.                 default:
  303.                     attacker.pers["cur_kill_streak"]++;
  304.                     break;
  305.             }
  306.         }
  307.         else
  308.         {
  309.             attacker.pers["cur_kill_streak"]++;
  310.         }
  311.  
  312.         attacker setPlayerStatIfGreater( "killstreak", attacker.pers["cur_kill_streak"] );
  313.  
  314.         if ( attacker.pers["cur_kill_streak"] > attacker getPersStat( "longestStreak" ) )
  315.             attacker setPersStat( "longestStreak", attacker.pers["cur_kill_streak"] );
  316.     }
  317.  
  318.     attacker.pers["cur_death_streak"] = 0;
  319.  
  320.     if ( attacker.pers["cur_kill_streak"] > attacker maps\mp\gametypes\_persistence::statGetChild( "round", "killStreak" ) )
  321.     {
  322.         attacker maps\mp\gametypes\_persistence::statSetChild( "round", "killStreak", attacker.pers["cur_kill_streak"] );
  323.     }
  324.  
  325.     if ( attacker.pers["cur_kill_streak"] > attacker.kill_streak )
  326.     {
  327.         attacker maps\mp\gametypes\_persistence::statSet( "killStreak", attacker.pers["cur_kill_streak"] );
  328.         attacker.kill_streak = attacker.pers["cur_kill_streak"];
  329.     }
  330.  
  331.     maps\mp\gametypes\_gamescore::givePlayerScore( "kill", attacker, self );
  332.     maps\mp\_skill::processKill( attacker, self );
  333.  
  334.     scoreSub = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "deathpointloss" );
  335.     maps\mp\gametypes\_gamescore::_setPlayerScore( self, maps\mp\gametypes\_gamescore::_getPlayerScore( self ) - scoreSub );
  336.  
  337.     if ( isDefined( level.ac130player ) && level.ac130player == attacker )
  338.         level notify( "ai_killed", self );
  339.  
  340.     //if ( lastKillStreak != attacker.pers["cur_kill_streak"] )
  341.     level notify ( "player_got_killstreak_" + attacker.pers["cur_kill_streak"], attacker );
  342.    
  343.     if ( isAlive( attacker ) )
  344.         attacker thread maps\mp\killstreaks\_killstreaks::checkKillstreakReward( attacker.pers["cur_kill_streak"] );
  345.  
  346.     attacker notify ( "killed_enemy" );
  347.  
  348.     if ( !level.teamBased )
  349.     {
  350.         self.attackers = [];
  351.         return;
  352.     }
  353.  
  354.     if ( isDefined( level.onNormalDeath ) && attacker.pers[ "team" ] != "spectator" )
  355.         [[ level.onNormalDeath ]]( self, attacker, lifeId );
  356.  
  357.     level thread maps\mp\gametypes\_battlechatter_mp::sayLocalSoundDelayed( attacker, "kill", 0.75 );  
  358.    
  359.     if ( isDefined( self.lastAttackedShieldPlayer ) && isDefined( self.lastAttackedShieldTime ) && self.lastAttackedShieldPlayer != attacker )
  360.     {
  361.         if ( getTime() - self.lastAttackedShieldTime < 2500 )
  362.         {
  363.             self.lastAttackedShieldPlayer thread maps\mp\gametypes\_gamescore::processShieldAssist( self );
  364.         }
  365.         else if ( isAlive( self.lastAttackedShieldPlayer ) && getTime() - self.lastAttackedShieldTime < 5000 )
  366.         {
  367.             forwardVec = vectorNormalize( anglesToForward( self.angles ) );
  368.             shieldVec = vectorNormalize( self.lastAttackedShieldPlayer.origin - self.origin );
  369.        
  370.             if ( vectorDot( shieldVec, forwardVec ) > 0.925 )
  371.                 self.lastAttackedShieldPlayer thread maps\mp\gametypes\_gamescore::processShieldAssist( self );
  372.         }
  373.     }
  374.  
  375.     if ( isDefined( self.attackers ) )
  376.     {
  377.         foreach ( player in self.attackers )
  378.         {
  379.             if ( !isDefined( player ) )
  380.                 continue;
  381.  
  382.             if ( player == attacker )
  383.                 continue;
  384.  
  385.             player thread maps\mp\gametypes\_gamescore::processAssist( self );
  386.         }
  387.         self.attackers = [];
  388.     }
  389. }
  390.  
  391. isPlayerWeapon( weaponName )
  392. {
  393.     if ( weaponClass( weaponName ) == "non-player" )
  394.         return false;
  395.        
  396.     if ( weaponClass( weaponName ) == "turret" )
  397.         return false;
  398.  
  399.     if ( weaponInventoryType( weaponName ) == "primary" || weaponInventoryType( weaponName ) == "altmode" )
  400.         return true;
  401.        
  402.     return false;
  403. }
  404.  
  405. Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
  406. {
  407.     PlayerKilled_internal( eInflictor, attacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, false );
  408. }
  409.  
  410.  
  411. QueueShieldForRemoval( shield )
  412. {
  413.     MY_MAX_SHIELDS_AT_A_TIME = 5;
  414.  
  415.     if ( !isDefined( level.shieldTrashArray ) )
  416.         level.shieldTrashArray = [];
  417.  
  418.     if ( level.shieldTrashArray.size >= MY_MAX_SHIELDS_AT_A_TIME )
  419.     {
  420.         idxMax = (level.shieldTrashArray.size - 1);
  421.         level.shieldTrashArray[0] delete();
  422.         for ( idx = 0; idx < idxMax; idx++ )
  423.             level.shieldTrashArray[idx] = level.shieldTrashArray[idx + 1];
  424.         level.shieldTrashArray[idxMax] = undefined;
  425.     }
  426.  
  427.     level.shieldTrashArray[level.shieldTrashArray.size] = shield;
  428. }
  429.  
  430.  
  431. LaunchShield( damage, meansOfDeath )
  432. {
  433.     shieldModel = "weapon_riot_shield_mp";
  434.  
  435.     self DetachShieldModel( shieldModel, "tag_weapon_left" );
  436.     self.hasRiotShield = false;
  437.     self.hasRiotShieldEquipped = false;
  438. }
  439.  
  440.  
  441. PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, isFauxDeath )
  442. {
  443.     prof_begin( "PlayerKilled" );
  444.     //prof_begin( " PlayerKilled_1" );
  445.    
  446.     victim endon( "spawned" );
  447.     victim notify( "killed_player" );
  448.  
  449.     assert( victim.sessionteam != "spectator" );
  450.  
  451.     if ( isDefined( attacker ) )
  452.         attacker.assistedSuicide = undefined;
  453.  
  454.     if ( !isDefined( victim.idFlags ) )
  455.     {
  456.         if ( sMeansOfDeath == "MOD_SUICIDE" )
  457.             victim.idFlags = 0;
  458.         else if ( sMeansOfDeath == "MOD_GRENADE" && isSubstr( sWeapon, "frag_grenade" ) && iDamage == 100000 )
  459.             victim.idFlags = 0;
  460.         else if ( sWeapon == "nuke_mp" )
  461.             victim.idFlags = 0;
  462.         else if ( level.friendlyfire >= 2)
  463.             victim.idFlags = 0;
  464.         else
  465.             assertEx( 0, "Victims ID flags not set, but means of death was gr or nuke: " + sMeansOfDeath  );
  466.     }
  467.  
  468.     if ( victim.hasRiotShieldEquipped )
  469.         victim LaunchShield( iDamage, sMeansofDeath );
  470.        
  471.     //victim thread checkForceBleedOut();
  472.  
  473.     if ( !isFauxDeath )
  474.     {
  475.         if ( isDefined( victim.endGame ) )
  476.         {
  477.             victim VisionSetNakedForPlayer( getDvar( "mapname" ), 2 );
  478.         }
  479.         else if ( !isDefined( victim.nuked ) )
  480.         {
  481.             victim VisionSetNakedForPlayer( getDvar( "mapname" ), 0 );
  482.             victim ThermalVisionOff();
  483.         }
  484.     }
  485.     else
  486.     {
  487.         victim.fauxDead = true;
  488.         self notify ( "death" );
  489.     }
  490.  
  491.     if ( game[ "state" ] == "postgame" )
  492.     {
  493.         //prof_end( " PlayerKilled_1" );
  494.         prof_end( "PlayerKilled" );
  495.         return;
  496.     }
  497.  
  498.     // replace params with last stand info
  499.     deathTimeOffset = 0;
  500.  
  501.     if ( !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) )
  502.         sPrimaryWeapon = eInflictor.primaryWeapon;
  503.     else if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" )
  504.         sPrimaryWeapon = attacker getCurrentPrimaryWeapon();
  505.     else
  506.         sPrimaryWeapon = undefined;
  507.  
  508.     if ( isdefined( victim.useLastStandParams ) )
  509.     {
  510.         victim ensureLastStandParamsValidity();
  511.         victim.useLastStandParams = undefined;
  512.  
  513.         assert( isdefined( victim.lastStandParams ) );
  514.  
  515.         eInflictor = victim.lastStandParams.eInflictor;
  516.         attacker = victim.lastStandParams.attacker;
  517.         iDamage = victim.lastStandParams.iDamage;
  518.         sMeansOfDeath = victim.lastStandParams.sMeansOfDeath;
  519.         sWeapon = victim.lastStandParams.sWeapon;
  520.         sPrimaryWeapon = victim.lastStandParams.sPrimaryWeapon;
  521.         vDir = victim.lastStandParams.vDir;
  522.         sHitLoc = victim.lastStandParams.sHitLoc;
  523.  
  524.         deathTimeOffset = ( gettime() - victim.lastStandParams.lastStandStartTime ) / 1000;
  525.         victim.lastStandParams = undefined;
  526.     }
  527.    
  528.     //prof_end( " PlayerKilled_1" );
  529.     //prof_begin( " PlayerKilled_2" );
  530.    
  531.     //used for endgame perk and assisted suicide.
  532.     if ( (!isDefined( attacker ) || attacker.classname == "trigger_hurt" || attacker.classname == "worldspawn" || attacker == victim ) && isDefined( self.attackers )  )
  533.     {
  534.         bestPlayer = undefined;
  535.        
  536.         foreach ( player in self.attackers )
  537.         {
  538.             if ( !isDefined( player ) )
  539.                 continue;
  540.            
  541.             if (! isDefined( victim.attackerData[ player.guid ].damage ) )
  542.                 continue;
  543.            
  544.             if ( player == victim || (level.teamBased && player.team == victim.team ) )
  545.                 continue;
  546.            
  547.             if ( victim.attackerData[ player.guid ].lasttimedamaged + 2500 < getTime() )
  548.                 continue;          
  549.            
  550.             if ( victim.attackerData[ player.guid ].damage > 1 && ! isDefined( bestPlayer ) )
  551.                 bestPlayer = player;
  552.             else if ( isDefined( bestPlayer ) && victim.attackerData[ player.guid ].damage > victim.attackerData[ bestPlayer.guid ].damage )
  553.                 bestPlayer = player;       
  554.         }
  555.        
  556.         if ( isDefined( bestPlayer ) )
  557.         {
  558.             attacker = bestPlayer;
  559.             attacker.assistedSuicide = true;
  560.             sWeapon = victim.attackerData[ bestPlayer.guid ].weapon;
  561.             vDir = victim.attackerData[ bestPlayer.guid ].vDir;
  562.             sHitLoc = victim.attackerData[ bestPlayer.guid ].sHitLoc;
  563.             psOffsetTime = victim.attackerData[ bestPlayer.guid ].psOffsetTime;
  564.             sMeansOfDeath = victim.attackerData[ bestPlayer.guid ].sMeansOfDeath;
  565.             iDamage = victim.attackerData[ bestPlayer.guid ].damage;
  566.             sPrimaryWeapon = victim.attackerData[ bestPlayer.guid ].sPrimaryWeapon;
  567.             eInflictor = attacker;
  568.         }
  569.     }
  570.     else
  571.     {
  572.         if ( isDefined( attacker ) )
  573.             attacker.assistedSuicide = undefined;  
  574.     }
  575.  
  576.     // override MOD
  577.     if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker ) )
  578.         sMeansOfDeath = "MOD_HEAD_SHOT";
  579.     else if ( sMeansOfDeath != "MOD_MELEE" && !isDefined( victim.nuked ) )
  580.         victim playDeathSound();
  581.    
  582.     friendlyFire = isFriendlyFire( victim, attacker );
  583.    
  584.     if ( isDefined( attacker ) )
  585.     {
  586.         // override attacker if it's a vehicle 
  587.         if ( attacker.code_classname == "script_vehicle" && isDefined( attacker.owner ) )
  588.             attacker = attacker.owner;
  589.  
  590.         // override attacker if it's a sentry  
  591.         if ( attacker.code_classname == "misc_turret" && isDefined( attacker.owner ) )
  592.             attacker = attacker.owner;
  593.  
  594.         // override attacker if it's a crate   
  595.         if ( attacker.code_classname == "script_model" && isDefined( attacker.owner ) )
  596.         {
  597.             attacker = attacker.owner;
  598.            
  599.             if ( !isFriendlyFire( victim, attacker ) && attacker != victim )
  600.                 attacker notify( "crushed_enemy" );
  601.         }
  602.     }
  603.    
  604.     //prof_end( " PlayerKilled_2" );
  605.     //prof_begin( " PlayerKilled_3" );
  606.    
  607.     //prof_begin( " PlayerKilled_3_drop" );
  608.     // drop weapons from killed player
  609.     if ( getDvar("g_gametype") != "oitc" && getDvar("g_gametype") != "gg" && getDvar("g_gametype") != "ss" )
  610.     {
  611.         victim maps\mp\gametypes\_weapons::dropScavengerForDeath( attacker );   // must be done before dropWeaponForDeath, since we use some weapon information
  612.         victim maps\mp\gametypes\_weapons::dropWeaponForDeath( attacker );
  613.     }
  614.     //prof_end( " PlayerKilled_3_drop" );
  615.    
  616.     if ( !isFauxDeath )
  617.     {
  618.         victim.sessionstate = "dead";
  619.         victim.statusicon = "hud_status_dead";
  620.     }
  621.  
  622.     // UTS update aliveCount
  623.     victim maps\mp\gametypes\_playerlogic::removeFromAliveCount();
  624.    
  625.     if ( !isDefined( victim.switching_teams ) )
  626.     {
  627.         // update our various stats
  628.         victim incPersStat( "deaths", 1 );
  629.         victim.deaths = victim getPersStat( "deaths" );
  630.         victim updatePersRatio( "kdRatio", "kills", "deaths" );
  631.         victim maps\mp\gametypes\_persistence::statSetChild( "round", "deaths", victim.deaths );
  632.         victim incPlayerStat( "deaths", 1 );
  633.     }
  634.  
  635.     if ( isDefined( attacker ) )
  636.         attacker checkKillSteal( victim );
  637.    
  638.     // obituary
  639.     obituary( victim, attacker, sWeapon, sMeansOfDeath );
  640.  
  641.     doKillcam = false;
  642.  
  643.     lifeId = getNextLifeId();
  644.    
  645.     victim logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc );
  646.     victim maps\mp\_matchdata::logPlayerLife( lifeId );
  647.     victim maps\mp\_matchdata::logPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc );
  648.    
  649.     if ( (sMeansOfDeath == "MOD_MELEE") )
  650.     {
  651.         if ( IsSubStr( sWeapon, "riotshield" ) )
  652.         {
  653.             attacker incPlayerStat( "shieldkills", 1 );
  654.            
  655.             if ( !matchMakingGame() )
  656.                 victim incPlayerStat( "shielddeaths", 1 );
  657.         }
  658.         else
  659.             attacker incPlayerStat( "knifekills", 1 );
  660.     }
  661.    
  662.     //prof_end( " PlayerKilled_3" );
  663.     //prof_begin( " PlayerKilled_4" );
  664.    
  665.     if ( victim isSwitchingTeams() )
  666.     {
  667.         handleTeamChangeDeath();
  668.     }
  669.     else if ( !isPlayer( attacker ) || (isPlayer( attacker ) && sMeansOfDeath == "MOD_FALLING") )
  670.     {
  671.         handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc );
  672.     }
  673.     else if ( attacker == victim )
  674.     {
  675.         handleSuicideDeath( sMeansOfDeath, sHitLoc );
  676.     }
  677.     else if ( friendlyFire )
  678.     {
  679.         if ( !isDefined( victim.nuked ) )
  680.         {
  681.             handleFriendlyFireDeath( attacker );
  682.         }
  683.     }
  684.     else
  685.     {
  686.         if ( sMeansOfDeath == "MOD_GRENADE" && eInflictor == attacker )
  687.             addAttacker( victim, attacker, eInflictor, sWeapon, iDamage, (0,0,0), vDir, sHitLoc, psOffsetTime, sMeansOfDeath );
  688.  
  689.         doKillcam = true;
  690.         handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath );
  691.         victim thread maps\mp\gametypes\_missions::playerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc, attacker.modifiers );
  692.        
  693.         victim.pers["cur_death_streak"]++;
  694.        
  695.         if ( !getGametypeNumLives() && !matchMakingGame() )
  696.             victim setPlayerStatIfGreater( "deathstreak", victim.pers["cur_death_streak"] );
  697.     }
  698.    
  699.     //prof_end( " PlayerKilled_4" );
  700.     //prof_begin( " PlayerKilled_5" );
  701.    
  702.     // clear any per life variables
  703.     victim resetPlayerVariables();
  704.     victim.lastAttacker = attacker;
  705.     victim.lastDeathPos = victim.origin;
  706.     victim.deathTime = getTime();
  707.     victim.wantSafeSpawn = false;
  708.     victim.revived = false;
  709.     victim.sameShotDamage = 0;
  710.  
  711.     if ( isFauxDeath )
  712.     {
  713.         doKillcam = false;
  714.         deathAnimDuration = (victim PlayerForceDeathAnim( eInflictor, sMeansOfDeath, sWeapon, sHitLoc, vDir ));
  715.     }
  716.  
  717.     victim.body = victim clonePlayer( deathAnimDuration );
  718.  
  719.     if ( isFauxDeath )
  720.         victim PlayerHide();
  721.  
  722.     if ( victim isOnLadder() || victim isMantling() || !victim isOnGround() || isDefined( victim.nuked ) )
  723.         victim.body startRagDoll();
  724.  
  725.     if ( !isDefined( victim.switching_teams ) )
  726.         thread maps\mp\gametypes\_deathicons::addDeathicon( victim.body, victim, victim.team, 5.0 );
  727.  
  728.     thread delayStartRagdoll( victim.body, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath );
  729.  
  730.     // allow per gametype death handling   
  731.     victim thread [[ level.onPlayerKilled ]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, lifeId );
  732.  
  733.     if ( isPlayer( attacker ) )
  734.         attackerNum = attacker getEntityNumber();
  735.     else
  736.         attackerNum = -1;
  737.     killcamentity = victim getKillcamEntity( attacker, eInflictor, sWeapon );
  738.     killcamentityindex = -1;
  739.     killcamentitystarttime = 0;
  740.  
  741.     if ( isDefined( killcamentity ) )
  742.     {
  743.         killcamentityindex = killcamentity getEntityNumber();// must do this before any waiting lest the entity be deleted
  744.         killcamentitystarttime = killcamentity.birthtime;
  745.         if ( !isdefined( killcamentitystarttime ) )
  746.             killcamentitystarttime = 0;
  747.     }
  748.  
  749.      /#
  750.     if ( getDvarInt( "scr_forcekillcam" ) != 0 )
  751.         doKillcam = true;
  752.     #/
  753.  
  754.     if ( isDefined( attacker.finalKill ) )
  755.         maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid );
  756.    
  757.     //prof_end( " PlayerKilled_5" );
  758.     //prof_begin( " PlayerKilled_6" );
  759.    
  760.     if ( isDefined( attacker.finalKill ) && doKillcam && !isDefined( level.nukeDetonated ) )
  761.     {
  762.         level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime );
  763.  
  764.         if ( !isFauxDeath )
  765.             wait ( 1.0 );
  766.     }
  767.    
  768.     if ( isDefined(level.ggended) && level.ggended == true || isDefined(level.ssended) && level.ssended == true )
  769.     {
  770.         foreach( player in level.players )
  771.         {
  772.             player notify("killcum");
  773.         }
  774.         wait 0.1;
  775.         level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime );
  776.        
  777.         if ( !isFauxDeath )
  778.             wait ( 1.0 );
  779.     }
  780.    
  781.     if ( !isFauxDeath )
  782.     {
  783.         if ( !level.showingFinalKillcam && !level.killcam && doKillcam )
  784.         {
  785.             if ( victim _hasPerk( "specialty_copycat" ) && isDefined( victim.pers["copyCatLoadout"] ) )
  786.             {
  787.                 victim thread maps\mp\gametypes\_killcam::waitDeathCopyCatButton( attacker );
  788.                 wait ( 1.0 );
  789.             }
  790.         }
  791.        
  792.         // let the player watch themselves die
  793.         wait( 0.25 );
  794.         victim thread maps\mp\gametypes\_killcam::cancelKillCamOnUse();
  795.         wait( 0.25 );
  796.        
  797.         self.respawnTimerStartTime = gettime() + 1000;
  798.         timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true );
  799.         if ( timeUntilSpawn < 1 )
  800.             timeUntilSpawn = 1;
  801.         victim thread maps\mp\gametypes\_playerlogic::predictAboutToSpawnPlayerOverTime( timeUntilSpawn );
  802.        
  803.         wait( 1.0 );
  804.         victim notify( "death_delay_finished" );
  805.     }
  806.  
  807.     postDeathDelay = ( getTime() - victim.deathTime ) / 1000;
  808.     self.respawnTimerStartTime = gettime();
  809.  
  810.     if ( !(isDefined( victim.cancelKillcam) && victim.cancelKillcam) && doKillcam && level.killcam && game[ "state" ] == "playing" && !victim isUsingRemote() && !level.showingFinalKillcam )
  811.     {
  812.         livesLeft = !( getGametypeNumLives() && !victim.pers[ "lives" ] );
  813.         timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true );
  814.         willRespawnImmediately = livesLeft && ( timeUntilSpawn <= 0 );
  815.        
  816.         if ( !livesLeft )
  817.             timeUntilSpawn = -1;
  818.  
  819.         victim maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, timeUntilSpawn, maps\mp\gametypes\_gamelogic::timeUntilRoundEnd(), attacker, victim );
  820.     }
  821.    
  822.     //prof_end( " PlayerKilled_6" );
  823.     //prof_begin( " PlayerKilled_7" );
  824.    
  825.     //self openMenu( "killedby_card_hide" );
  826.  
  827.     if ( game[ "state" ] != "playing" )
  828.     {
  829.         if ( !level.showingFinalKillcam )
  830.         {
  831.             victim.sessionstate = "dead";
  832.             victim ClearKillcamState();
  833.         }
  834.        
  835.         //prof_end( " PlayerKilled_7" );
  836.         prof_end( "PlayerKilled" );
  837.         return;
  838.     }
  839.  
  840.     // class may be undefined if we have changed teams
  841.     if ( isValidClass( victim.class ) )
  842.     {
  843.         victim thread maps\mp\gametypes\_playerlogic::spawnClient();
  844.     }
  845.    
  846.     //prof_end( " PlayerKilled_7" );
  847.     prof_end( "PlayerKilled" );
  848. }
  849.  
  850. checkForceBleedout()
  851. {
  852.     if ( level.dieHardMode != 1 )
  853.         return false;
  854.    
  855.     if ( !getGametypeNumLives() )
  856.         return false;
  857.    
  858.     if ( level.livesCount[self.team] > 0 )
  859.         return false;
  860.    
  861.     foreach ( player in level.players )
  862.     {
  863.         if ( !isAlive( player ) )
  864.             continue;
  865.            
  866.         if ( player.team != self.team )
  867.             continue;
  868.            
  869.         if ( player == self )
  870.             continue;
  871.        
  872.         if ( !player.inLastStand )
  873.             return false;
  874.     }
  875.    
  876.     foreach ( player in level.players )
  877.     {
  878.         if ( !isAlive( player ) )
  879.             continue;
  880.        
  881.         if ( player.team != self.team )
  882.             continue;
  883.        
  884.         if ( player.inLastStand && player != self )
  885.             player lastStandBleedOut(false);       
  886.     }
  887.    
  888.     return true;                   
  889. }
  890.  
  891. checkKillSteal( vic )
  892. {
  893.     if ( matchMakingGame() )
  894.         return;
  895.    
  896.     greatestDamage = 0;
  897.     greatestAttacker = undefined;
  898.    
  899.     if ( isDefined( vic.attackerdata ) && vic.attackerdata.size > 1 )  
  900.     {
  901.         foreach ( attacker in vic.attackerdata )
  902.         {
  903.             if ( attacker.damage > greatestDamage )
  904.             {
  905.                 greatestDamage = attacker.damage;
  906.                 greatestAttacker = attacker.attackerEnt;   
  907.             }
  908.         }
  909.        
  910.         if ( isDefined( greatestAttacker ) && greatestAttacker != self )
  911.             self incPlayerStat( "killsteals", 1 );
  912.     }
  913. }
  914.  
  915. doFinalKillcam( delay, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime )
  916. {
  917.     level.showingFinalKillcam = true;
  918.  
  919.     level waittill ( "round_end_finished" );
  920.  
  921.     if ( !isDefined( victim ) || !isDefined( attacker ) )
  922.     {
  923.         level.showingFinalKillcam = false;
  924.         return;
  925.     }
  926.  
  927.     postDeathDelay = (( getTime() - victim.deathTime ) / 1000);
  928.    
  929.     foreach ( player in level.players )
  930.     {
  931.         player closePopupMenu();
  932.         player closeInGameMenu();
  933.         player VisionSetNakedForPlayer( getDvar( "mapname" ), 0 );
  934.         player.killcamentitylookat = victim getEntityNumber();
  935.        
  936.         if ( (player != victim || (!isRoundBased() || isLastRound())) && player _hasPerk( "specialty_copycat" ) )
  937.             player _unsetPerk( "specialty_copycat" );
  938.        
  939.         player thread maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, 0, 10000, attacker, victim );
  940.     }
  941.  
  942.     wait( 0.1 );
  943.  
  944.     while ( anyPlayersInKillcam() )
  945.         wait( 0.05 );
  946.    
  947.     level.showingFinalKillcam = false;
  948. }
  949.  
  950.  
  951. anyPlayersInKillcam()
  952. {
  953.     foreach ( player in level.players )
  954.     {
  955.         if ( isDefined( player.killcam ) )
  956.             return true;
  957.     }
  958.    
  959.     return false;
  960. }
  961.  
  962.  
  963. resetPlayerVariables()
  964. {
  965.     self.killedPlayersCurrent = [];
  966.     self.switching_teams = undefined;
  967.     self.joining_team = undefined;
  968.     self.leaving_team = undefined;
  969.  
  970.     self.pers["cur_kill_streak"] = 0;
  971.  
  972.     self maps\mp\gametypes\_gameobjects::detachUseModels();// want them detached before we create our corpse
  973. }
  974.  
  975.  
  976. getKillcamEntity( attacker, eInflictor, sWeapon )
  977. {
  978.     if ( !isDefined( eInflictor ) )
  979.         return undefined;
  980.    
  981.     if ( eInflictor == attacker )
  982.         return undefined;
  983.    
  984.     if ( isSubStr( sWeapon, "ac130_" ) )
  985.         return undefined;
  986.  
  987.     if ( sWeapon == "cobra_player_minigun_mp" )
  988.         return undefined;
  989.    
  990.     if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" || sWeapon == "pavelow_minigun_mp" )
  991.         return eInflictor.killCamEnt;
  992.    
  993.     if ( isDefined( eInflictor.script_gameobjectname ) && eInflictor.script_gameobjectname == "bombzone" )
  994.         return eInflictor.killCamEnt;
  995.    
  996.     if ( eInflictor.classname == "script_origin" || eInflictor.classname == "script_model" || eInflictor.classname == "script_brushmodel" )
  997.         return undefined; // probably a barrel or a car... code does airstrike cam for these things which looks bad
  998.    
  999.     if ( issubstr( sWeapon, "remotemissile_" ) )
  1000.         return undefined;
  1001.     if ( issubstr( sWeapon, "ac130_" ) )
  1002.         return undefined;
  1003.    
  1004.     return eInflictor;
  1005. }
  1006.  
  1007.  
  1008. HitlocDebug( attacker, victim, damage, hitloc, dflags )
  1009. {
  1010.     colors = [];
  1011.     colors[ 0 ] = 2;
  1012.     colors[ 1 ] = 3;
  1013.     colors[ 2 ] = 5;
  1014.     colors[ 3 ] = 7;
  1015.  
  1016.     if ( !getdvarint( "scr_hitloc_debug" ) )
  1017.         return;
  1018.  
  1019.     if ( !isdefined( attacker.hitlocInited ) )
  1020.     {
  1021.         for ( i = 0; i < 6; i++ )
  1022.         {
  1023.             attacker setClientDvar( "ui_hitloc_" + i, "" );
  1024.         }
  1025.         attacker.hitlocInited = true;
  1026.     }
  1027.  
  1028.     if ( level.splitscreen || !isPLayer( attacker ) )
  1029.         return;
  1030.  
  1031.     elemcount = 6;
  1032.     if ( !isdefined( attacker.damageInfo ) )
  1033.     {
  1034.         attacker.damageInfo = [];
  1035.         for ( i = 0; i < elemcount; i++ )
  1036.         {
  1037.             attacker.damageInfo[ i ] = spawnstruct();
  1038.             attacker.damageInfo[ i ].damage = 0;
  1039.             attacker.damageInfo[ i ].hitloc = "";
  1040.             attacker.damageInfo[ i ].bp = false;
  1041.             attacker.damageInfo[ i ].jugg = false;
  1042.             attacker.damageInfo[ i ].colorIndex = 0;
  1043.         }
  1044.         attacker.damageInfoColorIndex = 0;
  1045.         attacker.damageInfoVictim = undefined;
  1046.     }
  1047.  
  1048.     for ( i = elemcount - 1; i > 0; i -- )
  1049.     {
  1050.         attacker.damageInfo[ i ].damage = attacker.damageInfo[ i - 1 ].damage;
  1051.         attacker.damageInfo[ i ].hitloc = attacker.damageInfo[ i - 1 ].hitloc;
  1052.         attacker.damageInfo[ i ].bp = attacker.damageInfo[ i - 1 ].bp;
  1053.         attacker.damageInfo[ i ].jugg = attacker.damageInfo[ i - 1 ].jugg;
  1054.         attacker.damageInfo[ i ].colorIndex = attacker.damageInfo[ i - 1 ].colorIndex;
  1055.     }
  1056.     attacker.damageInfo[ 0 ].damage = damage;
  1057.     attacker.damageInfo[ 0 ].hitloc = hitloc;
  1058.     attacker.damageInfo[ 0 ].bp = ( dflags & level.iDFLAGS_PENETRATION );
  1059.     attacker.damageInfo[ 0 ].jugg = victim hasPerk( "specialty_armorvest", true );
  1060.     if ( isdefined( attacker.damageInfoVictim ) && ( attacker.damageInfoVictim != victim ) )
  1061.     {
  1062.         attacker.damageInfoColorIndex++ ;
  1063.         if ( attacker.damageInfoColorIndex == colors.size )
  1064.             attacker.damageInfoColorIndex = 0;
  1065.     }
  1066.     attacker.damageInfoVictim = victim;
  1067.     attacker.damageInfo[ 0 ].colorIndex = attacker.damageInfoColorIndex;
  1068.  
  1069.     for ( i = 0; i < elemcount; i++ )
  1070.     {
  1071.         color = "^" + colors[ attacker.damageInfo[ i ].colorIndex ];
  1072.         if ( attacker.damageInfo[ i ].hitloc != "" )
  1073.         {
  1074.             val = color + attacker.damageInfo[ i ].hitloc;
  1075.             if ( attacker.damageInfo[ i ].bp )
  1076.                 val += " (BP)";
  1077.             if ( attacker.damageInfo[ i ].jugg )
  1078.                 val += " (Jugg)";
  1079.             attacker setClientDvar( "ui_hitloc_" + i, val );
  1080.         }
  1081.         attacker setClientDvar( "ui_hitloc_damage_" + i, color + attacker.damageInfo[ i ].damage );
  1082.     }
  1083. }
  1084.  
  1085. giveRecentShieldXP()
  1086. {
  1087.     self endon ( "death" );
  1088.     self endon ( "disconnect" );
  1089.    
  1090.     self notify ( "giveRecentShieldXP" );
  1091.     self endon ( "giveRecentShieldXP" );
  1092.    
  1093.     self.recentShieldXP++;
  1094.    
  1095.     wait ( 20.0 );
  1096.    
  1097.     self.recentShieldXP = 0;
  1098. }
  1099.  
  1100.  
  1101. Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
  1102. {
  1103.  
  1104.     if ( getDvar("g_gametype") == "oitc" && sWeapon == "turret_minigun_mp" || getDvar("g_gametype") == "gg" && sWeapon == "turret_minigun_mp" || getDvar("g_gametype") == "ss" && sWeapon == "turret_minigun_mp" )
  1105.     {
  1106.         iDamage = 0;
  1107.     }
  1108.    
  1109.     if ( !isReallyAlive( victim ) )
  1110.         return;
  1111.    
  1112.     if ( isDefined( eAttacker ) && eAttacker.classname == "script_origin" && isDefined( eAttacker.type ) && eAttacker.type == "soft_landing" )
  1113.         return;
  1114.    
  1115.     if ( isDefined( level.hostMigrationTimer ) )
  1116.         return;
  1117.    
  1118.     if ( sMeansOfDeath == "MOD_FALLING" )
  1119.         victim thread emitFallDamage( iDamage );
  1120.        
  1121.     if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && iDamage != 1 )
  1122.     {
  1123.         iDamage *= getDvarFloat( "scr_explBulletMod" );
  1124.         iDamage = int( iDamage );
  1125.     }
  1126.  
  1127.     if ( isDefined( eAttacker ) && eAttacker.classname == "worldspawn" )
  1128.         eAttacker = undefined;
  1129.    
  1130.     if ( isDefined( eAttacker ) && isDefined( eAttacker.gunner ) )
  1131.         eAttacker = eAttacker.gunner;
  1132.    
  1133.     attackerIsNPC = isDefined( eAttacker ) && !isDefined( eAttacker.gunner ) && (eAttacker.classname == "script_vehicle" || eAttacker.classname == "misc_turret" || eAttacker.classname == "script_model");
  1134.     attackerIsHittingTeammate = level.teamBased && isDefined( eAttacker ) && ( victim != eAttacker ) && isDefined( eAttacker.team ) && ( victim.pers[ "team" ] == eAttacker.team );
  1135.  
  1136.     stunFraction = 0.0;
  1137.  
  1138.     if ( iDFlags & level.iDFLAGS_STUN )
  1139.     {
  1140.         stunFraction = 0.0;
  1141.         //victim StunPlayer( 1.0 );
  1142.         iDamage = 0.0;
  1143.     }
  1144.     else if ( sHitLoc == "shield" )
  1145.     {
  1146.         if ( attackerIsHittingTeammate && level.friendlyfire == 0 )
  1147.             return;
  1148.        
  1149.         if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && !attackerIsHittingTeammate )
  1150.         {
  1151.             if ( isPlayer( eAttacker ) )
  1152.             {
  1153.                 eAttacker.lastAttackedShieldPlayer = victim;
  1154.                 eAttacker.lastAttackedShieldTime = getTime();
  1155.             }
  1156.             victim notify ( "shield_blocked" );
  1157.  
  1158.             // fix turret + shield challenge exploits
  1159.             if ( sWeapon == "turret_minigun_mp" )
  1160.                 shieldDamage = 25;
  1161.             else
  1162.                 shieldDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );
  1163.                        
  1164.             victim.shieldDamage += shieldDamage;
  1165.  
  1166.             // fix turret + shield challenge exploits
  1167.             if ( sWeapon != "turret_minigun_mp" || cointoss() )
  1168.                 victim.shieldBulletHits++;
  1169.  
  1170.             if ( victim.shieldBulletHits >= level.riotShieldXPBullets )
  1171.             {
  1172.                 if ( self.recentShieldXP > 4 )
  1173.                     xpVal = int( 50 / self.recentShieldXP );
  1174.                 else
  1175.                     xpVal = 50;
  1176.                
  1177.                 printLn( xpVal );
  1178.                
  1179.                 victim thread maps\mp\gametypes\_rank::giveRankXP( "shield_damage", xpVal );
  1180.                 victim thread giveRecentShieldXP();
  1181.                
  1182.                 victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_damage", victim.shieldDamage );
  1183.  
  1184.                 victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_bullet_hits", victim.shieldBulletHits );
  1185.                
  1186.                 victim.shieldDamage = 0;
  1187.                 victim.shieldBulletHits = 0;
  1188.             }
  1189.         }
  1190.  
  1191.         if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT )
  1192.         {
  1193.             if (  !attackerIsHittingTeammate )
  1194.                 victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 );
  1195.  
  1196.             sHitLoc = "none";   // code ignores any damage to a "shield" bodypart.
  1197.             if ( !(iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT_HUGE) )
  1198.                 iDamage *= 0.0;
  1199.         }
  1200.         else if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_SPLASH )
  1201.         {
  1202.             if ( isDefined( eInflictor ) && isDefined( eInflictor.stuckEnemyEntity ) && eInflictor.stuckEnemyEntity == victim ) //does enough damage to shield carrier to ensure death
  1203.                 iDamage = 101;
  1204.            
  1205.             victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 );
  1206.             sHitLoc = "none";   // code ignores any damage to a "shield" bodypart.
  1207.         }
  1208.         else
  1209.         {
  1210.             return;
  1211.         }
  1212.     }
  1213.     else if ( (smeansofdeath == "MOD_MELEE") && IsSubStr( sweapon, "riotshield" ) )
  1214.     {
  1215.         if ( !(attackerIsHittingTeammate && (level.friendlyfire == 0)) )
  1216.         {
  1217.             stunFraction = 0.0;
  1218.             victim StunPlayer( 0.0 );
  1219.         }
  1220.     }
  1221.  
  1222.     if ( !attackerIsHittingTeammate )
  1223.         iDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );
  1224.    
  1225.     if ( !iDamage )
  1226.         return false;
  1227.    
  1228.     victim.iDFlags = iDFlags;
  1229.     victim.iDFlagsTime = getTime();
  1230.  
  1231.     if ( game[ "state" ] == "postgame" )
  1232.         return;
  1233.     if ( victim.sessionteam == "spectator" )
  1234.         return;
  1235.     if ( isDefined( victim.canDoCombat ) && !victim.canDoCombat )
  1236.         return;
  1237.     if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat )
  1238.         return;
  1239.  
  1240.     // handle vehicles/turrets and friendly fire
  1241.     if ( attackerIsNPC && attackerIsHittingTeammate )
  1242.     {
  1243.         if ( sMeansOfDeath == "MOD_CRUSH" )
  1244.         {
  1245.             victim _suicide();
  1246.             return;
  1247.         }
  1248.        
  1249.         if ( !level.friendlyfire )
  1250.             return;
  1251.     }
  1252.  
  1253.     prof_begin( "PlayerDamage flags/tweaks" );
  1254.  
  1255.     // Don't do knockback if the damage direction was not specified
  1256.     if ( !isDefined( vDir ) )
  1257.         iDFlags |= level.iDFLAGS_NO_KNOCKBACK;
  1258.  
  1259.     friendly = false;
  1260.  
  1261.     if ( ( victim.health == victim.maxhealth && ( !isDefined( victim.lastStand ) || !victim.lastStand )  ) || !isDefined( victim.attackers ) && !isDefined( victim.lastStand )  )
  1262.     {
  1263.         victim.attackers = [];
  1264.         victim.attackerData = [];
  1265.     }
  1266.  
  1267.     if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, eAttacker ) )
  1268.         sMeansOfDeath = "MOD_HEAD_SHOT";
  1269.  
  1270.     if ( maps\mp\gametypes\_tweakables::getTweakableValue( "game", "onlyheadshots" ) )
  1271.     {
  1272.         if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" )
  1273.             return;
  1274.         else if ( sMeansOfDeath == "MOD_HEAD_SHOT" )
  1275.             iDamage = 150;
  1276.     }
  1277.  
  1278.     // explosive barrel/car detection
  1279.     if ( sWeapon == "none" && isDefined( eInflictor ) )
  1280.     {
  1281.         if ( isDefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) )
  1282.             sWeapon = "destructible_car";
  1283.     }
  1284.  
  1285.     prof_end( "PlayerDamage flags/tweaks" );
  1286.  
  1287.     // check for completely getting out of the damage
  1288.     if ( !(iDFlags & level.iDFLAGS_NO_PROTECTION) )
  1289.     {
  1290.         // items you own don't damage you in FFA
  1291.         if ( !level.teamBased && attackerIsNPC && isDefined( eAttacker.owner ) && eAttacker.owner == victim )
  1292.         {
  1293.             prof_end( "PlayerDamage player" );
  1294.  
  1295.             if ( sMeansOfDeath == "MOD_CRUSH" )
  1296.                 victim _suicide();
  1297.  
  1298.             return;
  1299.         }
  1300.  
  1301.         if ( ( isSubStr( sMeansOfDeath, "MOD_GRENADE" ) || isSubStr( sMeansOfDeath, "MOD_EXPLOSIVE" ) || isSubStr( sMeansOfDeath, "MOD_PROJECTILE" ) ) && isDefined( eInflictor ) && isDefined( eAttacker ) )
  1302.         {
  1303.             // protect players from spawnkill grenades
  1304.             if ( eInflictor.classname == "grenade" && ( victim.lastSpawnTime + 3500 ) > getTime() && isDefined( victim.lastSpawnPoint ) && distance( eInflictor.origin, victim.lastSpawnPoint.origin ) < 250 )
  1305.             {
  1306.                 prof_end( "PlayerDamage player" );
  1307.                 return;
  1308.             }
  1309.  
  1310.             victim.explosiveInfo = [];
  1311.             victim.explosiveInfo[ "damageTime" ] = getTime();
  1312.             victim.explosiveInfo[ "damageId" ] = eInflictor getEntityNumber();
  1313.             victim.explosiveInfo[ "returnToSender" ] = false;
  1314.             victim.explosiveInfo[ "counterKill" ] = false;
  1315.             victim.explosiveInfo[ "chainKill" ] = false;
  1316.             victim.explosiveInfo[ "cookedKill" ] = false;
  1317.             victim.explosiveInfo[ "throwbackKill" ] = false;
  1318.             victim.explosiveInfo[ "suicideGrenadeKill" ] = false;
  1319.             victim.explosiveInfo[ "weapon" ] = sWeapon;
  1320.  
  1321.             isFrag = isSubStr( sWeapon, "frag_" );
  1322.  
  1323.             if ( eAttacker != victim )
  1324.             {
  1325.                 if ( ( isSubStr( sWeapon, "c4_" ) || isSubStr( sWeapon, "claymore_" ) ) && isDefined( eAttacker ) && isDefined( eInflictor.owner ) )
  1326.                 {
  1327.                     victim.explosiveInfo[ "returnToSender" ] = ( eInflictor.owner == victim );
  1328.                     victim.explosiveInfo[ "counterKill" ] = isDefined( eInflictor.wasDamaged );
  1329.                     victim.explosiveInfo[ "chainKill" ] = isDefined( eInflictor.wasChained );
  1330.                     victim.explosiveInfo[ "bulletPenetrationKill" ] = isDefined( eInflictor.wasDamagedFromBulletPenetration );
  1331.                     victim.explosiveInfo[ "cookedKill" ] = false;
  1332.                 }
  1333.  
  1334.                 if ( isDefined( eAttacker.lastGrenadeSuicideTime ) && eAttacker.lastGrenadeSuicideTime >= gettime() - 50 && isFrag )
  1335.                     victim.explosiveInfo[ "suicideGrenadeKill" ] = true;
  1336.             }
  1337.  
  1338.             if ( isFrag )
  1339.             {
  1340.                 victim.explosiveInfo[ "cookedKill" ] = isDefined( eInflictor.isCooked );
  1341.                 victim.explosiveInfo[ "throwbackKill" ] = isDefined( eInflictor.threwBack );
  1342.             }
  1343.            
  1344.             victim.explosiveInfo[ "stickKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "enemy";
  1345.             victim.explosiveInfo[ "stickFriendlyKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "friendly";
  1346.         }
  1347.    
  1348.         if ( isPlayer( eAttacker ) )
  1349.             eAttacker.pers[ "participation" ]++ ;
  1350.  
  1351.         prevHealthRatio = victim.health / victim.maxhealth;
  1352.  
  1353.         if ( attackerIsHittingTeammate )
  1354.         {
  1355.             if ( !matchMakingGame() && isPlayer(eAttacker) )
  1356.                 eAttacker incPlayerStat( "mostff", 1 );
  1357.            
  1358.             prof_begin( "PlayerDamage player" );// profs automatically end when the function returns
  1359.             if ( level.friendlyfire == 0 || ( !isPlayer(eAttacker) && level.friendlyfire != 1 ) )// no one takes damage
  1360.             {
  1361.                 if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" )
  1362.                     victim damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker );
  1363.                 return;
  1364.             }
  1365.             else if ( level.friendlyfire == 1 )// the friendly takes damage
  1366.             {
  1367.                 if ( iDamage < 1 )
  1368.                     iDamage = 1;
  1369.  
  1370.                 victim.lastDamageWasFromEnemy = false;
  1371.  
  1372.                 victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1373.             }
  1374.             else if ( ( level.friendlyfire == 2 ) && isReallyAlive( eAttacker ) )// only the attacker takes damage
  1375.             {
  1376.                 iDamage = int( iDamage * .5 );
  1377.                 if ( iDamage < 1 )
  1378.                     iDamage = 1;
  1379.  
  1380.                 eAttacker.lastDamageWasFromEnemy = false;
  1381.  
  1382.                 eAttacker.friendlydamage = true;
  1383.                 eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1384.                 eAttacker.friendlydamage = undefined;
  1385.             }
  1386.             else if ( level.friendlyfire == 3 && isReallyAlive( eAttacker ) )// both friendly and attacker take damage
  1387.             {
  1388.                 iDamage = int( iDamage * .5 );
  1389.                 if ( iDamage < 1 )
  1390.                     iDamage = 1;
  1391.  
  1392.                 victim.lastDamageWasFromEnemy = false;
  1393.                 eAttacker.lastDamageWasFromEnemy = false;
  1394.  
  1395.                 victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1396.                 if ( isReallyAlive( eAttacker ) )// may have died due to friendly fire punishment
  1397.                 {
  1398.                     eAttacker.friendlydamage = true;
  1399.                     eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1400.                     eAttacker.friendlydamage = undefined;
  1401.                 }
  1402.             }
  1403.  
  1404.             friendly = true;
  1405.            
  1406.         }
  1407.         else// not hitting teammate
  1408.         {
  1409.             prof_begin( "PlayerDamage world" );
  1410.  
  1411.             if ( iDamage < 1 )
  1412.                 iDamage = 1;
  1413.  
  1414.             if ( isDefined( eAttacker ) && isPlayer( eAttacker ) )
  1415.                 addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath );
  1416.            
  1417.             if ( sMeansOfDeath == "MOD_EXPLOSIVE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" && iDamage < victim.health )
  1418.                 victim notify( "survived_explosion" );
  1419.  
  1420.             if ( isdefined( eAttacker ) )
  1421.                 level.lastLegitimateAttacker = eAttacker;
  1422.  
  1423.             if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) )
  1424.                 eAttacker thread maps\mp\gametypes\_weapons::checkHit( sWeapon, victim );
  1425.  
  1426.             if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) && eAttacker != victim )
  1427.             {
  1428.                 eAttacker thread maps\mp\_events::damagedPlayer( self, iDamage, sWeapon );
  1429.                 victim.attackerPosition = eAttacker.origin;
  1430.             }
  1431.             else
  1432.             {
  1433.                 victim.attackerPosition = undefined;
  1434.             }
  1435.  
  1436.             if ( issubstr( sMeansOfDeath, "MOD_GRENADE" ) && isDefined( eInflictor.isCooked ) )
  1437.                 victim.wasCooked = getTime();
  1438.             else
  1439.                 victim.wasCooked = undefined;
  1440.  
  1441.             victim.lastDamageWasFromEnemy = ( isDefined( eAttacker ) && ( eAttacker != victim ) );
  1442.  
  1443.             if ( victim.lastDamageWasFromEnemy )
  1444.                 eAttacker.damagedPlayers[ victim.guid ] = getTime();
  1445.  
  1446.             victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1447.  
  1448.             if ( isDefined( level.ac130player ) && isDefined( eAttacker ) && ( level.ac130player == eAttacker ) )
  1449.                 level notify( "ai_pain", victim );
  1450.  
  1451.             victim thread maps\mp\gametypes\_missions::playerDamaged( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc );
  1452.  
  1453.             prof_end( "PlayerDamage world" );
  1454.            
  1455.         }
  1456.  
  1457.         if ( attackerIsNPC && isDefined( eAttacker.gunner ) )
  1458.             damager = eAttacker.gunner;
  1459.         else
  1460.             damager = eAttacker;
  1461.  
  1462.         if ( isDefined( damager) && damager != victim && iDamage > 0 )
  1463.         {
  1464.             if ( iDFlags & level.iDFLAGS_STUN )
  1465.                 typeHit = "stun";
  1466.             else if ( victim hasPerk( "specialty_armorvest", true ) || (isExplosiveDamage( sMeansOfDeath ) && victim _hasPerk( "_specialty_blastshield" )) )
  1467.                 typeHit = "hitBodyArmor";
  1468.             else if ( victim _hasPerk( "specialty_combathigh") )
  1469.                 typeHit = "hitEndGame";
  1470.             else
  1471.                 typeHit = "standard";
  1472.                
  1473.             damager thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( typeHit );
  1474.         }
  1475.  
  1476.         victim.hasDoneCombat = true;
  1477.     }
  1478.  
  1479.     if ( isdefined( eAttacker ) && ( eAttacker != victim ) && !friendly )
  1480.         level.useStartSpawns = false;
  1481.  
  1482.  
  1483.     //=================
  1484.     // Damage Logging
  1485.     //=================
  1486.  
  1487.     prof_begin( "PlayerDamage log" );
  1488.  
  1489.     // why getEntityNumber() for victim and .clientid for attacker?
  1490.     if ( getDvarInt( "g_debugDamage" ) )
  1491.         println( "client:" + victim getEntityNumber() + " health:" + victim.health + " attacker:" + eAttacker.clientid + " inflictor is player:" + isPlayer( eInflictor ) + " damage:" + iDamage + " hitLoc:" + sHitLoc );
  1492.  
  1493.     if ( victim.sessionstate != "dead" )
  1494.     {
  1495.         lpselfnum = victim getEntityNumber();
  1496.         lpselfname = victim.name;
  1497.         lpselfteam = victim.pers[ "team" ];
  1498.         lpselfGuid = victim.guid;
  1499.         lpattackerteam = "";
  1500.  
  1501.         if ( isPlayer( eAttacker ) )
  1502.         {
  1503.             lpattacknum = eAttacker getEntityNumber();
  1504.             lpattackGuid = eAttacker.guid;
  1505.             lpattackname = eAttacker.name;
  1506.             lpattackerteam = eAttacker.pers[ "team" ];
  1507.         }
  1508.         else
  1509.         {
  1510.             lpattacknum = -1;
  1511.             lpattackGuid = "";
  1512.             lpattackname = "";
  1513.             lpattackerteam = "world";
  1514.         }
  1515.  
  1516.         logPrint( "D;" + lpselfGuid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" );
  1517.     }
  1518.  
  1519.     HitlocDebug( eAttacker, victim, iDamage, sHitLoc, iDFlags );
  1520.  
  1521.     /*if( isDefined( eAttacker ) && eAttacker != victim )
  1522.     {
  1523.         if ( isPlayer( eAttacker ) )
  1524.             eAttacker incPlayerStat( "damagedone", iDamage );
  1525.        
  1526.         victim incPlayerStat( "damagetaken", iDamage );
  1527.     }*/
  1528.  
  1529.     prof_end( "PlayerDamage log" );
  1530. }
  1531.  
  1532.  
  1533. addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath )
  1534. {
  1535.     if ( !isDefined( victim.attackerData ) )
  1536.         victim.attackerData = [];
  1537.    
  1538.     if ( !isDefined( victim.attackerData[ eAttacker.guid ] ) )
  1539.     {
  1540.         victim.attackers[ eAttacker.guid ] = eAttacker;
  1541.         // we keep an array of attackers by their client ID so we can easily tell
  1542.         // if they're already one of the existing attackers in the above if().
  1543.         // we store in this array data that is useful for other things, like challenges
  1544.         victim.attackerData[ eAttacker.guid ] = SpawnStruct();
  1545.         victim.attackerData[ eAttacker.guid ].damage = 0;  
  1546.         victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker;
  1547.         victim.attackerData[ eAttacker.guid ].firstTimeDamaged = getTime();            
  1548.     }
  1549.     if ( maps\mp\gametypes\_weapons::isPrimaryWeapon( sWeapon ) && ! maps\mp\gametypes\_weapons::isSideArm( sWeapon ) )
  1550.         victim.attackerData[ eAttacker.guid ].isPrimary = true;
  1551.    
  1552.     victim.attackerData[ eAttacker.guid ].damage += iDamage;
  1553.     victim.attackerData[ eAttacker.guid ].weapon = sWeapon;
  1554.     victim.attackerData[ eAttacker.guid ].vPoint = vPoint;
  1555.     victim.attackerData[ eAttacker.guid ].vDir = vDir;
  1556.     victim.attackerData[ eAttacker.guid ].sHitLoc = sHitLoc;
  1557.     victim.attackerData[ eAttacker.guid ].psOffsetTime = psOffsetTime;
  1558.     victim.attackerData[ eAttacker.guid ].sMeansOfDeath = sMeansOfDeath;
  1559.     victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker;
  1560.     victim.attackerData[ eAttacker.guid ].lasttimeDamaged = getTime();
  1561.    
  1562.     if ( isDefined( eInflictor ) && !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) )
  1563.         victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eInflictor.primaryWeapon;
  1564.     else if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker getCurrentPrimaryWeapon() != "none" )
  1565.         victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eAttacker getCurrentPrimaryWeapon();
  1566.     else
  1567.         victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = undefined;
  1568. }
  1569.  
  1570. resetAttackerList()
  1571. {
  1572.     self endon( "disconnect" );
  1573.     self endon( "death" );
  1574.     level endon( "game_ended" );
  1575.    
  1576.     //wait is to offset premature calling in _healthOverlay
  1577.     wait( 1.75 );
  1578.     self.attackers = [];
  1579.     self.attackerData = [];
  1580. }
  1581.  
  1582.  
  1583. Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
  1584. {
  1585.     Callback_PlayerDamage_internal( eInflictor, eAttacker, self, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime );
  1586. }
  1587.  
  1588.  
  1589. finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction )
  1590. {
  1591.     if ( (self isUsingRemote() ) && (iDamage >= self.health) && !(iDFlags & level.iDFLAGS_STUN) )
  1592.     {
  1593.         if ( !isDefined( vDir ) )
  1594.             vDir = ( 0,0,0 );
  1595.  
  1596.         if ( !isDefined( eAttacker ) && !isDefined( eInflictor ) )
  1597.         {
  1598.             eAttacker = self;
  1599.             eInflictor = eAttacker;
  1600.         }
  1601.        
  1602.         assert( isDefined( eAttacker ) );
  1603.         assert( isDefined( eInflictor ) );
  1604.  
  1605.         PlayerKilled_internal( eInflictor, eAttacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, 0, true );
  1606.     }
  1607.     else
  1608.     {
  1609.         if ( !self Callback_KillingBlow( eInflictor, eAttacker, iDamage - (iDamage * stunFraction), iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) )
  1610.             return;
  1611.  
  1612.         self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1613.     }
  1614.  
  1615.     if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" )
  1616.         self shellShock( "damage_mp", getDvarFloat( "scr_csmode" ) );
  1617.  
  1618.     self damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker );
  1619. }
  1620.  
  1621.  
  1622. Callback_PlayerLastStand( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
  1623. {  
  1624.        
  1625.     lastStandParams = spawnStruct();
  1626.     lastStandParams.eInflictor = eInflictor;
  1627.     lastStandParams.attacker = attacker;
  1628.     lastStandParams.iDamage = iDamage;
  1629.     lastStandParams.attackerPosition = attacker.origin;
  1630.     if ( attacker == self )
  1631.         lastStandParams.sMeansOfDeath = "MOD_SUICIDE";
  1632.     else
  1633.         lastStandParams.sMeansOfDeath = sMeansOfDeath;
  1634.    
  1635.     lastStandParams.sWeapon = sWeapon;
  1636.     if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" )
  1637.         lastStandParams.sPrimaryWeapon = attacker getCurrentPrimaryWeapon();
  1638.     else
  1639.         lastStandParams.sPrimaryWeapon = undefined;
  1640.     lastStandParams.vDir = vDir;
  1641.     lastStandParams.sHitLoc = sHitLoc;
  1642.     lastStandParams.lastStandStartTime = getTime();
  1643.  
  1644.     mayDoLastStand = mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc );
  1645.    
  1646.     //if ( mayDoLastStand )
  1647.     //  mayDoLastStand = !self checkForceBleedOut();
  1648.    
  1649.     if ( isDefined( self.endGame ) )
  1650.         mayDoLastStand = false;
  1651.    
  1652.     if ( level.teamBased && isDefined( attacker.team ) && attacker.team == self.team )
  1653.         mayDoLastStand = false;
  1654.  
  1655.      /#
  1656.     if ( getdvar( "scr_forcelaststand" ) == "1" )
  1657.         mayDoLastStand = true;
  1658.     #/
  1659.    
  1660.     if ( !mayDoLastStand )
  1661.     {
  1662.         self.lastStandParams = lastStandParams;
  1663.         self.useLastStandParams = true;
  1664.         self _suicide();
  1665.         return;
  1666.     }
  1667.    
  1668.     self.inLastStand = true;
  1669.  
  1670.     notifyData = spawnStruct();
  1671.     if ( self _hasPerk( "specialty_finalstand" ) )
  1672.     {
  1673.         notifyData.titleText = game[ "strings" ][ "final_stand" ];
  1674.         notifyData.iconName = "specialty_finalstand";
  1675.     }
  1676.     else
  1677.     {
  1678.         notifyData.titleText = game[ "strings" ][ "last_stand" ];
  1679.         notifyData.iconName = "specialty_pistoldeath";
  1680.     }
  1681.     notifyData.glowColor = ( 1, 0, 0 );
  1682.     notifyData.sound = "mp_last_stand";
  1683.     notifyData.duration = 2.0;
  1684.  
  1685.     self.health = 1;
  1686.  
  1687.     self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData );
  1688.  
  1689.     grenadeTypePrimary = "frag_grenade_mp";
  1690.  
  1691.     if ( isDefined( level.ac130player ) && isDefined( attacker ) && level.ac130player == attacker )
  1692.         level notify( "ai_crawling", self );
  1693.    
  1694.     if ( self _hasPerk( "specialty_finalstand" ) )
  1695.     {
  1696.         self.lastStandParams = lastStandParams;
  1697.         self.inFinalStand = true;
  1698.        
  1699.         weaponList = self GetWeaponsListExclusives();
  1700.         foreach ( weapon in weaponList )
  1701.             self takeWeapon( weapon );
  1702.        
  1703.         self _disableUsability();
  1704.  
  1705.         self thread enableLastStandWeapons();
  1706.         self thread lastStandTimer( 20, true );    
  1707.     }
  1708.     /*
  1709.     else if ( self _hasPerk( "specialty_c4death" ) )
  1710.     {
  1711.         self.lastStandParams = lastStandParams;
  1712.  
  1713.         self takeAllWeapons();
  1714.         self giveWeapon( "c4Death_mp", 0, false );
  1715.         self switchToWeapon( "c4Death_mp" );
  1716.         self _disableUsability();
  1717.         self.inC4Death = true;
  1718.                
  1719.         //self thread dieAfterTime( 7 );
  1720.         self thread lastStandTimer( 10, false );   
  1721.         self thread detonateOnUse();
  1722.         //self thread detonateOnDeath();   
  1723.     }
  1724.     */
  1725.     else if ( level.dieHardMode )
  1726.     {  
  1727.         self.lastStandParams = lastStandParams;
  1728.         self thread enableLastStandWeapons();
  1729.         self thread lastStandTimer( 20, false );
  1730.         self _disableUsability();
  1731.     }
  1732.     else // normal last stand
  1733.     {
  1734.         self.lastStandParams = lastStandParams;
  1735.        
  1736.         pistolWeapon = undefined;
  1737.        
  1738.         weaponsList = self GetWeaponsListPrimaries();
  1739.         foreach ( weapon in weaponsList )
  1740.         {
  1741.             if ( maps\mp\gametypes\_weapons::isSideArm( weapon ) )
  1742.                 pistolWeapon = weapon;         
  1743.         }
  1744.            
  1745.         if ( !isDefined( pistolWeapon ) )
  1746.         {
  1747.             pistolWeapon = "beretta_mp";
  1748.             self _giveWeapon( pistolWeapon );
  1749.         }
  1750.    
  1751.         self giveMaxAmmo( pistolWeapon );
  1752.         self DisableWeaponSwitch();
  1753.         self _disableUsability();
  1754.        
  1755.         if ( !self _hasPerk("specialty_laststandoffhand") )
  1756.             self DisableOffhandWeapons();
  1757.                
  1758.         self switchToWeapon( pistolWeapon );
  1759.        
  1760.         self thread lastStandTimer( 10, false );
  1761.     }
  1762. }
  1763.  
  1764. dieAfterTime( time )
  1765. {
  1766.     self endon( "death" );
  1767.     self endon( "disconnect" );
  1768.     self endon( "joined_team" );
  1769.     level endon( "game_ended" );
  1770.    
  1771.     wait ( time );
  1772.     self.useLastStandParams = true;
  1773.     self _suicide();
  1774. }
  1775.  
  1776. detonateOnUse()
  1777. {
  1778.     self endon( "death" );
  1779.     self endon( "disconnect" );
  1780.     self endon( "joined_team" );
  1781.     level endon( "game_ended" );
  1782.    
  1783.     self waittill( "detonate" );
  1784.     self.useLastStandParams = true;
  1785.     self c4DeathDetonate();
  1786. }
  1787.  
  1788. detonateOnDeath()
  1789. {
  1790.     self endon( "detonate" );
  1791.     self endon( "disconnect" );
  1792.     self endon( "joined_team" );
  1793.     level endon( "game_ended" );
  1794.    
  1795.     self waittill( "death" );
  1796.     self c4DeathDetonate();
  1797. }
  1798.  
  1799. c4DeathDetonate()
  1800. {
  1801.     self playSound( "detpack_explo_default" );
  1802.     self.c4DeathEffect = playFX( level.c4Death, self.origin );
  1803.     RadiusDamage( self.origin, 400, 100, 100, self );
  1804.    
  1805.     if ( isAlive( self ) )
  1806.         self _suicide();
  1807. }
  1808.  
  1809. enableLastStandWeapons()
  1810. {
  1811.     self endon( "death" );
  1812.     self endon( "disconnect" );
  1813.     level endon( "game_ended" );
  1814.  
  1815.     self freezeControlsWrapper( true );
  1816.     wait .30;
  1817.    
  1818.     self freezeControlsWrapper( false );
  1819. }
  1820.  
  1821. lastStandTimer( delay, isFinalStand )
  1822. {
  1823.     self endon( "death" );
  1824.     self endon( "disconnect" );
  1825.     self endon( "revive");
  1826.     level endon( "game_ended" );
  1827.    
  1828.     level notify ( "player_last_stand" );
  1829.    
  1830.     self thread lastStandWaittillDeath();
  1831.    
  1832.     self.lastStand = true;
  1833.    
  1834.     if ( !isFinalStand && !level.dieHardMode && ( !isDefined( self.inC4Death ) || !self.inC4Death ) )
  1835.     {
  1836.         self thread lastStandAllowSuicide();
  1837.         self setLowerMessage( "last_stand", &"PLATFORM_COWARDS_WAY_OUT" );
  1838.         self thread lastStandKeepOverlay();
  1839.     }
  1840.    
  1841.     if ( level.dieHardMode == 1 && level.dieHardMode != 2 )
  1842.     {
  1843.         reviveEnt = spawn( "script_model", self.origin );
  1844.         reviveEnt setModel( "tag_origin" );
  1845.         reviveEnt setCursorHint( "HINT_NOICON" );
  1846.         reviveEnt setHintString( &"PLATFORM_REVIVE" );
  1847.  
  1848.         reviveEnt reviveSetup( self );
  1849.         reviveEnt endon ( "death" );
  1850.  
  1851.         reviveIcon = newTeamHudElem( self.team );
  1852.         reviveIcon setShader( "waypoint_revive", 8, 8 );
  1853.         reviveIcon setWaypoint( true, true );
  1854.         reviveIcon SetTargetEnt( self );
  1855.         reviveIcon thread destroyOnReviveEntDeath( reviveEnt );
  1856.  
  1857.         reviveIcon.color = (0.33, 0.75, 0.24);
  1858.         self playDeathSound();
  1859.        
  1860.         if ( isFinalStand )
  1861.         {
  1862.             wait( delay );
  1863.            
  1864.             if ( self.inFinalStand )
  1865.                 self thread lastStandBleedOut( isFinalStand, reviveEnt );
  1866.         }
  1867.        
  1868.         return;
  1869.     }
  1870.     else if( level.dieHardMode == 2 )
  1871.     {
  1872.         self thread lastStandKeepOverlay();
  1873.         reviveEnt = spawn( "script_model", self.origin );
  1874.         reviveEnt setModel( "tag_origin" );
  1875.         reviveEnt setCursorHint( "HINT_NOICON" );
  1876.         reviveEnt setHintString( &"PLATFORM_REVIVE" );
  1877.  
  1878.         reviveEnt reviveSetup( self );
  1879.         reviveEnt endon ( "death" );
  1880.  
  1881.         reviveIcon = newTeamHudElem( self.team );
  1882.         reviveIcon setShader( "waypoint_revive", 8, 8 );
  1883.         reviveIcon setWaypoint( true, true );
  1884.         reviveIcon SetTargetEnt( self );
  1885.         reviveIcon thread destroyOnReviveEntDeath( reviveEnt );
  1886.  
  1887.         reviveIcon.color = (0.33, 0.75, 0.24);
  1888.         self playDeathSound();
  1889.        
  1890.         if ( isFinalStand )
  1891.         {
  1892.             wait( delay );
  1893.            
  1894.             if ( self.inFinalStand )
  1895.                 self thread lastStandBleedOut( isFinalStand, reviveEnt );
  1896.         }
  1897.        
  1898.         wait delay / 3;
  1899.         reviveIcon.color = (1.0, 0.64, 0.0);
  1900.        
  1901.         while ( reviveEnt.inUse )
  1902.             wait ( 0.05 );
  1903.        
  1904.         self playDeathSound(); 
  1905.         wait delay / 3;
  1906.         reviveIcon.color = (1.0, 0.0, 0.0);
  1907.  
  1908.         while ( reviveEnt.inUse )
  1909.             wait ( 0.05 );
  1910.  
  1911.         self playDeathSound();
  1912.         wait delay / 3;
  1913.  
  1914.         while ( reviveEnt.inUse )
  1915.             wait ( 0.05 );
  1916.        
  1917.         wait( 0.05 );
  1918.         self thread lastStandBleedOut( isFinalStand );
  1919.         return;
  1920.     }
  1921.    
  1922.     wait( delay );
  1923.     self thread lastStandBleedout( isFinalStand );
  1924.  
  1925. }
  1926.  
  1927. maxHealthOverlay( maxHealth, refresh )
  1928. {
  1929.     self endon( "stop_maxHealthOverlay" );
  1930.     self endon( "revive" );
  1931.     self endon( "death" );
  1932.    
  1933.     for( ;; )
  1934.     {
  1935.         self.health -= 1;
  1936.         self.maxHealth = maxHealth;
  1937.         wait( .05 );
  1938.         self.maxHealth = 50;
  1939.         self.health += 1;
  1940.    
  1941.         wait ( .50 );
  1942.     }  
  1943. }
  1944.  
  1945. lastStandBleedOut( reviveOnBleedOut, reviveEnt )
  1946. {
  1947.     if ( reviveOnBleedOut )
  1948.     {
  1949.         self.lastStand = undefined;
  1950.         self.inFinalStand = false;
  1951.         self clearLowerMessage( "last_stand" );
  1952.         maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer();
  1953.        
  1954.         if( isDefined( reviveEnt ) )
  1955.             reviveEnt Delete();
  1956.     }
  1957.     else
  1958.     {
  1959.         self.useLastStandParams = true;
  1960.         self.beingRevived = false;
  1961.         self _suicide();
  1962.     }
  1963. }
  1964.  
  1965.  
  1966. lastStandAllowSuicide()
  1967. {
  1968.     self endon( "death" );
  1969.     self endon( "disconnect" );
  1970.     self endon( "game_ended" );
  1971.     self endon( "revive");
  1972.  
  1973.     while ( 1 )
  1974.     {
  1975.         if ( self useButtonPressed() )
  1976.         {
  1977.             pressStartTime = gettime();
  1978.             while ( self useButtonPressed() )
  1979.             {
  1980.                 wait .05;
  1981.                 if ( gettime() - pressStartTime > 700 )
  1982.                     break;
  1983.             }
  1984.             if ( gettime() - pressStartTime > 700 )
  1985.                 break;
  1986.         }
  1987.         wait .05;
  1988.     }
  1989.  
  1990.     self thread lastStandBleedOut( false );
  1991. }
  1992.  
  1993. lastStandKeepOverlay()
  1994. {
  1995.     level endon( "game_ended" );
  1996.     self endon( "death" );
  1997.     self endon( "disconnect" );
  1998.     self endon( "revive" );
  1999.  
  2000.     // keep the health overlay going by making code think the player is getting damaged
  2001.     while ( !level.gameEnded )
  2002.     {
  2003.         self.health = 2;
  2004.         wait .05;
  2005.         self.health = 1;
  2006.         wait .5;
  2007.     }
  2008.    
  2009.     self.health = self.maxhealth;
  2010. }
  2011.  
  2012.  
  2013. lastStandWaittillDeath()
  2014. {
  2015.     self endon( "disconnect" );
  2016.     self endon( "revive" );
  2017.     level endon( "game_ended" );
  2018.     self waittill( "death" );
  2019.  
  2020.     self clearLowerMessage( "last_stand" );
  2021.     self.lastStand = undefined;
  2022. }
  2023.  
  2024.  
  2025. mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc )
  2026. {
  2027.     if ( sMeansOfDeath == "MOD_TRIGGER_HURT" )
  2028.         return false;
  2029.    
  2030.     if ( sMeansOfDeath != "MOD_PISTOL_BULLET" && sMeansOfDeath != "MOD_RIFLE_BULLET" && sMeansOfDeath != "MOD_FALLING" && sMeansOfDeath != "MOD_EXPLOSIVE_BULLET" )
  2031.         return false;
  2032.  
  2033.     if ( sMeansOfDeath == "MOD_IMPACT" && sWeapon == "throwingknife_mp" )
  2034.         return false;
  2035.        
  2036.     if ( sMeansOfDeath == "MOD_IMPACT" && ( sWeapon == "m79_mp" || isSubStr(sWeapon, "gl_") ) )
  2037.         return false;
  2038.  
  2039.     if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath ) )
  2040.         return false;
  2041.    
  2042.     if ( self isUsingRemote() )
  2043.         return false;
  2044.  
  2045.     return true;
  2046. }
  2047.  
  2048.  
  2049. ensureLastStandParamsValidity()
  2050. {
  2051.     // attacker may have become undefined if the player that killed me has disconnected
  2052.     if ( !isDefined( self.lastStandParams.attacker ) )
  2053.         self.lastStandParams.attacker = self;
  2054. }
  2055.  
  2056. getHitLocHeight( sHitLoc )
  2057. {
  2058.     switch( sHitLoc )
  2059.     {
  2060.         case "helmet":
  2061.         case "head":
  2062.         case "neck":
  2063.             return 60;
  2064.         case "torso_upper":
  2065.         case "right_arm_upper":
  2066.         case "left_arm_upper":
  2067.         case "right_arm_lower":
  2068.         case "left_arm_lower":
  2069.         case "right_hand":
  2070.         case "left_hand":
  2071.         case "gun":
  2072.             return 48;
  2073.         case "torso_lower":
  2074.             return 40;
  2075.         case "right_leg_upper":
  2076.         case "left_leg_upper":
  2077.             return 32;
  2078.         case "right_leg_lower":
  2079.         case "left_leg_lower":
  2080.             return 10;
  2081.         case "right_foot":
  2082.         case "left_foot":
  2083.             return 5;
  2084.     }
  2085.     return 48;
  2086. }
  2087.  
  2088. delayStartRagdoll( ent, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath )
  2089. {
  2090.     if ( isDefined( ent ) )
  2091.     {
  2092.         deathAnim = ent getCorpseAnim();
  2093.         if ( animhasnotetrack( deathAnim, "ignore_ragdoll" ) )
  2094.             return;
  2095.     }
  2096.  
  2097.     wait( 0.2 );
  2098.  
  2099.     if ( !isDefined( ent ) )
  2100.         return;
  2101.  
  2102.     if ( ent isRagDoll() )
  2103.         return;
  2104.  
  2105.     deathAnim = ent getcorpseanim();
  2106.  
  2107.     startFrac = 0.35;
  2108.  
  2109.     if ( animhasnotetrack( deathAnim, "start_ragdoll" ) )
  2110.     {
  2111.         times = getnotetracktimes( deathAnim, "start_ragdoll" );
  2112.         if ( isDefined( times ) )
  2113.             startFrac = times[ 0 ];
  2114.     }
  2115.  
  2116.     waitTime = startFrac * getanimlength( deathAnim );
  2117.     wait( waitTime );
  2118.  
  2119.     if ( isDefined( ent ) )
  2120.     {
  2121.         ent startragdoll( 1 );
  2122.     }
  2123. }
  2124.  
  2125.  
  2126. getMostKilledBy()
  2127. {
  2128.     mostKilledBy = "";
  2129.     killCount = 0;
  2130.  
  2131.     killedByNames = getArrayKeys( self.killedBy );
  2132.  
  2133.     for ( index = 0; index < killedByNames.size; index++ )
  2134.     {
  2135.         killedByName = killedByNames[ index ];
  2136.         if ( self.killedBy[ killedByName ] <= killCount )
  2137.             continue;
  2138.  
  2139.         killCount = self.killedBy[ killedByName ];
  2140.         mostKilleBy = killedByName;
  2141.     }
  2142.  
  2143.     return mostKilledBy;
  2144. }
  2145.  
  2146.  
  2147. getMostKilled()
  2148. {
  2149.     mostKilled = "";
  2150.     killCount = 0;
  2151.  
  2152.     killedNames = getArrayKeys( self.killedPlayers );
  2153.  
  2154.     for ( index = 0; index < killedNames.size; index++ )
  2155.     {
  2156.         killedName = killedNames[ index ];
  2157.         if ( self.killedPlayers[ killedName ] <= killCount )
  2158.             continue;
  2159.  
  2160.         killCount = self.killedPlayers[ killedName ];
  2161.         mostKilled = killedName;
  2162.     }
  2163.  
  2164.     return mostKilled;
  2165. }
  2166.  
  2167.  
  2168. damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker )
  2169. {
  2170.     self thread maps\mp\gametypes\_weapons::onWeaponDamage( eInflictor, sWeapon, sMeansOfDeath, iDamage, eAttacker );
  2171.     self PlayRumbleOnEntity( "damage_heavy" );
  2172. }
  2173.  
  2174.  
  2175. reviveSetup( owner )
  2176. {
  2177.     team = owner.team;
  2178.    
  2179.     self linkTo( owner, "tag_origin" );
  2180.  
  2181.     self.owner = owner;
  2182.     self.inUse = false;
  2183.     self makeUsable();
  2184.     self updateUsableByTeam( team );
  2185.     self thread trackTeamChanges( team );
  2186.    
  2187.     self thread reviveTriggerThink( team );
  2188.    
  2189.     self thread deleteOnReviveOrDeathOrDisconnect();
  2190. }
  2191.  
  2192.  
  2193. deleteOnReviveOrDeathOrDisconnect()
  2194. {
  2195.     self endon ( "death" );
  2196.    
  2197.     self.owner waittill_any ( "death", "disconnect" );
  2198.    
  2199.     self delete();
  2200. }
  2201.  
  2202.  
  2203. updateUsableByTeam( team )
  2204. {
  2205.     foreach (player in level.players)
  2206.     {
  2207.         if ( team == player.team && player != self.owner )
  2208.             self enablePlayerUse( player );
  2209.         else
  2210.             self disablePlayerUse( player );   
  2211.     }  
  2212. }
  2213.  
  2214.  
  2215. trackTeamChanges( team )
  2216. {
  2217.     self endon ( "death" );
  2218.    
  2219.     while ( true )
  2220.     {
  2221.         level waittill ( "joined_team" );
  2222.        
  2223.         self updateUsableByTeam( team );
  2224.     }
  2225. }
  2226.  
  2227.  
  2228. trackLastStandChanges( team )
  2229. {
  2230.     self endon ( "death" );
  2231.    
  2232.     while ( true )
  2233.     {
  2234.         level waittill ( "player_last_stand" );
  2235.        
  2236.         self updateUsableByTeam( team );
  2237.     }
  2238. }
  2239.  
  2240.  
  2241. reviveTriggerThink( team )
  2242. {
  2243.     self endon ( "death" );
  2244.     level endon ( "game_ended" );
  2245.    
  2246.     for ( ;; )
  2247.     {
  2248.         self waittill ( "trigger", player );
  2249.         self.owner.beingRevived = true;
  2250.  
  2251.         if ( isDefined(player.beingRevived) && player.beingRevived )
  2252.         {
  2253.             self.owner.beingRevived = false;
  2254.             continue;
  2255.         }
  2256.            
  2257.         self makeUnUsable();
  2258.         self.owner freezeControlsWrapper( true );
  2259.  
  2260.         revived = self useHoldThink( player );
  2261.         self.owner.beingRevived = false;
  2262.        
  2263.         if ( !isAlive( self.owner ) )
  2264.         {  
  2265.             self delete();
  2266.             return;
  2267.         }
  2268.  
  2269.         self.owner freezeControlsWrapper( false );
  2270.            
  2271.         if ( revived )
  2272.         {
  2273.             player thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "reviver", 200 );
  2274.             player thread maps\mp\gametypes\_rank::giveRankXP( "reviver", 200 );
  2275.  
  2276.             self.owner.lastStand = undefined;
  2277.             self.owner clearLowerMessage( "last_stand" );
  2278.            
  2279.             if ( self.owner _hasPerk( "specialty_lightweight" ) )
  2280.                 self.owner.moveSpeedScaler = 1.07;
  2281.             else
  2282.                 self.owner.moveSpeedScaler = 1;
  2283.            
  2284.             self.owner.maxHealth = 100;
  2285.            
  2286.             self.owner maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" );
  2287.             self.owner maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer();
  2288.  
  2289.             self.owner setPerk( "specialty_pistoldeath", true );
  2290.             self.owner.beingRevived = false;
  2291.            
  2292.             self delete();
  2293.             return;
  2294.         }
  2295.            
  2296.         self makeUsable();
  2297.         self updateUsableByTeam( team );
  2298.     }
  2299. }
  2300.  
  2301.  
  2302.  
  2303. /*
  2304. =============
  2305. useHoldThink
  2306.  
  2307. Claims the use trigger for player and displays a use bar
  2308. Returns true if the player sucessfully fills the use bar
  2309. =============
  2310. */
  2311. useHoldThink( player )
  2312. {
  2313.     reviveSpot = spawn( "script_origin", self.origin );
  2314.     reviveSpot hide(); 
  2315.     player playerLinkTo( reviveSpot );     
  2316.     player PlayerLinkedOffsetEnable();
  2317.    
  2318.     player _disableWeapon();
  2319.    
  2320.     self.curProgress = 0;
  2321.     self.inUse = true;
  2322.     self.useRate = 0;
  2323.     self.useTime = 3000;
  2324.    
  2325.     player thread personalUseBar( self );
  2326.    
  2327.     result = useHoldThinkLoop( player );
  2328.    
  2329.     if ( isDefined( player ) && isReallyAlive( player ) )
  2330.     {
  2331.         player Unlink();
  2332.         player _enableWeapon();
  2333.     }
  2334.  
  2335.     if ( isDefined( result ) && result )
  2336.     {
  2337.         self.owner thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "revived", player );
  2338.         self.owner.inlaststand = false;
  2339.         return true;
  2340.     }
  2341.    
  2342.     self.inUse = false;
  2343.     reviveSpot Delete();   
  2344.     return false;
  2345. }
  2346.  
  2347.  
  2348. personalUseBar( object )
  2349. {
  2350.     useBar = self createPrimaryProgressBar();
  2351.     useBarText = self createPrimaryProgressBarText();
  2352.     useBarText setText( &"MPUI_REVIVING" );
  2353.  
  2354.     objUseBar = object.owner createPrimaryProgressBar();
  2355.     objUseBarText = object.owner createPrimaryProgressBarText();
  2356.     objUseBarText setText( &"MPUI_BEING_REVIVED" );
  2357.  
  2358.     lastRate = -1;
  2359.     while ( isReallyAlive( self ) && isDefined( object ) && object.inUse && !level.gameEnded && isDefined( self ) )
  2360.     {
  2361.         if ( lastRate != object.useRate )
  2362.         {
  2363.             if( object.curProgress > object.useTime)
  2364.                 object.curProgress = object.useTime;
  2365.                
  2366.             useBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate );
  2367.             objUseBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate );
  2368.  
  2369.             if ( !object.useRate )
  2370.             {
  2371.                 useBar hideElem();
  2372.                 useBarText hideElem();
  2373.  
  2374.                 objUseBar hideElem();
  2375.                 objUseBarText hideElem();
  2376.             }
  2377.             else
  2378.             {
  2379.                 useBar showElem();
  2380.                 useBarText showElem();
  2381.  
  2382.                 objUseBar showElem();
  2383.                 objUseBarText showElem();
  2384.             }
  2385.         }  
  2386.         lastRate = object.useRate;
  2387.         wait ( 0.05 );
  2388.     }
  2389.    
  2390.     // when the players disconnect the hudElems are destroyed automatically
  2391.     if ( isDefined( useBar ) )
  2392.         useBar destroyElem();
  2393.     if ( isDefined( useBarText ) )
  2394.         useBarText destroyElem();
  2395.  
  2396.     if ( isDefined( objUseBar ) )
  2397.         objUseBar destroyElem();
  2398.     if ( isDefined( objUseBarText ) )
  2399.         objUseBarText destroyElem();
  2400. }
  2401.  
  2402.  
  2403. useHoldThinkLoop( player )
  2404. {
  2405.     level endon ( "game_ended" );
  2406.     self.owner endon( "death" );
  2407.     self.owner endon( "disconnect" );
  2408.  
  2409.     while( isReallyAlive( player ) && player useButtonPressed() && self.curProgress < self.useTime  )
  2410.     {
  2411.         self.curProgress += (50 * self.useRate);
  2412.         self.useRate = 1; /* * player.objectiveScaler;*/
  2413.  
  2414.         if ( self.curProgress >= self.useTime )
  2415.         {
  2416.             self.inUse = false;
  2417.            
  2418.             return isReallyAlive( player );
  2419.         }
  2420.        
  2421.         wait 0.05;
  2422.     }
  2423.    
  2424.     return false;
  2425. }
  2426.  
  2427.  
  2428. Callback_KillingBlow( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
  2429. {
  2430.     if ( isDefined(self.lastDamageWasFromEnemy) && self.lastDamageWasFromEnemy && iDamage >= self.health && isDefined( self.combatHigh ) && self.combatHigh == "specialty_endgame" )
  2431.     {
  2432.         self setAdrenaline( 0 );
  2433.         self _setPerk( "specialty_endgame" );
  2434.         return false;
  2435.     }
  2436.    
  2437.     return true;
  2438. }
  2439.  
  2440.  
  2441. emitFallDamage( iDamage )
  2442. {
  2443.     PhysicsExplosionSphere( self.origin, 64, 64, 1 );
  2444.    
  2445.     // get the entities we landed on
  2446.     damageEnts = [];
  2447.     for ( testAngle = 0; testAngle < 360; testAngle += 30 )
  2448.     {
  2449.         xOffset = cos( testAngle ) * 16;
  2450.         yOffset = sin( testAngle ) * 16;
  2451.  
  2452.         traceData = bulletTrace( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), true, self );
  2453.         //thread drawLine( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), 10.0 );
  2454.        
  2455.         if ( isDefined( traceData["entity"] ) && isDefined( traceData["entity"].targetname ) && (traceData["entity"].targetname == "destructible_vehicle" || traceData["entity"].targetname == "destructible_toy") )
  2456.             damageEnts[damageEnts.size] = traceData["entity"];
  2457.     }
  2458.  
  2459.     if ( damageEnts.size )
  2460.     {
  2461.         damageOwner = spawn( "script_origin", self.origin );
  2462.         damageOwner hide();
  2463.         damageOwner.type = "soft_landing";
  2464.         damageOwner.destructibles = damageEnts;
  2465.         radiusDamage( self.origin, 64, 100, 100, damageOwner );
  2466.  
  2467.         wait ( 0.1 );  
  2468.         damageOwner delete();
  2469.     }
  2470. }
  2471.  
  2472. drawLine( start, end, timeSlice )
  2473. {
  2474.     drawTime = int(timeSlice * 20);
  2475.     for( time = 0; time < drawTime; time++ )
  2476.     {
  2477.         line( start, end, (1,0,0),false, 1 );
  2478.         wait ( 0.05 );
  2479.     }
  2480. }
  2481.  
  2482. isFlankKill( victim, attacker )
  2483. {
  2484.     victimForward = anglestoforward( victim.angles );
  2485.     victimForward = ( victimForward[0], victimForward[1], 0 );
  2486.     victimForward = VectorNormalize( victimForward );
  2487.  
  2488.     attackDirection = victim.origin - attacker.origin;
  2489.     attackDirection = ( attackDirection[0], attackDirection[1], 0 );
  2490.     attackDirection = VectorNormalize( attackDirection );
  2491.  
  2492.     dotProduct = VectorDot( victimForward, attackDirection );
  2493.     if ( dotProduct > 0 ) // 0 = cos( 90 ), 180 degree arc total
  2494.         return true;
  2495.     else
  2496.         return false;
  2497. }
  2498.  
  2499. _obituary( victim, attacker, sWeapon, sMeansOfDeath )
  2500. {
  2501.     victimTeam = victim.team;
  2502.    
  2503.     foreach ( player in level.players )
  2504.     {
  2505.         playerTeam = player.team;
  2506.         if ( playerTeam == "spectator" )
  2507.             player iPrintLn( &"MP_OBITUARY_NEUTRAL", attacker.name, victim.name );
  2508.         else if ( playerTeam == victimTeam )
  2509.             player iPrintLn( &"MP_OBITUARY_ENEMY", attacker.name, victim.name );
  2510.         else
  2511.             player iPrintLn( &"MP_OBITUARY_FRIENDLY", attacker.name, victim.name );
  2512.     }
  2513. }
  2514.  
  2515.  
  2516. logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc )
  2517. {
  2518.     // create a lot of redundant data for the log print
  2519.     lpselfnum = self getEntityNumber();
  2520.     lpselfname = self.name;
  2521.     lpselfteam = self.team;
  2522.     lpselfguid = self.guid;
  2523.  
  2524.     if ( isPlayer( attacker ) )
  2525.     {
  2526.         lpattackGuid = attacker.guid;
  2527.         lpattackname = attacker.name;
  2528.         lpattackerteam = attacker.team;
  2529.         lpattacknum = attacker getEntityNumber();
  2530.         attackerString = attacker getXuid() + "(" + lpattackname + ")";
  2531.     }
  2532.     else
  2533.     {
  2534.         lpattackGuid = "";
  2535.         lpattackname = "";
  2536.         lpattackerteam = "world";
  2537.         lpattacknum = -1;
  2538.         attackerString = "none";
  2539.     }
  2540.  
  2541.     logPrint( "K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" );
  2542. }
  2543.  
  2544.  
  2545. destroyOnReviveEntDeath( reviveEnt )
  2546. {
  2547.     reviveEnt waittill ( "death" );
  2548.    
  2549.     self destroy();
  2550. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement