Перейти к содержимому
View in the app

A better way to browse. Learn more.

Zloplay community

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

[HELP] COD4/Promod type "Killed" Text

Featured Replies

Опубликовано:

Hey guys, I've been trying to find the "Killed by" and You killed" text from promod 3.2v but I can't find it due to really unorganized text :evil: ...

 

Can anyone provide me the code for that type? I hate seeing people's BOOSTED/HACKED Nuke emblem...

Опубликовано:

Okay so found it and in CoD 4 it's done by a menu, hud.menu to be specific. You can try and disable playercard popup but I think that's where it keeps all the files including player killed X so you're well out of luck until menus are perfectly modifiable.

Опубликовано:
Okay so found it and in a popular FPS series 4 it's done by a menu, hud.menu to be specific. You can try and disable playercard popup but I think that's where it keeps all the files including player killed X so you're well out of luck until menus are perfectly modifiable.

It's done in banz's (older/newer) promod so I'm pretty sure it's doable in IW4M without menus.

Опубликовано:

I made this a while back

Not 100% sure it works but give it a try.

Just add these gsc's to the same place i got them.

If your trying to add it to a mod which already has these files ask me and ill add it to that mod.

Опубликовано:

this is the code iw3 used for you killed works in iw4 :D

even better cause it works in pub ^_^

 

#include "ui/menudef.h"

#define CG_CENTER_MESSAGE 90	// for things like "You were killed by ..."
{
menuDef
{
	name			"playercard_killedby_hd"
	rect			0 150 0 0 HORIZONTAL_ALIGN_CENTER VERTICAL_ALIGN_CENTER
	fullScreen		0
	visible			1

	itemDef 
	{
		name			"chRect"
		rect			0 0 0 0
		textscale		TEXTSIZE_DEFAULT
		textstyle		ITEM_TEXTSTYLE_SHADOWED
		ownerdraw		CG_CENTER_MESSAGE
		visible			1
		decoration
	}
}
}	


#include "ui/menudef.h"

#define CG_CENTER_MESSAGE 90	// for things like "You were killed by ..."
{
menuDef
{
	name			"playercard_youkilled_hd"
	rect			0 150 0 0 HORIZONTAL_ALIGN_CENTER VERTICAL_ALIGN_CENTER
	fullScreen		0
	visible			1

	itemDef 
	{
		name			"chRect"
		rect			0 0 0 0
		textscale		TEXTSIZE_DEFAULT
		textstyle		ITEM_TEXTSTYLE_SHADOWED
		ownerdraw		CG_CENTER_MESSAGE
		visible			1
		decoration
	}
}
}	

Опубликовано:

I did like this in the earlier versions due to the .menu file bugs:

in _damage.gsc

handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath )
{
	attacker thread maps\mp\_events::killedPlayer( lifeId, self, sWeapon, sMeansOfDeath );

	self ClearLowerMessage("youkilled");
	attacker ClearLowerMessage("killedby");
	attacker SetLowerMessage("youkilled", "You killed " + self.name, undefined, 30);
	self SetLowerMessage("killedby", "Killed by " + attacker.name, undefined, 35);

	attacker thread clearYouKilled();
	self thread clearKilledBy();
...

 

 

handleFriendlyFireDeath( attacker )
{
	self ClearLowerMessage("youkilled");
	attacker ClearLowerMessage("killedby");
	attacker SetLowerMessage("youkilled", "You killed ^1your teammate^7 " + self.name, undefined, 30);
	self SetLowerMessage("killedby", "Killed by ^1your teammate^7 " + attacker.name, undefined, 35);

	attacker thread clearYouKilled();
	self thread clearKilledBy();
...

 

 

handleSuicideDeath( sMeansOfDeath, sHitLoc )
{
	self SetLowerMessage("suicide", "You killed yourself", undefined, 35);

	self thread clearSuicide();
...

 

 

clearSuicide()
{
self endon("clear_low_a");	
self endon("disconnect");	
wait 3.5;
self ClearLowerMessage("suicide");
self notify("clear_low_a");
}

clearYouKilled()
{
self endon("clear_low_b");
self endon("disconnect");	
wait 3.5;
self ClearLowerMessage("youkilled");
self notify("clear_low_b");
}

clearKilledBy()
{
self endon("clear_low_c");
self endon("disconnect");	
wait 3.5;
self ClearLowerMessage("killedby");
self notify("clear_low_c");
}

 

And removed all the playercard killedby stuff of course...

  • 2 weeks later...
Опубликовано:
  • Автор
I did like this in the earlier versions due to the .menu file bugs:

in _damage.gsc

handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath )
{
	attacker thread maps\mp\_events::killedPlayer( lifeId, self, sWeapon, sMeansOfDeath );

	self ClearLowerMessage("youkilled");
	attacker ClearLowerMessage("killedby");
	attacker SetLowerMessage("youkilled", "You killed " + self.name, undefined, 30);
	self SetLowerMessage("killedby", "Killed by " + attacker.name, undefined, 35);

	attacker thread clearYouKilled();
	self thread clearKilledBy();
...

 

 

handleFriendlyFireDeath( attacker )
{
	self ClearLowerMessage("youkilled");
	attacker ClearLowerMessage("killedby");
	attacker SetLowerMessage("youkilled", "You killed ^1your teammate^7 " + self.name, undefined, 30);
	self SetLowerMessage("killedby", "Killed by ^1your teammate^7 " + attacker.name, undefined, 35);

	attacker thread clearYouKilled();
	self thread clearKilledBy();
...

 

 

handleSuicideDeath( sMeansOfDeath, sHitLoc )
{
	self SetLowerMessage("suicide", "You killed yourself", undefined, 35);

	self thread clearSuicide();
...

 

 

clearSuicide()
{
self endon("clear_low_a");	
self endon("disconnect");	
wait 3.5;
self ClearLowerMessage("suicide");
self notify("clear_low_a");
}

clearYouKilled()
{
self endon("clear_low_b");
self endon("disconnect");	
wait 3.5;
self ClearLowerMessage("youkilled");
self notify("clear_low_b");
}

clearKilledBy()
{
self endon("clear_low_c");
self endon("disconnect");	
wait 3.5;
self ClearLowerMessage("killedby");
self notify("clear_low_c");
}

 

And removed all the playercard killedby stuff of course...

 

It works great, but how come people can't spawn after the first death?

 

also the you killed text never goes away.....

Опубликовано:
I did like this in the earlier versions due to the .menu file bugs:

in _damage.gsc

-snippet-

It works great, but how come people can't spawn after the first death?

 

also the you killed text never goes away.....

 

Then you did something wrong. It works without any problems for me.

You might want to post your _damage.gsc here.

Опубликовано:
  • Автор
I did like this in the earlier versions due to the .menu file bugs:

in _damage.gsc

-snippet-

It works great, but how come people can't spawn after the first death?

 

also the you killed text never goes away.....

 

Then you did something wrong. It works without any problems for me.

You might want to post your _damage.gsc here.

 

 

Please help me on this (I'm sorry I suck at modding :P)

 

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


isSwitchingTeams()
{
if ( isDefined( self.switching_teams ) )
	return true;

return false;
}


isTeamSwitchBalanced()
{
playerCounts = self maps\mp\gametypes\_teams::CountPlayers();
playerCounts[ self.leaving_team ] -- ;
playerCounts[ self.joining_team ]++ ;

return( ( playerCounts[ self.joining_team ] - playerCounts[ self.leaving_team ] ) < 2 );
}


isFriendlyFire( victim, attacker )
{
if ( !level.teamBased )
	return false;

if ( !isDefined( attacker ) )
	return false;

if ( !isPlayer( attacker ) && !isDefined( attacker.team ) )
	return false;

if ( victim.team != attacker.team )
	return false;

if ( victim == attacker )
	return false;

return true;
}


killedSelf( attacker )
{
if ( !isPlayer( attacker ) )
	return false;

if ( attacker != self )
	return false;

return true;
}


isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker )
{	
if ( isDefined( attacker ) )
{
	if ( attacker.code_classname == "script_vehicle" && isDefined( attacker.owner ) )
		return false;
	if ( attacker.code_classname == "misc_turret" && isDefined( attacker.owner ) )
		return false;
	if ( attacker.code_classname == "script_model" && isDefined( attacker.owner ) )
		return false;
}

return( sHitLoc == "head" || sHitLoc == "helmet" ) && sMeansOfDeath != "MOD_MELEE" && sMeansOfDeath != "MOD_IMPACT" && !isMG( sWeapon );
}


handleTeamChangeDeath()
{
if ( !level.teamBased )
	return;

// this might be able to happen now, but we should remove instances where it can
assert( self.leaving_team != self.joining_team );

if ( self.joining_team == "spectator" || !isTeamSwitchBalanced() )
{
	self thread [[ level.onXPEvent ]]( "suicide" );
	self incPersStat( "suicides", 1 );
	self.suicides = self getPersStat( "suicides" );
}
}


handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc )
{
if ( !isDefined( attacker ) )
	return;

if ( !isDefined( attacker.team ) )
{	
	handleSuicideDeath( sMeansOfDeath, sHitLoc );
	return;
}

assert( attacker.team == "axis" || attacker.team == "allies" );

if ( level.teamBased && attacker.team != self.team )
{
	if ( isDefined( level.onNormalDeath ) && isPlayer( attacker ) && attacker.team != "spectator" )
		[[ level.onNormalDeath ]]( self, attacker, lifeId );
}
}


handleSuicideDeath( sMeansOfDeath, sHitLoc )
{
//self SetCardDisplaySlot( self, 7 );
//self openMenu( "killedby_card_display" );

self thread [[ level.onXPEvent ]]( "suicide" );
self incPersStat( "suicides", 1 );
self.suicides = self getPersStat( "suicides" );

if ( !matchMakingGame() )
	self incPlayerStat( "suicides", 1 );

scoreSub = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "suicidepointloss" );
maps\mp\gametypes\_gamescore::_setPlayerScore( self, maps\mp\gametypes\_gamescore::_getPlayerScore( self ) - scoreSub );

if ( sMeansOfDeath == "MOD_SUICIDE" && sHitLoc == "none" && isDefined( self.throwingGrenade ) )
	self.lastGrenadeSuicideTime = gettime();

// suicide was caused by too many team kills
if ( isDefined( self.friendlydamage ) )
	self iPrintLnBold( &"MP_FRIENDLY_FIRE_WILL_NOT" );
}


handleFriendlyFireDeath( attacker )
{
//attacker SetCardDisplaySlot( self, 8 );
//attacker openMenu( "youkilled_card_display" );

//self SetCardDisplaySlot( attacker, 7 );
//self openMenu( "killedby_card_display" );

attacker thread [[ level.onXPEvent ]]( "teamkill" );
attacker.pers[ "teamkills" ] += 1.0;

attacker.teamkillsThisRound++ ;

if ( maps\mp\gametypes\_tweakables::getTweakableValue( "team", "teamkillpointloss" ) )
{
	scoreSub = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" );
	maps\mp\gametypes\_gamescore::_setPlayerScore( attacker, maps\mp\gametypes\_gamescore::_getPlayerScore( attacker ) - scoreSub );
}

	if ( level.maxAllowedTeamkills < 0 )
		return;

if ( level.inGracePeriod )
{
	teamKillDelay = 1;
	attacker.pers["teamkills"] += level.maxAllowedTeamkills;
}
else if ( attacker.pers[ "teamkills" ] > 1 && getTimePassed() < ( (level.gracePeriod * 1000) + 8000 + ( attacker.pers[ "teamkills" ] * 1000 ) ) )
{
	teamKillDelay = 1;
	attacker.pers["teamkills"] += level.maxAllowedTeamkills;
}
else
{
	teamKillDelay = attacker maps\mp\gametypes\_playerlogic::TeamKillDelay();
}

if ( teamKillDelay > 0 )
{
	attacker.pers["teamKillPunish"] = true;
	attacker _suicide();
}
}


handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath )
{
attacker thread maps\mp\_events::killedPlayer( lifeId, self, sWeapon, sMeansOfDeath );

//if ( attacker.pers["teamkills"] <= level.maxAllowedTeamkills )
//	attacker.pers["teamkills"] = max( attacker.pers["teamkills"] - 1, 0 );

//attacker SetCardDisplaySlot( self, 8 );
//attacker openMenu( "youkilled_card_display" );

//self SetCardDisplaySlot( attacker, 7 );
//self openMenu( "killedby_card_display" );

Text2 = self createFontString("default", 1.8);
Text2 setPoint("CENTER", "CENTER", 0, 160);
Text2 setText("");
wait .01;
if (self.deathrefresh == 1) {
	Text2 setText( "Killed By " + attacker.name );
	self.deathrefresh = 0;
	self waittill("spawned_player");
	wait 1;
	Text2 setText("");
	self.deathrefresh = 1;
}

if ( sMeansOfDeath == "MOD_HEAD_SHOT" )
{
	attacker incPersStat( "headshots", 1 );
	attacker.headshots = attacker getPersStat( "headshots" );
	attacker incPlayerStat( "headshots", 1 );

	if ( isDefined( attacker.lastStand ) )
		value = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 2;
	else
		value = undefined;

	attacker playLocalSound( "bullet_impact_headshot_2" );
}
else
{
	if ( isDefined( attacker.lastStand ) )
		value = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 2;
	else
		value = undefined;
}

attacker thread maps\mp\gametypes\_rank::giveRankXP( "kill", value );

attacker incPersStat( "kills", 1 );
attacker.kills = attacker getPersStat( "kills" );
attacker updatePersRatio( "kdRatio", "kills", "deaths" );
attacker maps\mp\gametypes\_persistence::statSetChild( "round", "kills", attacker.kills );
attacker incPlayerStat( "kills", 1 );

if ( isFlankKill( self, attacker ) )
{
	attacker incPlayerStat( "flankkills", 1 );

	self incPlayerStat( "flankdeaths", 1 );
}

lastKillStreak = attacker.pers["cur_kill_streak"];

self.pers["copyCatLoadout"] = undefined;

if ( self _hasPerk( "specialty_copycat" ) )
	self.pers["copyCatLoadout"] = attacker maps\mp\gametypes\_class::cloneLoadout();

if ( isAlive( attacker ) )
{
	// killstreaks only advance from kills earned this life
	if ( isDefined( level.killStreakSpecialCaseWeapons[sWeapon] ) ) // this is an optimization
	{
		switch ( sWeapon )
		{
			case "ac130_105mm_mp":
			case "ac130_40mm_mp":
			case "ac130_25mm_mp":
				if ( attacker.ac130LifeId == attacker.pers["deaths"] )
					attacker.pers["cur_kill_streak"]++;
				break;
			case "cobra_player_minigun_mp":
			case "weapon_cobra_mk19_mp":
				if ( attacker.heliRideLifeId == attacker.pers["deaths"] )
					attacker.pers["cur_kill_streak"]++;
				break;
			case "cobra_20mm_mp":
			case "artillery_mp":
			case "stealth_bomb_mp":
			case "remotemissile_projectile_mp":
			case "sentry_minigun_mp":
			case "harrier_20mm_mp":
			case "pavelow_minigun_mp":
				if ( isDefined( eInflictor ) && isDefined( eInflictor.lifeId ) )
					killstreakLifeId = eInflictor.lifeId;
				else
					killstreakLifeId = attacker.lifeId;

				if ( killstreakLifeId == attacker.pers["deaths"] )
					attacker.pers["cur_kill_streak"]++;
				break;
			default:
				attacker.pers["cur_kill_streak"]++;
				break;
		}
	}
	else
	{
		attacker.pers["cur_kill_streak"]++;
	}

	attacker setPlayerStatIfGreater( "killstreak", attacker.pers["cur_kill_streak"] );

	if ( attacker.pers["cur_kill_streak"] > attacker getPersStat( "longestStreak" ) )
		attacker setPersStat( "longestStreak", attacker.pers["cur_kill_streak"] );
}

attacker.pers["cur_death_streak"] = 0;

if ( attacker.pers["cur_kill_streak"] > attacker maps\mp\gametypes\_persistence::statGetChild( "round", "killStreak" ) )
{
	attacker maps\mp\gametypes\_persistence::statSetChild( "round", "killStreak", attacker.pers["cur_kill_streak"] );
}

if ( attacker.pers["cur_kill_streak"] > attacker.kill_streak )
{
	attacker maps\mp\gametypes\_persistence::statSet( "killStreak", attacker.pers["cur_kill_streak"] );
	attacker.kill_streak = attacker.pers["cur_kill_streak"];
}

maps\mp\gametypes\_gamescore::givePlayerScore( "kill", attacker, self );
maps\mp\_skill::processKill( attacker, self );

scoreSub = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "deathpointloss" );
maps\mp\gametypes\_gamescore::_setPlayerScore( self, maps\mp\gametypes\_gamescore::_getPlayerScore( self ) - scoreSub );

if ( isDefined( level.ac130player ) && level.ac130player == attacker )
	level notify( "ai_killed", self );

//if ( lastKillStreak != attacker.pers["cur_kill_streak"] )
level notify ( "player_got_killstreak_" + attacker.pers["cur_kill_streak"], attacker );

if ( isAlive( attacker ) )
	attacker thread maps\mp\killstreaks\_killstreaks::checkKillstreakReward( attacker.pers["cur_kill_streak"] );

attacker notify ( "killed_enemy" );

if ( !level.teamBased )
{
	self.attackers = [];
	return;
}

if ( isDefined( level.onNormalDeath ) && attacker.pers[ "team" ] != "spectator" )
	[[ level.onNormalDeath ]]( self, attacker, lifeId );

level thread maps\mp\gametypes\_battlechatter_mp::sayLocalSoundDelayed( attacker, "kill", 0.75 );	

if ( isDefined( self.lastAttackedShieldPlayer ) && isDefined( self.lastAttackedShieldTime ) && self.lastAttackedShieldPlayer != attacker )
{
	if ( getTime() - self.lastAttackedShieldTime < 2500 )
	{
		self.lastAttackedShieldPlayer thread maps\mp\gametypes\_gamescore::processShieldAssist( self );
	}
	else if ( isAlive( self.lastAttackedShieldPlayer ) && getTime() - self.lastAttackedShieldTime < 5000 )
	{
		forwardVec = vectorNormalize( anglesToForward( self.angles ) );
		shieldVec = vectorNormalize( self.lastAttackedShieldPlayer.origin - self.origin );

		if ( vectorDot( shieldVec, forwardVec ) > 0.925 )
			self.lastAttackedShieldPlayer thread maps\mp\gametypes\_gamescore::processShieldAssist( self );
	}
}

if ( isDefined( self.attackers ) )
{
	foreach ( player in self.attackers )
	{
		if ( !isDefined( player ) )
			continue;

		if ( player == attacker )
			continue;

		player thread maps\mp\gametypes\_gamescore::processAssist( self );
	}
	self.attackers = [];
}
}

isPlayerWeapon( weaponName )
{
if ( weaponClass( weaponName ) == "non-player" )
	return false;

if ( weaponClass( weaponName ) == "turret" )
	return false;

if ( weaponInventoryType( weaponName ) == "primary" || weaponInventoryType( weaponName ) == "altmode" )
	return true;

return false;
}

Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
{
PlayerKilled_internal( eInflictor, attacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, false );
}


QueueShieldForRemoval( shield )
{
MY_MAX_SHIELDS_AT_A_TIME = 5;

if ( !isDefined( level.shieldTrashArray ) )
	level.shieldTrashArray = [];

if ( level.shieldTrashArray.size >= MY_MAX_SHIELDS_AT_A_TIME )
{
	idxMax = (level.shieldTrashArray.size - 1);
	level.shieldTrashArray[0] delete();
	for ( idx = 0; idx < idxMax; idx++ )
		level.shieldTrashArray[idx] = level.shieldTrashArray[idx + 1];
	level.shieldTrashArray[idxMax] = undefined;
}

level.shieldTrashArray[level.shieldTrashArray.size] = shield;
}


LaunchShield( damage, meansOfDeath )
{
shieldModel = "weapon_riot_shield_mp";

self DetachShieldModel( shieldModel, "tag_weapon_left" );
self.hasRiotShield = false;
self.hasRiotShieldEquipped = false;
}


PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, isFauxDeath )
{
prof_begin( "PlayerKilled" );
//prof_begin( " PlayerKilled_1" );

victim endon( "spawned" );
victim notify( "killed_player" );

assert( victim.sessionteam != "spectator" );

if ( isDefined( attacker ) )
	attacker.assistedSuicide = undefined;

if ( !isDefined( victim.idFlags ) )
{
	if ( sMeansOfDeath == "MOD_SUICIDE" )
		victim.idFlags = 0;
	else if ( sMeansOfDeath == "MOD_GRENADE" && isSubstr( sWeapon, "frag_grenade" ) && iDamage == 100000 )
		victim.idFlags = 0;
	else if ( sWeapon == "nuke_mp" )
		victim.idFlags = 0;
	else if ( level.friendlyfire >= 2)
		victim.idFlags = 0;
	else
		assertEx( 0, "Victims ID flags not set, but means of death was gr or nuke: " + sMeansOfDeath  );
}

if ( victim.hasRiotShieldEquipped )
	victim LaunchShield( iDamage, sMeansofDeath );

//victim thread checkForceBleedOut();

if ( !isFauxDeath )
{
	if ( isDefined( victim.endGame ) )
	{
		victim VisionSetNakedForPlayer( getDvar( "mapname" ), 2 );
	}
	else if ( !isDefined( victim.nuked ) )
	{
		victim VisionSetNakedForPlayer( getDvar( "mapname" ), 0 );
		victim ThermalVisionOff();
	}
}
else
{
	victim.fauxDead = true;
	self notify ( "death" );
}

if ( game[ "state" ] == "postgame" )
{
	//prof_end( " PlayerKilled_1" );
	prof_end( "PlayerKilled" );
	return;
}

// replace params with last stand info
deathTimeOffset = 0;

if ( !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) )
	sPrimaryWeapon = eInflictor.primaryWeapon;
else if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" )
	sPrimaryWeapon = attacker getCurrentPrimaryWeapon();
else
	sPrimaryWeapon = undefined;

if ( isdefined( victim.useLastStandParams ) )
{
	victim ensureLastStandParamsValidity();
	victim.useLastStandParams = undefined;

	assert( isdefined( victim.lastStandParams ) );

	eInflictor = victim.lastStandParams.eInflictor;
	attacker = victim.lastStandParams.attacker;
	iDamage = victim.lastStandParams.iDamage;
	sMeansOfDeath = victim.lastStandParams.sMeansOfDeath;
	sWeapon = victim.lastStandParams.sWeapon;
	sPrimaryWeapon = victim.lastStandParams.sPrimaryWeapon;
	vDir = victim.lastStandParams.vDir;
	sHitLoc = victim.lastStandParams.sHitLoc;

	deathTimeOffset = ( gettime() - victim.lastStandParams.lastStandStartTime ) / 1000;
	victim.lastStandParams = undefined;
}

//prof_end( " PlayerKilled_1" );
//prof_begin( " PlayerKilled_2" );

//used for endgame perk and assisted suicide.
if ( (!isDefined( attacker ) || attacker.classname == "trigger_hurt" || attacker.classname == "worldspawn" || attacker == victim ) && isDefined( self.attackers )  )
{
	bestPlayer = undefined;

	foreach ( player in self.attackers )
	{
		if ( !isDefined( player ) )
			continue;

		if (! isDefined( victim.attackerData[ player.guid ].damage ) )
			continue;

		if ( player == victim || (level.teamBased && player.team == victim.team ) )
			continue;

		if ( victim.attackerData[ player.guid ].lasttimedamaged + 2500 < getTime() )
			continue;			

		if ( victim.attackerData[ player.guid ].damage > 1 && ! isDefined( bestPlayer ) )
			bestPlayer = player;
		else if ( isDefined( bestPlayer ) && victim.attackerData[ player.guid ].damage > victim.attackerData[ bestPlayer.guid ].damage )
			bestPlayer = player;		
	}

	if ( isDefined( bestPlayer ) )
	{
		attacker = bestPlayer;
		attacker.assistedSuicide = true;
		sWeapon = victim.attackerData[ bestPlayer.guid ].weapon; 
		vDir = victim.attackerData[ bestPlayer.guid ].vDir;
		sHitLoc = victim.attackerData[ bestPlayer.guid ].sHitLoc;
		psOffsetTime = victim.attackerData[ bestPlayer.guid ].psOffsetTime;
		sMeansOfDeath = victim.attackerData[ bestPlayer.guid ].sMeansOfDeath;
		iDamage = victim.attackerData[ bestPlayer.guid ].damage;
		sPrimaryWeapon = victim.attackerData[ bestPlayer.guid ].sPrimaryWeapon;
		eInflictor = attacker;
	}
}
else
{
	if ( isDefined( attacker ) )
		attacker.assistedSuicide = undefined;	
}

// override MOD
if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker ) )
	sMeansOfDeath = "MOD_HEAD_SHOT";
else if ( sMeansOfDeath != "MOD_MELEE" && !isDefined( victim.nuked ) )
	victim playDeathSound();

friendlyFire = isFriendlyFire( victim, attacker );

if ( isDefined( attacker ) )
{
	// override attacker if it's a vehicle	
	if ( attacker.code_classname == "script_vehicle" && isDefined( attacker.owner ) )
		attacker = attacker.owner;

	// override attacker if it's a sentry	
	if ( attacker.code_classname == "misc_turret" && isDefined( attacker.owner ) )
		attacker = attacker.owner;

	// override attacker if it's a crate	
	if ( attacker.code_classname == "script_model" && isDefined( attacker.owner ) )
	{
		attacker = attacker.owner;

		if ( !isFriendlyFire( victim, attacker ) && attacker != victim )
			attacker notify( "crushed_enemy" );
	}
}

//prof_end( " PlayerKilled_2" );
//prof_begin( " PlayerKilled_3" );

//prof_begin( " PlayerKilled_3_drop" );
// drop weapons from killed player
victim maps\mp\gametypes\_weapons::dropScavengerForDeath( attacker );	// must be done before dropWeaponForDeath, since we use some weapon information
victim maps\mp\gametypes\_weapons::dropWeaponForDeath( attacker );
//prof_end( " PlayerKilled_3_drop" );

if ( !isFauxDeath )
{
	victim.sessionstate = "dead";
	victim.statusicon = "hud_status_dead";
}

// UTS update aliveCount
victim maps\mp\gametypes\_playerlogic::removeFromAliveCount();

if ( !isDefined( victim.switching_teams ) )
{
	// update our various stats
	victim incPersStat( "deaths", 1 );
	victim.deaths = victim getPersStat( "deaths" );
	victim updatePersRatio( "kdRatio", "kills", "deaths" );
	victim maps\mp\gametypes\_persistence::statSetChild( "round", "deaths", victim.deaths );
	victim incPlayerStat( "deaths", 1 );
}

if ( isDefined( attacker ) )
	attacker checkKillSteal( victim );

// obituary
obituary( victim, attacker, sWeapon, sMeansOfDeath );

doKillcam = false;

lifeId = getNextLifeId();

victim logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc );
victim maps\mp\_matchdata::logPlayerLife( lifeId );
victim maps\mp\_matchdata::logPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc );

if ( (sMeansOfDeath == "MOD_MELEE") )
{
	if ( IsSubStr( sWeapon, "riotshield" ) )
	{
		attacker incPlayerStat( "shieldkills", 1 );

		if ( !matchMakingGame() )
			victim incPlayerStat( "shielddeaths", 1 );
	}
	else
		attacker incPlayerStat( "knifekills", 1 );
}

//prof_end( " PlayerKilled_3" );
//prof_begin( " PlayerKilled_4" );

if ( victim isSwitchingTeams() )
{
	handleTeamChangeDeath();
}
else if ( !isPlayer( attacker ) || (isPlayer( attacker ) && sMeansOfDeath == "MOD_FALLING") )
{
	handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc );
}
else if ( attacker == victim )
{
	handleSuicideDeath( sMeansOfDeath, sHitLoc );
}
else if ( friendlyFire )
{
	if ( !isDefined( victim.nuked ) )
	{
		handleFriendlyFireDeath( attacker );
	}
}
else
{
	if ( sMeansOfDeath == "MOD_GRENADE" && eInflictor == attacker )
		addAttacker( victim, attacker, eInflictor, sWeapon, iDamage, (0,0,0), vDir, sHitLoc, psOffsetTime, sMeansOfDeath );

	doKillcam = true;
	handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath );
	victim thread maps\mp\gametypes\_missions::playerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc, attacker.modifiers );

	victim.pers["cur_death_streak"]++;

	if ( !getGametypeNumLives() && !matchMakingGame() )
		victim setPlayerStatIfGreater( "deathstreak", victim.pers["cur_death_streak"] );
}

//prof_end( " PlayerKilled_4" );
//prof_begin( " PlayerKilled_5" );

// clear any per life variables
victim resetPlayerVariables();
victim.lastAttacker = attacker;
victim.lastDeathPos = victim.origin;
victim.deathTime = getTime();
victim.wantSafeSpawn = false;
victim.revived = false;
victim.sameShotDamage = 0;

if ( isFauxDeath )
{
	doKillcam = false;
	deathAnimDuration = (victim PlayerForceDeathAnim( eInflictor, sMeansOfDeath, sWeapon, sHitLoc, vDir ));
}

victim.body = victim clonePlayer( deathAnimDuration );

if ( isFauxDeath )
	victim PlayerHide();

if ( victim isOnLadder() || victim isMantling() || !victim isOnGround() || isDefined( victim.nuked ) )
	victim.body startRagDoll();

if ( !isDefined( victim.switching_teams ) )
	thread maps\mp\gametypes\_deathicons::addDeathicon( victim.body, victim, victim.team, 5.0 );

thread delayStartRagdoll( victim.body, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath );

// allow per gametype death handling	
victim thread [[ level.onPlayerKilled ]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, lifeId );

if ( isPlayer( attacker ) )
	attackerNum = attacker getEntityNumber();
else
	attackerNum = -1;
killcamentity = victim getKillcamEntity( attacker, eInflictor, sWeapon );
killcamentityindex = -1;
killcamentitystarttime = 0;

if ( isDefined( killcamentity ) )
{
	killcamentityindex = killcamentity getEntityNumber();// must do this before any waiting lest the entity be deleted
	killcamentitystarttime = killcamentity.birthtime;
	if ( !isdefined( killcamentitystarttime ) )
		killcamentitystarttime = 0;
}

 /#
if ( getDvarInt( "scr_forcekillcam" ) != 0 )
	doKillcam = true;
#/

if ( isDefined( attacker.finalKill ) )
	maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid );

//prof_end( " PlayerKilled_5" );
//prof_begin( " PlayerKilled_6" );

if ( isDefined( attacker.finalKill ) && doKillcam && !isDefined( level.nukeDetonated ) )
{
	level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime );

	if ( !isFauxDeath )
		wait ( 1.0 );
}

if ( !isFauxDeath )
{
	if ( !level.showingFinalKillcam && !level.killcam && doKillcam )
	{
		if ( victim _hasPerk( "specialty_copycat" ) && isDefined( victim.pers["copyCatLoadout"] ) )
		{
			victim thread maps\mp\gametypes\_killcam::waitDeathCopyCatButton( attacker );
			wait ( 1.0 );
		}
	}

	// let the player watch themselves die
	wait( 0.25 );
	victim thread maps\mp\gametypes\_killcam::cancelKillCamOnUse();
	wait( 0.25 );

	self.respawnTimerStartTime = gettime() + 1000;
	timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true );
	if ( timeUntilSpawn < 1 )
		timeUntilSpawn = 1;
	victim thread maps\mp\gametypes\_playerlogic::predictAboutToSpawnPlayerOverTime( timeUntilSpawn );

	wait( 1.0 );
	victim notify( "death_delay_finished" );
}

postDeathDelay = ( getTime() - victim.deathTime ) / 1000;
self.respawnTimerStartTime = gettime();

if ( !(isDefined( victim.cancelKillcam) && victim.cancelKillcam) && doKillcam && level.killcam && game[ "state" ] == "playing" && !victim isUsingRemote() && !level.showingFinalKillcam )
{
	livesLeft = !( getGametypeNumLives() && !victim.pers[ "lives" ] );
	timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true );
	willRespawnImmediately = livesLeft && ( timeUntilSpawn <= 0 );

	if ( !livesLeft )
		timeUntilSpawn = -1;

	victim maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, timeUntilSpawn, maps\mp\gametypes\_gamelogic::timeUntilRoundEnd(), attacker, victim );
}

//prof_end( " PlayerKilled_6" );
//prof_begin( " PlayerKilled_7" );

//self openMenu( "killedby_card_hide" );

if ( game[ "state" ] != "playing" )
{
	if ( !level.showingFinalKillcam )
	{
		victim.sessionstate = "dead";
		victim ClearKillcamState();
	}

	//prof_end( " PlayerKilled_7" );
	prof_end( "PlayerKilled" );
	return;
}

// class may be undefined if we have changed teams
if ( isValidClass( victim.class ) )
{
	victim thread maps\mp\gametypes\_playerlogic::spawnClient();
}

//prof_end( " PlayerKilled_7" );
prof_end( "PlayerKilled" );
}

checkForceBleedout()
{
if ( level.dieHardMode != 1 )
	return false;

if ( !getGametypeNumLives() )
	return false;

if ( level.livesCount[self.team] > 0 )
	return false;

foreach ( player in level.players )
{
	if ( !isAlive( player ) )
		continue;

	if ( player.team != self.team )
		continue;

	if ( player == self )
		continue;

	if ( !player.inLastStand )
		return false;
}

foreach ( player in level.players )
{
	if ( !isAlive( player ) )
		continue;

	if ( player.team != self.team )
		continue;

	if ( player.inLastStand && player != self )
		player lastStandBleedOut(false);		
}

return true;					
}

checkKillSteal( vic )
{
if ( matchMakingGame() )
	return;

greatestDamage = 0;
greatestAttacker = undefined;

if ( isDefined( vic.attackerdata ) && vic.attackerdata.size > 1 )	
{
	foreach ( attacker in vic.attackerdata )
	{
		if ( attacker.damage > greatestDamage )
		{
			greatestDamage = attacker.damage;
			greatestAttacker = attacker.attackerEnt;	
		}
	}

	if ( isDefined( greatestAttacker ) && greatestAttacker != self )
		self incPlayerStat( "killsteals", 1 );
}
}

doFinalKillcam( delay, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime )
{
level.showingFinalKillcam = true;

level waittill ( "round_end_finished" );

if ( !isDefined( victim ) || !isDefined( attacker ) )
{
	level.showingFinalKillcam = false;
	return;
}

postDeathDelay = (( getTime() - victim.deathTime ) / 1000);

foreach ( player in level.players )
{
	player closePopupMenu();
	player closeInGameMenu();
	player VisionSetNakedForPlayer( getDvar( "mapname" ), 0 );
	player.killcamentitylookat = victim getEntityNumber();

	if ( (player != victim || (!isRoundBased() || isLastRound())) && player _hasPerk( "specialty_copycat" ) )
		player _unsetPerk( "specialty_copycat" );

	player thread maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, 0, 10000, attacker, victim );
}

wait( 0.1 );

while ( anyPlayersInKillcam() )
	wait( 0.05 );

level.showingFinalKillcam = false;
}


anyPlayersInKillcam()
{
foreach ( player in level.players )
{
	if ( isDefined( player.killcam ) )
		return true;
}

return false;
}


resetPlayerVariables()
{
self.killedPlayersCurrent = [];
self.switching_teams = undefined;
self.joining_team = undefined;
self.leaving_team = undefined;

self.pers["cur_kill_streak"] = 0;

self maps\mp\gametypes\_gameobjects::detachUseModels();// want them detached before we create our corpse
}


getKillcamEntity( attacker, eInflictor, sWeapon )
{
if ( !isDefined( eInflictor ) )
	return undefined;

if ( eInflictor == attacker )
	return undefined;

if ( isSubStr( sWeapon, "ac130_" ) )
	return undefined;

if ( sWeapon == "cobra_player_minigun_mp" )
	return undefined;

if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" || sWeapon == "pavelow_minigun_mp" )
	return eInflictor.killCamEnt;

if ( isDefined( eInflictor.script_gameobjectname ) && eInflictor.script_gameobjectname == "bombzone" )
	return eInflictor.killCamEnt;

if ( eInflictor.classname == "script_origin" || eInflictor.classname == "script_model" || eInflictor.classname == "script_brushmodel" )
	return undefined; // probably a barrel or a car... code does airstrike cam for these things which looks bad

if ( issubstr( sWeapon, "remotemissile_" ) )
	return undefined;
if ( issubstr( sWeapon, "ac130_" ) )
	return undefined;

return eInflictor;
}


HitlocDebug( attacker, victim, damage, hitloc, dflags )
{
colors = [];
colors[ 0 ] = 2;
colors[ 1 ] = 3;
colors[ 2 ] = 5;
colors[ 3 ] = 7;

if ( !getdvarint( "scr_hitloc_debug" ) )
	return;

if ( !isdefined( attacker.hitlocInited ) )
{
	for ( i = 0; i < 6; i++ )
	{
		attacker setClientDvar( "ui_hitloc_" + i, "" );
	}
	attacker.hitlocInited = true;
}

if ( level.splitscreen || !isPLayer( attacker ) )
	return;

elemcount = 6;
if ( !isdefined( attacker.damageInfo ) )
{
	attacker.damageInfo = [];
	for ( i = 0; i < elemcount; i++ )
	{
		attacker.damageInfo[ i ] = spawnstruct();
		attacker.damageInfo[ i ].damage = 0;
		attacker.damageInfo[ i ].hitloc = "";
		attacker.damageInfo[ i ].bp = false;
		attacker.damageInfo[ i ].jugg = false;
		attacker.damageInfo[ i ].colorIndex = 0;
	}
	attacker.damageInfoColorIndex = 0;
	attacker.damageInfoVictim = undefined;
}

for ( i = elemcount - 1; i > 0; i -- )
{
	attacker.damageInfo[ i ].damage = attacker.damageInfo[ i - 1 ].damage;
	attacker.damageInfo[ i ].hitloc = attacker.damageInfo[ i - 1 ].hitloc;
	attacker.damageInfo[ i ].bp = attacker.damageInfo[ i - 1 ].bp;
	attacker.damageInfo[ i ].jugg = attacker.damageInfo[ i - 1 ].jugg;
	attacker.damageInfo[ i ].colorIndex = attacker.damageInfo[ i - 1 ].colorIndex;
}
attacker.damageInfo[ 0 ].damage = damage;
attacker.damageInfo[ 0 ].hitloc = hitloc;
attacker.damageInfo[ 0 ].bp = ( dflags & level.iDFLAGS_PENETRATION );
attacker.damageInfo[ 0 ].jugg = victim hasPerk( "specialty_armorvest", true );
if ( isdefined( attacker.damageInfoVictim ) && ( attacker.damageInfoVictim != victim ) )
{
	attacker.damageInfoColorIndex++ ;
	if ( attacker.damageInfoColorIndex == colors.size )
		attacker.damageInfoColorIndex = 0;
}
attacker.damageInfoVictim = victim;
attacker.damageInfo[ 0 ].colorIndex = attacker.damageInfoColorIndex;

for ( i = 0; i < elemcount; i++ )
{
	color = "^" + colors[ attacker.damageInfo[ i ].colorIndex ];
	if ( attacker.damageInfo[ i ].hitloc != "" )
	{
		val = color + attacker.damageInfo[ i ].hitloc;
		if ( attacker.damageInfo[ i ].bp )
			val += " (BP)";
		if ( attacker.damageInfo[ i ].jugg )
			val += " (Jugg)";
		attacker setClientDvar( "ui_hitloc_" + i, val );
	}
	attacker setClientDvar( "ui_hitloc_damage_" + i, color + attacker.damageInfo[ i ].damage );
}
}

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

self notify ( "giveRecentShieldXP" );
self endon ( "giveRecentShieldXP" );

self.recentShieldXP++;

wait ( 20.0 );

