Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2013
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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.     // added
  731.     if(sMeansOfDeath == "MOD_HEADSHOT" || sMeansOfDeath == "MOD_HEAD_SHOT" ) // since cod4 it changed
  732.     {
  733.         attacker.modifiers["headshot"] = true;
  734.         attacker thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "headshot", maps\mp\gametypes\_rank::getScoreInfoValue( "headshot" ) );   
  735.     }
  736.  
  737.     // ======
  738.     // allow per gametype death handling   
  739.     victim thread [[ level.onPlayerKilled ]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, lifeId );
  740.  
  741.     if ( isPlayer( attacker ) )
  742.         attackerNum = attacker getEntityNumber();
  743.     else
  744.         attackerNum = -1;
  745.     killcamentity = victim getKillcamEntity( attacker, eInflictor, sWeapon );
  746.     killcamentityindex = -1;
  747.     killcamentitystarttime = 0;
  748.  
  749.     if ( isDefined( killcamentity ) )
  750.     {
  751.         killcamentityindex = killcamentity getEntityNumber();// must do this before any waiting lest the entity be deleted
  752.         killcamentitystarttime = killcamentity.birthtime;
  753.         if ( !isdefined( killcamentitystarttime ) )
  754.             killcamentitystarttime = 0;
  755.     }
  756.  
  757.      /#
  758.     if ( getDvarInt( "scr_forcekillcam" ) != 0 )
  759.         doKillcam = true;
  760.     #/
  761.  
  762.     if ( isDefined( attacker.finalKill ) )
  763.         maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid );
  764.    
  765.     //prof_end( " PlayerKilled_5" );
  766.     //prof_begin( " PlayerKilled_6" );
  767.    
  768.     if ( isDefined( attacker.finalKill ) && doKillcam && !isDefined( level.nukeDetonated ) )
  769.     {
  770.         level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime );
  771.  
  772.         if ( !isFauxDeath )
  773.             wait ( 1.0 );
  774.     }
  775.    
  776.     if ( isDefined(level.ggended) && level.ggended == true || isDefined(level.ssended) && level.ssended == true )
  777.     {
  778.         foreach( player in level.players )
  779.         {
  780.             player notify("killcum");
  781.         }
  782.         wait 0.1;
  783.         level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime );
  784.        
  785.         if ( !isFauxDeath )
  786.             wait ( 1.0 );
  787.     }
  788.    
  789.     if ( !isFauxDeath )
  790.     {
  791.         if ( !level.showingFinalKillcam && !level.killcam && doKillcam )
  792.         {
  793.             if ( victim _hasPerk( "specialty_copycat" ) && isDefined( victim.pers["copyCatLoadout"] ) )
  794.             {
  795.                 victim thread maps\mp\gametypes\_killcam::waitDeathCopyCatButton( attacker );
  796.                 wait ( 1.0 );
  797.             }
  798.         }
  799.        
  800.         // let the player watch themselves die
  801.         wait( 0.25 );
  802.         victim thread maps\mp\gametypes\_killcam::cancelKillCamOnUse();
  803.         wait( 0.25 );
  804.        
  805.         self.respawnTimerStartTime = gettime() + 1000;
  806.         timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true );
  807.         if ( timeUntilSpawn < 1 )
  808.             timeUntilSpawn = 1;
  809.         victim thread maps\mp\gametypes\_playerlogic::predictAboutToSpawnPlayerOverTime( timeUntilSpawn );
  810.        
  811.         wait( 1.0 );
  812.         victim notify( "death_delay_finished" );
  813.     }
  814.  
  815.     postDeathDelay = ( getTime() - victim.deathTime ) / 1000;
  816.     self.respawnTimerStartTime = gettime();
  817.  
  818.     if ( !(isDefined( victim.cancelKillcam) && victim.cancelKillcam) && doKillcam && level.killcam && game[ "state" ] == "playing" && !victim isUsingRemote() && !level.showingFinalKillcam )
  819.     {
  820.         livesLeft = !( getGametypeNumLives() && !victim.pers[ "lives" ] );
  821.         timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true );
  822.         willRespawnImmediately = livesLeft && ( timeUntilSpawn <= 0 );
  823.        
  824.         if ( !livesLeft )
  825.             timeUntilSpawn = -1;
  826.  
  827.         victim maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, timeUntilSpawn, maps\mp\gametypes\_gamelogic::timeUntilRoundEnd(), attacker, victim );
  828.     }
  829.    
  830.     //prof_end( " PlayerKilled_6" );
  831.     //prof_begin( " PlayerKilled_7" );
  832.    
  833.     //self openMenu( "killedby_card_hide" );
  834.  
  835.     if ( game[ "state" ] != "playing" )
  836.     {
  837.         if ( !level.showingFinalKillcam )
  838.         {
  839.             victim.sessionstate = "dead";
  840.             victim ClearKillcamState();
  841.         }
  842.        
  843.         //prof_end( " PlayerKilled_7" );
  844.         prof_end( "PlayerKilled" );
  845.         return;
  846.     }
  847.  
  848.     // class may be undefined if we have changed teams
  849.     if ( isValidClass( victim.class ) )
  850.     {
  851.         victim thread maps\mp\gametypes\_playerlogic::spawnClient();
  852.     }
  853.    
  854.     //prof_end( " PlayerKilled_7" );
  855.     prof_end( "PlayerKilled" );
  856. }
  857.  
  858. checkForceBleedout()
  859. {
  860.     if ( level.dieHardMode != 1 )
  861.         return false;
  862.    
  863.     if ( !getGametypeNumLives() )
  864.         return false;
  865.    
  866.     if ( level.livesCount[self.team] > 0 )
  867.         return false;
  868.    
  869.     foreach ( player in level.players )
  870.     {
  871.         if ( !isAlive( player ) )
  872.             continue;
  873.            
  874.         if ( player.team != self.team )
  875.             continue;
  876.            
  877.         if ( player == self )
  878.             continue;
  879.        
  880.         if ( !player.inLastStand )
  881.             return false;
  882.     }
  883.    
  884.     foreach ( player in level.players )
  885.     {
  886.         if ( !isAlive( player ) )
  887.             continue;
  888.        
  889.         if ( player.team != self.team )
  890.             continue;
  891.        
  892.         if ( player.inLastStand && player != self )
  893.             player lastStandBleedOut(false);       
  894.     }
  895.    
  896.     return true;                   
  897. }
  898.  
  899. checkKillSteal( vic )
  900. {
  901.     if ( matchMakingGame() )
  902.         return;
  903.    
  904.     greatestDamage = 0;
  905.     greatestAttacker = undefined;
  906.    
  907.     if ( isDefined( vic.attackerdata ) && vic.attackerdata.size > 1 )  
  908.     {
  909.         foreach ( attacker in vic.attackerdata )
  910.         {
  911.             if ( attacker.damage > greatestDamage )
  912.             {
  913.                 greatestDamage = attacker.damage;
  914.                 greatestAttacker = attacker.attackerEnt;   
  915.             }
  916.         }
  917.        
  918.         if ( isDefined( greatestAttacker ) && greatestAttacker != self )
  919.             self incPlayerStat( "killsteals", 1 );
  920.     }
  921. }
  922.  
  923. doFinalKillcam( delay, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime )
  924. {
  925.     level.showingFinalKillcam = true;
  926.  
  927.     level waittill ( "round_end_finished" );
  928.  
  929.     if ( !isDefined( victim ) || !isDefined( attacker ) )
  930.     {
  931.         level.showingFinalKillcam = false;
  932.         return;
  933.     }
  934.  
  935.     postDeathDelay = (( getTime() - victim.deathTime ) / 1000);
  936.    
  937.     foreach ( player in level.players )
  938.     {
  939.         player closePopupMenu();
  940.         player closeInGameMenu();
  941.         player VisionSetNakedForPlayer( getDvar( "mapname" ), 0 );
  942.         player.killcamentitylookat = victim getEntityNumber();
  943.        
  944.         if ( (player != victim || (!isRoundBased() || isLastRound())) && player _hasPerk( "specialty_copycat" ) )
  945.             player _unsetPerk( "specialty_copycat" );
  946.        
  947.         player thread maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, 0, 10000, attacker, victim );
  948.     }
  949.  
  950.     wait( 0.1 );
  951.  
  952.     while ( anyPlayersInKillcam() )
  953.         wait( 0.05 );
  954.    
  955.     level.showingFinalKillcam = false;
  956. }
  957.  
  958.  
  959. anyPlayersInKillcam()
  960. {
  961.     foreach ( player in level.players )
  962.     {
  963.         if ( isDefined( player.killcam ) )
  964.             return true;
  965.     }
  966.    
  967.     return false;
  968. }
  969.  
  970.  
  971. resetPlayerVariables()
  972. {
  973.     self.killedPlayersCurrent = [];
  974.     self.switching_teams = undefined;
  975.     self.joining_team = undefined;
  976.     self.leaving_team = undefined;
  977.  
  978.     self.pers["cur_kill_streak"] = 0;
  979.  
  980.     self maps\mp\gametypes\_gameobjects::detachUseModels();// want them detached before we create our corpse
  981. }
  982.  
  983.  
  984. getKillcamEntity( attacker, eInflictor, sWeapon )
  985. {
  986.     if ( !isDefined( eInflictor ) )
  987.         return undefined;
  988.    
  989.     if ( eInflictor == attacker )
  990.         return undefined;
  991.    
  992.     if ( isSubStr( sWeapon, "ac130_" ) )
  993.         return undefined;
  994.  
  995.     if ( sWeapon == "cobra_player_minigun_mp" )
  996.         return undefined;
  997.    
  998.     if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" || sWeapon == "pavelow_minigun_mp" )
  999.         return eInflictor.killCamEnt;
  1000.    
  1001.     if ( isDefined( eInflictor.script_gameobjectname ) && eInflictor.script_gameobjectname == "bombzone" )
  1002.         return eInflictor.killCamEnt;
  1003.    
  1004.     if ( eInflictor.classname == "script_origin" || eInflictor.classname == "script_model" || eInflictor.classname == "script_brushmodel" )
  1005.         return undefined; // probably a barrel or a car... code does airstrike cam for these things which looks bad
  1006.    
  1007.     if ( issubstr( sWeapon, "remotemissile_" ) )
  1008.         return undefined;
  1009.     if ( issubstr( sWeapon, "ac130_" ) )
  1010.         return undefined;
  1011.    
  1012.     return eInflictor;
  1013. }
  1014.  
  1015.  
  1016. HitlocDebug( attacker, victim, damage, hitloc, dflags )
  1017. {
  1018.     colors = [];
  1019.     colors[ 0 ] = 2;
  1020.     colors[ 1 ] = 3;
  1021.     colors[ 2 ] = 5;
  1022.     colors[ 3 ] = 7;
  1023.  
  1024.     if ( !getdvarint( "scr_hitloc_debug" ) )
  1025.         return;
  1026.  
  1027.     if ( !isdefined( attacker.hitlocInited ) )
  1028.     {
  1029.         for ( i = 0; i < 6; i++ )
  1030.         {
  1031.             attacker setClientDvar( "ui_hitloc_" + i, "" );
  1032.         }
  1033.         attacker.hitlocInited = true;
  1034.     }
  1035.  
  1036.     if ( level.splitscreen || !isPLayer( attacker ) )
  1037.         return;
  1038.  
  1039.     elemcount = 6;
  1040.     if ( !isdefined( attacker.damageInfo ) )
  1041.     {
  1042.         attacker.damageInfo = [];
  1043.         for ( i = 0; i < elemcount; i++ )
  1044.         {
  1045.             attacker.damageInfo[ i ] = spawnstruct();
  1046.             attacker.damageInfo[ i ].damage = 0;
  1047.             attacker.damageInfo[ i ].hitloc = "";
  1048.             attacker.damageInfo[ i ].bp = false;
  1049.             attacker.damageInfo[ i ].jugg = false;
  1050.             attacker.damageInfo[ i ].colorIndex = 0;
  1051.         }
  1052.         attacker.damageInfoColorIndex = 0;
  1053.         attacker.damageInfoVictim = undefined;
  1054.     }
  1055.  
  1056.     for ( i = elemcount - 1; i > 0; i -- )
  1057.     {
  1058.         attacker.damageInfo[ i ].damage = attacker.damageInfo[ i - 1 ].damage;
  1059.         attacker.damageInfo[ i ].hitloc = attacker.damageInfo[ i - 1 ].hitloc;
  1060.         attacker.damageInfo[ i ].bp = attacker.damageInfo[ i - 1 ].bp;
  1061.         attacker.damageInfo[ i ].jugg = attacker.damageInfo[ i - 1 ].jugg;
  1062.         attacker.damageInfo[ i ].colorIndex = attacker.damageInfo[ i - 1 ].colorIndex;
  1063.     }
  1064.     attacker.damageInfo[ 0 ].damage = damage;
  1065.     attacker.damageInfo[ 0 ].hitloc = hitloc;
  1066.     attacker.damageInfo[ 0 ].bp = ( dflags & level.iDFLAGS_PENETRATION );
  1067.     attacker.damageInfo[ 0 ].jugg = victim hasPerk( "specialty_armorvest", true );
  1068.     if ( isdefined( attacker.damageInfoVictim ) && ( attacker.damageInfoVictim != victim ) )
  1069.     {
  1070.         attacker.damageInfoColorIndex++ ;
  1071.         if ( attacker.damageInfoColorIndex == colors.size )
  1072.             attacker.damageInfoColorIndex = 0;
  1073.     }
  1074.     attacker.damageInfoVictim = victim;
  1075.     attacker.damageInfo[ 0 ].colorIndex = attacker.damageInfoColorIndex;
  1076.  
  1077.     for ( i = 0; i < elemcount; i++ )
  1078.     {
  1079.         color = "^" + colors[ attacker.damageInfo[ i ].colorIndex ];
  1080.         if ( attacker.damageInfo[ i ].hitloc != "" )
  1081.         {
  1082.             val = color + attacker.damageInfo[ i ].hitloc;
  1083.             if ( attacker.damageInfo[ i ].bp )
  1084.                 val += " (BP)";
  1085.             if ( attacker.damageInfo[ i ].jugg )
  1086.                 val += " (Jugg)";
  1087.             attacker setClientDvar( "ui_hitloc_" + i, val );
  1088.         }
  1089.         attacker setClientDvar( "ui_hitloc_damage_" + i, color + attacker.damageInfo[ i ].damage );
  1090.     }
  1091. }
  1092.  
  1093. giveRecentShieldXP()
  1094. {
  1095.     self endon ( "death" );
  1096.     self endon ( "disconnect" );
  1097.    
  1098.     self notify ( "giveRecentShieldXP" );
  1099.     self endon ( "giveRecentShieldXP" );
  1100.    
  1101.     self.recentShieldXP++;
  1102.    
  1103.     wait ( 20.0 );
  1104.    
  1105.     self.recentShieldXP = 0;
  1106. }
  1107.  
  1108.  
  1109. Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
  1110. {
  1111.  
  1112.     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" )
  1113.     {
  1114.         iDamage = 0;
  1115.     }
  1116.    
  1117.     if ( !isReallyAlive( victim ) )
  1118.         return;
  1119.    
  1120.     if ( isDefined( eAttacker ) && eAttacker.classname == "script_origin" && isDefined( eAttacker.type ) && eAttacker.type == "soft_landing" )
  1121.         return;
  1122.    
  1123.     if ( isDefined( level.hostMigrationTimer ) )
  1124.         return;
  1125.    
  1126.     if ( sMeansOfDeath == "MOD_FALLING" )
  1127.         victim thread emitFallDamage( iDamage );
  1128.        
  1129.     if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && iDamage != 1 )
  1130.     {
  1131.         iDamage *= getDvarFloat( "scr_explBulletMod" );
  1132.         iDamage = int( iDamage );
  1133.     }
  1134.  
  1135.     if ( isDefined( eAttacker ) && eAttacker.classname == "worldspawn" )
  1136.         eAttacker = undefined;
  1137.    
  1138.     if ( isDefined( eAttacker ) && isDefined( eAttacker.gunner ) )
  1139.         eAttacker = eAttacker.gunner;
  1140.    
  1141.     attackerIsNPC = isDefined( eAttacker ) && !isDefined( eAttacker.gunner ) && (eAttacker.classname == "script_vehicle" || eAttacker.classname == "misc_turret" || eAttacker.classname == "script_model");
  1142.     attackerIsHittingTeammate = level.teamBased && isDefined( eAttacker ) && ( victim != eAttacker ) && isDefined( eAttacker.team ) && ( victim.pers[ "team" ] == eAttacker.team );
  1143.  
  1144.     stunFraction = 0.0;
  1145.  
  1146.     if ( iDFlags & level.iDFLAGS_STUN )
  1147.     {
  1148.         stunFraction = 0.0;
  1149.         //victim StunPlayer( 1.0 );
  1150.         iDamage = 0.0;
  1151.     }
  1152.     else if ( sHitLoc == "shield" )
  1153.     {
  1154.         if ( attackerIsHittingTeammate && level.friendlyfire == 0 )
  1155.             return;
  1156.        
  1157.         if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && !attackerIsHittingTeammate )
  1158.         {
  1159.             if ( isPlayer( eAttacker ) )
  1160.             {
  1161.                 eAttacker.lastAttackedShieldPlayer = victim;
  1162.                 eAttacker.lastAttackedShieldTime = getTime();
  1163.             }
  1164.             victim notify ( "shield_blocked" );
  1165.  
  1166.             // fix turret + shield challenge exploits
  1167.             if ( sWeapon == "turret_minigun_mp" )
  1168.                 shieldDamage = 25;
  1169.             else
  1170.                 shieldDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );
  1171.                        
  1172.             victim.shieldDamage += shieldDamage;
  1173.  
  1174.             // fix turret + shield challenge exploits
  1175.             if ( sWeapon != "turret_minigun_mp" || cointoss() )
  1176.                 victim.shieldBulletHits++;
  1177.  
  1178.             if ( victim.shieldBulletHits >= level.riotShieldXPBullets )
  1179.             {
  1180.                 if ( self.recentShieldXP > 4 )
  1181.                     xpVal = int( 50 / self.recentShieldXP );
  1182.                 else
  1183.                     xpVal = 50;
  1184.                
  1185.                 printLn( xpVal );
  1186.                
  1187.                 victim thread maps\mp\gametypes\_rank::giveRankXP( "shield_damage", xpVal );
  1188.                 victim thread giveRecentShieldXP();
  1189.                
  1190.                 victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_damage", victim.shieldDamage );
  1191.  
  1192.                 victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_bullet_hits", victim.shieldBulletHits );
  1193.                
  1194.                 victim.shieldDamage = 0;
  1195.                 victim.shieldBulletHits = 0;
  1196.             }
  1197.         }
  1198.  
  1199.         if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT )
  1200.         {
  1201.             if (  !attackerIsHittingTeammate )
  1202.                 victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 );
  1203.  
  1204.             sHitLoc = "none";   // code ignores any damage to a "shield" bodypart.
  1205.             if ( !(iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT_HUGE) )
  1206.                 iDamage *= 0.0;
  1207.         }
  1208.         else if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_SPLASH )
  1209.         {
  1210.             if ( isDefined( eInflictor ) && isDefined( eInflictor.stuckEnemyEntity ) && eInflictor.stuckEnemyEntity == victim ) //does enough damage to shield carrier to ensure death
  1211.                 iDamage = 101;
  1212.            
  1213.             victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 );
  1214.             sHitLoc = "none";   // code ignores any damage to a "shield" bodypart.
  1215.         }
  1216.         else
  1217.         {
  1218.             return;
  1219.         }
  1220.     }
  1221.     else if ( (smeansofdeath == "MOD_MELEE") && IsSubStr( sweapon, "riotshield" ) )
  1222.     {
  1223.         if ( !(attackerIsHittingTeammate && (level.friendlyfire == 0)) )
  1224.         {
  1225.             stunFraction = 0.0;
  1226.             victim StunPlayer( 0.0 );
  1227.         }
  1228.     }
  1229.  
  1230.     if ( !attackerIsHittingTeammate )
  1231.         iDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );
  1232.    
  1233.     if ( !iDamage )
  1234.         return false;
  1235.    
  1236.     victim.iDFlags = iDFlags;
  1237.     victim.iDFlagsTime = getTime();
  1238.  
  1239.     if ( game[ "state" ] == "postgame" )
  1240.         return;
  1241.     if ( victim.sessionteam == "spectator" )
  1242.         return;
  1243.     if ( isDefined( victim.canDoCombat ) && !victim.canDoCombat )
  1244.         return;
  1245.     if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat )
  1246.         return;
  1247.  
  1248.     // handle vehicles/turrets and friendly fire
  1249.     if ( attackerIsNPC && attackerIsHittingTeammate )
  1250.     {
  1251.         if ( sMeansOfDeath == "MOD_CRUSH" )
  1252.         {
  1253.             victim _suicide();
  1254.             return;
  1255.         }
  1256.        
  1257.         if ( !level.friendlyfire )
  1258.             return;
  1259.     }
  1260.  
  1261.     prof_begin( "PlayerDamage flags/tweaks" );
  1262.  
  1263.     // Don't do knockback if the damage direction was not specified
  1264.     if ( !isDefined( vDir ) )
  1265.         iDFlags |= level.iDFLAGS_NO_KNOCKBACK;
  1266.  
  1267.     friendly = false;
  1268.  
  1269.     if ( ( victim.health == victim.maxhealth && ( !isDefined( victim.lastStand ) || !victim.lastStand )  ) || !isDefined( victim.attackers ) && !isDefined( victim.lastStand )  )
  1270.     {
  1271.         victim.attackers = [];
  1272.         victim.attackerData = [];
  1273.     }
  1274.  
  1275.     if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, eAttacker ) )
  1276.         sMeansOfDeath = "MOD_HEAD_SHOT";
  1277.  
  1278.     if ( maps\mp\gametypes\_tweakables::getTweakableValue( "game", "onlyheadshots" ) )
  1279.     {
  1280.         if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" )
  1281.             return;
  1282.         else if ( sMeansOfDeath == "MOD_HEAD_SHOT" )
  1283.             iDamage = 150;
  1284.     }
  1285.  
  1286.     // explosive barrel/car detection
  1287.     if ( sWeapon == "none" && isDefined( eInflictor ) )
  1288.     {
  1289.         if ( isDefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) )
  1290.             sWeapon = "destructible_car";
  1291.     }
  1292.  
  1293.     prof_end( "PlayerDamage flags/tweaks" );
  1294.  
  1295.     // check for completely getting out of the damage
  1296.     if ( !(iDFlags & level.iDFLAGS_NO_PROTECTION) )
  1297.     {
  1298.         // items you own don't damage you in FFA
  1299.         if ( !level.teamBased && attackerIsNPC && isDefined( eAttacker.owner ) && eAttacker.owner == victim )
  1300.         {
  1301.             prof_end( "PlayerDamage player" );
  1302.  
  1303.             if ( sMeansOfDeath == "MOD_CRUSH" )
  1304.                 victim _suicide();
  1305.  
  1306.             return;
  1307.         }
  1308.  
  1309.         if ( ( isSubStr( sMeansOfDeath, "MOD_GRENADE" ) || isSubStr( sMeansOfDeath, "MOD_EXPLOSIVE" ) || isSubStr( sMeansOfDeath, "MOD_PROJECTILE" ) ) && isDefined( eInflictor ) && isDefined( eAttacker ) )
  1310.         {
  1311.             // protect players from spawnkill grenades
  1312.             if ( eInflictor.classname == "grenade" && ( victim.lastSpawnTime + 3500 ) > getTime() && isDefined( victim.lastSpawnPoint ) && distance( eInflictor.origin, victim.lastSpawnPoint.origin ) < 250 )
  1313.             {
  1314.                 prof_end( "PlayerDamage player" );
  1315.                 return;
  1316.             }
  1317.  
  1318.             victim.explosiveInfo = [];
  1319.             victim.explosiveInfo[ "damageTime" ] = getTime();
  1320.             victim.explosiveInfo[ "damageId" ] = eInflictor getEntityNumber();
  1321.             victim.explosiveInfo[ "returnToSender" ] = false;
  1322.             victim.explosiveInfo[ "counterKill" ] = false;
  1323.             victim.explosiveInfo[ "chainKill" ] = false;
  1324.             victim.explosiveInfo[ "cookedKill" ] = false;
  1325.             victim.explosiveInfo[ "throwbackKill" ] = false;
  1326.             victim.explosiveInfo[ "suicideGrenadeKill" ] = false;
  1327.             victim.explosiveInfo[ "weapon" ] = sWeapon;
  1328.  
  1329.             isFrag = isSubStr( sWeapon, "frag_" );
  1330.  
  1331.             if ( eAttacker != victim )
  1332.             {
  1333.                 if ( ( isSubStr( sWeapon, "c4_" ) || isSubStr( sWeapon, "claymore_" ) ) && isDefined( eAttacker ) && isDefined( eInflictor.owner ) )
  1334.                 {
  1335.                     victim.explosiveInfo[ "returnToSender" ] = ( eInflictor.owner == victim );
  1336.                     victim.explosiveInfo[ "counterKill" ] = isDefined( eInflictor.wasDamaged );
  1337.                     victim.explosiveInfo[ "chainKill" ] = isDefined( eInflictor.wasChained );
  1338.                     victim.explosiveInfo[ "bulletPenetrationKill" ] = isDefined( eInflictor.wasDamagedFromBulletPenetration );
  1339.                     victim.explosiveInfo[ "cookedKill" ] = false;
  1340.                 }
  1341.  
  1342.                 if ( isDefined( eAttacker.lastGrenadeSuicideTime ) && eAttacker.lastGrenadeSuicideTime >= gettime() - 50 && isFrag )
  1343.                     victim.explosiveInfo[ "suicideGrenadeKill" ] = true;
  1344.             }
  1345.  
  1346.             if ( isFrag )
  1347.             {
  1348.                 victim.explosiveInfo[ "cookedKill" ] = isDefined( eInflictor.isCooked );
  1349.                 victim.explosiveInfo[ "throwbackKill" ] = isDefined( eInflictor.threwBack );
  1350.             }
  1351.            
  1352.             victim.explosiveInfo[ "stickKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "enemy";
  1353.             victim.explosiveInfo[ "stickFriendlyKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "friendly";
  1354.         }
  1355.    
  1356.         if ( isPlayer( eAttacker ) )
  1357.             eAttacker.pers[ "participation" ]++ ;
  1358.  
  1359.         prevHealthRatio = victim.health / victim.maxhealth;
  1360.  
  1361.         if ( attackerIsHittingTeammate )
  1362.         {
  1363.             if ( !matchMakingGame() && isPlayer(eAttacker) )
  1364.                 eAttacker incPlayerStat( "mostff", 1 );
  1365.            
  1366.             prof_begin( "PlayerDamage player" );// profs automatically end when the function returns
  1367.             if ( level.friendlyfire == 0 || ( !isPlayer(eAttacker) && level.friendlyfire != 1 ) )// no one takes damage
  1368.             {
  1369.                 if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" )
  1370.                     victim damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker );
  1371.                 return;
  1372.             }
  1373.             else if ( level.friendlyfire == 1 )// the friendly takes damage
  1374.             {
  1375.                 if ( iDamage < 1 )
  1376.                     iDamage = 1;
  1377.  
  1378.                 victim.lastDamageWasFromEnemy = false;
  1379.  
  1380.                 victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1381.             }
  1382.             else if ( ( level.friendlyfire == 2 ) && isReallyAlive( eAttacker ) )// only the attacker takes damage
  1383.             {
  1384.                 iDamage = int( iDamage * .5 );
  1385.                 if ( iDamage < 1 )
  1386.                     iDamage = 1;
  1387.  
  1388.                 eAttacker.lastDamageWasFromEnemy = false;
  1389.  
  1390.                 eAttacker.friendlydamage = true;
  1391.                 eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1392.                 eAttacker.friendlydamage = undefined;
  1393.             }
  1394.             else if ( level.friendlyfire == 3 && isReallyAlive( eAttacker ) )// both friendly and attacker take damage
  1395.             {
  1396.                 iDamage = int( iDamage * .5 );
  1397.                 if ( iDamage < 1 )
  1398.                     iDamage = 1;
  1399.  
  1400.                 victim.lastDamageWasFromEnemy = false;
  1401.                 eAttacker.lastDamageWasFromEnemy = false;
  1402.  
  1403.                 victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1404.                 if ( isReallyAlive( eAttacker ) )// may have died due to friendly fire punishment
  1405.                 {
  1406.                     eAttacker.friendlydamage = true;
  1407.                     eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1408.                     eAttacker.friendlydamage = undefined;
  1409.                 }
  1410.             }
  1411.  
  1412.             friendly = true;
  1413.            
  1414.         }
  1415.         else// not hitting teammate
  1416.         {
  1417.             prof_begin( "PlayerDamage world" );
  1418.  
  1419.             if ( iDamage < 1 )
  1420.                 iDamage = 1;
  1421.  
  1422.             if ( isDefined( eAttacker ) && isPlayer( eAttacker ) )
  1423.                 addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath );
  1424.            
  1425.             if ( sMeansOfDeath == "MOD_EXPLOSIVE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" && iDamage < victim.health )
  1426.                 victim notify( "survived_explosion" );
  1427.  
  1428.             if ( isdefined( eAttacker ) )
  1429.                 level.lastLegitimateAttacker = eAttacker;
  1430.  
  1431.             if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) )
  1432.                 eAttacker thread maps\mp\gametypes\_weapons::checkHit( sWeapon, victim );
  1433.  
  1434.             if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) && eAttacker != victim )
  1435.             {
  1436.                 eAttacker thread maps\mp\_events::damagedPlayer( self, iDamage, sWeapon );
  1437.                 victim.attackerPosition = eAttacker.origin;
  1438.             }
  1439.             else
  1440.             {
  1441.                 victim.attackerPosition = undefined;
  1442.             }
  1443.  
  1444.             if ( issubstr( sMeansOfDeath, "MOD_GRENADE" ) && isDefined( eInflictor.isCooked ) )
  1445.                 victim.wasCooked = getTime();
  1446.             else
  1447.                 victim.wasCooked = undefined;
  1448.  
  1449.             victim.lastDamageWasFromEnemy = ( isDefined( eAttacker ) && ( eAttacker != victim ) );
  1450.  
  1451.             if ( victim.lastDamageWasFromEnemy )
  1452.                 eAttacker.damagedPlayers[ victim.guid ] = getTime();
  1453.  
  1454.             victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1455.  
  1456.             if ( isDefined( level.ac130player ) && isDefined( eAttacker ) && ( level.ac130player == eAttacker ) )
  1457.                 level notify( "ai_pain", victim );
  1458.  
  1459.             victim thread maps\mp\gametypes\_missions::playerDamaged( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc );
  1460.  
  1461.             prof_end( "PlayerDamage world" );
  1462.            
  1463.         }
  1464.  
  1465.         if ( attackerIsNPC && isDefined( eAttacker.gunner ) )
  1466.             damager = eAttacker.gunner;
  1467.         else
  1468.             damager = eAttacker;
  1469.  
  1470.         if ( isDefined( damager) && damager != victim && iDamage > 0 )
  1471.         {
  1472.             if ( iDFlags & level.iDFLAGS_STUN )
  1473.                 typeHit = "stun";
  1474.             else if ( victim hasPerk( "specialty_armorvest", true ) || (isExplosiveDamage( sMeansOfDeath ) && victim _hasPerk( "_specialty_blastshield" )) )
  1475.                 typeHit = "hitBodyArmor";
  1476.             else if ( victim _hasPerk( "specialty_combathigh") )
  1477.                 typeHit = "hitEndGame";
  1478.             else
  1479.                 typeHit = "standard";
  1480.                
  1481.             damager thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( typeHit );
  1482.         }
  1483.  
  1484.         victim.hasDoneCombat = true;
  1485.     }
  1486.  
  1487.     if ( isdefined( eAttacker ) && ( eAttacker != victim ) && !friendly )
  1488.         level.useStartSpawns = false;
  1489.  
  1490.  
  1491.     //=================
  1492.     // Damage Logging
  1493.     //=================
  1494.  
  1495.     prof_begin( "PlayerDamage log" );
  1496.  
  1497.     // why getEntityNumber() for victim and .clientid for attacker?
  1498.     if ( getDvarInt( "g_debugDamage" ) )
  1499.         println( "client:" + victim getEntityNumber() + " health:" + victim.health + " attacker:" + eAttacker.clientid + " inflictor is player:" + isPlayer( eInflictor ) + " damage:" + iDamage + " hitLoc:" + sHitLoc );
  1500.  
  1501.     if ( victim.sessionstate != "dead" )
  1502.     {
  1503.         lpselfnum = victim getEntityNumber();
  1504.         lpselfname = victim.name;
  1505.         lpselfteam = victim.pers[ "team" ];
  1506.         lpselfGuid = victim.guid;
  1507.         lpattackerteam = "";
  1508.  
  1509.         if ( isPlayer( eAttacker ) )
  1510.         {
  1511.             lpattacknum = eAttacker getEntityNumber();
  1512.             lpattackGuid = eAttacker.guid;
  1513.             lpattackname = eAttacker.name;
  1514.             lpattackerteam = eAttacker.pers[ "team" ];
  1515.         }
  1516.         else
  1517.         {
  1518.             lpattacknum = -1;
  1519.             lpattackGuid = "";
  1520.             lpattackname = "";
  1521.             lpattackerteam = "world";
  1522.         }
  1523.  
  1524.         logPrint( "D;" + lpselfGuid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" );
  1525.     }
  1526.  
  1527.     HitlocDebug( eAttacker, victim, iDamage, sHitLoc, iDFlags );
  1528.  
  1529.     /*if( isDefined( eAttacker ) && eAttacker != victim )
  1530.     {
  1531.         if ( isPlayer( eAttacker ) )
  1532.             eAttacker incPlayerStat( "damagedone", iDamage );
  1533.        
  1534.         victim incPlayerStat( "damagetaken", iDamage );
  1535.     }*/
  1536.  
  1537.     prof_end( "PlayerDamage log" );
  1538. }
  1539.  
  1540.  
  1541. addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath )
  1542. {
  1543.     if ( !isDefined( victim.attackerData ) )
  1544.         victim.attackerData = [];
  1545.    
  1546.     if ( !isDefined( victim.attackerData[ eAttacker.guid ] ) )
  1547.     {
  1548.         victim.attackers[ eAttacker.guid ] = eAttacker;
  1549.         // we keep an array of attackers by their client ID so we can easily tell
  1550.         // if they're already one of the existing attackers in the above if().
  1551.         // we store in this array data that is useful for other things, like challenges
  1552.         victim.attackerData[ eAttacker.guid ] = SpawnStruct();
  1553.         victim.attackerData[ eAttacker.guid ].damage = 0;  
  1554.         victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker;
  1555.         victim.attackerData[ eAttacker.guid ].firstTimeDamaged = getTime();            
  1556.     }
  1557.     if ( maps\mp\gametypes\_weapons::isPrimaryWeapon( sWeapon ) && ! maps\mp\gametypes\_weapons::isSideArm( sWeapon ) )
  1558.         victim.attackerData[ eAttacker.guid ].isPrimary = true;
  1559.    
  1560.     victim.attackerData[ eAttacker.guid ].damage += iDamage;
  1561.     victim.attackerData[ eAttacker.guid ].weapon = sWeapon;
  1562.     victim.attackerData[ eAttacker.guid ].vPoint = vPoint;
  1563.     victim.attackerData[ eAttacker.guid ].vDir = vDir;
  1564.     victim.attackerData[ eAttacker.guid ].sHitLoc = sHitLoc;
  1565.     victim.attackerData[ eAttacker.guid ].psOffsetTime = psOffsetTime;
  1566.     victim.attackerData[ eAttacker.guid ].sMeansOfDeath = sMeansOfDeath;
  1567.     victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker;
  1568.     victim.attackerData[ eAttacker.guid ].lasttimeDamaged = getTime();
  1569.    
  1570.     if ( isDefined( eInflictor ) && !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) )
  1571.         victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eInflictor.primaryWeapon;
  1572.     else if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker getCurrentPrimaryWeapon() != "none" )
  1573.         victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eAttacker getCurrentPrimaryWeapon();
  1574.     else
  1575.         victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = undefined;
  1576. }
  1577.  
  1578. resetAttackerList()
  1579. {
  1580.     self endon( "disconnect" );
  1581.     self endon( "death" );
  1582.     level endon( "game_ended" );
  1583.    
  1584.     //wait is to offset premature calling in _healthOverlay
  1585.     wait( 1.75 );
  1586.     self.attackers = [];
  1587.     self.attackerData = [];
  1588. }
  1589.  
  1590.  
  1591. Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
  1592. {
  1593.     Callback_PlayerDamage_internal( eInflictor, eAttacker, self, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime );
  1594. }
  1595.  
  1596.  
  1597. finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction )
  1598. {
  1599.     if ( (self isUsingRemote() ) && (iDamage >= self.health) && !(iDFlags & level.iDFLAGS_STUN) )
  1600.     {
  1601.         if ( !isDefined( vDir ) )
  1602.             vDir = ( 0,0,0 );
  1603.  
  1604.         if ( !isDefined( eAttacker ) && !isDefined( eInflictor ) )
  1605.         {
  1606.             eAttacker = self;
  1607.             eInflictor = eAttacker;
  1608.         }
  1609.        
  1610.         assert( isDefined( eAttacker ) );
  1611.         assert( isDefined( eInflictor ) );
  1612.  
  1613.         PlayerKilled_internal( eInflictor, eAttacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, 0, true );
  1614.     }
  1615.     else
  1616.     {
  1617.         if ( !self Callback_KillingBlow( eInflictor, eAttacker, iDamage - (iDamage * stunFraction), iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) )
  1618.             return;
  1619.  
  1620.         self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
  1621.     }
  1622.  
  1623.     if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" )
  1624.         self shellShock( "damage_mp", getDvarFloat( "scr_csmode" ) );
  1625.  
  1626.     self damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker );
  1627. }
  1628.  
  1629.  
  1630. Callback_PlayerLastStand( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
  1631. {  
  1632.        
  1633.     lastStandParams = spawnStruct();
  1634.     lastStandParams.eInflictor = eInflictor;
  1635.     lastStandParams.attacker = attacker;
  1636.     lastStandParams.iDamage = iDamage;
  1637.     lastStandParams.attackerPosition = attacker.origin;
  1638.     if ( attacker == self )
  1639.         lastStandParams.sMeansOfDeath = "MOD_SUICIDE";
  1640.     else
  1641.         lastStandParams.sMeansOfDeath = sMeansOfDeath;
  1642.    
  1643.     lastStandParams.sWeapon = sWeapon;
  1644.     if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" )
  1645.         lastStandParams.sPrimaryWeapon = attacker getCurrentPrimaryWeapon();
  1646.     else
  1647.         lastStandParams.sPrimaryWeapon = undefined;
  1648.     lastStandParams.vDir = vDir;
  1649.     lastStandParams.sHitLoc = sHitLoc;
  1650.     lastStandParams.lastStandStartTime = getTime();
  1651.  
  1652.     mayDoLastStand = mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc );
  1653.    
  1654.     //if ( mayDoLastStand )
  1655.     //  mayDoLastStand = !self checkForceBleedOut();
  1656.    
  1657.     if ( isDefined( self.endGame ) )
  1658.         mayDoLastStand = false;
  1659.    
  1660.     if ( level.teamBased && isDefined( attacker.team ) && attacker.team == self.team )
  1661.         mayDoLastStand = false;
  1662.  
  1663.      /#
  1664.     if ( getdvar( "scr_forcelaststand" ) == "1" )
  1665.         mayDoLastStand = true;
  1666.     #/
  1667.    
  1668.     if ( !mayDoLastStand )
  1669.     {
  1670.         self.lastStandParams = lastStandParams;
  1671.         self.useLastStandParams = true;
  1672.         self _suicide();
  1673.         return;
  1674.     }
  1675.    
  1676.     self.inLastStand = true;
  1677.  
  1678.     notifyData = spawnStruct();
  1679.     if ( self _hasPerk( "specialty_finalstand" ) )
  1680.     {
  1681.         notifyData.titleText = game[ "strings" ][ "final_stand" ];
  1682.         notifyData.iconName = "specialty_finalstand";
  1683.     }
  1684.     else
  1685.     {
  1686.         notifyData.titleText = game[ "strings" ][ "last_stand" ];
  1687.         notifyData.iconName = "specialty_pistoldeath";
  1688.     }
  1689.     notifyData.glowColor = ( 1, 0, 0 );
  1690.     notifyData.sound = "mp_last_stand";
  1691.     notifyData.duration = 2.0;
  1692.  
  1693.     self.health = 1;
  1694.  
  1695.     self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData );
  1696.  
  1697.     grenadeTypePrimary = "frag_grenade_mp";
  1698.  
  1699.     if ( isDefined( level.ac130player ) && isDefined( attacker ) && level.ac130player == attacker )
  1700.         level notify( "ai_crawling", self );
  1701.    
  1702.     if ( self _hasPerk( "specialty_finalstand" ) )
  1703.     {
  1704.         self.lastStandParams = lastStandParams;
  1705.         self.inFinalStand = true;
  1706.        
  1707.         weaponList = self GetWeaponsListExclusives();
  1708.         foreach ( weapon in weaponList )
  1709.             self takeWeapon( weapon );
  1710.        
  1711.         self _disableUsability();
  1712.  
  1713.         self thread enableLastStandWeapons();
  1714.         self thread lastStandTimer( 20, true );    
  1715.     }
  1716.     /*
  1717.     else if ( self _hasPerk( "specialty_c4death" ) )
  1718.     {
  1719.         self.lastStandParams = lastStandParams;
  1720.  
  1721.         self takeAllWeapons();
  1722.         self giveWeapon( "c4Death_mp", 0, false );
  1723.         self switchToWeapon( "c4Death_mp" );
  1724.         self _disableUsability();
  1725.         self.inC4Death = true;
  1726.                
  1727.         //self thread dieAfterTime( 7 );
  1728.         self thread lastStandTimer( 10, false );   
  1729.         self thread detonateOnUse();
  1730.         //self thread detonateOnDeath();   
  1731.     }
  1732.     */
  1733.     else if ( level.dieHardMode )
  1734.     {  
  1735.         self.lastStandParams = lastStandParams;
  1736.         self thread enableLastStandWeapons();
  1737.         self thread lastStandTimer( 20, false );
  1738.         self _disableUsability();
  1739.     }
  1740.     else // normal last stand
  1741.     {
  1742.         self.lastStandParams = lastStandParams;
  1743.        
  1744.         pistolWeapon = undefined;
  1745.        
  1746.         weaponsList = self GetWeaponsListPrimaries();
  1747.         foreach ( weapon in weaponsList )
  1748.         {
  1749.             if ( maps\mp\gametypes\_weapons::isSideArm( weapon ) )
  1750.                 pistolWeapon = weapon;         
  1751.         }
  1752.            
  1753.         if ( !isDefined( pistolWeapon ) )
  1754.         {
  1755.             pistolWeapon = "beretta_mp";
  1756.             self _giveWeapon( pistolWeapon );
  1757.         }
  1758.    
  1759.         self giveMaxAmmo( pistolWeapon );
  1760.         self DisableWeaponSwitch();
  1761.         self _disableUsability();
  1762.        
  1763.         if ( !self _hasPerk("specialty_laststandoffhand") )
  1764.             self DisableOffhandWeapons();
  1765.                
  1766.         self switchToWeapon( pistolWeapon );
  1767.        
  1768.         self thread lastStandTimer( 10, false );
  1769.     }
  1770. }
  1771.  
  1772. dieAfterTime( time )
  1773. {
  1774.     self endon( "death" );
  1775.     self endon( "disconnect" );
  1776.     self endon( "joined_team" );
  1777.     level endon( "game_ended" );
  1778.    
  1779.     wait ( time );
  1780.     self.useLastStandParams = true;
  1781.     self _suicide();
  1782. }
  1783.  
  1784. detonateOnUse()
  1785. {
  1786.     self endon( "death" );
  1787.     self endon( "disconnect" );
  1788.     self endon( "joined_team" );
  1789.     level endon( "game_ended" );
  1790.    
  1791.     self waittill( "detonate" );
  1792.     self.useLastStandParams = true;
  1793.     self c4DeathDetonate();
  1794. }
  1795.  
  1796. detonateOnDeath()
  1797. {
  1798.     self endon( "detonate" );
  1799.     self endon( "disconnect" );
  1800.     self endon( "joined_team" );
  1801.     level endon( "game_ended" );
  1802.    
  1803.     self waittill( "death" );
  1804.     self c4DeathDetonate();
  1805. }
  1806.  
  1807. c4DeathDetonate()
  1808. {
  1809.     self playSound( "detpack_explo_default" );
  1810.     self.c4DeathEffect = playFX( level.c4Death, self.origin );
  1811.     RadiusDamage( self.origin, 400, 100, 100, self );
  1812.    
  1813.     if ( isAlive( self ) )
  1814.         self _suicide();
  1815. }
  1816.  
  1817. enableLastStandWeapons()
  1818. {
  1819.     self endon( "death" );
  1820.     self endon( "disconnect" );
  1821.     level endon( "game_ended" );
  1822.  
  1823.     self freezeControlsWrapper( true );
  1824.     wait .30;
  1825.    
  1826.     self freezeControlsWrapper( false );
  1827. }
  1828.  
  1829. lastStandTimer( delay, isFinalStand )
  1830. {
  1831.     self endon( "death" );
  1832.     self endon( "disconnect" );
  1833.     self endon( "revive");
  1834.     level endon( "game_ended" );
  1835.    
  1836.     level notify ( "player_last_stand" );
  1837.    
  1838.     self thread lastStandWaittillDeath();
  1839.    
  1840.     self.lastStand = true;
  1841.    
  1842.     if ( !isFinalStand && !level.dieHardMode && ( !isDefined( self.inC4Death ) || !self.inC4Death ) )
  1843.     {
  1844.         self thread lastStandAllowSuicide();
  1845.         self setLowerMessage( "last_stand", &"PLATFORM_COWARDS_WAY_OUT" );
  1846.         self thread lastStandKeepOverlay();
  1847.     }
  1848.    
  1849.     if ( level.dieHardMode == 1 && level.dieHardMode != 2 )
  1850.     {
  1851.         reviveEnt = spawn( "script_model", self.origin );
  1852.         reviveEnt setModel( "tag_origin" );
  1853.         reviveEnt setCursorHint( "HINT_NOICON" );
  1854.         reviveEnt setHintString( &"PLATFORM_REVIVE" );
  1855.  
  1856.         reviveEnt reviveSetup( self );
  1857.         reviveEnt endon ( "death" );
  1858.  
  1859.         reviveIcon = newTeamHudElem( self.team );
  1860.         reviveIcon setShader( "waypoint_revive", 8, 8 );
  1861.         reviveIcon setWaypoint( true, true );
  1862.         reviveIcon SetTargetEnt( self );
  1863.         reviveIcon thread destroyOnReviveEntDeath( reviveEnt );
  1864.  
  1865.         reviveIcon.color = (0.33, 0.75, 0.24);
  1866.         self playDeathSound();
  1867.        
  1868.         if ( isFinalStand )
  1869.         {
  1870.             wait( delay );
  1871.            
  1872.             if ( self.inFinalStand )
  1873.                 self thread lastStandBleedOut( isFinalStand, reviveEnt );
  1874.         }
  1875.        
  1876.         return;
  1877.     }
  1878.     else if( level.dieHardMode == 2 )
  1879.     {
  1880.         self thread lastStandKeepOverlay();
  1881.         reviveEnt = spawn( "script_model", self.origin );
  1882.         reviveEnt setModel( "tag_origin" );
  1883.         reviveEnt setCursorHint( "HINT_NOICON" );
  1884.         reviveEnt setHintString( &"PLATFORM_REVIVE" );
  1885.  
  1886.         reviveEnt reviveSetup( self );
  1887.         reviveEnt endon ( "death" );
  1888.  
  1889.         reviveIcon = newTeamHudElem( self.team );
  1890.         reviveIcon setShader( "waypoint_revive", 8, 8 );
  1891.         reviveIcon setWaypoint( true, true );
  1892.         reviveIcon SetTargetEnt( self );
  1893.         reviveIcon thread destroyOnReviveEntDeath( reviveEnt );
  1894.  
  1895.         reviveIcon.color = (0.33, 0.75, 0.24);
  1896.         self playDeathSound();
  1897.        
  1898.         if ( isFinalStand )
  1899.         {
  1900.             wait( delay );
  1901.            
  1902.             if ( self.inFinalStand )
  1903.                 self thread lastStandBleedOut( isFinalStand, reviveEnt );
  1904.         }
  1905.        
  1906.         wait delay / 3;
  1907.         reviveIcon.color = (1.0, 0.64, 0.0);
  1908.        
  1909.         while ( reviveEnt.inUse )
  1910.             wait ( 0.05 );
  1911.        
  1912.         self playDeathSound(); 
  1913.         wait delay / 3;
  1914.         reviveIcon.color = (1.0, 0.0, 0.0);
  1915.  
  1916.         while ( reviveEnt.inUse )
  1917.             wait ( 0.05 );
  1918.  
  1919.         self playDeathSound();
  1920.         wait delay / 3;
  1921.  
  1922.         while ( reviveEnt.inUse )
  1923.             wait ( 0.05 );
  1924.        
  1925.         wait( 0.05 );
  1926.         self thread lastStandBleedOut( isFinalStand );
  1927.         return;
  1928.     }
  1929.    
  1930.     wait( delay );
  1931.     self thread lastStandBleedout( isFinalStand );
  1932.  
  1933. }
  1934.  
  1935. maxHealthOverlay( maxHealth, refresh )
  1936. {
  1937.     self endon( "stop_maxHealthOverlay" );
  1938.     self endon( "revive" );
  1939.     self endon( "death" );
  1940.    
  1941.     for( ;; )
  1942.     {
  1943.         self.health -= 1;
  1944.         self.maxHealth = maxHealth;
  1945.         wait( .05 );
  1946.         self.maxHealth = 50;
  1947.         self.health += 1;
  1948.    
  1949.         wait ( .50 );
  1950.     }  
  1951. }
  1952.  
  1953. lastStandBleedOut( reviveOnBleedOut, reviveEnt )
  1954. {
  1955.     if ( reviveOnBleedOut )
  1956.     {
  1957.         self.lastStand = undefined;
  1958.         self.inFinalStand = false;
  1959.         self clearLowerMessage( "last_stand" );
  1960.         maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer();
  1961.        
  1962.         if( isDefined( reviveEnt ) )
  1963.             reviveEnt Delete();
  1964.     }
  1965.     else
  1966.     {
  1967.         self.useLastStandParams = true;
  1968.         self.beingRevived = false;
  1969.         self _suicide();
  1970.     }
  1971. }
  1972.  
  1973.  
  1974. lastStandAllowSuicide()
  1975. {
  1976.     self endon( "death" );
  1977.     self endon( "disconnect" );
  1978.     self endon( "game_ended" );
  1979.     self endon( "revive");
  1980.  
  1981.     while ( 1 )
  1982.     {
  1983.         if ( self useButtonPressed() )
  1984.         {
  1985.             pressStartTime = gettime();
  1986.             while ( self useButtonPressed() )
  1987.             {
  1988.                 wait .05;
  1989.                 if ( gettime() - pressStartTime > 700 )
  1990.                     break;
  1991.             }
  1992.             if ( gettime() - pressStartTime > 700 )
  1993.                 break;
  1994.         }
  1995.         wait .05;
  1996.     }
  1997.  
  1998.     self thread lastStandBleedOut( false );
  1999. }
  2000.  
  2001. lastStandKeepOverlay()
  2002. {
  2003.     level endon( "game_ended" );
  2004.     self endon( "death" );
  2005.     self endon( "disconnect" );
  2006.     self endon( "revive" );
  2007.  
  2008.     // keep the health overlay going by making code think the player is getting damaged
  2009.     while ( !level.gameEnded )
  2010.     {
  2011.         self.health = 2;
  2012.         wait .05;
  2013.         self.health = 1;
  2014.         wait .5;
  2015.     }
  2016.    
  2017.     self.health = self.maxhealth;
  2018. }
  2019.  
  2020.  
  2021. lastStandWaittillDeath()
  2022. {
  2023.     self endon( "disconnect" );
  2024.     self endon( "revive" );
  2025.     level endon( "game_ended" );
  2026.     self waittill( "death" );
  2027.  
  2028.     self clearLowerMessage( "last_stand" );
  2029.     self.lastStand = undefined;
  2030. }
  2031.  
  2032.  
  2033. mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc )
  2034. {
  2035.     if ( sMeansOfDeath == "MOD_TRIGGER_HURT" )
  2036.         return false;
  2037.    
  2038.     if ( sMeansOfDeath != "MOD_PISTOL_BULLET" && sMeansOfDeath != "MOD_RIFLE_BULLET" && sMeansOfDeath != "MOD_FALLING" && sMeansOfDeath != "MOD_EXPLOSIVE_BULLET" )
  2039.         return false;
  2040.  
  2041.     if ( sMeansOfDeath == "MOD_IMPACT" && sWeapon == "throwingknife_mp" )
  2042.         return false;
  2043.        
  2044.     if ( sMeansOfDeath == "MOD_IMPACT" && ( sWeapon == "m79_mp" || isSubStr(sWeapon, "gl_") ) )
  2045.         return false;
  2046.  
  2047.     if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath ) )
  2048.         return false;
  2049.    
  2050.     if ( self isUsingRemote() )
  2051.         return false;
  2052.  
  2053.     return true;
  2054. }
  2055.  
  2056.  
  2057. ensureLastStandParamsValidity()
  2058. {
  2059.     // attacker may have become undefined if the player that killed me has disconnected
  2060.     if ( !isDefined( self.lastStandParams.attacker ) )
  2061.         self.lastStandParams.attacker = self;
  2062. }
  2063.  
  2064. getHitLocHeight( sHitLoc )
  2065. {
  2066.     switch( sHitLoc )
  2067.     {
  2068.         case "helmet":
  2069.         case "head":
  2070.         case "neck":
  2071.             return 60;
  2072.         case "torso_upper":
  2073.         case "right_arm_upper":
  2074.         case "left_arm_upper":
  2075.         case "right_arm_lower":
  2076.         case "left_arm_lower":
  2077.         case "right_hand":
  2078.         case "left_hand":
  2079.         case "gun":
  2080.             return 48;
  2081.         case "torso_lower":
  2082.             return 40;
  2083.         case "right_leg_upper":
  2084.         case "left_leg_upper":
  2085.             return 32;
  2086.         case "right_leg_lower":
  2087.         case "left_leg_lower":
  2088.             return 10;
  2089.         case "right_foot":
  2090.         case "left_foot":
  2091.             return 5;
  2092.     }
  2093.     return 48;
  2094. }
  2095.  
  2096. delayStartRagdoll( ent, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath )
  2097. {
  2098.     if ( isDefined( ent ) )
  2099.     {
  2100.         deathAnim = ent getCorpseAnim();
  2101.         if ( animhasnotetrack( deathAnim, "ignore_ragdoll" ) )
  2102.             return;
  2103.     }
  2104.  
  2105.     wait( 0.2 );
  2106.  
  2107.     if ( !isDefined( ent ) )
  2108.         return;
  2109.  
  2110.     if ( ent isRagDoll() )
  2111.         return;
  2112.  
  2113.     deathAnim = ent getcorpseanim();
  2114.  
  2115.     startFrac = 0.35;
  2116.  
  2117.     if ( animhasnotetrack( deathAnim, "start_ragdoll" ) )
  2118.     {
  2119.         times = getnotetracktimes( deathAnim, "start_ragdoll" );
  2120.         if ( isDefined( times ) )
  2121.             startFrac = times[ 0 ];
  2122.     }
  2123.  
  2124.     waitTime = startFrac * getanimlength( deathAnim );
  2125.     wait( waitTime );
  2126.  
  2127.     if ( isDefined( ent ) )
  2128.     {
  2129.         ent startragdoll( 1 );
  2130.     }
  2131. }
  2132.  
  2133.  
  2134. getMostKilledBy()
  2135. {
  2136.     mostKilledBy = "";
  2137.     killCount = 0;
  2138.  
  2139.     killedByNames = getArrayKeys( self.killedBy );
  2140.  
  2141.     for ( index = 0; index < killedByNames.size; index++ )
  2142.     {
  2143.         killedByName = killedByNames[ index ];
  2144.         if ( self.killedBy[ killedByName ] <= killCount )
  2145.             continue;
  2146.  
  2147.         killCount = self.killedBy[ killedByName ];
  2148.         mostKilleBy = killedByName;
  2149.     }
  2150.  
  2151.     return mostKilledBy;
  2152. }
  2153.  
  2154.  
  2155. getMostKilled()
  2156. {
  2157.     mostKilled = "";
  2158.     killCount = 0;
  2159.  
  2160.     killedNames = getArrayKeys( self.killedPlayers );
  2161.  
  2162.     for ( index = 0; index < killedNames.size; index++ )
  2163.     {
  2164.         killedName = killedNames[ index ];
  2165.         if ( self.killedPlayers[ killedName ] <= killCount )
  2166.             continue;
  2167.  
  2168.         killCount = self.killedPlayers[ killedName ];
  2169.         mostKilled = killedName;
  2170.     }
  2171.  
  2172.     return mostKilled;
  2173. }
  2174.  
  2175.  
  2176. damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker )
  2177. {
  2178.     self thread maps\mp\gametypes\_weapons::onWeaponDamage( eInflictor, sWeapon, sMeansOfDeath, iDamage, eAttacker );
  2179.     self PlayRumbleOnEntity( "damage_heavy" );
  2180. }
  2181.  
  2182.  
  2183. reviveSetup( owner )
  2184. {
  2185.     team = owner.team;
  2186.    
  2187.     self linkTo( owner, "tag_origin" );
  2188.  
  2189.     self.owner = owner;
  2190.     self.inUse = false;
  2191.     self makeUsable();
  2192.     self updateUsableByTeam( team );
  2193.     self thread trackTeamChanges( team );
  2194.    
  2195.     self thread reviveTriggerThink( team );
  2196.    
  2197.     self thread deleteOnReviveOrDeathOrDisconnect();
  2198. }
  2199.  
  2200.  
  2201. deleteOnReviveOrDeathOrDisconnect()
  2202. {
  2203.     self endon ( "death" );
  2204.    
  2205.     self.owner waittill_any ( "death", "disconnect" );
  2206.    
  2207.     self delete();
  2208. }
  2209.  
  2210.  
  2211. updateUsableByTeam( team )
  2212. {
  2213.     foreach (player in level.players)
  2214.     {
  2215.         if ( team == player.team && player != self.owner )
  2216.             self enablePlayerUse( player );
  2217.         else
  2218.             self disablePlayerUse( player );   
  2219.     }  
  2220. }
  2221.  
  2222.  
  2223. trackTeamChanges( team )
  2224. {
  2225.     self endon ( "death" );
  2226.    
  2227.     while ( true )
  2228.     {
  2229.         level waittill ( "joined_team" );
  2230.        
  2231.         self updateUsableByTeam( team );
  2232.     }
  2233. }
  2234.  
  2235.  
  2236. trackLastStandChanges( team )
  2237. {
  2238.     self endon ( "death" );
  2239.    
  2240.     while ( true )
  2241.     {
  2242.         level waittill ( "player_last_stand" );
  2243.        
  2244.         self updateUsableByTeam( team );
  2245.     }
  2246. }
  2247.  
  2248.  
  2249. reviveTriggerThink( team )
  2250. {
  2251.     self endon ( "death" );
  2252.     level endon ( "game_ended" );
  2253.    
  2254.     for ( ;; )
  2255.     {
  2256.         self waittill ( "trigger", player );
  2257.         self.owner.beingRevived = true;
  2258.  
  2259.         if ( isDefined(player.beingRevived) && player.beingRevived )
  2260.         {
  2261.             self.owner.beingRevived = false;
  2262.             continue;
  2263.         }
  2264.            
  2265.         self makeUnUsable();
  2266.         self.owner freezeControlsWrapper( true );
  2267.  
  2268.         revived = self useHoldThink( player );
  2269.         self.owner.beingRevived = false;
  2270.        
  2271.         if ( !isAlive( self.owner ) )
  2272.         {  
  2273.             self delete();
  2274.             return;
  2275.         }
  2276.  
  2277.         self.owner freezeControlsWrapper( false );
  2278.            
  2279.         if ( revived )
  2280.         {
  2281.             player thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "reviver", 200 );
  2282.             player thread maps\mp\gametypes\_rank::giveRankXP( "reviver", 200 );
  2283.  
  2284.             self.owner.lastStand = undefined;
  2285.             self.owner clearLowerMessage( "last_stand" );
  2286.            
  2287.             if ( self.owner _hasPerk( "specialty_lightweight" ) )
  2288.                 self.owner.moveSpeedScaler = 1.07;
  2289.             else
  2290.                 self.owner.moveSpeedScaler = 1;
  2291.            
  2292.             self.owner.maxHealth = 100;
  2293.            
  2294.             self.owner maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" );
  2295.             self.owner maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer();
  2296.  
  2297.             self.owner setPerk( "specialty_pistoldeath", true );
  2298.             self.owner.beingRevived = false;
  2299.            
  2300.             self delete();
  2301.             return;
  2302.         }
  2303.            
  2304.         self makeUsable();
  2305.         self updateUsableByTeam( team );
  2306.     }
  2307. }
  2308.  
  2309.  
  2310.  
  2311. /*
  2312. =============
  2313. useHoldThink
  2314.  
  2315. Claims the use trigger for player and displays a use bar
  2316. Returns true if the player sucessfully fills the use bar
  2317. =============
  2318. */
  2319. useHoldThink( player )
  2320. {
  2321.     reviveSpot = spawn( "script_origin", self.origin );
  2322.     reviveSpot hide(); 
  2323.     player playerLinkTo( reviveSpot );     
  2324.     player PlayerLinkedOffsetEnable();
  2325.    
  2326.     player _disableWeapon();
  2327.    
  2328.     self.curProgress = 0;
  2329.     self.inUse = true;
  2330.     self.useRate = 0;
  2331.     self.useTime = 3000;
  2332.    
  2333.     player thread personalUseBar( self );
  2334.    
  2335.     result = useHoldThinkLoop( player );
  2336.    
  2337.     if ( isDefined( player ) && isReallyAlive( player ) )
  2338.     {
  2339.         player Unlink();
  2340.         player _enableWeapon();
  2341.     }
  2342.  
  2343.     if ( isDefined( result ) && result )
  2344.     {
  2345.         self.owner thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "revived", player );
  2346.         self.owner.inlaststand = false;
  2347.         return true;
  2348.     }
  2349.    
  2350.     self.inUse = false;
  2351.     reviveSpot Delete();   
  2352.     return false;
  2353. }
  2354.  
  2355.  
  2356. personalUseBar( object )
  2357. {
  2358.     useBar = self createPrimaryProgressBar();
  2359.     useBarText = self createPrimaryProgressBarText();
  2360.     useBarText setText( &"MPUI_REVIVING" );
  2361.  
  2362.     objUseBar = object.owner createPrimaryProgressBar();
  2363.     objUseBarText = object.owner createPrimaryProgressBarText();
  2364.     objUseBarText setText( &"MPUI_BEING_REVIVED" );
  2365.  
  2366.     lastRate = -1;
  2367.     while ( isReallyAlive( self ) && isDefined( object ) && object.inUse && !level.gameEnded && isDefined( self ) )
  2368.     {
  2369.         if ( lastRate != object.useRate )
  2370.         {
  2371.             if( object.curProgress > object.useTime)
  2372.                 object.curProgress = object.useTime;
  2373.                
  2374.             useBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate );
  2375.             objUseBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate );
  2376.  
  2377.             if ( !object.useRate )
  2378.             {
  2379.                 useBar hideElem();
  2380.                 useBarText hideElem();
  2381.  
  2382.                 objUseBar hideElem();
  2383.                 objUseBarText hideElem();
  2384.             }
  2385.             else
  2386.             {
  2387.                 useBar showElem();
  2388.                 useBarText showElem();
  2389.  
  2390.                 objUseBar showElem();
  2391.                 objUseBarText showElem();
  2392.             }
  2393.         }  
  2394.         lastRate = object.useRate;
  2395.         wait ( 0.05 );
  2396.     }
  2397.    
  2398.     // when the players disconnect the hudElems are destroyed automatically
  2399.     if ( isDefined( useBar ) )
  2400.         useBar destroyElem();
  2401.     if ( isDefined( useBarText ) )
  2402.         useBarText destroyElem();
  2403.  
  2404.     if ( isDefined( objUseBar ) )
  2405.         objUseBar destroyElem();
  2406.     if ( isDefined( objUseBarText ) )
  2407.         objUseBarText destroyElem();
  2408. }
  2409.  
  2410.  
  2411. useHoldThinkLoop( player )
  2412. {
  2413.     level endon ( "game_ended" );
  2414.     self.owner endon( "death" );
  2415.     self.owner endon( "disconnect" );
  2416.  
  2417.     while( isReallyAlive( player ) && player useButtonPressed() && self.curProgress < self.useTime  )
  2418.     {
  2419.         self.curProgress += (50 * self.useRate);
  2420.         self.useRate = 1; /* * player.objectiveScaler;*/
  2421.  
  2422.         if ( self.curProgress >= self.useTime )
  2423.         {
  2424.             self.inUse = false;
  2425.            
  2426.             return isReallyAlive( player );
  2427.         }
  2428.        
  2429.         wait 0.05;
  2430.     }
  2431.    
  2432.     return false;
  2433. }
  2434.  
  2435.  
  2436. Callback_KillingBlow( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
  2437. {
  2438.     if ( isDefined(self.lastDamageWasFromEnemy) && self.lastDamageWasFromEnemy && iDamage >= self.health && isDefined( self.combatHigh ) && self.combatHigh == "specialty_endgame" )
  2439.     {
  2440.         self setAdrenaline( 0 );
  2441.         self _setPerk( "specialty_endgame" );
  2442.         return false;
  2443.     }
  2444.    
  2445.     return true;
  2446. }
  2447.  
  2448.  
  2449. emitFallDamage( iDamage )
  2450. {
  2451.     PhysicsExplosionSphere( self.origin, 64, 64, 1 );
  2452.    
  2453.     // get the entities we landed on
  2454.     damageEnts = [];
  2455.     for ( testAngle = 0; testAngle < 360; testAngle += 30 )
  2456.     {
  2457.         xOffset = cos( testAngle ) * 16;
  2458.         yOffset = sin( testAngle ) * 16;
  2459.  
  2460.         traceData = bulletTrace( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), true, self );
  2461.         //thread drawLine( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), 10.0 );
  2462.        
  2463.         if ( isDefined( traceData["entity"] ) && isDefined( traceData["entity"].targetname ) && (traceData["entity"].targetname == "destructible_vehicle" || traceData["entity"].targetname == "destructible_toy") )
  2464.             damageEnts[damageEnts.size] = traceData["entity"];
  2465.     }
  2466.  
  2467.     if ( damageEnts.size )
  2468.     {
  2469.         damageOwner = spawn( "script_origin", self.origin );
  2470.         damageOwner hide();
  2471.         damageOwner.type = "soft_landing";
  2472.         damageOwner.destructibles = damageEnts;
  2473.         radiusDamage( self.origin, 64, 100, 100, damageOwner );
  2474.  
  2475.         wait ( 0.1 );  
  2476.         damageOwner delete();
  2477.     }
  2478. }
  2479.  
  2480. drawLine( start, end, timeSlice )
  2481. {
  2482.     drawTime = int(timeSlice * 20);
  2483.     for( time = 0; time < drawTime; time++ )
  2484.     {
  2485.         line( start, end, (1,0,0),false, 1 );
  2486.         wait ( 0.05 );
  2487.     }
  2488. }
  2489.  
  2490. isFlankKill( victim, attacker )
  2491. {
  2492.     victimForward = anglestoforward( victim.angles );
  2493.     victimForward = ( victimForward[0], victimForward[1], 0 );
  2494.     victimForward = VectorNormalize( victimForward );
  2495.  
  2496.     attackDirection = victim.origin - attacker.origin;
  2497.     attackDirection = ( attackDirection[0], attackDirection[1], 0 );
  2498.     attackDirection = VectorNormalize( attackDirection );
  2499.  
  2500.     dotProduct = VectorDot( victimForward, attackDirection );
  2501.     if ( dotProduct > 0 ) // 0 = cos( 90 ), 180 degree arc total
  2502.         return true;
  2503.     else
  2504.         return false;
  2505. }
  2506.  
  2507. _obituary( victim, attacker, sWeapon, sMeansOfDeath )
  2508. {
  2509.     victimTeam = victim.team;
  2510.    
  2511.     foreach ( player in level.players )
  2512.     {
  2513.         playerTeam = player.team;
  2514.         if ( playerTeam == "spectator" )
  2515.             player iPrintLn( &"MP_OBITUARY_NEUTRAL", attacker.name, victim.name );
  2516.         else if ( playerTeam == victimTeam )
  2517.             player iPrintLn( &"MP_OBITUARY_ENEMY", attacker.name, victim.name );
  2518.         else
  2519.             player iPrintLn( &"MP_OBITUARY_FRIENDLY", attacker.name, victim.name );
  2520.     }
  2521. }
  2522.  
  2523.  
  2524. logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc )
  2525. {
  2526.     // create a lot of redundant data for the log print
  2527.     lpselfnum = self getEntityNumber();
  2528.     lpselfname = self.name;
  2529.     lpselfteam = self.team;
  2530.     lpselfguid = self.guid;
  2531.  
  2532.     if ( isPlayer( attacker ) )
  2533.     {
  2534.         lpattackGuid = attacker.guid;
  2535.         lpattackname = attacker.name;
  2536.         lpattackerteam = attacker.team;
  2537.         lpattacknum = attacker getEntityNumber();
  2538.         attackerString = attacker getXuid() + "(" + lpattackname + ")";
  2539.     }
  2540.     else
  2541.     {
  2542.         lpattackGuid = "";
  2543.         lpattackname = "";
  2544.         lpattackerteam = "world";
  2545.         lpattacknum = -1;
  2546.         attackerString = "none";
  2547.     }
  2548.  
  2549.     logPrint( "K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" );
  2550. }
  2551.  
  2552.  
  2553. destroyOnReviveEntDeath( reviveEnt )
  2554. {
  2555.     reviveEnt waittill ( "death" );
  2556.    
  2557.     self destroy();
  2558. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement