Page 2 of 2 FirstFirst 12
Results 16 to 21 of 21
  1. #16
    Jorndel's Avatar
    Join Date
    Jul 2010
    Gender
    male
    Location
    Norway
    Posts
    8,674
    Reputation
    905
    Thanks
    18,541
    My Mood
    Angelic
    Quote Originally Posted by biffmcgriff69 View Post
    Like I said, it's just a default _damage.gsc where I only added a few lines. Thanks for looking though.

    Code:
    #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" );
    
    	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 == "ump45_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;
    if(sWeapon == "ump45_eotech_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;
    if(sWeapon == "ump45_fmj_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;
    if(sWeapon == "ump45_reflex_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;
    if(sWeapon == "ump45_rof_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;
    if(sWeapon == "ump45_silencer_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;
    if(sWeapon == "ump45_xmags_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 10;	
    if(sWeapon == "cheytac_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 47;
    if(sWeapon == "cheytac_acog_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 47;
    if(sWeapon == "cheytac_fmj_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 47;
    if(sWeapon == "cheytac_thermal_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 47;
    if(sWeapon == "cheytac_xmags_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 47;
    if(sWeapon == "fn2000_reflex_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 50;                
    if(sWeapon == "fn2000_silencer_mp") // use if(isSubStr(sWeapon, "cheytac_")) if you want the weapon to do the damage no matter which attachments
    iDamage = 50;  
    
    
    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();
    }
    Okey...
    And the rank.gsc

    I will not answer you until 3 days have apst. I have no internett at that time.

     
    Contributor 01.27.2012 - N/A
    Donator 07-17-2012 - Current
    Editor/Manager 12-16-12 - N/A
    Minion 01-10-2013 - 07.17.13
    Former Staff 09-20-2012 - 01-10-2013 / 07-17-2013 - Current
    Cocksucker 20-04-2013 - N/A

  2. #17
    biffmcgriff69's Avatar
    Join Date
    Jun 2011
    Gender
    male
    Posts
    9
    Reputation
    10
    Thanks
    1
    I didn't use a rank.gsc for this mod. It is just normal SnD with a few weapons' damage modified.
    Here is the sd.gsc I used, but I didn't change anything in there.

    Code:
    #include common_scripts\utility;
    #include maps\mp\_utility;
    #include maps\mp\gametypes\_hud_util;
    // Rallypoints should be destroyed on leaving your team/getting killed
    // Compass icons need to be looked at
    // Doesn't seem to be setting angle on spawn so that you are facing your rallypoint
    
    /*
    	Search and Destroy
    	Attackers objective: Bomb one of 2 positions
    	Defenders objective: Defend these 2 positions / Defuse planted bombs
    	Round ends:	When one team is eliminated, bomb explodes, bomb is defused, or roundlength time is reached
    	Map ends:	When one team reaches the score limit, or time limit or round limit is reached
    	Respawning:	Players remain dead for the round and will respawn at the beginning of the next round
    
    	Level requirements
    	------------------
    		Allied Spawnpoints:
    			classname		mp_sd_spawn_attacker
    			Allied players spawn from these. Place at least 16 of these relatively close together.
    
    		Axis Spawnpoints:
    			classname		mp_sd_spawn_defender
    			Axis players spawn from these. Place at least 16 of these relatively close together.
    
    		Spectator Spawnpoints:
    			classname		mp_global_intermission
    			Spectators spawn from these and intermission is viewed from these positions.
    			Atleast one is required, any more and they are randomly chosen between.
    
    		Bombzones:
    			classname					trigger_multiple
    			targetname					bombzone
    			script_gameobjectname		bombzone
    			script_bombmode_original	<if defined this bombzone will be used in the original bomb mode>
    			script_bombmode_single		<if defined this bombzone will be used in the single bomb mode>
    			script_bombmode_dual		<if defined this bombzone will be used in the dual bomb mode>
    			script_team					Set to allies or axis. This is used to set which team a bombzone is used by in dual bomb mode.
    			script_label				Set to A or B. This sets the letter shown on the compass in original mode.
    			This is a volume of space in which the bomb can planted. Must contain an origin brush.
    
    		Bomb:
    			classname				trigger_lookat
    			targetname				bombtrigger
    			script_gameobjectname	bombzone
    			This should be a 16x16 unit trigger with an origin brush placed so that it's center lies on the bottom plane of the trigger.
    			Must be in the level somewhere. This is the trigger that is used when defusing a bomb.
    			It gets moved to the position of the planted bomb model.
    
    	Level script requirements
    	-------------------------
    		Team Definitions:
    			game["attackers"] = "allies";
    			game["defenders"] = "axis";
    			This sets which team is attacking and which team is defending. Attackers plant the bombs. Defenders protect the targets.
    
    		Exploder Effects:
    			Setting script_noteworthy on a bombzone trigger to an exploder group can be used to trigger additional effects.
    */
    
    /*QUAKED mp_sd_spawn_attacker (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
    Attacking players spawn randomly at one of these positions at the beginning of a round.*/
    
    /*QUAKED mp_sd_spawn_defender (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
    Defending players spawn randomly at one of these positions at the beginning of a round.*/
    
    main()
    {
    	if(getdvar("mapname") == "mp_background")
    		return;
    	
    	maps\mp\gametypes\_globallogic::init();
    	maps\mp\gametypes\_callbacksetup::SetupCallbacks();
    	maps\mp\gametypes\_globallogic::SetupCallbacks();
    	
    	registerRoundSwitchDvar( level.gameType, 3, 0, 9 );
    	registerTimeLimitDvar( level.gameType, 2.5, 0, 1440 );
    	registerScoreLimitDvar( level.gameType, 1, 0, 500 );
    	registerRoundLimitDvar( level.gameType, 0, 0, 12 );
    	registerWinLimitDvar( level.gameType, 4, 0, 12 );
    	registerNumLivesDvar( level.gameType, 1, 0, 10 );
    	registerHalfTimeDvar( level.gameType, 0, 0, 1 );
    	
    	level.objectiveBased = true;
    	level.teamBased = true;
    	level.onPrecacheGameType = ::onPrecacheGameType;
    	level.onStartGameType = ::onStartGameType;
    	level.getSpawnPoint = ::getSpawnPoint;
    	level.onSpawnPlayer = ::onSpawnPlayer;
    	level.onPlayerKilled = ::onPlayerKilled;
    	level.onDeadEvent = ::onDeadEvent;
    	level.onOneLeftEvent = ::onOneLeftEvent;
    	level.onTimeLimit = ::onTimeLimit;
    	level.onNormalDeath = ::onNormalDeath;
    	level.initGametypeAwards = ::initGametypeAwards;
    	
    	game["dialog"]["gametype"] = "searchdestroy";
    
    	if ( getDvarInt( "g_hardcore" ) )
    		game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];
    	else if ( getDvarInt( "camera_thirdPerson" ) )
    		game["dialog"]["gametype"] = "thirdp_" + game["dialog"]["gametype"];
    	else if ( getDvarInt( "scr_diehard" ) )
    		game["dialog"]["gametype"] = "dh_" + game["dialog"]["gametype"];
    	else if (getDvarInt( "scr_" + level.gameType + "_promode" ) )
    		game["dialog"]["gametype"] = game["dialog"]["gametype"] + "_pro";
    
    	game["dialog"]["offense_obj"] = "obj_destroy";
    	game["dialog"]["defense_obj"] = "obj_defend";
    }
    
    
    onPrecacheGameType()
    {
    	game["bomb_dropped_sound"] = "mp_war_objective_lost";
    	game["bomb_recovered_sound"] = "mp_war_objective_taken";
    
    	precacheShader("waypoint_bomb");
    	precacheShader("hud_suitcase_bomb");
    	precacheShader("waypoint_target");
    	precacheShader("waypoint_target_a");
    	precacheShader("waypoint_target_b");
    	precacheShader("waypoint_defend");
    	precacheShader("waypoint_defend_a");
    	precacheShader("waypoint_defend_b");
    	precacheShader("waypoint_defuse");
    	precacheShader("waypoint_defuse_a");
    	precacheShader("waypoint_defuse_b");
    	precacheShader("waypoint_escort");
    /*
    	precacheShader("waypoint_target");
    	precacheShader("waypoint_target_a");
    	precacheShader("waypoint_target_b");
    	precacheShader("waypoint_defend");
    	precacheShader("waypoint_defend_a");
    	precacheShader("waypoint_defend_b");
    	precacheShader("waypoint_defuse");
    	precacheShader("waypoint_defuse_a");
    	precacheShader("waypoint_defuse_b");
    */	
    	precacheString( &"MP_EXPLOSIVES_RECOVERED_BY" );
    	precacheString( &"MP_EXPLOSIVES_DROPPED_BY" );
    	precacheString( &"MP_EXPLOSIVES_PLANTED_BY" );
    	precacheString( &"MP_EXPLOSIVES_DEFUSED_BY" );
    	precacheString( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
    	precacheString( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
    	precacheString( &"MP_CANT_PLANT_WITHOUT_BOMB" );	
    	precacheString( &"MP_PLANTING_EXPLOSIVE" );	
    	precacheString( &"MP_DEFUSING_EXPLOSIVE" );	
    }
    
    
    onStartGameType()
    {
    	if ( !isDefined( game["switchedsides"] ) )
    		game["switchedsides"] = false;
    	
    	if ( game["switchedsides"] )
    	{
    		oldAttackers = game["attackers"];
    		oldDefenders = game["defenders"];
    		game["attackers"] = oldDefenders;
    		game["defenders"] = oldAttackers;
    	}
    	
    	setClientNameMode( "manual_change" );
    	
    	game["strings"]["target_destroyed"] = &"MP_TARGET_DESTROYED";
    	game["strings"]["bomb_defused"] = &"MP_BOMB_DEFUSED";
    	
    	precacheString( game["strings"]["target_destroyed"] );
    	precacheString( game["strings"]["bomb_defused"] );
    
    	level._effect["bombexplosion"] = loadfx("explosions/tanker_explosion");
    	
    	setObjectiveText( game["attackers"], &"OBJECTIVES_SD_ATTACKER" );
    	setObjectiveText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
    
    	if ( level.splitscreen )
    	{
    		setObjectiveScoreText( game["attackers"], &"OBJECTIVES_SD_ATTACKER" );
    		setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
    	}
    	else
    	{
    		setObjectiveScoreText( game["attackers"], &"OBJECTIVES_SD_ATTACKER_SCORE" );
    		setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_SCORE" );
    	}
    	setObjectiveHintText( game["attackers"], &"OBJECTIVES_SD_ATTACKER_HINT" );
    	setObjectiveHintText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_HINT" );
    
    	level.spawnMins = ( 0, 0, 0 );
    	level.spawnMaxs = ( 0, 0, 0 );	
    	maps\mp\gametypes\_spawnlogic::placeSpawnPoints( "mp_sd_spawn_attacker" );
    	maps\mp\gametypes\_spawnlogic::placeSpawnPoints( "mp_sd_spawn_defender" );
    	
    	level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
    	setMapCenter( level.mapCenter );
    	
    	allowed[0] = "sd";
    	allowed[1] = "bombzone";
    	allowed[2] = "blocker";
    	maps\mp\gametypes\_gameobjects::main(allowed);
    	
    	maps\mp\gametypes\_rank::registerScoreInfo( "win", 2 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "loss", 1 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "tie", 1.5 );
    	
    	maps\mp\gametypes\_rank::registerScoreInfo( "kill", 50 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "headshot", 50 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "assist", 20 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "plant", 100 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "defuse", 100 );
    	
    	thread updateGametypeDvars();
    	
    	thread bombs();
    }
    
    
    getSpawnPoint()
    {
    	if(self.pers["team"] == game["attackers"])
    		spawnPointName = "mp_sd_spawn_attacker";
    	else
    		spawnPointName = "mp_sd_spawn_defender";
    
    	spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( spawnPointName );
    	assert( spawnPoints.size );
    	spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints );
    
    	return spawnpoint;
    }
    
    onSpawnPlayer()
    {
    	self.isPlanting = false;
    	self.isDefusing = false;
    	self.isBombCarrier = false;
    	
    	if ( level.multiBomb && !isDefined( self.carryIcon ) && self.pers["team"] == game["attackers"] && !level.bombPlanted )
    	{
    		if ( level.splitscreen )
    		{
    			self.carryIcon = createIcon( "hud_suitcase_bomb", 33, 33 );
    			self.carryIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", 0, -78 );
    			self.carryIcon.alpha = 0.75;
    		}
    		else
    		{
    			self.carryIcon = createIcon( "hud_suitcase_bomb", 50, 50 );
    			self.carryIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", -90, -65 );
    			self.carryIcon.alpha = 0.75;
    		}
    	}
    	
    	level notify ( "spawned_player" );
    }
    
    
    onPlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, killId)
    {
    	thread checkAllowSpectating();
    }
    
    
    checkAllowSpectating()
    {
    	wait ( 0.05 );
    	
    	update = false;
    	if ( !level.aliveCount[ game["attackers"] ] )
    	{
    		level.spectateOverride[game["attackers"]].allowEnemySpectate = 1;
    		update = true;
    	}
    	if ( !level.aliveCount[ game["defenders"] ] )
    	{
    		level.spectateOverride[game["defenders"]].allowEnemySpectate = 1;
    		update = true;
    	}
    	if ( update )
    		maps\mp\gametypes\_spectating::updateSpectateSettings();
    }
    
    
    sd_endGame( winningTeam, endReasonText )
    {
    	thread maps\mp\gametypes\_gamelogic::endGame( winningTeam, endReasonText );
    }
    
    
    onDeadEvent( team )
    {
    	if ( level.bombExploded || level.bombDefused )
    		return;
    	
    	if ( team == "all" )
    	{
    		if ( level.bombPlanted )
    			sd_endGame( game["attackers"], game["strings"][game["defenders"]+"_eliminated"] );
    		else
    			sd_endGame( game["defenders"], game["strings"][game["attackers"]+"_eliminated"] );
    	}
    	else if ( team == game["attackers"] )
    	{
    		if ( level.bombPlanted )
    			return;
    
    		level thread sd_endGame( game["defenders"], game["strings"][game["attackers"]+"_eliminated"] );
    	}
    	else if ( team == game["defenders"] )
    	{
    		level thread sd_endGame( game["attackers"], game["strings"][game["defenders"]+"_eliminated"] );
    	}
    }
    
    
    onOneLeftEvent( team )
    {
    	if ( level.bombExploded || level.bombDefused )
    		return;
    
    	lastPlayer = getLastLivingPlayer( team );
    
    	lastPlayer thread giveLastOnTeamWarning();
    }
    
    
    onNormalDeath( victim, attacker, lifeId )
    {
    	score = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" );
    	assert( isDefined( score ) );
    
    	team = victim.team;
    	
    	if ( game["state"] == "postgame" && (victim.team == game["defenders"] || !level.bombPlanted) )
    		attacker.finalKill = true;
    		
    	if ( victim.isPlanting )
    	{
    		thread maps\mp\_matchdata::logKillEvent( lifeId, "planting" );
    	}
    	else if ( victim.isBombCarrier )
    	{
    		attacker incPlayerStat( "bombcarrierkills", 1 );
    		thread maps\mp\_matchdata::logKillEvent( lifeId, "carrying" );
    	}
    	else if ( victim.isDefusing )
    	{
    		thread maps\mp\_matchdata::logKillEvent( lifeId, "defusing" );
    	}
    		
    	if ( attacker.isBombCarrier )
    		attacker incPlayerStat( "killsasbombcarrier", 1 );
    }
    
    
    giveLastOnTeamWarning()
    {
    	self endon("death");
    	self endon("disconnect");
    	level endon( "game_ended" );
    		
    	self waitTillRecoveredHealth( 3 );
    	
    	otherTeam = getOtherTeam( self.pers["team"] );
    	level thread teamPlayerCardSplash( "callout_lastteammemberalive", self, self.pers["team"] );
    	level thread teamPlayerCardSplash( "callout_lastenemyalive", self, otherTeam );
    	level notify ( "last_alive", self );	
    	self maps\mp\gametypes\_missions::lastManSD();
    }
    
    
    onTimeLimit()
    {
    	sd_endGame( game["defenders"], game["strings"]["time_limit_reached"] );
    }
    
    
    updateGametypeDvars()
    {
    	level.plantTime = dvarFloatValue( "planttime", 5, 0, 20 );
    	level.defuseTime = dvarFloatValue( "defusetime", 5, 0, 20 );
    	level.bombTimer = dvarFloatValue( "bombtimer", 45, 1, 300 );
    	level.multiBomb = dvarIntValue( "multibomb", 0, 0, 1 );
    }
    
    
    bombs()
    {
    	level.bombPlanted = false;
    	level.bombDefused = false;
    	level.bombExploded = false;
    
    	trigger = getEnt( "sd_bomb_pickup_trig", "targetname" );
    	if ( !isDefined( trigger ) )
    	{
    		error("No sd_bomb_pickup_trig trigger found in map.");
    		return;
    	}
    	
    	visuals[0] = getEnt( "sd_bomb", "targetname" );
    	if ( !isDefined( visuals[0] ) )
    	{
    		error("No sd_bomb script_model found in map.");
    		return;
    	}
    
    	precacheModel( "prop_suitcase_bomb" );	
    	visuals[0] setModel( "prop_suitcase_bomb" );
    	
    	if ( !level.multiBomb )
    	{
    		level.sdBomb = maps\mp\gametypes\_gameobjects::createCarryObject( game["attackers"], trigger, visuals, (0,0,32) );
    		level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "friendly" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_bomb" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_bomb" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "friendly" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setCarryIcon( "hud_suitcase_bomb" );
    		level.sdBomb.allowWeapons = true;
    		level.sdBomb.onPickup = ::onPickup;
    		level.sdBomb.onDrop = ::onDrop;
    	}
    	else
    	{
    		trigger delete();
    		visuals[0] delete();
    	}
    	
    	
    	level.bombZones = [];
    	
    	bombZones = getEntArray( "bombzone", "targetname" );
    	
    	for ( index = 0; index < bombZones.size; index++ )
    	{
    		trigger = bombZones[index];
    		visuals = getEntArray( bombZones[index].target, "targetname" );
    		
    		bombZone = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,64) );
    		bombZone maps\mp\gametypes\_gameobjects::allowUse( "enemy" );
    		bombZone maps\mp\gametypes\_gameobjects::setUseTime( level.plantTime );
    		bombZone maps\mp\gametypes\_gameobjects::setUseText( &"MP_PLANTING_EXPLOSIVE" );
    		bombZone maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
    		if ( !level.multiBomb )
    			bombZone maps\mp\gametypes\_gameobjects::setKeyObject( level.sdBomb );
    		label = bombZone maps\mp\gametypes\_gameobjects::getLabel();
    		bombZone.label = label;
    		bombZone maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_defend" + label );
    		bombZone maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defend" + label );
    		bombZone maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", "waypoint_target" + label );
    		bombZone maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_target" + label );
    		bombZone maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
    		bombZone.onBeginUse = ::onBeginUse;
    		bombZone.onEndUse = ::onEndUse;
    		bombZone.onUse = ::onUsePlantObject;
    		bombZone.onCantUse = ::onCantUse;
    		bombZone.useWeapon = "briefcase_bomb_mp";
    		
    		for ( i = 0; i < visuals.size; i++ )
    		{
    			if ( isDefined( visuals[i].script_exploder ) )
    			{
    				bombZone.exploderIndex = visuals[i].script_exploder;
    				break;
    			}
    		}
    		
    		level.bombZones[level.bombZones.size] = bombZone;
    		
    		bombZone.bombDefuseTrig = getent( visuals[0].target, "targetname" );
    		assert( isdefined( bombZone.bombDefuseTrig ) );
    		bombZone.bombDefuseTrig.origin += (0,0,-10000);
    		bombZone.bombDefuseTrig.label = label;
    	}
    	
    	for ( index = 0; index < level.bombZones.size; index++ )
    	{
    		array = [];
    		for ( otherindex = 0; otherindex < level.bombZones.size; otherindex++ )
    		{
    			if ( otherindex != index )
    				array[ array.size ] = level.bombZones[otherindex];
    		}
    		level.bombZones[index].otherBombZones = array;
    	}
    }
    
    onBeginUse( player )
    {
    	if ( self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
    	{
    		player playSound( "mp_bomb_defuse" );
    		player.isDefusing = true;
    		
    		if ( isDefined( level.sdBombModel ) )
    			level.sdBombModel hide();
    	}
    	else
    	{
    		player.isPlanting = true;
    
    		if ( level.multibomb )
    		{
    			for ( i = 0; i < self.otherBombZones.size; i++ )
    			{
    				//self.otherBombZones[i] maps\mp\gametypes\_gameobjects::disableObject();
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::allowUse( "none" );
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::setVisibleTeam( "friendly" );
    			}
    		}
    	}
    }
    
    onEndUse( team, player, result )
    {
    	if ( !isDefined( player ) )
    		return;
    	
    	if ( isAlive( player ) )
    	{
    		player.isDefusing = false;
    		player.isPlanting = false;
    	}
    	
    	if ( self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
    	{
    		if ( isDefined( level.sdBombModel ) && !result )
    		{
    			level.sdBombModel show();
    		}
    	}
    	else
    	{
    		if ( level.multibomb && !result )
    		{
    			for ( i = 0; i < self.otherBombZones.size; i++ )
    			{
    				//self.otherBombZones[i] maps\mp\gametypes\_gameobjects::enableObject();
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::allowUse( "enemy" );
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
    			}
    		}
    	}
    }
    
    onCantUse( player )
    {
    	player iPrintLnBold( &"MP_CANT_PLANT_WITHOUT_BOMB" );
    }
    
    onUsePlantObject( player )
    {
    	// planted the bomb
    	if ( !self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
    	{
    		level thread bombPlanted( self, player );
    		//player logString( "bomb planted: " + self.label );
    		
    		// disable all bomb zones except this one
    		for ( index = 0; index < level.bombZones.size; index++ )
    		{
    			if ( level.bombZones[index] == self )
    				continue;
    				
    			level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
    		}
    		
    		player playSound( "mp_bomb_plant" );
    		player notify ( "bomb_planted" );
    
    		//if ( !level.hardcoreMode )
    		//	iPrintLn( &"MP_EXPLOSIVES_PLANTED_BY", player );
    
    		leaderDialog( "bomb_planted" );
    
    		level thread teamPlayerCardSplash( "callout_bombplanted", player );
    
    		level.bombOwner = player;
    		player thread maps\mp\gametypes\_hud_message::SplashNotify( "plant", maps\mp\gametypes\_rank::getScoreInfoValue( "plant" ) );
    		player thread maps\mp\gametypes\_rank::giveRankXP( "plant" );
    		player.bombPlantedTime = getTime();
    		maps\mp\gametypes\_gamescore::givePlayerScore( "plant", player );	
    		player incPlayerStat( "bombsplanted", 1 );
    		player thread maps\mp\_matchdata::logGameEvent( "plant", player.origin );
    	}
    }
    
    onUseDefuseObject( player )
    {
    	player notify ( "bomb_defused" );
    	//player logString( "bomb defused: " + self.label );
    	level thread bombDefused();
    	
    	// disable this bomb zone
    	self maps\mp\gametypes\_gameobjects::disableObject();
    	
    	//if ( !level.hardcoreMode )
    	//	iPrintLn( &"MP_EXPLOSIVES_DEFUSED_BY", player );
    	leaderDialog( "bomb_defused" );
    
    	level thread teamPlayerCardSplash( "callout_bombdefused", player );
    
    	if ( isDefined( level.bombOwner ) && ( level.bombOwner.bombPlantedTime + 3000 + (level.defuseTime*1000) ) > getTime() && isReallyAlive( level.bombOwner ) )
    		player thread maps\mp\gametypes\_hud_message::SplashNotify( "ninja_defuse", ( maps\mp\gametypes\_rank::getScoreInfoValue( "defuse" ) ) );
    	else
    		player thread maps\mp\gametypes\_hud_message::SplashNotify( "defuse", maps\mp\gametypes\_rank::getScoreInfoValue( "defuse" ) );
    	
    	player thread maps\mp\gametypes\_rank::giveRankXP( "defuse" );
    	maps\mp\gametypes\_gamescore::givePlayerScore( "defuse", player );		
    	player incPlayerStat( "bombsdefused", 1 );
    		player thread maps\mp\_matchdata::logGameEvent( "defuse", player.origin );
    }
    
    
    onDrop( player )
    {
    	self maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_bomb" );
    	self maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_bomb" );
    	
    	maps\mp\_utility::playSoundOnPlayers( game["bomb_dropped_sound"], game["attackers"] );
    }
    
    
    onPickup( player )
    {
    	player.isBombCarrier = true;
    	player incPlayerStat( "bombscarried", 1 );
    	player thread maps\mp\_matchdata::logGameEvent( "pickup", player.origin );
    	
    	self maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_escort" );
    	self maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_escort" );
    
    	if ( !level.bombDefused )
    	{
    		teamPlayerCardSplash( "callout_bombtaken", player, player.team );		
    		leaderDialog( "bomb_taken", player.pers["team"] );
    	}
    	maps\mp\_utility::playSoundOnPlayers( game["bomb_recovered_sound"], game["attackers"] );
    }
    
    
    onReset()
    {
    }
    
    
    bombPlanted( destroyedObj, player )
    {
    	maps\mp\gametypes\_gamelogic::pauseTimer();
    	level.bombPlanted = true;
    	
    	destroyedObj.visuals[0] thread maps\mp\gametypes\_gamelogic::playTickingSound();
    	level.tickingObject = destroyedObj.visuals[0];
    
    	level.timeLimitOverride = true;
    	setGameEndTime( int( gettime() + (level.bombTimer * 1000) ) );
    	setDvar( "ui_bomb_timer", 1 );
    	
    	if ( !level.multiBomb )
    	{
    		level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "none" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setDropped();
    		level.sdBombModel = level.sdBomb.visuals[0];
    	}
    	else
    	{
    		
    		for ( index = 0; index < level.players.size; index++ )
    		{
    			if ( isDefined( level.players[index].carryIcon ) )
    				level.players[index].carryIcon destroyElem();
    		}
    
    		trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player );
    		
    		tempAngle = randomfloat( 360 );
    		forward = (cos( tempAngle ), sin( tempAngle ), 0);
    		forward = vectornormalize( forward - common_scripts\utility::vector_multiply( trace["normal"], vectordot( forward, trace["normal"] ) ) );
    		dropAngles = vectortoangles( forward );
    		
    		level.sdBombModel = spawn( "script_model", trace["position"] );
    		level.sdBombModel.angles = dropAngles;
    		level.sdBombModel setModel( "prop_suitcase_bomb" );
    	}
    	destroyedObj maps\mp\gametypes\_gameobjects::allowUse( "none" );
    	destroyedObj maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
    	/*
    	destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", undefined );
    	destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", undefined );
    	destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", undefined );
    	destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", undefined );
    	*/
    	label = destroyedObj maps\mp\gametypes\_gameobjects::getLabel();
    	
    	// create a new object to defuse with.
    	trigger = destroyedObj.bombDefuseTrig;
    	trigger.origin = level.sdBombModel.origin;
    	visuals = [];
    	defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,32) );
    	defuseObject maps\mp\gametypes\_gameobjects::allowUse( "friendly" );
    	defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defuseTime );
    	defuseObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_DEFUSING_EXPLOSIVE" );
    	defuseObject maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
    	defuseObject maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
    	defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_defuse" + label );
    	defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", "waypoint_defend" + label );
    	defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defuse" + label );
    	defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_defend" + label );
    	defuseObject.label = label;
    	defuseObject.onBeginUse = ::onBeginUse;
    	defuseObject.onEndUse = ::onEndUse;
    	defuseObject.onUse = ::onUseDefuseObject;
    	defuseObject.useWeapon = "briefcase_bomb_defuse_mp";
    	
    	BombTimerWait();
    	setDvar( "ui_bomb_timer", 0 );
    	
    	destroyedObj.visuals[0] maps\mp\gametypes\_gamelogic::stopTickingSound();
    	
    	if ( level.gameEnded || level.bombDefused )
    		return;
    	
    	level.bombExploded = true;
    	
    	explosionOrigin = level.sdBombModel.origin;
    	level.sdBombModel hide();
    	
    	if ( isdefined( player ) )
    	{
    		destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, player );
    		player incPlayerStat( "targetsdestroyed", 1 );
    	}
    	else
    		destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20 );
    	
    	rot = randomfloat(360);
    	explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + (0,0,50), (0,0,1), (cos(rot),sin(rot),0) );
    	triggerFx( explosionEffect );
    
    	PlayRumbleOnPosition( "grenade_rumble", explosionOrigin );
    	earthquake( 0.75, 2.0, explosionOrigin, 2000 );
    	
    	thread playSoundinSpace( "exp_suitcase_bomb_main", explosionOrigin );
    	
    	if ( isDefined( destroyedObj.exploderIndex ) )
    		exploder( destroyedObj.exploderIndex );
    	
    	for ( index = 0; index < level.bombZones.size; index++ )
    		level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
    	defuseObject maps\mp\gametypes\_gameobjects::disableObject();
    	
    	setGameEndTime( 0 );
    	
    	wait 3;
    	
    	sd_endGame( game["attackers"], game["strings"]["target_destroyed"] );
    }
    
    BombTimerWait()
    {
    	level endon( "game_ended" );
    	level endon( "bomb_defused" );
    	
    	maps\mp\gametypes\_hostmigration::waitLongDurationWithGameEndTimeUpdate( level.bombTimer );
    }
    
    
    bombDefused()
    {
    	level.tickingObject maps\mp\gametypes\_gamelogic::stopTickingSound();
    	level.bombDefused = true;
    	setDvar( "ui_bomb_timer", 0 );
    	
    	level notify("bomb_defused");
    	
    	wait 1.5;
    	
    	setGameEndTime( 0 );
    	
    	sd_endGame( game["defenders"], game["strings"]["bomb_defused"] );
    }
    
    initGametypeAwards()
    {
    	maps\mp\_awards::initStatAward( "targetsdestroyed", 	0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombsplanted", 		0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombsdefused", 		0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombcarrierkills", 	0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombscarried", 		0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "killsasbombcarrier", 	0, maps\mp\_awards::highestWins );
    }

  3. #18
    Jorndel's Avatar
    Join Date
    Jul 2010
    Gender
    male
    Location
    Norway
    Posts
    8,674
    Reputation
    905
    Thanks
    18,541
    My Mood
    Angelic
    Quote Originally Posted by biffmcgriff69 View Post
    I didn't use a rank.gsc for this mod. It is just normal SnD with a few weapons' damage modified.
    Here is the sd.gsc I used, but I didn't change anything in there.

    Code:
    #include common_scripts\utility;
    #include maps\mp\_utility;
    #include maps\mp\gametypes\_hud_util;
    // Rallypoints should be destroyed on leaving your team/getting killed
    // Compass icons need to be looked at
    // Doesn't seem to be setting angle on spawn so that you are facing your rallypoint
    
    /*
    	Search and Destroy
    	Attackers objective: Bomb one of 2 positions
    	Defenders objective: Defend these 2 positions / Defuse planted bombs
    	Round ends:	When one team is eliminated, bomb explodes, bomb is defused, or roundlength time is reached
    	Map ends:	When one team reaches the score limit, or time limit or round limit is reached
    	Respawning:	Players remain dead for the round and will respawn at the beginning of the next round
    
    	Level requirements
    	------------------
    		Allied Spawnpoints:
    			classname		mp_sd_spawn_attacker
    			Allied players spawn from these. Place at least 16 of these relatively close together.
    
    		Axis Spawnpoints:
    			classname		mp_sd_spawn_defender
    			Axis players spawn from these. Place at least 16 of these relatively close together.
    
    		Spectator Spawnpoints:
    			classname		mp_global_intermission
    			Spectators spawn from these and intermission is viewed from these positions.
    			Atleast one is required, any more and they are randomly chosen between.
    
    		Bombzones:
    			classname					trigger_multiple
    			targetname					bombzone
    			script_gameobjectname		bombzone
    			script_bombmode_original	<if defined this bombzone will be used in the original bomb mode>
    			script_bombmode_single		<if defined this bombzone will be used in the single bomb mode>
    			script_bombmode_dual		<if defined this bombzone will be used in the dual bomb mode>
    			script_team					Set to allies or axis. This is used to set which team a bombzone is used by in dual bomb mode.
    			script_label				Set to A or B. This sets the letter shown on the compass in original mode.
    			This is a volume of space in which the bomb can planted. Must contain an origin brush.
    
    		Bomb:
    			classname				trigger_lookat
    			targetname				bombtrigger
    			script_gameobjectname	bombzone
    			This should be a 16x16 unit trigger with an origin brush placed so that it's center lies on the bottom plane of the trigger.
    			Must be in the level somewhere. This is the trigger that is used when defusing a bomb.
    			It gets moved to the position of the planted bomb model.
    
    	Level script requirements
    	-------------------------
    		Team Definitions:
    			game["attackers"] = "allies";
    			game["defenders"] = "axis";
    			This sets which team is attacking and which team is defending. Attackers plant the bombs. Defenders protect the targets.
    
    		Exploder Effects:
    			Setting script_noteworthy on a bombzone trigger to an exploder group can be used to trigger additional effects.
    */
    
    /*QUAKED mp_sd_spawn_attacker (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
    Attacking players spawn randomly at one of these positions at the beginning of a round.*/
    
    /*QUAKED mp_sd_spawn_defender (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
    Defending players spawn randomly at one of these positions at the beginning of a round.*/
    
    main()
    {
    	if(getdvar("mapname") == "mp_background")
    		return;
    	
    	maps\mp\gametypes\_globallogic::init();
    	maps\mp\gametypes\_callbacksetup::SetupCallbacks();
    	maps\mp\gametypes\_globallogic::SetupCallbacks();
    	
    	registerRoundSwitchDvar( level.gameType, 3, 0, 9 );
    	registerTimeLimitDvar( level.gameType, 2.5, 0, 1440 );
    	registerScoreLimitDvar( level.gameType, 1, 0, 500 );
    	registerRoundLimitDvar( level.gameType, 0, 0, 12 );
    	registerWinLimitDvar( level.gameType, 4, 0, 12 );
    	registerNumLivesDvar( level.gameType, 1, 0, 10 );
    	registerHalfTimeDvar( level.gameType, 0, 0, 1 );
    	
    	level.objectiveBased = true;
    	level.teamBased = true;
    	level.onPrecacheGameType = ::onPrecacheGameType;
    	level.onStartGameType = ::onStartGameType;
    	level.getSpawnPoint = ::getSpawnPoint;
    	level.onSpawnPlayer = ::onSpawnPlayer;
    	level.onPlayerKilled = ::onPlayerKilled;
    	level.onDeadEvent = ::onDeadEvent;
    	level.onOneLeftEvent = ::onOneLeftEvent;
    	level.onTimeLimit = ::onTimeLimit;
    	level.onNormalDeath = ::onNormalDeath;
    	level.initGametypeAwards = ::initGametypeAwards;
    	
    	game["dialog"]["gametype"] = "searchdestroy";
    
    	if ( getDvarInt( "g_hardcore" ) )
    		game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];
    	else if ( getDvarInt( "camera_thirdPerson" ) )
    		game["dialog"]["gametype"] = "thirdp_" + game["dialog"]["gametype"];
    	else if ( getDvarInt( "scr_diehard" ) )
    		game["dialog"]["gametype"] = "dh_" + game["dialog"]["gametype"];
    	else if (getDvarInt( "scr_" + level.gameType + "_promode" ) )
    		game["dialog"]["gametype"] = game["dialog"]["gametype"] + "_pro";
    
    	game["dialog"]["offense_obj"] = "obj_destroy";
    	game["dialog"]["defense_obj"] = "obj_defend";
    }
    
    
    onPrecacheGameType()
    {
    	game["bomb_dropped_sound"] = "mp_war_objective_lost";
    	game["bomb_recovered_sound"] = "mp_war_objective_taken";
    
    	precacheShader("waypoint_bomb");
    	precacheShader("hud_suitcase_bomb");
    	precacheShader("waypoint_target");
    	precacheShader("waypoint_target_a");
    	precacheShader("waypoint_target_b");
    	precacheShader("waypoint_defend");
    	precacheShader("waypoint_defend_a");
    	precacheShader("waypoint_defend_b");
    	precacheShader("waypoint_defuse");
    	precacheShader("waypoint_defuse_a");
    	precacheShader("waypoint_defuse_b");
    	precacheShader("waypoint_escort");
    /*
    	precacheShader("waypoint_target");
    	precacheShader("waypoint_target_a");
    	precacheShader("waypoint_target_b");
    	precacheShader("waypoint_defend");
    	precacheShader("waypoint_defend_a");
    	precacheShader("waypoint_defend_b");
    	precacheShader("waypoint_defuse");
    	precacheShader("waypoint_defuse_a");
    	precacheShader("waypoint_defuse_b");
    */	
    	precacheString( &"MP_EXPLOSIVES_RECOVERED_BY" );
    	precacheString( &"MP_EXPLOSIVES_DROPPED_BY" );
    	precacheString( &"MP_EXPLOSIVES_PLANTED_BY" );
    	precacheString( &"MP_EXPLOSIVES_DEFUSED_BY" );
    	precacheString( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
    	precacheString( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
    	precacheString( &"MP_CANT_PLANT_WITHOUT_BOMB" );	
    	precacheString( &"MP_PLANTING_EXPLOSIVE" );	
    	precacheString( &"MP_DEFUSING_EXPLOSIVE" );	
    }
    
    
    onStartGameType()
    {
    	if ( !isDefined( game["switchedsides"] ) )
    		game["switchedsides"] = false;
    	
    	if ( game["switchedsides"] )
    	{
    		oldAttackers = game["attackers"];
    		oldDefenders = game["defenders"];
    		game["attackers"] = oldDefenders;
    		game["defenders"] = oldAttackers;
    	}
    	
    	setClientNameMode( "manual_change" );
    	
    	game["strings"]["target_destroyed"] = &"MP_TARGET_DESTROYED";
    	game["strings"]["bomb_defused"] = &"MP_BOMB_DEFUSED";
    	
    	precacheString( game["strings"]["target_destroyed"] );
    	precacheString( game["strings"]["bomb_defused"] );
    
    	level._effect["bombexplosion"] = loadfx("explosions/tanker_explosion");
    	
    	setObjectiveText( game["attackers"], &"OBJECTIVES_SD_ATTACKER" );
    	setObjectiveText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
    
    	if ( level.splitscreen )
    	{
    		setObjectiveScoreText( game["attackers"], &"OBJECTIVES_SD_ATTACKER" );
    		setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
    	}
    	else
    	{
    		setObjectiveScoreText( game["attackers"], &"OBJECTIVES_SD_ATTACKER_SCORE" );
    		setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_SCORE" );
    	}
    	setObjectiveHintText( game["attackers"], &"OBJECTIVES_SD_ATTACKER_HINT" );
    	setObjectiveHintText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_HINT" );
    
    	level.spawnMins = ( 0, 0, 0 );
    	level.spawnMaxs = ( 0, 0, 0 );	
    	maps\mp\gametypes\_spawnlogic::placeSpawnPoints( "mp_sd_spawn_attacker" );
    	maps\mp\gametypes\_spawnlogic::placeSpawnPoints( "mp_sd_spawn_defender" );
    	
    	level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
    	setMapCenter( level.mapCenter );
    	
    	allowed[0] = "sd";
    	allowed[1] = "bombzone";
    	allowed[2] = "blocker";
    	maps\mp\gametypes\_gameobjects::main(allowed);
    	
    	maps\mp\gametypes\_rank::registerScoreInfo( "win", 2 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "loss", 1 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "tie", 1.5 );
    	
    	maps\mp\gametypes\_rank::registerScoreInfo( "kill", 50 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "headshot", 50 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "assist", 20 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "plant", 100 );
    	maps\mp\gametypes\_rank::registerScoreInfo( "defuse", 100 );
    	
    	thread updateGametypeDvars();
    	
    	thread bombs();
    }
    
    
    getSpawnPoint()
    {
    	if(self.pers["team"] == game["attackers"])
    		spawnPointName = "mp_sd_spawn_attacker";
    	else
    		spawnPointName = "mp_sd_spawn_defender";
    
    	spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( spawnPointName );
    	assert( spawnPoints.size );
    	spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints );
    
    	return spawnpoint;
    }
    
    onSpawnPlayer()
    {
    	self.isPlanting = false;
    	self.isDefusing = false;
    	self.isBombCarrier = false;
    	
    	if ( level.multiBomb && !isDefined( self.carryIcon ) && self.pers["team"] == game["attackers"] && !level.bombPlanted )
    	{
    		if ( level.splitscreen )
    		{
    			self.carryIcon = createIcon( "hud_suitcase_bomb", 33, 33 );
    			self.carryIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", 0, -78 );
    			self.carryIcon.alpha = 0.75;
    		}
    		else
    		{
    			self.carryIcon = createIcon( "hud_suitcase_bomb", 50, 50 );
    			self.carryIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", -90, -65 );
    			self.carryIcon.alpha = 0.75;
    		}
    	}
    	
    	level notify ( "spawned_player" );
    }
    
    
    onPlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, killId)
    {
    	thread checkAllowSpectating();
    }
    
    
    checkAllowSpectating()
    {
    	wait ( 0.05 );
    	
    	update = false;
    	if ( !level.aliveCount[ game["attackers"] ] )
    	{
    		level.spectateOverride[game["attackers"]].allowEnemySpectate = 1;
    		update = true;
    	}
    	if ( !level.aliveCount[ game["defenders"] ] )
    	{
    		level.spectateOverride[game["defenders"]].allowEnemySpectate = 1;
    		update = true;
    	}
    	if ( update )
    		maps\mp\gametypes\_spectating::updateSpectateSettings();
    }
    
    
    sd_endGame( winningTeam, endReasonText )
    {
    	thread maps\mp\gametypes\_gamelogic::endGame( winningTeam, endReasonText );
    }
    
    
    onDeadEvent( team )
    {
    	if ( level.bombExploded || level.bombDefused )
    		return;
    	
    	if ( team == "all" )
    	{
    		if ( level.bombPlanted )
    			sd_endGame( game["attackers"], game["strings"][game["defenders"]+"_eliminated"] );
    		else
    			sd_endGame( game["defenders"], game["strings"][game["attackers"]+"_eliminated"] );
    	}
    	else if ( team == game["attackers"] )
    	{
    		if ( level.bombPlanted )
    			return;
    
    		level thread sd_endGame( game["defenders"], game["strings"][game["attackers"]+"_eliminated"] );
    	}
    	else if ( team == game["defenders"] )
    	{
    		level thread sd_endGame( game["attackers"], game["strings"][game["defenders"]+"_eliminated"] );
    	}
    }
    
    
    onOneLeftEvent( team )
    {
    	if ( level.bombExploded || level.bombDefused )
    		return;
    
    	lastPlayer = getLastLivingPlayer( team );
    
    	lastPlayer thread giveLastOnTeamWarning();
    }
    
    
    onNormalDeath( victim, attacker, lifeId )
    {
    	score = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" );
    	assert( isDefined( score ) );
    
    	team = victim.team;
    	
    	if ( game["state"] == "postgame" && (victim.team == game["defenders"] || !level.bombPlanted) )
    		attacker.finalKill = true;
    		
    	if ( victim.isPlanting )
    	{
    		thread maps\mp\_matchdata::logKillEvent( lifeId, "planting" );
    	}
    	else if ( victim.isBombCarrier )
    	{
    		attacker incPlayerStat( "bombcarrierkills", 1 );
    		thread maps\mp\_matchdata::logKillEvent( lifeId, "carrying" );
    	}
    	else if ( victim.isDefusing )
    	{
    		thread maps\mp\_matchdata::logKillEvent( lifeId, "defusing" );
    	}
    		
    	if ( attacker.isBombCarrier )
    		attacker incPlayerStat( "killsasbombcarrier", 1 );
    }
    
    
    giveLastOnTeamWarning()
    {
    	self endon("death");
    	self endon("disconnect");
    	level endon( "game_ended" );
    		
    	self waitTillRecoveredHealth( 3 );
    	
    	otherTeam = getOtherTeam( self.pers["team"] );
    	level thread teamPlayerCardSplash( "callout_lastteammemberalive", self, self.pers["team"] );
    	level thread teamPlayerCardSplash( "callout_lastenemyalive", self, otherTeam );
    	level notify ( "last_alive", self );	
    	self maps\mp\gametypes\_missions::lastManSD();
    }
    
    
    onTimeLimit()
    {
    	sd_endGame( game["defenders"], game["strings"]["time_limit_reached"] );
    }
    
    
    updateGametypeDvars()
    {
    	level.plantTime = dvarFloatValue( "planttime", 5, 0, 20 );
    	level.defuseTime = dvarFloatValue( "defusetime", 5, 0, 20 );
    	level.bombTimer = dvarFloatValue( "bombtimer", 45, 1, 300 );
    	level.multiBomb = dvarIntValue( "multibomb", 0, 0, 1 );
    }
    
    
    bombs()
    {
    	level.bombPlanted = false;
    	level.bombDefused = false;
    	level.bombExploded = false;
    
    	trigger = getEnt( "sd_bomb_pickup_trig", "targetname" );
    	if ( !isDefined( trigger ) )
    	{
    		error("No sd_bomb_pickup_trig trigger found in map.");
    		return;
    	}
    	
    	visuals[0] = getEnt( "sd_bomb", "targetname" );
    	if ( !isDefined( visuals[0] ) )
    	{
    		error("No sd_bomb script_model found in map.");
    		return;
    	}
    
    	precacheModel( "prop_suitcase_bomb" );	
    	visuals[0] setModel( "prop_suitcase_bomb" );
    	
    	if ( !level.multiBomb )
    	{
    		level.sdBomb = maps\mp\gametypes\_gameobjects::createCarryObject( game["attackers"], trigger, visuals, (0,0,32) );
    		level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "friendly" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_bomb" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_bomb" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "friendly" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setCarryIcon( "hud_suitcase_bomb" );
    		level.sdBomb.allowWeapons = true;
    		level.sdBomb.onPickup = ::onPickup;
    		level.sdBomb.onDrop = ::onDrop;
    	}
    	else
    	{
    		trigger delete();
    		visuals[0] delete();
    	}
    	
    	
    	level.bombZones = [];
    	
    	bombZones = getEntArray( "bombzone", "targetname" );
    	
    	for ( index = 0; index < bombZones.size; index++ )
    	{
    		trigger = bombZones[index];
    		visuals = getEntArray( bombZones[index].target, "targetname" );
    		
    		bombZone = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,64) );
    		bombZone maps\mp\gametypes\_gameobjects::allowUse( "enemy" );
    		bombZone maps\mp\gametypes\_gameobjects::setUseTime( level.plantTime );
    		bombZone maps\mp\gametypes\_gameobjects::setUseText( &"MP_PLANTING_EXPLOSIVE" );
    		bombZone maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
    		if ( !level.multiBomb )
    			bombZone maps\mp\gametypes\_gameobjects::setKeyObject( level.sdBomb );
    		label = bombZone maps\mp\gametypes\_gameobjects::getLabel();
    		bombZone.label = label;
    		bombZone maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_defend" + label );
    		bombZone maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defend" + label );
    		bombZone maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", "waypoint_target" + label );
    		bombZone maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_target" + label );
    		bombZone maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
    		bombZone.onBeginUse = ::onBeginUse;
    		bombZone.onEndUse = ::onEndUse;
    		bombZone.onUse = ::onUsePlantObject;
    		bombZone.onCantUse = ::onCantUse;
    		bombZone.useWeapon = "briefcase_bomb_mp";
    		
    		for ( i = 0; i < visuals.size; i++ )
    		{
    			if ( isDefined( visuals[i].script_exploder ) )
    			{
    				bombZone.exploderIndex = visuals[i].script_exploder;
    				break;
    			}
    		}
    		
    		level.bombZones[level.bombZones.size] = bombZone;
    		
    		bombZone.bombDefuseTrig = getent( visuals[0].target, "targetname" );
    		assert( isdefined( bombZone.bombDefuseTrig ) );
    		bombZone.bombDefuseTrig.origin += (0,0,-10000);
    		bombZone.bombDefuseTrig.label = label;
    	}
    	
    	for ( index = 0; index < level.bombZones.size; index++ )
    	{
    		array = [];
    		for ( otherindex = 0; otherindex < level.bombZones.size; otherindex++ )
    		{
    			if ( otherindex != index )
    				array[ array.size ] = level.bombZones[otherindex];
    		}
    		level.bombZones[index].otherBombZones = array;
    	}
    }
    
    onBeginUse( player )
    {
    	if ( self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
    	{
    		player playSound( "mp_bomb_defuse" );
    		player.isDefusing = true;
    		
    		if ( isDefined( level.sdBombModel ) )
    			level.sdBombModel hide();
    	}
    	else
    	{
    		player.isPlanting = true;
    
    		if ( level.multibomb )
    		{
    			for ( i = 0; i < self.otherBombZones.size; i++ )
    			{
    				//self.otherBombZones[i] maps\mp\gametypes\_gameobjects::disableObject();
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::allowUse( "none" );
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::setVisibleTeam( "friendly" );
    			}
    		}
    	}
    }
    
    onEndUse( team, player, result )
    {
    	if ( !isDefined( player ) )
    		return;
    	
    	if ( isAlive( player ) )
    	{
    		player.isDefusing = false;
    		player.isPlanting = false;
    	}
    	
    	if ( self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
    	{
    		if ( isDefined( level.sdBombModel ) && !result )
    		{
    			level.sdBombModel show();
    		}
    	}
    	else
    	{
    		if ( level.multibomb && !result )
    		{
    			for ( i = 0; i < self.otherBombZones.size; i++ )
    			{
    				//self.otherBombZones[i] maps\mp\gametypes\_gameobjects::enableObject();
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::allowUse( "enemy" );
    				self.otherBombZones[i] maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
    			}
    		}
    	}
    }
    
    onCantUse( player )
    {
    	player iPrintLnBold( &"MP_CANT_PLANT_WITHOUT_BOMB" );
    }
    
    onUsePlantObject( player )
    {
    	// planted the bomb
    	if ( !self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
    	{
    		level thread bombPlanted( self, player );
    		//player logString( "bomb planted: " + self.label );
    		
    		// disable all bomb zones except this one
    		for ( index = 0; index < level.bombZones.size; index++ )
    		{
    			if ( level.bombZones[index] == self )
    				continue;
    				
    			level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
    		}
    		
    		player playSound( "mp_bomb_plant" );
    		player notify ( "bomb_planted" );
    
    		//if ( !level.hardcoreMode )
    		//	iPrintLn( &"MP_EXPLOSIVES_PLANTED_BY", player );
    
    		leaderDialog( "bomb_planted" );
    
    		level thread teamPlayerCardSplash( "callout_bombplanted", player );
    
    		level.bombOwner = player;
    		player thread maps\mp\gametypes\_hud_message::SplashNotify( "plant", maps\mp\gametypes\_rank::getScoreInfoValue( "plant" ) );
    		player thread maps\mp\gametypes\_rank::giveRankXP( "plant" );
    		player.bombPlantedTime = getTime();
    		maps\mp\gametypes\_gamescore::givePlayerScore( "plant", player );	
    		player incPlayerStat( "bombsplanted", 1 );
    		player thread maps\mp\_matchdata::logGameEvent( "plant", player.origin );
    	}
    }
    
    onUseDefuseObject( player )
    {
    	player notify ( "bomb_defused" );
    	//player logString( "bomb defused: " + self.label );
    	level thread bombDefused();
    	
    	// disable this bomb zone
    	self maps\mp\gametypes\_gameobjects::disableObject();
    	
    	//if ( !level.hardcoreMode )
    	//	iPrintLn( &"MP_EXPLOSIVES_DEFUSED_BY", player );
    	leaderDialog( "bomb_defused" );
    
    	level thread teamPlayerCardSplash( "callout_bombdefused", player );
    
    	if ( isDefined( level.bombOwner ) && ( level.bombOwner.bombPlantedTime + 3000 + (level.defuseTime*1000) ) > getTime() && isReallyAlive( level.bombOwner ) )
    		player thread maps\mp\gametypes\_hud_message::SplashNotify( "ninja_defuse", ( maps\mp\gametypes\_rank::getScoreInfoValue( "defuse" ) ) );
    	else
    		player thread maps\mp\gametypes\_hud_message::SplashNotify( "defuse", maps\mp\gametypes\_rank::getScoreInfoValue( "defuse" ) );
    	
    	player thread maps\mp\gametypes\_rank::giveRankXP( "defuse" );
    	maps\mp\gametypes\_gamescore::givePlayerScore( "defuse", player );		
    	player incPlayerStat( "bombsdefused", 1 );
    		player thread maps\mp\_matchdata::logGameEvent( "defuse", player.origin );
    }
    
    
    onDrop( player )
    {
    	self maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_bomb" );
    	self maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_bomb" );
    	
    	maps\mp\_utility::playSoundOnPlayers( game["bomb_dropped_sound"], game["attackers"] );
    }
    
    
    onPickup( player )
    {
    	player.isBombCarrier = true;
    	player incPlayerStat( "bombscarried", 1 );
    	player thread maps\mp\_matchdata::logGameEvent( "pickup", player.origin );
    	
    	self maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_escort" );
    	self maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_escort" );
    
    	if ( !level.bombDefused )
    	{
    		teamPlayerCardSplash( "callout_bombtaken", player, player.team );		
    		leaderDialog( "bomb_taken", player.pers["team"] );
    	}
    	maps\mp\_utility::playSoundOnPlayers( game["bomb_recovered_sound"], game["attackers"] );
    }
    
    
    onReset()
    {
    }
    
    
    bombPlanted( destroyedObj, player )
    {
    	maps\mp\gametypes\_gamelogic::pauseTimer();
    	level.bombPlanted = true;
    	
    	destroyedObj.visuals[0] thread maps\mp\gametypes\_gamelogic::playTickingSound();
    	level.tickingObject = destroyedObj.visuals[0];
    
    	level.timeLimitOverride = true;
    	setGameEndTime( int( gettime() + (level.bombTimer * 1000) ) );
    	setDvar( "ui_bomb_timer", 1 );
    	
    	if ( !level.multiBomb )
    	{
    		level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "none" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
    		level.sdBomb maps\mp\gametypes\_gameobjects::setDropped();
    		level.sdBombModel = level.sdBomb.visuals[0];
    	}
    	else
    	{
    		
    		for ( index = 0; index < level.players.size; index++ )
    		{
    			if ( isDefined( level.players[index].carryIcon ) )
    				level.players[index].carryIcon destroyElem();
    		}
    
    		trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player );
    		
    		tempAngle = randomfloat( 360 );
    		forward = (cos( tempAngle ), sin( tempAngle ), 0);
    		forward = vectornormalize( forward - common_scripts\utility::vector_multiply( trace["normal"], vectordot( forward, trace["normal"] ) ) );
    		dropAngles = vectortoangles( forward );
    		
    		level.sdBombModel = spawn( "script_model", trace["position"] );
    		level.sdBombModel.angles = dropAngles;
    		level.sdBombModel setModel( "prop_suitcase_bomb" );
    	}
    	destroyedObj maps\mp\gametypes\_gameobjects::allowUse( "none" );
    	destroyedObj maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
    	/*
    	destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", undefined );
    	destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", undefined );
    	destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", undefined );
    	destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", undefined );
    	*/
    	label = destroyedObj maps\mp\gametypes\_gameobjects::getLabel();
    	
    	// create a new object to defuse with.
    	trigger = destroyedObj.bombDefuseTrig;
    	trigger.origin = level.sdBombModel.origin;
    	visuals = [];
    	defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,32) );
    	defuseObject maps\mp\gametypes\_gameobjects::allowUse( "friendly" );
    	defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defuseTime );
    	defuseObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_DEFUSING_EXPLOSIVE" );
    	defuseObject maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
    	defuseObject maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
    	defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "waypoint_defuse" + label );
    	defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", "waypoint_defend" + label );
    	defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defuse" + label );
    	defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_defend" + label );
    	defuseObject.label = label;
    	defuseObject.onBeginUse = ::onBeginUse;
    	defuseObject.onEndUse = ::onEndUse;
    	defuseObject.onUse = ::onUseDefuseObject;
    	defuseObject.useWeapon = "briefcase_bomb_defuse_mp";
    	
    	BombTimerWait();
    	setDvar( "ui_bomb_timer", 0 );
    	
    	destroyedObj.visuals[0] maps\mp\gametypes\_gamelogic::stopTickingSound();
    	
    	if ( level.gameEnded || level.bombDefused )
    		return;
    	
    	level.bombExploded = true;
    	
    	explosionOrigin = level.sdBombModel.origin;
    	level.sdBombModel hide();
    	
    	if ( isdefined( player ) )
    	{
    		destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, player );
    		player incPlayerStat( "targetsdestroyed", 1 );
    	}
    	else
    		destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20 );
    	
    	rot = randomfloat(360);
    	explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + (0,0,50), (0,0,1), (cos(rot),sin(rot),0) );
    	triggerFx( explosionEffect );
    
    	PlayRumbleOnPosition( "grenade_rumble", explosionOrigin );
    	earthquake( 0.75, 2.0, explosionOrigin, 2000 );
    	
    	thread playSoundinSpace( "exp_suitcase_bomb_main", explosionOrigin );
    	
    	if ( isDefined( destroyedObj.exploderIndex ) )
    		exploder( destroyedObj.exploderIndex );
    	
    	for ( index = 0; index < level.bombZones.size; index++ )
    		level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
    	defuseObject maps\mp\gametypes\_gameobjects::disableObject();
    	
    	setGameEndTime( 0 );
    	
    	wait 3;
    	
    	sd_endGame( game["attackers"], game["strings"]["target_destroyed"] );
    }
    
    BombTimerWait()
    {
    	level endon( "game_ended" );
    	level endon( "bomb_defused" );
    	
    	maps\mp\gametypes\_hostmigration::waitLongDurationWithGameEndTimeUpdate( level.bombTimer );
    }
    
    
    bombDefused()
    {
    	level.tickingObject maps\mp\gametypes\_gamelogic::stopTickingSound();
    	level.bombDefused = true;
    	setDvar( "ui_bomb_timer", 0 );
    	
    	level notify("bomb_defused");
    	
    	wait 1.5;
    	
    	setGameEndTime( 0 );
    	
    	sd_endGame( game["defenders"], game["strings"]["bomb_defused"] );
    }
    
    initGametypeAwards()
    {
    	maps\mp\_awards::initStatAward( "targetsdestroyed", 	0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombsplanted", 		0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombsdefused", 		0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombcarrierkills", 	0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "bombscarried", 		0, maps\mp\_awards::highestWins );
    	maps\mp\_awards::initStatAward( "killsasbombcarrier", 	0, maps\mp\_awards::highestWins );
    }
    Try to add the _rank.gsc ?

     
    Contributor 01.27.2012 - N/A
    Donator 07-17-2012 - Current
    Editor/Manager 12-16-12 - N/A
    Minion 01-10-2013 - 07.17.13
    Former Staff 09-20-2012 - 01-10-2013 / 07-17-2013 - Current
    Cocksucker 20-04-2013 - N/A

  4. #19
    biffmcgriff69's Avatar
    Join Date
    Jun 2011
    Gender
    male
    Posts
    9
    Reputation
    10
    Thanks
    1
    I want to make it so grenade launchers do no damage. Does this look right?

    Code:
    if(isSubStr(sWeapon, "_gl_"))
    iDamage = 0;
    ^^tried that, didn't work. Can anyone help me out with the tube damage?

    I added a stock _rank.gsc file. People who use the Ump and Intervention still get knife hitmarkers.
    Last edited by biffmcgriff69; 06-10-2011 at 03:26 PM.

  5. #20
    mathieutje12's Avatar
    Join Date
    Jan 2010
    Gender
    male
    Location
    Close to my PC
    Posts
    578
    Reputation
    14
    Thanks
    165
    My Mood
    Angelic
    u added in under Callback_PlayerDamage_internal()?

    Or u can try this:
    Code:
    getWepDamageUMP45(sHitLoc, iDamage) {
    	switch( sHitLoc )
    	{
    		case "helmet":
    		case "head":
    		case "neck":
    			return 38;
    		case "torso_upper":
    		case "torso_lower":
    			return 34;
    		case "right_arm_upper":
    		case "left_arm_upper":
    			return 29;
    		case "right_arm_lower":
    		case "left_arm_lower":
    			return 28;
    		case "right_hand":
    		case "left_hand":
    		case "gun":
    			return 27;
    		case "right_leg_upper":
    		case "left_leg_upper":
    			return 16;
    		case "right_leg_lower":
    		case "left_leg_lower":
    			return 18;
    		case "right_foot":
    		case "left_foot":
    			return 15;
    	}
    	return iDamage;
    }
    
    if(isSubStr(sWeapon, "ump45_")) 
    	{
    		return getWepDamageUMP45(sHitLoc, iDamage);
    	}
    Last edited by mathieutje12; 06-10-2011 at 03:32 PM.

  6. #21
    biffmcgriff69's Avatar
    Join Date
    Jun 2011
    Gender
    male
    Posts
    9
    Reputation
    10
    Thanks
    1
    Quote Originally Posted by mathieutje12 View Post
    u added in under Callback_PlayerDamage_internal()?
    Yeah, I added it under that section.

    Another thing that I need help with...I tried to make grenade launchers do no damage so I put this line in:
    Code:
    if(isSubStr(sWeapon, "gl_"))
    iDamage = 0;
    and tubes do 0 damage now which is good. The problem is that if a gun has tubes on it the bullets don't kill either.
    Last edited by biffmcgriff69; 06-10-2011 at 04:47 PM.

Page 2 of 2 FirstFirst 12