self.recentShieldXP = 0;
}


Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
{

     if(sWeapon == "at4_mp")
iDamage = 0;
else
if(sHitloc == "head" && sWeapon != "riotshield_mp")
if(sWeapon == "cheytac_mp"){
iDamage = 300;
} else {
iDamage = 200;}
else
if(sHitloc == "neck")
if(sWeapon == "cheytac_mp"){
iDamage = 300;
} else {
iDamage = 200;}
else
if(sHitloc == "helmet")
if(sWeapon == "cheytac_mp"){
iDamage = 300;
} else {
iDamage = 200;}
else
     if(sWeapon == "javelin_mp")
iDamage = 0;
else
if(sWeapon == "m79_mp")
iDamage = 0;
    else
if(sWeapon == "gl_mp")
iDamage = 0;
    else
if(sWeapon == "stinger_mp")
iDamage = 0;
    else
    if(sHitloc == "neck" || "helmet" || "torso_upper" || "torso_lower")
if(sWeapon == "rpg_mp"){
iDamage = 30;
} else {
iDamage = 900;}


if ( !isReallyAlive( victim ) )
	return;

if ( isDefined( eAttacker ) && eAttacker.classname == "script_origin" && isDefined( eAttacker.type ) && eAttacker.type == "soft_landing" )
	return;

if ( isDefined( level.hostMigrationTimer ) )
	return;

if ( sMeansOfDeath == "MOD_FALLING" )
	victim thread emitFallDamage( iDamage );

if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && iDamage != 1 )
{
	iDamage *= getDvarFloat( "scr_explBulletMod" );	
	iDamage = int( iDamage );
}

if ( isDefined( eAttacker ) && eAttacker.classname == "worldspawn" )
	eAttacker = undefined;

if ( isDefined( eAttacker ) && isDefined( eAttacker.gunner ) )
	eAttacker = eAttacker.gunner;

attackerIsNPC = isDefined( eAttacker ) && !isDefined( eAttacker.gunner ) && (eAttacker.classname == "script_vehicle" || eAttacker.classname == "misc_turret" || eAttacker.classname == "script_model");
attackerIsHittingTeammate = level.teamBased && isDefined( eAttacker ) && ( victim != eAttacker ) && isDefined( eAttacker.team ) && ( victim.pers[ "team" ] == eAttacker.team );

stunFraction = 0.0;

if ( iDFlags & level.iDFLAGS_STUN )
{
	stunFraction = 0.0;
	//victim StunPlayer( 1.0 );
	iDamage = 0.0;
}
else if ( sHitLoc == "shield" )
{
	if ( attackerIsHittingTeammate && level.friendlyfire == 0 )
		return;

	if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && !attackerIsHittingTeammate )
	{
		if ( isPlayer( eAttacker ) )
		{
			eAttacker.lastAttackedShieldPlayer = victim;
			eAttacker.lastAttackedShieldTime = getTime();
		}
		victim notify ( "shield_blocked" );

		// fix turret + shield challenge exploits
		if ( sWeapon == "turret_minigun_mp" )
			shieldDamage = 25;
		else
			shieldDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );

		victim.shieldDamage += shieldDamage;

		// fix turret + shield challenge exploits
		if ( sWeapon != "turret_minigun_mp" || cointoss() )
			victim.shieldBulletHits++;

		if ( victim.shieldBulletHits >= level.riotShieldXPBullets )
		{
			if ( self.recentShieldXP > 4 )
				xpVal = int( 50 / self.recentShieldXP );
			else
				xpVal = 50;

			printLn( xpVal );

			victim thread maps\mp\gametypes\_rank::giveRankXP( "shield_damage", xpVal );
			victim thread giveRecentShieldXP();

			victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_damage", victim.shieldDamage );

			victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_bullet_hits", victim.shieldBulletHits );

			victim.shieldDamage = 0;
			victim.shieldBulletHits = 0;
		}
	}

	if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT )
	{
		if (  !attackerIsHittingTeammate )
			victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 );

		sHitLoc = "none";	// code ignores any damage to a "shield" bodypart.
		if ( !(iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT_HUGE) )
			iDamage *= 0.0;
	}
	else if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_SPLASH )
	{
		if ( isDefined( eInflictor ) && isDefined( eInflictor.stuckEnemyEntity ) && eInflictor.stuckEnemyEntity == victim ) //does enough damage to shield carrier to ensure death
			iDamage = 101;

		victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 );
		sHitLoc = "none";	// code ignores any damage to a "shield" bodypart.
	}
	else
	{
		return;
	}
}
else if ( (smeansofdeath == "MOD_MELEE") && IsSubStr( sweapon, "riotshield" ) )
{
	if ( !(attackerIsHittingTeammate && (level.friendlyfire == 0)) )
	{
		stunFraction = 0.0;
		victim StunPlayer( 0.0 );
	}
}

if ( !attackerIsHittingTeammate )
	iDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );

if ( !iDamage )
	return false;

victim.iDFlags = iDFlags;
victim.iDFlagsTime = getTime();

if ( game[ "state" ] == "postgame" )
	return;
if ( victim.sessionteam == "spectator" )
	return;
if ( isDefined( victim.canDoCombat ) && !victim.canDoCombat )
	return;
if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat )
	return;

// handle vehicles/turrets and friendly fire
if ( attackerIsNPC && attackerIsHittingTeammate )
{
	if ( sMeansOfDeath == "MOD_CRUSH" )
	{
		victim _suicide();
		return;
	}

	if ( !level.friendlyfire )
		return;
}

prof_begin( "PlayerDamage flags/tweaks" );

// Don't do knockback if the damage direction was not specified
if ( !isDefined( vDir ) )
	iDFlags |= level.iDFLAGS_NO_KNOCKBACK;

friendly = false;

if ( ( victim.health == victim.maxhealth && ( !isDefined( victim.lastStand ) || !victim.lastStand )  ) || !isDefined( victim.attackers ) && !isDefined( victim.lastStand )  )
{
	victim.attackers = [];
	victim.attackerData = [];
}

if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, eAttacker ) )
	sMeansOfDeath = "MOD_HEAD_SHOT";

if ( maps\mp\gametypes\_tweakables::getTweakableValue( "game", "onlyheadshots" ) )
{
	if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" )
		return;
	else if ( sMeansOfDeath == "MOD_HEAD_SHOT" )
		iDamage = 150;
}

// explosive barrel/car detection
if ( sWeapon == "none" && isDefined( eInflictor ) )
{
	if ( isDefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) )
		sWeapon = "destructible_car";
}

prof_end( "PlayerDamage flags/tweaks" );

// check for completely getting out of the damage
if ( !(iDFlags & level.iDFLAGS_NO_PROTECTION) )
{
	// items you own don't damage you in FFA
	if ( !level.teamBased && attackerIsNPC && isDefined( eAttacker.owner ) && eAttacker.owner == victim )
	{
		prof_end( "PlayerDamage player" );

		if ( sMeansOfDeath == "MOD_CRUSH" )
			victim _suicide();

		return;
	}

	if ( ( isSubStr( sMeansOfDeath, "MOD_GRENADE" ) || isSubStr( sMeansOfDeath, "MOD_EXPLOSIVE" ) || isSubStr( sMeansOfDeath, "MOD_PROJECTILE" ) ) && isDefined( eInflictor ) && isDefined( eAttacker ) )
	{
		// protect players from spawnkill grenades
		if ( eInflictor.classname == "grenade" && ( victim.lastSpawnTime + 3500 ) > getTime() && isDefined( victim.lastSpawnPoint ) && distance( eInflictor.origin, victim.lastSpawnPoint.origin ) < 250 )
		{
			prof_end( "PlayerDamage player" );
			return;
		}

		victim.explosiveInfo = [];
		victim.explosiveInfo[ "damageTime" ] = getTime();
		victim.explosiveInfo[ "damageId" ] = eInflictor getEntityNumber();
		victim.explosiveInfo[ "returnToSender" ] = false;
		victim.explosiveInfo[ "counterKill" ] = false;
		victim.explosiveInfo[ "chainKill" ] = false;
		victim.explosiveInfo[ "cookedKill" ] = false;
		victim.explosiveInfo[ "throwbackKill" ] = false;
		victim.explosiveInfo[ "suicideGrenadeKill" ] = false;
		victim.explosiveInfo[ "weapon" ] = sWeapon;

		isFrag = isSubStr( sWeapon, "frag_" );

		if ( eAttacker != victim )
		{
			if ( ( isSubStr( sWeapon, "c4_" ) || isSubStr( sWeapon, "claymore_" ) ) && isDefined( eAttacker ) && isDefined( eInflictor.owner ) )
			{
				victim.explosiveInfo[ "returnToSender" ] = ( eInflictor.owner == victim );
				victim.explosiveInfo[ "counterKill" ] = isDefined( eInflictor.wasDamaged );
				victim.explosiveInfo[ "chainKill" ] = isDefined( eInflictor.wasChained );
				victim.explosiveInfo[ "bulletPenetrationKill" ] = isDefined( eInflictor.wasDamagedFromBulletPenetration );
				victim.explosiveInfo[ "cookedKill" ] = false;
			}

			if ( isDefined( eAttacker.lastGrenadeSuicideTime ) && eAttacker.lastGrenadeSuicideTime >= gettime() - 50 && isFrag )
				victim.explosiveInfo[ "suicideGrenadeKill" ] = true;
		}

		if ( isFrag )
		{
			victim.explosiveInfo[ "cookedKill" ] = isDefined( eInflictor.isCooked );
			victim.explosiveInfo[ "throwbackKill" ] = isDefined( eInflictor.threwBack );
		}

		victim.explosiveInfo[ "stickKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "enemy";
		victim.explosiveInfo[ "stickFriendlyKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "friendly";
	}

	if ( isPlayer( eAttacker ) )
		eAttacker.pers[ "participation" ]++ ;

	prevHealthRatio = victim.health / victim.maxhealth;

	if ( attackerIsHittingTeammate )
	{
		if ( !matchMakingGame() && isPlayer(eAttacker) )
			eAttacker incPlayerStat( "mostff", 1 );

		prof_begin( "PlayerDamage player" );// profs automatically end when the function returns
		if ( level.friendlyfire == 0 || ( !isPlayer(eAttacker) && level.friendlyfire != 1 ) )// no one takes damage
		{
			if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" )
				victim damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker );
			return;
		}
		else if ( level.friendlyfire == 1 )// the friendly takes damage
		{
			if ( iDamage < 1 )
				iDamage = 1;

			victim.lastDamageWasFromEnemy = false;

			victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
		}
		else if ( ( level.friendlyfire == 2 ) && isReallyAlive( eAttacker ) )// only the attacker takes damage
		{
			iDamage = int( iDamage * .5 );
			if ( iDamage < 1 )
				iDamage = 1;

			eAttacker.lastDamageWasFromEnemy = false;

			eAttacker.friendlydamage = true;
			eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
			eAttacker.friendlydamage = undefined;
		}
		else if ( level.friendlyfire == 3 && isReallyAlive( eAttacker ) )// both friendly and attacker take damage
		{
			iDamage = int( iDamage * .5 );
			if ( iDamage < 1 )
				iDamage = 1;

			victim.lastDamageWasFromEnemy = false;
			eAttacker.lastDamageWasFromEnemy = false;

			victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
			if ( isReallyAlive( eAttacker ) )// may have died due to friendly fire punishment
			{
				eAttacker.friendlydamage = true;
				eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
				eAttacker.friendlydamage = undefined;
			}
		}

		friendly = true;

	}
	else// not hitting teammate
	{
		prof_begin( "PlayerDamage world" );

		if ( iDamage < 1 )
			iDamage = 1;

		if ( isDefined( eAttacker ) && isPlayer( eAttacker ) )
			addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath );

		if ( sMeansOfDeath == "MOD_EXPLOSIVE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" && iDamage < victim.health )
			victim notify( "survived_explosion" );

		if ( isdefined( eAttacker ) )
			level.lastLegitimateAttacker = eAttacker;

		if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) )
			eAttacker thread maps\mp\gametypes\_weapons::checkHit( sWeapon, victim );

		if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) && eAttacker != victim )
		{
			eAttacker thread maps\mp\_events::damagedPlayer( self, iDamage, sWeapon );
			victim.attackerPosition = eAttacker.origin;
		}
		else
		{
			victim.attackerPosition = undefined;
		}

		if ( issubstr( sMeansOfDeath, "MOD_GRENADE" ) && isDefined( eInflictor.isCooked ) )
			victim.wasCooked = getTime();
		else
			victim.wasCooked = undefined;

		victim.lastDamageWasFromEnemy = ( isDefined( eAttacker ) && ( eAttacker != victim ) );

		if ( victim.lastDamageWasFromEnemy )
			eAttacker.damagedPlayers[ victim.guid ] = getTime();

		victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );

		if ( isDefined( level.ac130player ) && isDefined( eAttacker ) && ( level.ac130player == eAttacker ) )
			level notify( "ai_pain", victim );

		victim thread maps\mp\gametypes\_missions::playerDamaged( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc );

		prof_end( "PlayerDamage world" );

	}

	if ( attackerIsNPC && isDefined( eAttacker.gunner ) )
		damager = eAttacker.gunner;
	else
		damager = eAttacker;

	if ( isDefined( damager) && damager != victim && iDamage > 0 )
	{
		if ( iDFlags & level.iDFLAGS_STUN )
			typeHit = "stun";
		else if ( victim hasPerk( "specialty_armorvest", true ) || (isExplosiveDamage( sMeansOfDeath ) && victim _hasPerk( "_specialty_blastshield" )) )
			typeHit = "hitBodyArmor";
		else if ( victim _hasPerk( "specialty_combathigh") )
			typeHit = "hitEndGame";
		else
			typeHit = "standard";

		damager thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( typeHit );
	}

	victim.hasDoneCombat = true;
}

if ( isdefined( eAttacker ) && ( eAttacker != victim ) && !friendly )
	level.useStartSpawns = false;


//=================
// Damage Logging
//=================

prof_begin( "PlayerDamage log" );

// why getEntityNumber() for victim and .clientid for attacker?
if ( getDvarInt( "g_debugDamage" ) )
	println( "client:" + victim getEntityNumber() + " health:" + victim.health + " attacker:" + eAttacker.clientid + " inflictor is player:" + isPlayer( eInflictor ) + " damage:" + iDamage + " hitLoc:" + sHitLoc );

if ( victim.sessionstate != "dead" )
{
	lpselfnum = victim getEntityNumber();
	lpselfname = victim.name;
	lpselfteam = victim.pers[ "team" ];
	lpselfGuid = victim.guid;
	lpattackerteam = "";

	if ( isPlayer( eAttacker ) )
	{
		lpattacknum = eAttacker getEntityNumber();
		lpattackGuid = eAttacker.guid;
		lpattackname = eAttacker.name;
		lpattackerteam = eAttacker.pers[ "team" ];
	}
	else
	{
		lpattacknum = -1;
		lpattackGuid = "";
		lpattackname = "";
		lpattackerteam = "world";
	}

	logPrint( "D;" + lpselfGuid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" );
}

HitlocDebug( eAttacker, victim, iDamage, sHitLoc, iDFlags );

/*if( isDefined( eAttacker ) && eAttacker != victim )
{
	if ( isPlayer( eAttacker ) )
		eAttacker incPlayerStat( "damagedone", iDamage );

	victim incPlayerStat( "damagetaken", iDamage );
}*/

prof_end( "PlayerDamage log" );
}


addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath )
{
if ( !isDefined( victim.attackerData ) )
	victim.attackerData = [];

if ( !isDefined( victim.attackerData[ eAttacker.guid ] ) )
{
	victim.attackers[ eAttacker.guid ] = eAttacker;
	// we keep an array of attackers by their client ID so we can easily tell
	// if they're already one of the existing attackers in the above if().
	// we store in this array data that is useful for other things, like challenges
	victim.attackerData[ eAttacker.guid ] = SpawnStruct();
	victim.attackerData[ eAttacker.guid ].damage = 0;	
	victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker;
	victim.attackerData[ eAttacker.guid ].firstTimeDamaged = getTime();				
}
if ( maps\mp\gametypes\_weapons::isPrimaryWeapon( sWeapon ) && ! maps\mp\gametypes\_weapons::isSideArm( sWeapon ) )
	victim.attackerData[ eAttacker.guid ].isPrimary = true;

victim.attackerData[ eAttacker.guid ].damage += iDamage;
victim.attackerData[ eAttacker.guid ].weapon = sWeapon;
victim.attackerData[ eAttacker.guid ].vPoint = vPoint;
victim.attackerData[ eAttacker.guid ].vDir = vDir;
victim.attackerData[ eAttacker.guid ].sHitLoc = sHitLoc;
victim.attackerData[ eAttacker.guid ].psOffsetTime = psOffsetTime;
victim.attackerData[ eAttacker.guid ].sMeansOfDeath = sMeansOfDeath;
victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker;
victim.attackerData[ eAttacker.guid ].lasttimeDamaged = getTime();

if ( isDefined( eInflictor ) && !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) )
	victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eInflictor.primaryWeapon;
else if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker getCurrentPrimaryWeapon() != "none" )
	victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eAttacker getCurrentPrimaryWeapon();
else
	victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = undefined;
}

resetAttackerList()
{
self endon( "disconnect" );
self endon( "death" );
level endon( "game_ended" );

//wait is to offset premature calling in _healthOverlay
wait( 1.75 ); 
self.attackers = [];
self.attackerData = [];
}


Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
{
Callback_PlayerDamage_internal( eInflictor, eAttacker, self, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime );
}


finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction )
{
if ( (self isUsingRemote() ) && (iDamage >= self.health) && !(iDFlags & level.iDFLAGS_STUN) )
{
	if ( !isDefined( vDir ) )
		vDir = ( 0,0,0 );

	if ( !isDefined( eAttacker ) && !isDefined( eInflictor ) )
	{
		eAttacker = self;
		eInflictor = eAttacker;
	}

	assert( isDefined( eAttacker ) );
	assert( isDefined( eInflictor ) );

	PlayerKilled_internal( eInflictor, eAttacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, 0, true );
}
else
{
	if ( !self Callback_KillingBlow( eInflictor, eAttacker, iDamage - (iDamage * stunFraction), iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) )
		return;

	self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction );
}

if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" )
	self shellShock( "damage_mp", getDvarFloat( "scr_csmode" ) );

self damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker );
}


Callback_PlayerLastStand( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
{	

lastStandParams = spawnStruct();
lastStandParams.eInflictor = eInflictor;
lastStandParams.attacker = attacker;
lastStandParams.iDamage = iDamage;
lastStandParams.attackerPosition = attacker.origin;
if ( attacker == self )
	lastStandParams.sMeansOfDeath = "MOD_SUICIDE";
else
	lastStandParams.sMeansOfDeath = sMeansOfDeath;

lastStandParams.sWeapon = sWeapon;
if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" )
	lastStandParams.sPrimaryWeapon = attacker getCurrentPrimaryWeapon();
else
	lastStandParams.sPrimaryWeapon = undefined;
lastStandParams.vDir = vDir;
lastStandParams.sHitLoc = sHitLoc;
lastStandParams.lastStandStartTime = getTime();

mayDoLastStand = mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc );

//if ( mayDoLastStand )
//	mayDoLastStand = !self checkForceBleedOut();

if ( isDefined( self.endGame ) )
	mayDoLastStand = false;

if ( level.teamBased && isDefined( attacker.team ) && attacker.team == self.team )
	mayDoLastStand = false;

 /#
if ( getdvar( "scr_forcelaststand" ) == "1" )
	mayDoLastStand = true;
#/

if ( !mayDoLastStand )
{
	self.lastStandParams = lastStandParams;
	self.useLastStandParams = true;
	self _suicide();
	return;
}

self.inLastStand = true;

notifyData = spawnStruct();
if ( self _hasPerk( "specialty_finalstand" ) )
{
	notifyData.titleText = game[ "strings" ][ "final_stand" ];
	notifyData.iconName = "specialty_finalstand";
}
else
{
	notifyData.titleText = game[ "strings" ][ "last_stand" ];
	notifyData.iconName = "specialty_pistoldeath";
}
notifyData.glowColor = ( 1, 0, 0 );
notifyData.sound = "mp_last_stand";
notifyData.duration = 2.0;

self.health = 1;

self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData );

grenadeTypePrimary = "frag_grenade_mp";

if ( isDefined( level.ac130player ) && isDefined( attacker ) && level.ac130player == attacker )
	level notify( "ai_crawling", self );

if ( self _hasPerk( "specialty_finalstand" ) )
{
	self.lastStandParams = lastStandParams;
	self.inFinalStand = true;

	weaponList = self GetWeaponsListExclusives();
	foreach ( weapon in weaponList )
		self takeWeapon( weapon );

	self _disableUsability();

	self thread enableLastStandWeapons();
	self thread lastStandTimer( 20, true );		
}
/*
else if ( self _hasPerk( "specialty_c4death" ) )
{
	self.lastStandParams = lastStandParams;

	self takeAllWeapons();
	self giveWeapon( "c4Death_mp", 0, false );
	self switchToWeapon( "c4Death_mp" );
	self _disableUsability();
	self.inC4Death = true;

	//self thread dieAfterTime( 7 );
	self thread lastStandTimer( 10, false );	
	self thread detonateOnUse();
	//self thread detonateOnDeath();	
}
*/
else if ( level.dieHardMode )
{	
	self.lastStandParams = lastStandParams;
	self thread enableLastStandWeapons();
	self thread lastStandTimer( 20, false );
	self _disableUsability();
}
else // normal last stand
{
	self.lastStandParams = lastStandParams;

	pistolWeapon = undefined;

	weaponsList = self GetWeaponsListPrimaries();
	foreach ( weapon in weaponsList )
	{
		if ( maps\mp\gametypes\_weapons::isSideArm( weapon ) )
			pistolWeapon = weapon;			
	}

	if ( !isDefined( pistolWeapon ) )
	{
		pistolWeapon = "beretta_mp";
		self _giveWeapon( pistolWeapon );
	}

	self giveMaxAmmo( pistolWeapon );
	self DisableWeaponSwitch();
	self _disableUsability();

	if ( !self _hasPerk("specialty_laststandoffhand") )
		self DisableOffhandWeapons();

	self switchToWeapon( pistolWeapon );

	self thread lastStandTimer( 10, false );
}
}

dieAfterTime( time )
{
self endon( "death" );
self endon( "disconnect" );
self endon( "joined_team" );
level endon( "game_ended" );

wait ( time );
self.useLastStandParams = true;
self _suicide();
}

detonateOnUse()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "joined_team" );
level endon( "game_ended" );

self waittill( "detonate" );
self.useLastStandParams = true;
self c4DeathDetonate();
}

detonateOnDeath()
{
self endon( "detonate" );
self endon( "disconnect" );
self endon( "joined_team" );
level endon( "game_ended" );

self waittill( "death" );
self c4DeathDetonate();
}

c4DeathDetonate()
{
self playSound( "detpack_explo_default" );
self.c4DeathEffect = playFX( level.c4Death, self.origin );
RadiusDamage( self.origin, 400, 100, 100, self );

if ( isAlive( self ) )
	self _suicide();
}

enableLastStandWeapons()
{
self endon( "death" );
self endon( "disconnect" );
level endon( "game_ended" );

self freezeControlsWrapper( true );
wait .30;

self freezeControlsWrapper( false );
}

lastStandTimer( delay, isFinalStand )
{
self endon( "death" );
self endon( "disconnect" );
self endon( "revive");
level endon( "game_ended" );

level notify ( "player_last_stand" );

self thread lastStandWaittillDeath();

self.lastStand = true;

if ( !isFinalStand && !level.dieHardMode && ( !isDefined( self.inC4Death ) || !self.inC4Death ) )
{
	self thread lastStandAllowSuicide();
	self setLowerMessage( "last_stand", &"PLATFORM_COWARDS_WAY_OUT" );
	self thread lastStandKeepOverlay();
}

if ( level.dieHardMode == 1 && level.dieHardMode != 2 )
{
	reviveEnt = spawn( "script_model", self.origin );
	reviveEnt setModel( "tag_origin" );
	reviveEnt setCursorHint( "HINT_NOICON" );
	reviveEnt setHintString( &"PLATFORM_REVIVE" );

	reviveEnt reviveSetup( self );
	reviveEnt endon ( "death" );

	reviveIcon = newTeamHudElem( self.team );
	reviveIcon setShader( "waypoint_revive", 8, 8 );
	reviveIcon setWaypoint( true, true );
	reviveIcon SetTargetEnt( self );
	reviveIcon thread destroyOnReviveEntDeath( reviveEnt );

	reviveIcon.color = (0.33, 0.75, 0.24);
	self playDeathSound();

	if ( isFinalStand )
	{
		wait( delay );

		if ( self.inFinalStand )
			self thread lastStandBleedOut( isFinalStand, reviveEnt );
	}

	return;
}
else if( level.dieHardMode == 2 )
{
	self thread lastStandKeepOverlay();
	reviveEnt = spawn( "script_model", self.origin );
	reviveEnt setModel( "tag_origin" );
	reviveEnt setCursorHint( "HINT_NOICON" );
	reviveEnt setHintString( &"PLATFORM_REVIVE" );

	reviveEnt reviveSetup( self );
	reviveEnt endon ( "death" );

	reviveIcon = newTeamHudElem( self.team );
	reviveIcon setShader( "waypoint_revive", 8, 8 );
	reviveIcon setWaypoint( true, true );
	reviveIcon SetTargetEnt( self );
	reviveIcon thread destroyOnReviveEntDeath( reviveEnt );

	reviveIcon.color = (0.33, 0.75, 0.24);
	self playDeathSound();

	if ( isFinalStand )
	{
		wait( delay );

		if ( self.inFinalStand )
			self thread lastStandBleedOut( isFinalStand, reviveEnt );
	}

	wait delay / 3;
	reviveIcon.color = (1.0, 0.64, 0.0);

	while ( reviveEnt.inUse )
		wait ( 0.05 );

	self playDeathSound();	
	wait delay / 3;
	reviveIcon.color = (1.0, 0.0, 0.0);

	while ( reviveEnt.inUse )
		wait ( 0.05 );

	self playDeathSound();
	wait delay / 3;	

	while ( reviveEnt.inUse )
		wait ( 0.05 );

	wait( 0.05 ); 
	self thread lastStandBleedOut( isFinalStand );
	return;
}

wait( delay );
self thread lastStandBleedout( isFinalStand );

}

maxHealthOverlay( maxHealth, refresh )
{
self endon( "stop_maxHealthOverlay" );
self endon( "revive" );
self endon( "death" );

for( ;; )
{
	self.health -= 1;
	self.maxHealth = maxHealth;
	wait( .05 );
	self.maxHealth = 50;
	self.health += 1;

	wait ( .50 );
}	
}

lastStandBleedOut( reviveOnBleedOut, reviveEnt )
{
if ( reviveOnBleedOut )
{
	self.lastStand = undefined;
	self.inFinalStand = false;
	self clearLowerMessage( "last_stand" );
	maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer();

	if( isDefined( reviveEnt ) )
		reviveEnt Delete();
}
else
{
	self.useLastStandParams = true;
	self.beingRevived = false;
	self _suicide();
}
}


lastStandAllowSuicide()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "game_ended" );
self endon( "revive");

while ( 1 )
{
	if ( self useButtonPressed() )
	{
		pressStartTime = gettime();
		while ( self useButtonPressed() )
		{
			wait .05;
			if ( gettime() - pressStartTime > 700 )
				break;
		}
		if ( gettime() - pressStartTime > 700 )
			break;
	}
	wait .05;
}

self thread lastStandBleedOut( false );
}

lastStandKeepOverlay()
{
level endon( "game_ended" );
self endon( "death" );
self endon( "disconnect" );
self endon( "revive" );

// keep the health overlay going by making code think the player is getting damaged
while ( !level.gameEnded )
{
	self.health = 2;
	wait .05;
	self.health = 1;
	wait .5;
}

self.health = self.maxhealth;
}


lastStandWaittillDeath()
{
self endon( "disconnect" );
self endon( "revive" );
level endon( "game_ended" );
self waittill( "death" );

self clearLowerMessage( "last_stand" );
self.lastStand = undefined;
}


mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc )
{
if ( sMeansOfDeath == "MOD_TRIGGER_HURT" )
	return false;

if ( sMeansOfDeath != "MOD_PISTOL_BULLET" && sMeansOfDeath != "MOD_RIFLE_BULLET" && sMeansOfDeath != "MOD_FALLING" && sMeansOfDeath != "MOD_EXPLOSIVE_BULLET" )
	return false;

if ( sMeansOfDeath == "MOD_IMPACT" && sWeapon == "throwingknife_mp" )
	return false;

if ( sMeansOfDeath == "MOD_IMPACT" && ( sWeapon == "m79_mp" || isSubStr(sWeapon, "gl_") ) )
	return false;

if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath ) )
	return false;

if ( self isUsingRemote() )
	return false;

return true;
}


ensureLastStandParamsValidity()
{
// attacker may have become undefined if the player that killed me has disconnected
if ( !isDefined( self.lastStandParams.attacker ) )
	self.lastStandParams.attacker = self;
}

getHitLocHeight( sHitLoc )
{
switch( sHitLoc )
{
	case "helmet":
	case "head":
	case "neck":
		return 60;
	case "torso_upper":
	case "right_arm_upper":
	case "left_arm_upper":
	case "right_arm_lower":
	case "left_arm_lower":
	case "right_hand":
	case "left_hand":
	case "gun":
		return 48;
	case "torso_lower":
		return 40;
	case "right_leg_upper":
	case "left_leg_upper":
		return 32;
	case "right_leg_lower":
	case "left_leg_lower":
		return 10;
	case "right_foot":
	case "left_foot":
		return 5;
}
return 48;
}

delayStartRagdoll( ent, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath )
{
if ( isDefined( ent ) )
{
	deathAnim = ent getCorpseAnim();
	if ( animhasnotetrack( deathAnim, "ignore_ragdoll" ) )
		return;
}

wait( 0.2 );

if ( !isDefined( ent ) )
	return;

if ( ent isRagDoll() )
	return;

deathAnim = ent getcorpseanim();

startFrac = 0.35;

if ( animhasnotetrack( deathAnim, "start_ragdoll" ) )
{
	times = getnotetracktimes( deathAnim, "start_ragdoll" );
	if ( isDefined( times ) )
		startFrac = times[ 0 ];
}

waitTime = startFrac * getanimlength( deathAnim );
wait( waitTime );

if ( isDefined( ent ) )
{
	ent startragdoll( 1 );
}
}


getMostKilledBy()
{
mostKilledBy = "";
killCount = 0;

killedByNames = getArrayKeys( self.killedBy );

for ( index = 0; index < killedByNames.size; index++ )
{
	killedByName = killedByNames[ index ];
	if ( self.killedBy[ killedByName ] <= killCount )
		continue;

	killCount = self.killedBy[ killedByName ];
	mostKilleBy = killedByName;
}

return mostKilledBy;
}


getMostKilled()
{
mostKilled = "";
killCount = 0;

killedNames = getArrayKeys( self.killedPlayers );

for ( index = 0; index < killedNames.size; index++ )
{
	killedName = killedNames[ index ];
	if ( self.killedPlayers[ killedName ] <= killCount )
		continue;

	killCount = self.killedPlayers[ killedName ];
	mostKilled = killedName;
}

return mostKilled;
}


damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker )
{
self thread maps\mp\gametypes\_weapons::onWeaponDamage( eInflictor, sWeapon, sMeansOfDeath, iDamage, eAttacker );
self PlayRumbleOnEntity( "damage_heavy" );
}


reviveSetup( owner )
{
team = owner.team;

self linkTo( owner, "tag_origin" );

self.owner = owner;
self.inUse = false;
self makeUsable();
self updateUsableByTeam( team );
self thread trackTeamChanges( team );

self thread reviveTriggerThink( team );

self thread deleteOnReviveOrDeathOrDisconnect();
}


deleteOnReviveOrDeathOrDisconnect()
{
self endon ( "death" );

self.owner waittill_any ( "death", "disconnect" );

self delete();
}


updateUsableByTeam( team )
{
foreach (player in level.players)
{
	if ( team == player.team && player != self.owner )
		self enablePlayerUse( player );	
	else
		self disablePlayerUse( player );	
}	
}


trackTeamChanges( team )
{
self endon ( "death" );

while ( true )
{
	level waittill ( "joined_team" );

	self updateUsableByTeam( team );
}
}


trackLastStandChanges( team )
{
self endon ( "death" );

while ( true )
{
	level waittill ( "player_last_stand" );

	self updateUsableByTeam( team );
}
}


reviveTriggerThink( team )
{
self endon ( "death" );
level endon ( "game_ended" );

for ( ;; )
{
	self waittill ( "trigger", player );
	self.owner.beingRevived = true;

	if ( isDefined(player.beingRevived) && player.beingRevived )
	{
		self.owner.beingRevived = false;
		continue;
	}

	self makeUnUsable();
	self.owner freezeControlsWrapper( true );

	revived = self useHoldThink( player );
	self.owner.beingRevived = false;

	if ( !isAlive( self.owner ) )
	{	
		self delete();
		return;
	}

	self.owner freezeControlsWrapper( false );

	if ( revived )
	{
		player thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "reviver", 200 );
		player thread maps\mp\gametypes\_rank::giveRankXP( "reviver", 200 );

		self.owner.lastStand = undefined;
		self.owner clearLowerMessage( "last_stand" );

		if ( self.owner _hasPerk( "specialty_lightweight" ) )
			self.owner.moveSpeedScaler = 1.10;
		else
			self.owner.moveSpeedScaler = 1;

		self.owner.maxHealth = 100;

		self.owner maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" );
		self.owner maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer();

		self.owner setPerk( "specialty_pistoldeath", true );
		self.owner.beingRevived = false;

		self delete();
		return;
	}

	self makeUsable();
	self updateUsableByTeam( team );
}
}



/*
=============
useHoldThink

Claims the use trigger for player and displays a use bar
Returns true if the player sucessfully fills the use bar
=============
*/
useHoldThink( player )
{
reviveSpot = spawn( "script_origin", self.origin );
reviveSpot hide();	
player playerLinkTo( reviveSpot );		
player PlayerLinkedOffsetEnable();

player _disableWeapon();

self.curProgress = 0;
self.inUse = true;
self.useRate = 0;
self.useTime = 3000;

player thread personalUseBar( self );

result = useHoldThinkLoop( player );

if ( isDefined( player ) && isReallyAlive( player ) )
{
	player Unlink();
	player _enableWeapon();
}

if ( isDefined( result ) && result )
{
	self.owner thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "revived", player );
	self.owner.inlaststand = false;
	return true;
}

self.inUse = false;
reviveSpot Delete();	
return false;
}


personalUseBar( object )
{
useBar = self createPrimaryProgressBar();
useBarText = self createPrimaryProgressBarText();
useBarText setText( &"MPUI_REVIVING" );

objUseBar = object.owner createPrimaryProgressBar();
objUseBarText = object.owner createPrimaryProgressBarText();
objUseBarText setText( &"MPUI_BEING_REVIVED" );

lastRate = -1;
while ( isReallyAlive( self ) && isDefined( object ) && object.inUse && !level.gameEnded && isDefined( self ) )
{
	if ( lastRate != object.useRate )
	{
		if( object.curProgress > object.useTime)
			object.curProgress = object.useTime;

		useBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate );
		objUseBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate );

		if ( !object.useRate )
		{
			useBar hideElem();
			useBarText hideElem();

			objUseBar hideElem();
			objUseBarText hideElem();
		}
		else
		{
			useBar showElem();
			useBarText showElem();

			objUseBar showElem();
			objUseBarText showElem();
		}
	}	
	lastRate = object.useRate;
	wait ( 0.05 );
}

// when the players disconnect the hudElems are destroyed automatically
if ( isDefined( useBar ) )
	useBar destroyElem();
if ( isDefined( useBarText ) )
	useBarText destroyElem();

if ( isDefined( objUseBar ) )
	objUseBar destroyElem();
if ( isDefined( objUseBarText ) )
	objUseBarText destroyElem();
}


useHoldThinkLoop( player )
{
level endon ( "game_ended" );
self.owner endon( "death" );
self.owner endon( "disconnect" );

while( isReallyAlive( player ) && player useButtonPressed() && self.curProgress < self.useTime  )
{
	self.curProgress += (50 * self.useRate);
	self.useRate = 1; /* * player.objectiveScaler;*/

	if ( self.curProgress >= self.useTime )
	{
		self.inUse = false;

		return isReallyAlive( player );
	}

	wait 0.05;
}

return false;
}


Callback_KillingBlow( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
{
if ( isDefined(self.lastDamageWasFromEnemy) && self.lastDamageWasFromEnemy && iDamage >= self.health && isDefined( self.combatHigh ) && self.combatHigh == "specialty_endgame" )
{
	self setAdrenaline( 0 );
	self _setPerk( "specialty_endgame" );
	return false;
}

return true;
}


emitFallDamage( iDamage )
{
PhysicsExplosionSphere( self.origin, 64, 64, 1 );

// get the entities we landed on
damageEnts = [];
for ( testAngle = 0; testAngle < 360; testAngle += 30 )
{
	xOffset = cos( testAngle ) * 16;
	yOffset = sin( testAngle ) * 16;

	traceData = bulletTrace( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), true, self );
	//thread drawLine( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), 10.0 );

	if ( isDefined( traceData["entity"] ) && isDefined( traceData["entity"].targetname ) && (traceData["entity"].targetname == "destructible_vehicle" || traceData["entity"].targetname == "destructible_toy") )
		damageEnts[damageEnts.size] = traceData["entity"];
}

if ( damageEnts.size )
{
	damageOwner = spawn( "script_origin", self.origin );
	damageOwner hide();
	damageOwner.type = "soft_landing";
	damageOwner.destructibles = damageEnts;
	radiusDamage( self.origin, 64, 100, 100, damageOwner );

	wait ( 0.1 );	
	damageOwner delete();
}
}

drawLine( start, end, timeSlice )
{
drawTime = int(timeSlice * 20);
for( time = 0; time < drawTime; time++ )
{
	line( start, end, (1,0,0),false, 1 );
	wait ( 0.05 );
}
}

isFlankKill( victim, attacker )
{
victimForward = anglestoforward( victim.angles );
victimForward = ( victimForward[0], victimForward[1], 0 );
victimForward = VectorNormalize( victimForward );

attackDirection = victim.origin - attacker.origin;
attackDirection = ( attackDirection[0], attackDirection[1], 0 ); 
attackDirection = VectorNormalize( attackDirection );

dotProduct = VectorDot( victimForward, attackDirection );
if ( dotProduct > 0 ) // 0 = cos( 90 ), 180 degree arc total
	return true;
else
	return false;
}

_obituary( victim, attacker, sWeapon, sMeansOfDeath )
{
victimTeam = victim.team;

foreach ( player in level.players )
{
	playerTeam = player.team;
	if ( playerTeam == "spectator" )
		player iPrintLn( &"MP_OBITUARY_NEUTRAL", attacker.name, victim.name );
	else if ( playerTeam == victimTeam )
		player iPrintLn( &"MP_OBITUARY_ENEMY", attacker.name, victim.name );
	else
		player iPrintLn( &"MP_OBITUARY_FRIENDLY", attacker.name, victim.name );
}
}


logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc )
{
// create a lot of redundant data for the log print
lpselfnum = self getEntityNumber();
lpselfname = self.name;
lpselfteam = self.team;
lpselfguid = self.guid;

if ( isPlayer( attacker ) )
{
	lpattackGuid = attacker.guid;
	lpattackname = attacker.name;
	lpattackerteam = attacker.team;
	lpattacknum = attacker getEntityNumber();
	attackerString = attacker getXuid() + "(" + lpattackname + ")";
}
else
{
	lpattackGuid = "";
	lpattackname = "";
	lpattackerteam = "world";
	lpattacknum = -1;
	attackerString = "none";
}

logPrint( "K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" );
}


destroyOnReviveEntDeath( reviveEnt )
{
reviveEnt waittill ( "death" );

self destroy();
}

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Гость
Ответить в тему...

Сейчас на странице 0

  • Нет пользователей, просматривающих эту страницу

Важная информация

Используя этот сайт, вы соглашаетесь Условия использования.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.