Results 1 to 8 of 8
  1. #1
    NiNeOner's Avatar
    Join Date
    May 2011
    Gender
    male
    Posts
    16
    Reputation
    10
    Thanks
    0
    My Mood
    Happy

    Error Too many open { I can't find it.

    Hey i have two gsc files wich both have too many open { and i can't find where it is i have tried looking through it twice now =s. If someone could help me that would be greatly appreciated. I hope to see some replys lol.
    Code:
    #include maps\mp\_utility;
    
    init()
    {
    	if ( !isDefined( game["gamestarted"] ) )
    	{
    		game["menu_team"] = "team_marinesopfor";
    		game["menu_class_allies"] = "class_marines";
    		game["menu_changeclass_allies"] = "changeclass_marines";
    		game["menu_initteam_allies"] = "initteam_marines";
    		game["menu_class_axis"] = "class_opfor";
    		game["menu_changeclass_axis"] = "changeclass_opfor";
    		game["menu_initteam_axis"] = "initteam_opfor";
    		game["menu_class"] = "class";
    		game["menu_changeclass"] = "changeclass";
    		game["menu_onemanarmy"] = "onemanarmy";
    		game["menu_controls"] = "ingame_controls";
    	
    		if ( !level.console )
    		{
    			game["menu_muteplayer"] = "muteplayer";
    			precacheMenu(game["menu_muteplayer"]);			
    		}
    		else
    		{
    			//game["menu_options"] = "ingame_options";
    			game["menu_leavegame"] = "popup_leavegame";
    	
    			if(level.splitscreen)
    			{
    				game["menu_team"] += "_splitscreen";
    				game["menu_class_allies"] += "_splitscreen";
    				game["menu_changeclass_allies"] += "_splitscreen";
    				game["menu_class_axis"] += "_splitscreen";
    				game["menu_changeclass_axis"] += "_splitscreen";
    				game["menu_class"] += "_splitscreen";
    				game["menu_controls"] += "_splitscreen";
    				//game["menu_options"] += "_splitscreen";
    				game["menu_leavegame"] += "_splitscreen";
    				game["menu_onemanarmy"] += "_splitscreen";
    
    				game["menu_changeclass_defaults_splitscreen"] = "changeclass_defaults_splitscreen";
    				game["menu_changeclass_custom_splitscreen"] = "changeclass_custom_splitscreen";
    				game["menu_onemanarmy_defaults_splitscreen"] = "onemanarmy_defaults_splitscreen";
    				game["menu_onemanarmy_custom_splitscreen"] = "onemanarmy_custom_splitscreen";
    				
    				precacheMenu(game["menu_changeclass_defaults_splitscreen"]);
    				precacheMenu(game["menu_changeclass_custom_splitscreen"]);
    				precacheMenu(game["menu_onemanarmy_defaults_splitscreen"]);
    				precacheMenu(game["menu_onemanarmy_custom_splitscreen"]);
    			}
    	
    			precacheMenu(game["menu_controls"]);
    			//precacheMenu(game["menu_options"]);
    			precacheMenu(game["menu_leavegame"]);
    			
    			//precacheMenu("status_update");
    		}
    	
    		precacheMenu("scoreboard");
    		precacheMenu(game["menu_team"]);
    		precacheMenu(game["menu_class_allies"]);
    		precacheMenu(game["menu_changeclass_allies"]);
    		precacheMenu(game["menu_initteam_allies"]);
    		precacheMenu(game["menu_class_axis"]);
    		precacheMenu(game["menu_changeclass_axis"]);
    		precacheMenu(game["menu_class"]);
    		precacheMenu(game["menu_changeclass"]);
    		precacheMenu(game["menu_initteam_axis"]);
    		precacheMenu(game["menu_onemanarmy"]);
    		
    		precacheString( &"MP_HOST_ENDED_GAME" );
    		precacheString( &"MP_HOST_ENDGAME_RESPONSE" );
    	}
    
    	level thread onPlayerConnect();
    }
    
    onPlayerConnect()
    {
    	for(;;)
    	{
    		level waittill("connected", player);
    
    		player thread onMenuResponse();
    	}
    }
    
    
    isOptionsMenu( menu )
    {
    	if ( menu == game["menu_changeclass"] )
    		return true;
    		
    	if ( menu == game["menu_team"] )
    		return true;
    
    	if ( menu == game["menu_controls"] )
    		return true;
    
    	if ( isSubStr( menu, "pc_options" ) )
    		return true;
    
    	return false;
    }
    
    
    onMenuResponse()
    {
    	self endon("disconnect");
    	
    	for(;;)
    	{
    		self waittill("menuresponse", menu, response);
    		
    		if ( response == "back" )
    		{
    			self closepopupMenu();
    			self closeInGameMenu();
    
    			if ( isOptionsMenu( menu ) )
    			{
    				if( self.pers["team"] == "allies" )
    					self openpopupMenu( game["menu_class_allies"] );
    				if( self.pers["team"] == "axis" )
    					self openpopupMenu( game["menu_class_axis"] );
    			}
    			continue;
    		}
    		
    		if(response == "changeteam")
    		{
    			self closepopupMenu();
    			self closeInGameMenu();
    			self openpopupMenu(game["menu_team"]);
    		}
    	
    		if(response == "changeclass_marines" )
    		{
    			self closepopupMenu();
    			self closeInGameMenu();
    			//self openpopupMenu( game["menu_changeclass_allies"] );
    			continue;
    		}
    
    		if(response == "changeclass_opfor" )
    		{
    			self closepopupMenu();
    			self closeInGameMenu();
    			//self openpopupMenu( game["menu_changeclass_axis"] );
    			continue;
    		}
    
    		if(response == "changeclass_marines_splitscreen" )
    			self openpopupMenu( "changeclass_marines_splitscreen" );
    
    		if(response == "changeclass_opfor_splitscreen" )
    			self openpopupMenu( "changeclass_opfor_splitscreen" );
    		
    		if(response == "endgame")
    		{
    			if(level.splitscreen)
    			{
    				endparty();
    
    				if ( !level.gameEnded )
    				{
    					//level thread maps\mp\gametypes\_gamelogic::forceEnd();
    				}
    			}
    				
    			continue;
    		}
    
    		if ( response == "endround" )
    		{
    			if ( !level.gameEnded && self isHost())
    			{
    				level thread maps\mp\gametypes\_gamelogic::forceEnd();
    			}
    			else
    			{
    				self closepopupMenu();
    				self closeInGameMenu();
    				self iprintln( &"MP_HOST_ENDGAME_RESPONSE" );
    			}			
    			continue;
    		}
    
    		if(menu == game["menu_team"])
    		{
    			switch(response)
    			{
    			case "allies":
    				self [[level.allies]]();
    				break;
    
    			case "axis":
    				self [[level.axis]]();
    				break;
    
    			case "autoassign":
    				self [[level.autoassign]]();
    				break;
    
    			case "spectator":
    				self [[level.spectator]]();
    				break;
    			}
    		}	// the only responses remain are change class events
    		else if ( menu == game["menu_changeclass"] ||
    				( isDefined( game["menu_changeclass_defaults_splitscreen"] ) && menu == game["menu_changeclass_defaults_splitscreen"] ) ||
    				( isDefined( game["menu_changeclass_custom_splitscreen"] ) && menu == game["menu_changeclass_custom_splitscreen"] ) )
    		{
    			self closepopupMenu();
    			self closeInGameMenu();
    
    			self.selectedClass = true;
    			self [[level.class]](response);
    		}
    		else if ( !level.console )
    		{
    			if(menu == game["menu_quickcommands"])
    				maps\mp\gametypes\_quickmessages::quickcommands(response);
    			else if(menu == game["menu_quickstatements"])
    				maps\mp\gametypes\_quickmessages::quickstatements(response);
    			else if(menu == game["menu_quickresponses"])
    				maps\mp\gametypes\_quickmessages::quickresponses(response);
    		}
    	}
    }
    
    
    getTeamAssignment()
    {
    	teams[0] = "allies";
    	teams[1] = "axis";
    	
    	if ( !level.teamBased )
    		return teams[randomInt(2)];
    
    	if ( self.sessionteam != "none" && self.sessionteam != "spectator" && self.sessionstate != "playing" && self.sessionstate != "dead" )
    	{
    		assignment = self.sessionteam;
    	}
    	else
    	{
    		playerCounts = self maps\mp\gametypes\_teams::CountPlayers();
    				
    		// if teams are equal return the team with the lowest score
    		if ( playerCounts["allies"] == playerCounts["axis"] )
    		{
    			if( getTeamScore( "allies" ) == getTeamScore( "axis" ) )
    				assignment = teams[randomInt(2)];
    			else if ( getTeamScore( "allies" ) < getTeamScore( "axis" ) )
    				assignment = "allies";
    			else
    				assignment = "axis";
    		}
    		else if( playerCounts["allies"] < playerCounts["axis"] )
    		{
    			assignment = "allies";
    		}
    		else
    		{
    			assignment = "axis";
    		}
    	}
    	
    	return assignment;
    }
    
    
    menuAutoAssign()
    {
    	self closeMenus();
    
    	assignment = getTeamAssignment();
    		
    	if ( isDefined( self.pers["team"] ) && (self.sessionstate == "playing" || self.sessionstate == "dead") )
    	{
    		if ( assignment == self.pers["team"] )
    		{
    			self beginClassChoice();
    			return;
    		}
    		else
    		{
    			self.switching_teams = true;
    			self.joining_team = assignment;
    			self.leaving_team = self.pers["team"];
    			self suicide();
    		}
    	}
    
    	self addToTeam( assignment );
    	self.pers["class"] = undefined;
    	self.class = undefined;
    	
    	if ( !isAlive( self ) )
    		self.statusicon = "hud_status_dead";
    	
    	self notify("end_respawn");
    	
    	self beginClassChoice();
    }
    
    
    beginClassChoice( forceNewChoice )
    {
    	assert( self.pers["team"] == "axis" || self.pers["team"] == "allies" );
    	
    	team = self.pers["team"];
    
    	// menu_changeclass_team is the one where you choose one of the n classes to play as.
    	// menu_class_team is where you can choose to change your team, class, controls, or leave game.
    	//self openpopupMenu( game[ "menu_changeclass_" + team ] );
    	
    	self menuClass(0);
    	
    	if ( !isAlive( self ) )
    		self thread maps\mp\gametypes\_playerlogic::predictAboutToSpawnPlayerOverTime( 0.1 );
    }
    
    
    beginTeamChoice()
    {
    	self openpopupMenu( game["menu_team"] );
    }
    
    
    showMainMenuForTeam()
    {
    	assert( self.pers["team"] == "axis" || self.pers["team"] == "allies" );
    	
    	team = self.pers["team"];
    	
    	// menu_changeclass_team is the one where you choose one of the n classes to play as.
    	// menu_class_team is where you can choose to change your team, class, controls, or leave game.	
    	self openpopupMenu( game[ "menu_class_" + team ] );
    }
    
    menuAllies()
    {
    	self closeMenus();
    	
    	if(self.pers["team"] != "allies")
    	{
    		if( level.teamBased && !maps\mp\gametypes\_teams::getJoinTeamPermissions( "allies" ) )
    		{
    			self openpopupMenu(game["menu_team"]);
    			return;
    		}
    		
    		// allow respawn when switching teams during grace period.
    		if ( level.inGracePeriod && !self.hasDoneCombat )
    			self.hasSpawned = false;
    			
    		if(self.sessionstate == "playing")
    		{
    			self.switching_teams = true;
    			self.joining_team = "allies";
    			self.leaving_team = self.pers["team"];
    			self suicide();
    		}
    
    		self addToTeam( "allies" );
    		self.pers["class"] = undefined;
    		self.class = undefined;
    
    		self notify("end_respawn");
    	}
    	
    	self beginClassChoice();
    }
    
    
    menuAxis()
    {
    	self closeMenus();
    	
    	if(self.pers["team"] != "axis")
    	{
    		if( level.teamBased && !maps\mp\gametypes\_teams::getJoinTeamPermissions( "axis" ) )
    		{
    			self openpopupMenu(game["menu_team"]);
    			return;
    		}
    
    		// allow respawn when switching teams during grace period.
    		if ( level.inGracePeriod && !self.hasDoneCombat )
    			self.hasSpawned = false;
    
    		if(self.sessionstate == "playing")
    		{
    			self.switching_teams = true;
    			self.joining_team = "axis";
    			self.leaving_team = self.pers["team"];
    			self suicide();
    		}
    
    		self addToTeam( "axis" );
    		self.pers["class"] = undefined;
    		self.class = undefined;
    
    		self notify("end_respawn");
    	}
    	
    	self beginClassChoice();
    }
    
    
    menuSpectator()
    {
    	self closeMenus();
    	
    	if( isDefined( self.pers["team"] ) && self.pers["team"] == "spectator" )
    		return;
    
    	if( isAlive( self ) )
    	{
    		assert( isDefined( self.pers["team"] ) );
    		self.switching_teams = true;
    		self.joining_team = "spectator";
    		self.leaving_team = self.pers["team"];
    		self suicide();
    	}
    
    	self addToTeam( "spectator" );
    	self.pers["class"] = undefined;
    	self.class = undefined;
    
    	self thread maps\mp\gametypes\_playerlogic::spawnSpectator();
    }
    
    
    menuClass( response )
    {
    	self closeMenus();
    	
    	// clear new status of unlocked classes
    	if ( response == "demolitions_mp,0" && self getPlayerData( "featureNew", "demolitions" ) )
    	{
    		self setPlayerData( "featureNew", "demolitions", false );
    	}
    	if ( response == "sniper_mp,0" && self getPlayerData( "featureNew", "sniper" ) )
    	{
    		self setPlayerData( "featureNew", "sniper", false );
    	}
    
    	// this should probably be an assert
    	if(!isDefined(self.pers["team"]) || (self.pers["team"] != "allies" && self.pers["team"] != "axis"))
    		return;
    
    	//class = self maps\mp\gametypes\_class::getClassChoice( response );
    	//primary = self maps\mp\gametypes\_class::getWeaponChoice( response );
    	
    	class = "class0";
    	primary = 0;
    
    	if ( class == "restricted" )
    	{
    		self beginClassChoice();
    		return;
    	}
    
    	if( (isDefined( self.pers["class"] ) && self.pers["class"] == class) && 
    		(isDefined( self.pers["primary"] ) && self.pers["primary"] == primary) )
    		return;
    
    	if ( self.sessionstate == "playing" )
    	{
    		//self.pers["class"] = class;
    		//self.class = class;
    		//self.pers["primary"] = primary;
    
    		if ( game["state"] == "postgame" )
    			return;
    
    		/*if ( level.inGracePeriod && !self.hasDoneCombat ) // used weapons check?
    		{
    			self maps\mp\gametypes\_class::setClass( self.pers["class"] );
    			self.tag_stowed_back = undefined;
    			self.tag_stowed_hip = undefined;
    			self maps\mp\gametypes\_class::giveLoadout( self.pers["team"], self.pers["class"] );
    		}
    		else
    		{*/
    			//self iPrintLnBold( game["strings"]["change_class"] );
    		//}
    	}
    	else
    	{
    		self.pers["class"] = class;
    		self.class = class;
    		self.pers["primary"] = primary;
    
    		if ( game["state"] == "postgame" )
    			return;
    
    		if ( game["state"] == "playing" && !isInKillcam() )
    			self thread maps\mp\gametypes\_playerlogic::spawnClient();
    	}
    
    	self thread maps\mp\gametypes\_spectating::setSpectatePermissions();
    }
    
    
    
    addToTeam( team, firstConnect )
    {
    	// UTS update playerCount remove from team
    	if ( isDefined( self.team ) )
    		self maps\mp\gametypes\_playerlogic::removeFromTeamCount();
    		
    	self.pers["team"] = team;
    	// this is the only place self.team should ever be set
    	self.team = team;
    	
    	// session team is readonly in ranked matches on console
    	if ( !matchMakingGame() || isDefined( self.pers["isBot"] ) )
    	{
    		if ( level.teamBased )
    		{
    			self.sessionteam = team;
    		}
    		else
    		{
    			if ( team == "spectator" )
    				self.sessionteam = "spectator";
    			else
    				self.sessionteam = "none";
    		}
    	}
    
    	// UTS update playerCount add to team
    	if ( game["state"] != "postgame" )
    		self maps\mp\gametypes\_playerlogic::addToTeamCount();	
    
    	self updateObjectiveText();
    
    	// give "joined_team" and "joined_spectators" handlers a chance to start
    	// these are generally triggered from the "connected" notify, which can happen on the same
    	// frame as these notifies
    	if ( isDefined( firstConnect ) && firstConnect )
    		waittillframeend;
    
    	self updateMainMenu();
    
    	if ( team == "spectator" )
    	{
    		self notify( "joined_spectators" );
    		level notify( "joined_team" );
    	}
    	else
    	{
    		self notify( "joined_team" );
    		level notify( "joined_team" );
    	}
    }
    Code:
    #include common_scripts\utility;
    #include maps\mp\_utility;
    
    
    attachmentGroup( attachmentName )
    {
    	return tableLookup( "mp/attachmentTable.csv", 4, attachmentName, 2 );
    }
    
    getAttachmentList()
    {
    	attachmentList = [];
    	
    	index = 0;
    	attachmentName = tableLookup( "mp/attachmentTable.csv", 9, index, 4 );
    	
    	while ( attachmentName != "" )
    	{
    		attachmentList[attachmentList.size] = attachmentName;
    		
    		index++;
    		attachmentName = tableLookup( "mp/attachmentTable.csv", 9, index, 4 );
    	}
    	
    	return alphabetize( attachmentList );
    }
    
    init()
    {
    	level.scavenger_altmode = true;
    	level.scavenger_secondary = true;
    	
    	// 0 is not valid
    	level.maxPerPlayerExplosives = max( getIntProperty( "scr_maxPerPlayerExplosives", 2 ), 1 );
    	level.riotShieldXPBullets = getIntProperty( "scr_riotShieldXPBullets", 15 );
    
    	switch ( getIntProperty( "perk_scavengerMode", 0 ) )
    	{
    		case 1: // disable altmode
    			level.scavenger_altmode = false;
    			break;
    
    		case 2: // disable secondary
    			level.scavenger_secondary = false;
    			break;
    			
    		case 3: // disable altmode and secondary
    			level.scavenger_altmode = false;
    			level.scavenger_secondary = false;
    			break;		
    	}
    	
    	attachmentList = getAttachmentList();	
    	
    	// assigns weapons with stat numbers from 0-149
    	// attachments are now shown here, they are per weapon settings instead
    	
    	max_weapon_num = 149;
    
    	level.weaponList = [];
    	for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
    	{
    		weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
    		if( weapon_name == "" )
    			continue;
    	
    		if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
    			continue;
    			
    		level.weaponList[level.weaponList.size] = weapon_name + "_mp";
    		/#
    		if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    		{
    			printLn( "" );
    			printLn( "// " + weapon_name + " real assets" );
    			printLn( "weapon,mp/" + weapon_name + "_mp" );
    		}
    		#/
    
    		// the alphabetize function is slow so we try not to do it for every weapon/attachment combo; a code solution would be better.
    		attachmentNames = [];
    		for ( innerLoopCount = 0; innerLoopCount < 10; innerLoopCount++ )
    		{
    			// generating attachment combinations
    			attachmentName = tablelookup( "mp/statStable.csv", 0, weaponId, innerLoopCount + 11 );
    			
    			if( attachmentName == "" )
    				break;
    			
    			attachmentNames[attachmentName] = true;
    		}
    
    		// generate an alphabetized attachment list
    		attachments = [];
    		foreach ( attachmentName in attachmentList )
    		{
    			if ( !isDefined( attachmentNames[attachmentName] ) )
    				continue;
    				
    			level.weaponList[level.weaponList.size] = weapon_name + "_" + attachmentName + "_mp";
    			attachments[attachments.size] = attachmentName;
    			/#
    			if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    				println( "weapon,mp/" + weapon_name + "_" + attachmentName + "_mp" );
    			#/
    		}
    
    		attachmentCombos = [];
    		for ( i = 0; i < (attachments.size - 1); i++ )
    		{
    			colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, attachments[i] );
    			for ( j = i + 1; j < attachments.size; j++ )
    			{
    				if ( tableLookup( "mp/attachmentCombos.csv", 0, attachments[j], colIndex ) == "no" )
    					continue;
    					
    				attachmentCombos[attachmentCombos.size] = attachments[i] + "_" + attachments[j];
    			}
    		}
    
    		/#
    		if ( getDvar( "scr_dump_weapon_assets" ) != "" && attachmentCombos.size )
    			println( "// " + weapon_name + " virtual assets" );
    		#/
    		
    		foreach ( combo in attachmentCombos )
    		{
    			/#
    			if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    				println( "weapon,mp/" + weapon_name + "_" + combo + "_mp" );
    			#/
    
    			level.weaponList[level.weaponList.size] = weapon_name + "_" + combo + "_mp";
    		}
    	}
    
    	foreach ( weaponName in level.weaponList )
    	{
    		precacheItem( weaponName );
    		
    		/#
    		if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    		{
    			altWeapon = weaponAltWeaponName( weaponName );
    			if ( altWeapon != "none" )
    				println( "weapon,mp/" + altWeapon );				
    		}
    		#/
    	}
    
    	precacheItem( "flare_mp" );
    	precacheItem( "scavenger_bag_mp" );
    	precacheItem( "frag_grenade_short_mp" );	
    	precacheItem( "destructible_car" );
    	
    	precacheShellShock( "default" );
    	precacheShellShock( "concussion_grenade_mp" );
    	thread maps\mp\_flashgrenades::main();
    	thread maps\mp\_entityheadicons::init();
    
    	claymoreDetectionConeAngle = 70;
    	level.claymoreDetectionDot = cos( claymoreDetectionConeAngle );
    	level.claymoreDetectionMinDist = 20;
    	level.claymoreDetectionGracePeriod = .75;
    	level.claymoreDetonateRadius = 192;
    	
    	// this should move to _stinger.gsc
    	level.stingerFXid = loadfx ("explosions/aerial_explosion_large");
    
    	// generating weapon type arrays which classifies the weapon as primary (back stow), pistol, or inventory (side pack stow)
    	// using mp/statstable.csv's weapon grouping data ( numbering 0 - 149 )
    	level.primary_weapon_array = [];
    	level.side_arm_array = [];
    	level.grenade_array = [];
    	level.inventory_array = [];
    	level.stow_priority_model_array = [];
    	level.stow_offset_array = [];
    	
    	max_weapon_num = 149;
    	for( i = 0; i < max_weapon_num; i++ )
    	{
    		weapon = tableLookup( "mp/statsTable.csv", 0, i, 4 );
    		stow_model = tableLookup( "mp/statsTable.csv", 0, i, 9 );
    		
    		if ( stow_model == "" )
    			continue;
    
    		precacheModel( stow_model );		
    
    		if ( isSubStr( stow_model, "weapon_stow_" ) )
    			level.stow_offset_array[ weapon ] = stow_model;
    		else
    			level.stow_priority_model_array[ weapon + "_mp" ] = stow_model;
    	}
    	
    	precacheModel( "weapon_claymore_bombsquad" );
    	precacheModel( "weapon_c4_bombsquad" );
    	precacheModel( "projectile_m67fraggrenade_bombsquad" );
    	precacheModel( "projectile_semtex_grenade_bombsquad" );
    	precacheModel( "weapon_light_stick_tactical_bombsquad" );
    	
    	level.killStreakSpecialCaseWeapons = [];
    	level.killStreakSpecialCaseWeapons["cobra_player_minigun_mp"] = true;
    	level.killStreakSpecialCaseWeapons["artillery_mp"] = true;
    	level.killStreakSpecialCaseWeapons["stealth_bomb_mp"] = true;
    	level.killStreakSpecialCaseWeapons["pavelow_minigun_mp"] = true;
    	level.killStreakSpecialCaseWeapons["sentry_minigun_mp"] = true;
    	level.killStreakSpecialCaseWeapons["harrier_20mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["ac130_105mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["ac130_40mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["ac130_25mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["remotemissile_projectile_mp"] = true;
    	level.killStreakSpecialCaseWeapons["cobra_20mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["sentry_minigun_mp"] = true;
    
    	
    	level thread onPlayerConnect();
    	
    	level.c4explodethisframe = false;
    
    	array_thread( getEntArray( "misc_turret", "classname" ), ::turret_monitorUse );
    	
    //	thread dumpIt();
    }
    
    
    dumpIt()
    {
    	
    	wait ( 5.0 );
    	/#
    	max_weapon_num = 149;
    
    	for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
    	{
    		weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
    		if( weapon_name == "" )
    			continue;
    	
    		if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
    			continue;
    			
    		if ( getDvar( "scr_dump_weapon_challenges" ) != "" )
    		{
    			/*
    			sharpshooter
    			marksman
    			veteran
    			expert
    			master
    			*/
    
    			weaponLStringName = tableLookup( "mp/statsTable.csv", 0, weaponId, 3 );
    			weaponRealName = tableLookupIString( "mp/statsTable.csv", 0, weaponId, 3 );
    
    			prefix = "WEAPON_";
    			weaponCapsName = getSubStr( weaponLStringName, prefix.size, weaponLStringName.size );
    
    			weaponGroup = tableLookup( "mp/statsTable.csv", 0, weaponId, 2 );
    			
    			weaponGroupSuffix = getSubStr( weaponGroup, prefix.size, weaponGroup.size );
    
    			/*
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_SHARPSHOOTER" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Sharpshooter" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_MARKSMAN" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Marksman" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_VETERAN" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Veteran" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_EXPERT" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Expert" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_Master" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Master" );
    			*/
    			
    			iprintln( "cardtitle_" + weapon_name + "_sharpshooter,PLAYERCARDS_TITLE_" + weaponCapsName + "_SHARPSHOOTER,cardtitle_" + weaponGroupSuffix + "_sharpshooter,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_marksman,PLAYERCARDS_TITLE_" + weaponCapsName + "_MARKSMAN,cardtitle_" + weaponGroupSuffix + "_marksman,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_veteran,PLAYERCARDS_TITLE_" + weaponCapsName + "_VETERAN,cardtitle_" + weaponGroupSuffix + "_veteran,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_expert,PLAYERCARDS_TITLE_" + weaponCapsName + "_EXPERT,cardtitle_" + weaponGroupSuffix + "_expert,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_master,PLAYERCARDS_TITLE_" + weaponCapsName + "_MASTER,cardtitle_" + weaponGroupSuffix + "_master,1,1,1" );
    			
    			wait ( 0.05 );
    		}
    	}
    	#/
    }
    
    bombSquadWaiter()
    {
    	self endon ( "disconnect" );
    	
    	for ( ;; )
    	{
    		self waittill ( "grenade_fire", weaponEnt, weaponName );
    		
    		team = level.otherTeam[self.team];
    		
    		if ( weaponName == "c4_mp" )
    			weaponEnt thread createBombSquadModel( "weapon_c4_bombsquad", "tag_origin", team, self );
    		else if ( weaponName == "claymore_mp" )
    			weaponEnt thread createBombSquadModel( "weapon_claymore_bombsquad", "tag_origin", team, self );
    		else if ( weaponName == "frag_grenade_mp" )
    			weaponEnt thread createBombSquadModel( "projectile_m67fraggrenade_bombsquad", "tag_weapon", team, self );
    		else if ( weaponName == "frag_grenade_short_mp" )
    			weaponEnt thread createBombSquadModel( "projectile_m67fraggrenade_bombsquad", "tag_weapon", team, self );
    		else if ( weaponName == "semtex_mp" )
    			weaponEnt thread createBombSquadModel( "projectile_semtex_grenade_bombsquad", "tag_weapon", team, self );
    	}
    }
    
    
    createBombSquadModel( modelName, tagName, teamName, owner )
    {
    	bombSquadModel = spawn( "script_model", (0,0,0) );
    	bombSquadModel hide();
    	wait ( 0.05 );
    	
    	if (!isDefined( self ) ) //grenade model may not be around if picked up
    		return;
    		
    	bombSquadModel thread bombSquadVisibilityUpdater( teamName, owner );
    	bombSquadModel setModel( modelName );
    	bombSquadModel linkTo( self, tagName, (0,0,0), (0,0,0) );
    	bombSquadModel SetContents( 0 );
    	
    	self waittill ( "death" );
    	
    	bombSquadModel delete();
    }
    
    
    bombSquadVisibilityUpdater( teamName, owner )
    {
    	self endon ( "death" );
    
    	foreach ( player in level.players )
    	{
    		if ( level.teamBased )
    		{
    			if ( player.team == teamName && player _hasPerk( "specialty_detectexplosive" ) )
    				self showToPlayer( player );
    		}
    		else
    		{
    			if ( isDefined( owner ) && player == owner )
    				continue;
    			
    			if ( !player _hasPerk( "specialty_detectexplosive" ) )
    				continue;
    				
    			self showToPlayer( player );
    		}		
    	}
    	
    	for ( ;; )
    	{
    		level waittill_any( "joined_team", "player_spawned", "changed_kit" );
    		
    		self hide();
    
    		foreach ( player in level.players )
    		{
    			if ( level.teamBased )
    			{
    				if ( player.team == teamName && player _hasPerk( "specialty_detectexplosive" ) )
    					self showToPlayer( player );
    			}
    			else
    			{
    				if ( isDefined( owner ) && player == owner )
    					continue;
    				
    				if ( !player _hasPerk( "specialty_detectexplosive" ) )
    					continue;
    					
    				self showToPlayer( player );
    			}		
    		}
    	}
    }
    
    
    onPlayerConnect()
    {
    	for(;;)
    	{
    		level waittill("connected", player);
    
    		player.hits = 0;
    		player.hasDoneCombat = false;
    
    		player KC_RegWeaponForFXRemoval( "remotemissile_projectile_mp" );
    
    		player thread onPlayerSpawned();
    		player thread bombSquadWaiter();
    	}
    }
    
    
    onPlayerSpawned()
    {
    	self endon("disconnect");
    
    	for(;;)
    	{
    		self waittill("spawned_player");
    		
    		self.currentWeaponAtSpawn = self getCurrentWeapon(); // optimization so these threads we start don't have to call it.
    		
    		self.empEndTime = 0;
    		self.concussionEndTime = 0;
    		self.hasDoneCombat = false;
    		self thread watchWeaponUsage();
    		self thread watchGrenadeUsage();
    		self thread watchWeaponChange();
    		self thread watchStingerUsage();
    		self thread watchJavelinUsage();
    		self thread watchMissileUsage();
    		self thread watchSentryUsage();
    		self thread watchWeaponReload();
    		self thread maps\mp\gametypes\_class::trackRiotShield();
    
    		self.lastHitTime = [];
    		
    		self.droppedDeathWeapon = undefined;
    		self.tookWeaponFrom = [];
    		
    		self thread updateStowedWeapon();
    		
    		self thread updateSavedLastWeapon();
    		
    		if ( self hasWeapon( "semtex_mp" ) )
    			self thread monitorSemtex();
    		
    		self.currentWeaponAtSpawn = undefined;
    	}
    }
    
    WatchStingerUsage()
    {
    	self maps\mp\_stinger::StingerUsageLoop();
    }
    
    
    WatchJavelinUsage()
    {
    	self maps\mp\_javelin::JavelinUsageLoop();
    }
    
    watchWeaponChange()
    {
    	self endon("death");
    	self endon("disconnect");
    	
    	self thread watchStartWeaponChange();
    	self.lastDroppableWeapon = undefined;
    	self.hitsThisMag = [];
    
    	weapon = self getCurrentWeapon();
    	
    	if ( isCACPrimaryWeapon( weapon ) && !isDefined( self.hitsThisMag[ weapon ] ) )
    		self.hitsThisMag[ weapon ] = weaponClipSize( weapon );
    
    	self.bothBarrels = undefined;
    
    	if ( isSubStr( weapon, "ranger" ) )
    		self thread watchRangerUsage( weapon );
    
    	while(1)
    	{
    		self waittill( "weapon_change", newWeapon );
    		
    		tokedNewWeapon = StrTok( newWeapon, "_" );
    
    		self.bothBarrels = undefined;
    
    		if ( isSubStr( newWeapon, "ranger" ) )
    			self thread watchRangerUsage( newWeapon );
    
    		if ( tokedNewWeapon[0] == "gl" || ( tokedNewWeapon.size > 2 && tokedNewWeapon[2] == "attach" ) )
    			newWeapon = self getCurrentPrimaryWeapon();
    
    		if ( newWeapon != "none" )
    		{
    			if ( isCACPrimaryWeapon( newWeapon ) && !isDefined( self.hitsThisMag[ newWeapon ] ) )
    				self.hitsThisMag[ newWeapon ] = weaponClipSize( newWeapon );
    		}
    		self.changingWeapon = undefined;
    		if ( mayDropWeapon( newWeapon ) )
    			self.lastDroppableWeapon = newWeapon;
    	}
    }
    
    
    watchStartWeaponChange()
    {
    	self endon("death");
    	self endon("disconnect");
    	self.changingWeapon = undefined;
    
    	while(1)
    	{
    		self waittill( "weapon_switch_started", newWeapon );
    		self.changingWeapon = newWeapon;
    	}
    }
    
    watchWeaponReload()
    {
    	self endon("death");
    	self endon("disconnect");
    
    	for ( ;; )
    	{
    		self waittill( "reload" );
    
    		weaponName = self getCurrentWeapon();
    
    		self.bothBarrels = undefined;
    		
    		if ( !isSubStr( weaponName, "ranger" ) )
    			continue;
    
    		self thread watchRangerUsage( weaponName );
    	}
    }
    
    
    watchRangerUsage( rangerName )
    {
    	rightAmmo = self getWeaponAmmoClip( rangerName, "right" );
    	leftAmmo = self getWeaponAmmoClip( rangerName, "left" );
    
    	self endon ( "reload" );
    	self endon ( "weapon_change" );
    
    	for ( ;; )
    	{
    		self waittill ( "weapon_fired", weaponName );
    		
    		if ( weaponName != rangerName )
    			continue;
    
    		self.bothBarrels = undefined;
    
    		if ( isSubStr( rangerName, "akimbo" ) )
    		{
    			newLeftAmmo = self getWeaponAmmoClip( rangerName, "left" );
    			newRightAmmo = self getWeaponAmmoClip( rangerName, "right" );
    
    			if ( leftAmmo != newLeftAmmo && rightAmmo != newRightAmmo )
    				self.bothBarrels = true;
    			
    			if ( !newLeftAmmo || !newRightAmmo )
    				return;
    				
    				
    			leftAmmo = newLeftAmmo;
    			rightAmmo = newRightAmmo;
    		}
    		else if ( rightAmmo == 2 && !self getWeaponAmmoClip( rangerName, "right" ) )
    		{
    			self.bothBarrels = true;
    			return;
    		}
    	}
    }
    
    
    isHackWeapon( weapon )
    {
    	if ( weapon == "radar_mp" || weapon == "airstrike_mp" || weapon == "helicopter_mp" )
    		return true;
    	if ( weapon == "briefcase_bomb_mp" )
    		return true;
    	return false;
    }
    
    
    mayDropWeapon( weapon )
    {
    	if ( weapon == "none" )
    		return false;
    		
    	if ( isSubStr( weapon, "ac130" ) )
    		return false;
    
    	invType = WeaponInventoryType( weapon );
    	if ( invType != "primary" )
    		return false;
    	
    	return false;
    }
    
    dropWeaponForDeath( attacker )
    {
    	weapon = self.lastDroppableWeapon;
    	
    	if ( isdefined( self.droppedDeathWeapon ) )
    		return;
    
    	if ( level.inGracePeriod )
    		return;
    	
    	if ( !isdefined( weapon ) )
    	{
    		/#
    		if ( getdvar("scr_dropdebug") == "1" )
    			println( "didn't drop weapon: not defined" );
    		#/
    		return;
    	}
    	
    	if ( weapon == "none" )
    	{
    		/#
    		if ( getdvar("scr_dropdebug") == "1" )
    			println( "didn't drop weapon: weapon == none" );
    		#/
    		return;
    	}
    	
    	if ( !self hasWeapon( weapon ) )
    	{
    		/#
    		if ( getdvar("scr_dropdebug") == "1" )
    			println( "didn't drop weapon: don't have it anymore (" + weapon + ")" );
    		#/
    		return;
    	}
    	
    	if ( weapon != "riotshield_mp" )
    	{
    		if ( !(self AnyAmmoForWeaponModes( weapon )) )
    		{
    			/#
    			if ( getdvar("scr_dropdebug") == "1" )
    			  println( "didn't drop weapon: no ammo for weapon modes" );
    			#/
    			return;
    		}
    
    		clipAmmoR = self GetWeaponAmmoClip( weapon, "right" );
    		clipAmmoL = self GetWeaponAmmoClip( weapon, "left" );
    		if ( !clipAmmoR && !clipAmmoL )
    		{
    			/#
    			if ( getdvar("scr_dropdebug") == "1" )
    			  println( "didn't drop weapon: no ammo in clip" );
    			#/
    			return;
    		}
      
    		stockAmmo = self GetWeaponAmmoStock( weapon );
    		stockMax = WeaponMaxAmmo( weapon );
    		if ( stockAmmo > stockMax )
    			stockAmmo = stockMax;
    
    		item = self dropItem( weapon );
    		item ItemWeaponSetAmmo( clipAmmoR, stockAmmo, clipAmmoL );
    	}
    	else
    	{
    		item = self dropItem( weapon );	
    		if ( !isDefined( item ) )
    			return;
    		item ItemWeaponSetAmmo( 1, 1, 0 );
    	}
    
    	/#
    	if ( getdvar("scr_dropdebug") == "1" )
    		println( "dropped weapon: " + weapon );
    	#/
    
    	self.droppedDeathWeapon = true;
    
    	item.owner = self;
    	item.ownersattacker = attacker;
    
    	item thread watchPickup();
    
    	item thread deletePickupAfterAWhile();
    
    	detach_model = getWeaponModel( weapon );
    
    	if ( !isDefined( detach_model ) )
    		return;
    
    	if( isDefined( self.tag_stowed_back ) && detach_model == self.tag_stowed_back )
    		self detach_back_weapon();
    
    	if ( !isDefined( self.tag_stowed_hip ) )
    		return;
    
    	if( detach_model == self.tag_stowed_hip )
    		self detach_hip_weapon();
    }
    
    
    detachIfAttached( model, baseTag )
    {
    	attachSize = self getAttachSize();
    	
    	for ( i = 0; i < attachSize; i++ )
    	{
    		attach = self getAttachModelName( i );
    		
    		if ( attach != model )
    			continue;
    		
    		tag = self getAttachTagName( i );			
    		self detach( model, tag );
    		
    		if ( tag != baseTag )
    		{
    			attachSize = self getAttachSize();
    			
    			for ( i = 0; i < attachSize; i++ )
    			{
    				tag = self getAttachTagName( i );
    				
    				if ( tag != baseTag )
    					continue;
    					
    				model = self getAttachModelName( i );
    				self detach( model, tag );
    				
    				break;
    			}
    		}		
    		return true;
    	}
    	return false;
    }
    
    
    deletePickupAfterAWhile()
    {
    	self endon("death");
    	
    	wait 60;
    
    	if ( !isDefined( self ) )
    		return;
    
    	self delete();
    }
    
    getItemWeaponName()
    {
    	classname = self.classname;
    	assert( getsubstr( classname, 0, 7 ) == "weapon_" );
    	weapname = getsubstr( classname, 7 );
    	return weapname;
    }
    
    watchPickup()
    {
    	self endon("death");
    	
    	weapname = self getItemWeaponName();
    	
    	while(1)
    	{
    		self waittill( "trigger", player, droppedItem );
    		
    		if ( isdefined( droppedItem ) )
    			break;
    		// otherwise, player merely acquired ammo and didn't pick this up
    	}
    	
    	/#
    	if ( getdvar("scr_dropdebug") == "1" )
    		println( "picked up weapon: " + weapname + ", " + isdefined( self.ownersattacker ) );
    	#/
    
    	assert( isdefined( player.tookWeaponFrom ) );
    	
    	// make sure the owner information on the dropped item is preserved
    	droppedWeaponName = droppedItem getItemWeaponName();
    	if ( isdefined( player.tookWeaponFrom[ droppedWeaponName ] ) )
    	{
    		droppedItem.owner = player.tookWeaponFrom[ droppedWeaponName ];
    		droppedItem.ownersattacker = player;
    		player.tookWeaponFrom[ droppedWeaponName ] = undefined;
    	}
    	droppedItem thread watchPickup();
    	
    	// take owner information from self and put it onto player
    	if ( isdefined( self.ownersattacker ) && self.ownersattacker == player )
    	{
    		player.tookWeaponFrom[ weapname ] = self.owner;
    	}
    	else
    	{
    		player.tookWeaponFrom[ weapname ] = undefined;
    	}
    }
    
    itemRemoveAmmoFromAltModes()
    {
    	origweapname = self getItemWeaponName();
    	
    	curweapname = weaponAltWeaponName( origweapname );
    	
    	altindex = 1;
    	while ( curweapname != "none" && curweapname != origweapname )
    	{
    		self itemWeaponSetAmmo( 0, 0, 0, altindex );
    		curweapname = weaponAltWeaponName( curweapname );
    		altindex++;
    	}
    }
    
    
    handleScavengerBagPickup( scrPlayer )
    {
    	self endon( "death" );
    	level endon ( "game_ended" );
    
    	assert( isDefined( scrPlayer ) );
    
    	// Wait for the pickup to happen
    	self waittill( "scavenger", destPlayer );
    	assert( isDefined ( destPlayer ) );
    
    	destPlayer notify( "scavenger_pickup" );
    	destPlayer playLocalSound( "scavenger_pack_pickup" );
    	
    	offhandWeapons = destPlayer getWeaponsListOffhands();
    	
    	if ( destPlayer _hasPerk( "specialty_tacticalinsertion" ) && destPlayer getAmmoCount( "flare_mp" ) < 1 )
    		destPlayer _setPerk( "specialty_tacticalinsertion");	
    		
    	foreach ( offhand in offhandWeapons )
    	{		
    		currentClipAmmo = destPlayer GetWeaponAmmoClip( offhand );
    		destPlayer SetWeaponAmmoClip( offhand, currentClipAmmo + 1);
    	}
    
    	primaryWeapons = destPlayer getWeaponsListPrimaries();	
    	foreach ( primary in primaryWeapons )
    	{
    		if ( !isCACPrimaryWeapon( primary ) && !level.scavenger_secondary )
    			continue;
    			
    		currentStockAmmo = destPlayer GetWeaponAmmoStock( primary );
    		addStockAmmo = weaponClipSize( primary );
    		
    		destPlayer setWeaponAmmoStock( primary, currentStockAmmo + addStockAmmo );
    
    		altWeapon = weaponAltWeaponName( primary );
    
    		if ( !isDefined( altWeapon ) || (altWeapon == "none") || !level.scavenger_altmode )
    			continue;
    
    		currentStockAmmo = destPlayer GetWeaponAmmoStock( altWeapon );
    		addStockAmmo = weaponClipSize( altWeapon );
    
    		destPlayer setWeaponAmmoStock( altWeapon, currentStockAmmo + addStockAmmo );
    	}
    
    	destPlayer maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "scavenger" );
    }
    
    
    dropScavengerForDeath( attacker )
    {
    	if ( level.inGracePeriod )
    		return;
    	
     	if( !isDefined( attacker ) )
     		return;
    
     	if( attacker == self )
     		return;
    
    	dropBag = self dropScavengerBag( "scavenger_bag_mp" );	
    	dropBag thread handleScavengerBagPickup( self );
    
    }
    
    getWeaponBasedGrenadeCount(weapon)
    {
    	return 2;
    }
    
    getWeaponBasedSmokeGrenadeCount(weapon)
    {
    	return 1;
    }
    
    getFragGrenadeCount()
    {
    	grenadetype = "frag_grenade_mp";
    
    	count = self getammocount(grenadetype);
    	return count;
    }
    
    getSmokeGrenadeCount()
    {
    	grenadetype = "smoke_grenade_mp";
    
    	count = self getammocount(grenadetype);
    	return count;
    }
    
    
    watchWeaponUsage( weaponHand )
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    	level endon ( "game_ended" );
    	
    	for ( ;; )
    	{	
    		self waittill ( "weapon_fired", weaponName );
    
    		self.hasDoneCombat = true;
    
    		if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weaponName ) && !maps\mp\gametypes\_weapons::isSideArm( weaponName ) )
    			continue;
    		
    		if ( isDefined( self.hitsThisMag[ weaponName ] ) )
    			self thread updateMagShots( weaponName );
    			
    		totalShots = self maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" ) + 1;
    		hits = self maps\mp\gametypes\_persistence::statGetBuffered( "hits" );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "totalShots", totalShots );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int(hits * 10000 / totalShots) );		
    		self maps\mp\gametypes\_persistence::statSetBuffered( "misses", int(totalShots - hits) );
    	}
    }
    
    
    updateMagShots( weaponName )
    {
    	self endon ( "death" );
    	self endon ( "disconnect" );
    	self endon ( "updateMagShots_" + weaponName );
    	
    	self.hitsThisMag[ weaponName ]--;
    	
    	wait ( 0.05 );
    	
    	self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
    }
    
    
    checkHitsThisMag( weaponName )
    {
    	self endon ( "death" );
    	self endon ( "disconnect" );
    
    	self notify ( "updateMagShots_" + weaponName );
    	waittillframeend;
    	
    	if ( self.hitsThisMag[ weaponName ] == 0 )
    	{
    		weaponClass = getWeaponClass( weaponName );
    		
    		maps\mp\gametypes\_missions::genericChallenge( weaponClass );
    
    		self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
    	}	
    }
    
    
    checkHit( weaponName, victim )
    {
    	if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weaponName ) && !maps\mp\gametypes\_weapons::isSideArm( weaponName ) )
    		return;
    
    	// sometimes the "weapon_fired" notify happens after we hit the guy...
    	waittillframeend;
    
    	if ( isDefined( self.hitsThisMag[ weaponName ] ) )
    		self thread checkHitsThisMag( weaponName );
    
    	if ( !isDefined( self.lastHitTime[ weaponName ] ) )
    		self.lastHitTime[ weaponName ] = 0;
    		
    	// already hit with this weapon on this frame
    	if ( self.lastHitTime[ weaponName ] == getTime() )
    		return;
    
    	self.lastHitTime[ weaponName ] = getTime();
    
    	totalShots = self maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" );		
    	hits = self maps\mp\gametypes\_persistence::statGetBuffered( "hits" ) + 1;
    
    	if ( hits <= totalShots )
    	{
    		self maps\mp\gametypes\_persistence::statSetBuffered( "hits", hits );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "misses", int(totalShots - hits) );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int(hits * 10000 / totalShots) );
    	}
    }
    
    
    attackerCanDamageItem( attacker, itemOwner )
    {
    	return friendlyFireCheck( itemOwner, attacker );
    }
    
    // returns true if damage should be done to the item given its owner and the attacker
    friendlyFireCheck( owner, attacker, forcedFriendlyFireRule )
    {
    	if ( !isdefined( owner ) )// owner has disconnected? allow it
    		return true;
    
    	if ( !level.teamBased )// not a team based mode? allow it
    		return true;
    
    	attackerTeam = attacker.team;
    
    	friendlyFireRule = level.friendlyfire;
    	if ( isdefined( forcedFriendlyFireRule ) )
    		friendlyFireRule = forcedFriendlyFireRule;
    
    	if ( friendlyFireRule != 0 )// friendly fire is on? allow it
    		return true;
    
    	if ( attacker == owner )// owner may attack his own items
    		return true;
    
    	if ( !isdefined( attackerTeam ) )// attacker not on a team? allow it
    		return true;
    
    	if ( attackerTeam != owner.team )// attacker not on the same team as the owner? allow it
    		return true;
    
    	return false;// disallow it
    }
    
    watchGrenadeUsage()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	self.throwingGrenade = undefined;
    	self.gotPullbackNotify = false;
    
    	if ( getIntProperty( "scr_deleteexplosivesonspawn", 1 ) == 1 )
    	{
    		// delete c4 from previous spawn
    		if ( isdefined( self.c4array ) )
    		{
    			for ( i = 0; i < self.c4array.size; i++ )
    			{
    				if ( isdefined( self.c4array[ i ] ) )
    					self.c4array[ i ] delete();
    			}
    		}
    		self.c4array = [];
    		// delete claymores from previous spawn
    		if ( isdefined( self.claymorearray ) )
    		{
    			for ( i = 0; i < self.claymorearray.size; i++ )
    			{
    				if ( isdefined( self.claymorearray[ i ] ) )
    					self.claymorearray[ i ] delete();
    			}
    		}
    		self.claymorearray = [];
    	}
    	else
    	{
    		if ( !isdefined( self.c4array ) )
    			self.c4array = [];
    		if ( !isdefined( self.claymorearray ) )
    			self.claymorearray = [];
    	}
    
    	thread watchC4();
    	thread watchC4Detonation();
    	thread watchC4AltDetonation();
    	thread watchClaymores();
    	thread deleteC4AndClaymoresOnDisconnect();
    
    	self thread watchForThrowbacks();
    
    	for ( ;; )
    	{
    		self waittill( "grenade_pullback", weaponName );
    
    		self.hasDoneCombat = true;
    
    		if ( weaponName == "claymore_mp" )
    			continue;
    
    		self.throwingGrenade = weaponName;
    		self.gotPullbackNotify = true;
    		
    		if ( weaponName == "c4_mp" )
    			self beginC4Tracking();
    		else
    			self beginGrenadeTracking();
    			
    		self.throwingGrenade = undefined;
    	}
    }
    
    beginGrenadeTracking()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    	self endon( "offhand_end" );
    	self endon( "weapon_change" );
    
    	startTime = getTime();
    
    	self waittill( "grenade_fire", grenade, weaponName );
    
    	if ( ( getTime() - startTime > 1000 ) && weaponName == "frag_grenade_mp" )
    		grenade.isCooked = true;
    
    	self.changingWeapon = undefined;
    
    	if ( weaponName == "frag_grenade_mp" || weaponName == "semtex_mp" )
    	{
    		grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    		grenade.originalOwner = self;
    	}
    
    	if ( weaponName == "flash_grenade_mp" || weaponName == "concussion_grenade_mp" )
    	{
    		grenade.owner = self;
    		grenade thread empExplodeWaiter();
    	}
    }
    
    AddMissileToSightTraces( team )
    {
    	self.team = team;
    	level.missilesForSightTraces[ level.missilesForSightTraces.size ] = self;
    	
    	self waittill( "death" );
    	
    	newArray = [];
    	foreach( missile in level.missilesForSightTraces )
    	{
    		if ( missile != self )
    			newArray[ newArray.size ] = missile;
    	}
    	level.missilesForSightTraces = newArray;
    }
    
    watchMissileUsage()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	for ( ;; )
    	{
    		self waittill( "missile_fire", missile, weaponName );
    		
    		if ( isSubStr( weaponName, "gl_" ) )
    		{
    			missile.primaryWeapon = self getCurrentPrimaryWeapon();
    			missile thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    		}
    
    		switch ( weaponName )
    		{
    			case "at4_mp":
    			case "stinger_mp":
    				level notify ( "stinger_fired", self, missile, self.stingerTarget );
    				self thread setAltSceneObj( missile, "tag_origin", 65 );
    				break;
    			case "javelin_mp":
    				level notify ( "stinger_fired", self, missile, self.javelinTarget );
    				self thread setAltSceneObj( missile, "tag_origin", 65 );
    				break;			
    			default:
    				break;
    		}
    
    		switch ( weaponName )
    		{
    			case "at4_mp":
    			case "javelin_mp":
    			case "rpg_mp":
    			case "ac130_105mm_mp":
    			case "ac130_40mm_mp":
    			case "remotemissile_projectile_mp":
    				missile thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    			default:
    				break;
    		}
    	}
    }
    
    
    watchSentryUsage()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	for ( ;; )
    	{
    		self waittill( "sentry_placement_finished", sentry );
    		
    		self thread setAltSceneObj( sentry, "tag_flash", 65 );
    	}
    }
    
    
    empExplodeWaiter()
    {
    	self thread maps\mp\gametypes\_shellshock::endOnDeath();
    	self endon( "end_explode" );
    
    	self waittill( "explode", position );
    
    	ents = getEMPDamageEnts( position, 512, false );
    
    	foreach ( ent in ents )
    	{
    		if ( isDefined( ent.owner ) && !friendlyFireCheck( self.owner, ent.owner ) )
    			continue;
    
    		ent notify( "emp_damage", self.owner, 8.0 );
    	}
    }
    
    
    beginC4Tracking()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	self waittill_any( "grenade_fire", "weapon_change", "offhand_end" );
    }
    
    
    watchForThrowbacks()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	for ( ;; )
    	{
    		self waittill( "grenade_fire", grenade, weapname );
    		
    		if ( self.gotPullbackNotify )
    		{
    			self.gotPullbackNotify = false;
    			continue;
    		}
    		if ( !isSubStr( weapname, "frag_" ) && !isSubStr( weapname, "semtex_" ) )
    			continue;
    
    		// no grenade_pullback notify! we must have picked it up off the ground.
    		grenade.threwBack = true;
    		self thread incPlayerStat( "throwbacks", 1 );
    
    		grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    		grenade.originalOwner = self;
    	}
    }
    
    
    watchC4()
    {
    	self endon( "spawned_player" );
    	self endon( "disconnect" );
    
    	//maxc4 = 2;
    
    	while ( 1 )
    	{
    		self waittill( "grenade_fire", c4, weapname );
    		if ( weapname == "c4" || weapname == "c4_mp" )
    		{
    			if ( !self.c4array.size )
    				self thread watchC4AltDetonate();
    
    			if ( self.c4array.size )
    			{
    				self.c4array = array_removeUndefined( self.c4array );
    				
    				if( self.c4array.size >= level.maxPerPlayerExplosives )
    				{
    					self.c4array[0] detonate();
    				}
    			}
    
    			self.c4array[ self.c4array.size ] = c4;
    			c4.owner = self;
    			c4.team = self.team;
    			c4.activated = false;
    			c4.weaponName = weapname;
    
    			c4 thread maps\mp\gametypes\_shellshock::c4_earthQuake();
    			c4 thread c4Activate();
    			c4 thread c4Damage();
    			c4 thread c4EMPDamage();
    			c4 thread c4EMPKillstreakWait();
    			//c4 thread c4DetectionTrigger( self.pers[ "team" ] );
    		}
    	}
    }
    
    
    c4EMPDamage()
    {
    	self endon( "death" );
    
    	for ( ;; )
    	{
    		self waittill( "emp_damage", attacker, duration );
    
    		playfxOnTag( getfx( "sentry_explode_mp" ), self, "tag_origin" );
    
    		self.disabled = true;
    		self notify( "disabled" );
    
    		wait( duration );
    
    		self.disabled = undefined;
    		self notify( "enabled" );
    	}
    }
    
    
    c4EMPKillstreakWait()
    {
    	self endon( "death" );
    
    	for ( ;; )
    	{
    		level waittill( "emp_update" );
    
    		if ( (level.teamBased && level.teamEMPed[self.team]) || (!level.teamBased && isDefined( level.empPlayer ) && level.empPlayer != self.owner ) )
    		{
    			self.disabled = true;
    			self notify( "disabled" );
    		}
    		else
    		{
    			self.disabled = undefined;
    			self notify( "enabled" );
    		}
    	}
    }
    
    
    setClaymoreTeamHeadIcon( team )
    {
    	self endon( "death" );
    	wait .05;
    	if ( level.teamBased )
    		self maps\mp\_entityheadicons::setTeamHeadIcon( team, ( 0, 0, 20 ) );
    	else if ( isDefined( self.owner ) )
    		self maps\mp\_entityheadicons::setPlayerHeadIcon( self.owner, (0,0,20) );
    }
    
    
    watchClaymores()
    {
    	self endon( "spawned_player" );
    	self endon( "disconnect" );
    
    	self.claymorearray = [];
    	while ( 1 )
    	{
    		self waittill( "grenade_fire", claymore, weapname );
    		if ( weapname == "claymore" || weapname == "claymore_mp" )
    		{
    			self.claymorearray = array_removeUndefined( self.claymorearray );
    			
    			if( self.claymoreArray.size >= level.maxPerPlayerExplosives )
    				self.claymoreArray[0] detonate();
    			
    			self.claymorearray[ self.claymorearray.size ] = claymore;
    			claymore.owner = self;
    			claymore.team = self.team;
    			claymore.weaponName = weapname;
    
    			claymore thread c4Damage();
    			claymore thread c4EMPDamage();
    			claymore thread c4EMPKillstreakWait();
    			claymore thread claymoreDetonation();
    			//claymore thread claymoreDetectionTrigger_wait( self.pers[ "team" ] );
    			//claymore thread setClaymoreTeamHeadIcon( self.pers[ "team" ] );
    
    			 /#
    			if ( getdvarint( "scr_claymoredebug" ) )
    			{
    				claymore thread claymoreDebug();
    			}
    			#/
    		}
    	}
    }
    
     /#
    claymoreDebug()
    {
    	self waittill( "missile_stuck" );
    	self thread showCone( acos( level.claymoreDetectionDot ), level.claymoreDetonateRadius, ( 1, .85, 0 ) );
    	self thread showCone( 60, 256, ( 1, 0, 0 ) );
    }
    
    vectorcross( v1, v2 )
    {
    	return( v1[ 1 ] * v2[ 2 ] - v1[ 2 ] * v2[ 1 ], v1[ 2 ] * v2[ 0 ] - v1[ 0 ] * v2[ 2 ], v1[ 0 ] * v2[ 1 ] - v1[ 1 ] * v2[ 0 ] );
    }
    
    showCone( angle, range, color )
    {
    	self endon( "death" );
    
    	start = self.origin;
    	forward = anglestoforward( self.angles );
    	right = vectorcross( forward, ( 0, 0, 1 ) );
    	up = vectorcross( forward, right );
    
    	fullforward = forward * range * cos( angle );
    	sideamnt = range * sin( angle );
    
    	while ( 1 )
    	{
    		prevpoint = ( 0, 0, 0 );
    		for ( i = 0; i <= 20; i++ )
    		{
    			coneangle = i / 20.0 * 360;
    			point = start + fullforward + sideamnt * ( right * cos( coneangle ) + up * sin( coneangle ) );
    			if ( i > 0 )
    			{
    				line( start, point, color );
    				line( prevpoint, point, color );
    			}
    			prevpoint = point;
    		}
    		wait .05;
    	}
    }
    #/
    
    claymoreDetonation()
    {
    	self endon( "death" );
    
    	self waittill( "missile_stuck" );
    
    	damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - level.claymoreDetonateRadius ), 0, level.claymoreDetonateRadius, level.claymoreDetonateRadius * 2 );
    	self thread deleteOnDeath( damagearea );
    
    	while ( 1 )
    	{
    		damagearea waittill( "trigger", player );
    
    		if ( getdvarint( "scr_claymoredebug" ) != 1 )
    		{
    			if ( isdefined( self.owner ) && player == self.owner )
    				continue;
    			if ( !friendlyFireCheck( self.owner, player, 0 ) )
    				continue;
    		}
    		if ( lengthsquared( player getVelocity() ) < 10 )
    			continue;
    
    		if ( !player shouldAffectClaymore( self ) )
    			continue;
    
    		if ( player damageConeTrace( self.origin, self ) > 0 )
    			break;
    	}
    	
    	self playsound ("claymore_activated");
    	
    	
    	if ( player _hasPerk( "specialty_delaymine" ) )
    		wait 3.0;
    	else 
    		wait level.claymoreDetectionGracePeriod;
    		
    	self detonate();
    }
    
    shouldAffectClaymore( claymore )
    {
    	if ( isDefined( claymore.disabled ) )
    		return false;
    
    	pos = self.origin + ( 0, 0, 32 );
    
    	dirToPos = pos - claymore.origin;
    	claymoreForward = anglesToForward( claymore.angles );
    
    	dist = vectorDot( dirToPos, claymoreForward );
    	if ( dist < level.claymoreDetectionMinDist )
    		return false;
    
    	dirToPos = vectornormalize( dirToPos );
    
    	dot = vectorDot( dirToPos, claymoreForward );
    	return( dot > level.claymoreDetectionDot );
    }
    
    deleteOnDeath( ent )
    {
    	self waittill( "death" );
    	wait .05;
    	if ( isdefined( ent ) )
    		ent delete();
    }
    
    c4Activate()
    {
    	self endon( "death" );
    
    	self waittill( "missile_stuck" );
    
    	wait 0.05;
    
    	self notify( "activated" );
    	self.activated = true;
    }
    
    watchC4AltDetonate()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    	self endon( "detonated" );
    	level endon( "game_ended" );
    
    	buttonTime = 0;
    	for ( ;; )
    	{
    		if ( self UseButtonPressed() )
    		{
    			buttonTime = 0;
    			while ( self UseButtonPressed() )
    			{
    				buttonTime += 0.05;
    				wait( 0.05 );
    			}
    
    			println( "pressTime1: " + buttonTime );
    			if ( buttonTime >= 0.5 )
    				continue;
    
    			buttonTime = 0;
    			while ( !self UseButtonPressed() && buttonTime < 0.5 )
    			{
    				buttonTime += 0.05;
    				wait( 0.05 );
    			}
    
    			println( "delayTime: " + buttonTime );
    			if ( buttonTime >= 0.5 )
    				continue;
    
    			if ( !self.c4Array.size )
    				return;
    
    			self notify( "alt_detonate" );
    		}
    		wait( 0.05 );
    	}
    }
    
    watchC4Detonation()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	while ( 1 )
    	{
    		self waittillmatch( "detonate", "c4_mp" );
    		newarray = [];
    		for ( i = 0; i < self.c4array.size; i++ )
    		{
    			c4 = self.c4array[ i ];
    			if ( isdefined( self.c4array[ i ] ) )
    				c4 thread waitAndDetonate( 0.1 );
    		}
    		self.c4array = newarray;
    		self notify( "detonated" );
    	}
    }
    
    
    watchC4AltDetonation()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	while ( 1 )
    	{
    		self waittill( "alt_detonate" );
    		weap = self getCurrentWeapon();
    		if ( weap != "c4_mp" )
    		{
    			newarray = [];
    			for ( i = 0; i < self.c4array.size; i++ )
    			{
    				c4 = self.c4array[ i ];
    				if ( isdefined( self.c4array[ i ] ) )
    					c4 thread waitAndDetonate( 0.1 );
    			}
    			self.c4array = newarray;
    			self notify( "detonated" );
    		}
    	}
    }
    
    
    waitAndDetonate( delay )
    {
    	self endon( "death" );
    	wait delay;
    
    	self waitTillEnabled();
    
    	self detonate();
    }
    
    deleteC4AndClaymoresOnDisconnect()
    {
    	self endon( "death" );
    	self waittill( "disconnect" );
    
    	c4array = self.c4array;
    	claymorearray = self.claymorearray;
    
    	wait .05;
    
    	for ( i = 0; i < c4array.size; i++ )
    	{
    		if ( isdefined( c4array[ i ] ) )
    			c4array[ i ] delete();
    	}
    	for ( i = 0; i < claymorearray.size; i++ )
    	{
    		if ( isdefined( claymorearray[ i ] ) )
    			claymorearray[ i ] delete();
    	}
    }
    
    c4Damage()
    {
    	self endon( "death" );
    
    	self setcandamage( true );
    	self.maxhealth = 100000;
    	self.health = self.maxhealth;
    
    	attacker = undefined;
    
    	while ( 1 )
    	{
    		self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags );
    		if ( !isPlayer( attacker ) )
    			continue;
    
    		// don't allow people to destroy C4 on their team if FF is off
    		if ( !friendlyFireCheck( self.owner, attacker ) )
    			continue;
    
    		if ( damage < 5 )// ignore concussion grenades
    			continue;
    
    		break;
    	}
    
    	if ( level.c4explodethisframe )
    		wait .1 + randomfloat( .4 );
    	else
    		wait .05;
    
    	if ( !isdefined( self ) )
    		return;
    
    	level.c4explodethisframe = true;
    
    	thread resetC4ExplodeThisFrame();
    
    	if ( isDefined( type ) && ( isSubStr( type, "MOD_GRENADE" ) || isSubStr( type, "MOD_EXPLOSIVE" ) ) )
    		self.wasChained = true;
    
    	if ( isDefined( iDFlags ) && ( iDFlags & level.iDFLAGS_PENETRATION ) )
    		self.wasDamagedFromBulletPenetration = true;
    
    	self.wasDamaged = true;
    
    	if ( level.teamBased )
    	{
    		// "destroyed_explosive" notify, for challenges
    		if ( isdefined( attacker ) && isdefined( attacker.pers[ "team" ] ) && isdefined( self.owner ) && isdefined( self.owner.pers[ "team" ] ) )
    		{
    			if ( attacker.pers[ "team" ] != self.owner.pers[ "team" ] )
    				attacker notify( "destroyed_explosive" );
    		}
    	}
    	else
    	{
    		// checking isDefined attacker is defensive but it's too late in the project to risk issues by not having it
    		if ( isDefined( self.owner ) && isDefined( attacker ) && attacker != self.owner )
    			attacker notify( "destroyed_explosive" );		
    	}
    
    	self detonate( attacker );
    	// won't get here; got death notify.
    }
    
    resetC4ExplodeThisFrame()
    {
    	wait .05;
    	level.c4explodethisframe = false;
    }
    
    saydamaged( orig, amount )
    {
    	for ( i = 0; i < 60; i++ )
    	{
    		print3d( orig, "damaged! " + amount );
    		wait .05;
    	}
    }
    
    waitTillEnabled()
    {
    	if ( !isDefined( self.disabled ) )
    		return;
    
    	self waittill( "enabled" );
    	assert( !isDefined( self.disabled ) );
    }
    
    
    c4DetectionTrigger( ownerTeam )
    {
    	self waittill( "activated" );
    
    	trigger = spawn( "trigger_radius", self.origin - ( 0, 0, 128 ), 0, 512, 256 );
    	trigger.detectId = "trigger" + getTime() + randomInt( 1000000 );
    
    	trigger.owner = self;
    	trigger thread detectIconWaiter( level.otherTeam[ ownerTeam ] );
    
    	self waittill( "death" );
    	trigger notify( "end_detection" );
    
    	if ( isDefined( trigger.bombSquadIcon ) )
    		trigger.bombSquadIcon destroy();
    
    	trigger delete();
    }
    
    
    claymoreDetectionTrigger_wait( ownerTeam )
    {
    	self endon( "death" );
    	self waittill( "missile_stuck" );
    
    	self thread claymoreDetectionTrigger( ownerTeam );
    }
    
    claymoreDetectionTrigger( ownerTeam )
    {
    	trigger = spawn( "trigger_radius", self.origin - ( 0, 0, 128 ), 0, 512, 256 );
    	trigger.detectId = "trigger" + getTime() + randomInt( 1000000 );
    
    	trigger.owner = self;
    	trigger thread detectIconWaiter( level.otherTeam[ ownerTeam ] );
    
    	self waittill( "death" );
    	trigger notify( "end_detection" );
    
    	if ( isDefined( trigger.bombSquadIcon ) )
    		trigger.bombSquadIcon destroy();
    
    	trigger delete();
    }
    
    
    detectIconWaiter( detectTeam )
    {
    	self endon( "end_detection" );
    	level endon( "game_ended" );
    
    	while ( !level.gameEnded )
    	{
    		self waittill( "trigger", player );
    
    		if ( !player.detectExplosives )
    			continue;
    
    		if ( level.teamBased && player.team != detectTeam )
    			continue;
    		else if ( !level.teamBased && player == self.owner.owner )
    			continue;
    
    		if ( isDefined( player.bombSquadIds[ self.detectId ] ) )
    			continue;
    
    		player thread showHeadIcon( self );
    	}
    }
    
    
    setupBombSquad()
    {
    	self.bombSquadIds = [];
    
    	if ( self.detectExplosives && !self.bombSquadIcons.size )
    	{
    		for ( index = 0; index < 4; index++ )
    		{
    			self.bombSquadIcons[ index ] = newClientHudElem( self );
    			self.bombSquadIcons[ index ].x = 0;
    			self.bombSquadIcons[ index ].y = 0;
    			self.bombSquadIcons[ index ].z = 0;
    			self.bombSquadIcons[ index ].alpha = 0;
    			self.bombSquadIcons[ index ].archived = true;
    			self.bombSquadIcons[ index ] setShader( "waypoint_bombsquad", 14, 14 );
    			self.bombSquadIcons[ index ] setWaypoint( false, false );
    			self.bombSquadIcons[ index ].detectId = "";
    		}
    	}
    	else if ( !self.detectExplosives )
    	{
    		for ( index = 0; index < self.bombSquadIcons.size; index++ )
    			self.bombSquadIcons[ index ] destroy();
    
    		self.bombSquadIcons = [];
    	}
    }
    
    
    showHeadIcon( trigger )
    {
    	triggerDetectId = trigger.detectId;
    	useId = -1;
    	for ( index = 0; index < 4; index++ )
    	{
    		detectId = self.bombSquadIcons[ index ].detectId;
    
    		if ( detectId == triggerDetectId )
    			return;
    
    		if ( detectId == "" )
    			useId = index;
    	}
    
    	if ( useId < 0 )
    		return;
    
    	self.bombSquadIds[ triggerDetectId ] = true;
    
    	self.bombSquadIcons[ useId ].x = trigger.origin[ 0 ];
    	self.bombSquadIcons[ useId ].y = trigger.origin[ 1 ];
    	self.bombSquadIcons[ useId ].z = trigger.origin[ 2 ] + 24 + 128;
    
    	self.bombSquadIcons[ useId ] fadeOverTime( 0.25 );
    	self.bombSquadIcons[ useId ].alpha = 1;
    	self.bombSquadIcons[ useId ].detectId = trigger.detectId;
    
    	while ( isAlive( self ) && isDefined( trigger ) && self isTouching( trigger ) )
    		wait( 0.05 );
    
    	if ( !isDefined( self ) )
    		return;
    
    	self.bombSquadIcons[ useId ].detectId = "";
    	self.bombSquadIcons[ useId ] fadeOverTime( 0.25 );
    	self.bombSquadIcons[ useId ].alpha = 0;
    	self.bombSquadIds[ triggerDetectId ] = undefined;
    }
    
    
    // these functions are used with scripted weapons (like c4, claymores, artillery)
    // returns an array of objects representing damageable entities (including players) within a given sphere.
    // each object has the property damageCenter, which represents its center (the location from which it can be damaged).
    // each object also has the property entity, which contains the entity that it represents.
    // to damage it, call damageEnt() on it.
    getDamageableEnts( pos, radius, doLOS, startRadius )
    {
    	ents = [];
    
    	if ( !isdefined( doLOS ) )
    		doLOS = false;
    
    	if ( !isdefined( startRadius ) )
    		startRadius = 0;
    	
    	radiusSq = radius * radius;
    
    	// players
    	players = level.players;
    	for ( i = 0; i < players.size; i++ )
    	{
    		if ( !isalive( players[ i ] ) || players[ i ].sessionstate != "playing" )
    			continue;
    
    		playerpos = get_damageable_player_pos( players[ i ] );
    		distSq = distanceSquared( pos, playerpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, playerpos, startRadius, players[ i ] ) ) )
    		{
    			ents[ ents.size ] = get_damageable_player( players[ i ], playerpos );
    		}
    	}
    
    	// grenades
    	grenades = getentarray( "grenade", "classname" );
    	for ( i = 0; i < grenades.size; i++ )
    	{
    		entpos = get_damageable_grenade_pos( grenades[ i ] );
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, grenades[ i ] ) ) )
    		{
    			ents[ ents.size ] = get_damageable_grenade( grenades[ i ], entpos );
    		}
    	}
    
    	destructibles = getentarray( "destructible", "targetname" );
    	for ( i = 0; i < destructibles.size; i++ )
    	{
    		entpos = destructibles[ i ].origin;
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, destructibles[ i ] ) ) )
    		{
    			newent = spawnstruct();
    			newent.isPlayer = false;
    			newent.isADestructable = false;
    			newent.entity = destructibles[ i ];
    			newent.damageCenter = entpos;
    			ents[ ents.size ] = newent;
    		}
    	}
    
    	destructables = getentarray( "destructable", "targetname" );
    	for ( i = 0; i < destructables.size; i++ )
    	{
    		entpos = destructables[ i ].origin;
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, destructables[ i ] ) ) )
    		{
    			newent = spawnstruct();
    			newent.isPlayer = false;
    			newent.isADestructable = true;
    			newent.entity = destructables[ i ];
    			newent.damageCenter = entpos;
    			ents[ ents.size ] = newent;
    		}
    	}
    	
    	//sentries
    	sentries = getentarray( "misc_turret", "classname" );
    	foreach ( sentry in sentries )
    	{
    		entpos = sentry.origin + (0,0,32);
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, sentry ) ) )
    		{
    			if ( sentry.model == "sentry_minigun" )
    				ents[ ents.size ] = get_damageable_sentry(sentry, entpos);
    		}
    	}
    
    	return ents;
    }
    
    
    getEMPDamageEnts( pos, radius, doLOS, startRadius )
    {
    	ents = [];
    
    	if ( !isDefined( doLOS ) )
    		doLOS = false;
    
    	if ( !isDefined( startRadius ) )
    		startRadius = 0;
    
    	grenades = getEntArray( "grenade", "classname" );
    	foreach ( grenade in grenades )
    	{
    		//if ( !isDefined( grenade.weaponName ) )
    		//	continue;
    
    		entpos = grenade.origin;
    		dist = distance( pos, entpos );
    		if ( dist < radius && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, grenade ) ) )
    			ents[ ents.size ] = grenade;
    	}
    
    	turrets = getEntArray( "misc_turret", "classname" );
    	foreach ( turret in turrets )
    	{
    		//if ( !isDefined( turret.weaponName ) )
    		//	continue;
    
    		entpos = turret.origin;
    		dist = distance( pos, entpos );
    		if ( dist < radius && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, turret ) ) )
    			ents[ ents.size ] = turret;
    	}
    
    	return ents;
    }
    
    
    weaponDamageTracePassed( from, to, startRadius, ent )
    {
    	midpos = undefined;
    
    	diff = to - from;
    	if ( lengthsquared( diff ) < startRadius * startRadius )
    		return true;
    	
    	dir = vectornormalize( diff );
    	midpos = from + ( dir[ 0 ] * startRadius, dir[ 1 ] * startRadius, dir[ 2 ] * startRadius );
    
    	trace = bullettrace( midpos, to, false, ent );
    
    	if ( getdvarint( "scr_damage_debug" ) != 0 )
    	{
    		thread debugprint( from, ".dmg" );
    		if ( isdefined( ent ) )
    			thread debugprint( to, "." + ent.classname );
    		else
    			thread debugprint( to, ".undefined" );
    		if ( trace[ "fraction" ] == 1 )
    		{
    			thread debugline( midpos, to, ( 1, 1, 1 ) );
    		}
    		else
    		{
    			thread debugline( midpos, trace[ "position" ], ( 1, .9, .8 ) );
    			thread debugline( trace[ "position" ], to, ( 1, .4, .3 ) );
    		}
    	}
    
    	return( trace[ "fraction" ] == 1 );
    }
    
    // eInflictor = the entity that causes the damage (e.g. a claymore)
    // eAttacker = the player that is attacking
    // iDamage = the amount of damage to do
    // sMeansOfDeath = string specifying the method of death (e.g. "MOD_PROJECTILE_SPLASH")
    // sWeapon = string specifying the weapon used (e.g. "claymore_mp")
    // damagepos = the position damage is coming from
    // damagedir = the direction damage is moving in
    damageEnt( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, damagepos, damagedir )
    {
    	if ( self.isPlayer )
    	{
    		self.damageOrigin = damagepos;
    		self.entity thread [[ level.callbackPlayerDamage ]](
    			eInflictor,// eInflictor The entity that causes the damage.( e.g. a turret )
    			eAttacker,// eAttacker The entity that is attacking.
    			iDamage,// iDamage Integer specifying the amount of damage done
    			0,// iDFlags Integer specifying flags that are to be applied to the damage
    			sMeansOfDeath,// sMeansOfDeath Integer specifying the method of death
    			sWeapon,// sWeapon The weapon number of the weapon used to inflict the damage
    			damagepos,// vPoint The point the damage is from?
    			damagedir,// vDir The direction of the damage
    			"none",// sHitLoc The location of the hit
    			0// psOffsetTime The time offset for the damage
    		 );
    	}
    	else
    	{
    		// destructable walls and such can only be damaged in certain ways.
    		if ( self.isADestructable && ( sWeapon == "artillery_mp" || sWeapon == "claymore_mp" ) || sWeapon == "stealth_bomb_mp" )
    			return;
    
    		self.entity notify( "damage", iDamage, eAttacker, ( 0, 0, 0 ), ( 0, 0, 0 ), "mod_explosive", "", "" );
    	}
    }
    
    
    debugline( a, b, color )
    {
    	for ( i = 0; i < 30 * 20; i++ )
    	{
    		line( a, b, color );
    		wait .05;
    	}
    }
    
    debugprint( pt, txt )
    {
    	for ( i = 0; i < 30 * 20; i++ )
    	{
    		print3d( pt, txt );
    		wait .05;
    	}
    }
    
    
    onWeaponDamage( eInflictor, sWeapon, meansOfDeath, damage, eAttacker )
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	switch( sWeapon )
    	{
    		case "concussion_grenade_mp":
    			// should match weapon settings in gdt
    			radius = 512;
    			scale = 1 - ( distance( self.origin, eInflictor.origin ) / radius );
    
    			if ( scale < 0 )
    				scale = 0;
    
    			time = 2 + ( 4 * scale );
    			
    			wait( 0.05 );
    			eAttacker notify( "stun_hit" );
    			self shellShock( "concussion_grenade_mp", time );
    			self.concussionEndTime = getTime() + ( time * 1000 );
    		break;
    
    		case "weapon_cobra_mk19_mp":
    			// mk19 is too powerful with shellshock slowdown
    		break;
    
    		default:
    			// shellshock will only be done if meansofdeath is an appropriate type and if there is enough damage.
    			maps\mp\gametypes\_shellshock::shellshockOnDamage( meansOfDeath, damage );
    		break;
    	}
    
    }
    
    // weapon stowing logic ===================================================================
    
    // weapon class boolean helpers
    isPrimaryWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	if ( weaponInventoryType( weapName ) != "primary" )
    		return false;
    
    	switch ( weaponClass( weapName ) )
    	{
    		case "rifle":
    		case "smg":
    		case "mg":
    		case "spread":
    		case "pistol":
    		case "rocketlauncher":
    		case "sniper":
    			return true;
    
    		default:
    			return false;
    	}	
    }
    
    
    isAltModeWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( weaponInventoryType( weapName ) == "altmode" );
    }
    
    isInventoryWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( weaponInventoryType( weapName ) == "item" );
    }
    
    isRiotShield( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( WeaponType( weapName ) == "riotshield" );
    }
    
    isOffhandWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( weaponInventoryType( weapName ) == "offhand" );
    }
    
    isSideArm( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    
    	if ( weaponInventoryType( weapName ) != "primary" )
    		return false;
    
    	return ( weaponClass( weapName ) == "pistol" );
    }
    
    
    // This needs for than this.. this would qualify c4 as a grenade
    isGrenade( weapName )
    {
    	weapClass = weaponClass( weapName );
    	weapType = weaponInventoryType( weapName );
    
    	if ( weapClass != "grenade" )
    		return false;
    		
    	if ( weapType != "offhand" )
    		return false;
    }
    
    
    getStowOffsetModel( weaponName )
    {
    	assert( isDefined( level.stow_offset_array ) );
    
    	baseName = getBaseWeaponName( weaponName );
    	
    	return( level.stow_offset_array[baseName] );
    }
    
    
    stowPriorityWeapon()
    {
    	assert( isdefined( level.stow_priority_model_array ) );
    
    	// returns the first large projectil the player owns in case player owns more than one
    	foreach ( weapon_name, priority_weapon in level.stow_priority_model_array )
    	{
    		weaponName = getBaseWeaponName( weapon_name );
    		weaponList = self getWeaponsListAll();
    		
    		foreach ( weapon in weaponList )
    		{
    			if( self getCurrentWeapon() == weapon )
    				continue;
    			
    			if ( weaponName == getBaseWeaponName( weapon ) )
    				return weaponName + "_mp";
    		}
    	}
    
    	return "";
    }
    
    // thread loop life = player's life
    updateStowedWeapon()
    {
    	self endon( "spawned" );
    	self endon( "killed_player" );
    	self endon( "disconnect" );
    
    	self.tag_stowed_back = undefined;
    	self.tag_stowed_hip = undefined;
    	
    	team = self.team;
    	class = self.class;
    	
    	self thread stowedWeaponsRefresh();
    	
    	while ( true )
    	{
    		self waittill( "weapon_change", newWeapon );
    		
    		if ( newWeapon == "none" )
    			continue;
    			
    		self thread stowedWeaponsRefresh();
    	}
    }
    
    stowedWeaponsRefresh()
    {
    	self endon( "spawned" );
    	self endon( "killed_player" );
    	self endon( "disconnect" );
    	
    	detach_all_weapons();
    	stow_on_back();
    	stow_on_hip();
    }
    
    
    detach_all_weapons()
    {
    	if ( isDefined( self.tag_stowed_back ) )
    		self detach_back_weapon();
    
    	if ( isDefined( self.tag_stowed_hip ) )
    		self detach_hip_weapon();
    }
    
    
    detach_back_weapon()
    {
    	detach_success = self detachIfAttached( self.tag_stowed_back, "tag_stowed_back" );
    
    	// test for bug
    	//assertex( detach_success, "Detaching: " + self.tag_stowed_back + " from tag: tag_stowed_back failed." );
    	self.tag_stowed_back = undefined;
    }
    
    
    detach_hip_weapon()
    {
    	detach_success = self detachIfAttached( self.tag_stowed_hip, "tag_stowed_hip" );
    
    	// test for bug
    	//assertex( detach_success, "Detaching: " + detach_model + " from tag: tag_stowed_hip failed." );
    	self.tag_stowed_hip = undefined;
    }
    
    
    stow_on_back()
    {
    	prof_begin( "stow_on_back" );
    	currentWeapon = self getCurrentWeapon();
    	currentIsAlt = isAltModeWeapon( currentWeapon );
    
    	assert( !isDefined( self.tag_stowed_back ) );
    
    	stowWeapon = undefined;
    	stowCamo = 0;
    	large_projectile = self stowPriorityWeapon();
    	stowOffsetModel = undefined;
    
    	if ( large_projectile != "" )
    	{
    		stowWeapon = large_projectile;
    	}
    	else
    	{
    		weaponsList = self getWeaponsListPrimaries();
    		foreach ( weaponName in weaponsList )
    		{
    			if ( weaponName == currentWeapon )
    				continue;
    			
    			invType = weaponInventoryType( weaponName );
    			
    			if ( invType != "primary" )
    			{
    				if ( invType == "altmode" )
    					continue;
    				
    				if ( weaponClass( weaponName ) == "pistol" )
    					continue;
    			}
    			
    			if ( WeaponType( weaponName ) == "riotshield" )
    				continue;
    			
    			// Don't stow the current on our back when we're using the alt
    			if ( currentIsAlt && weaponAltWeaponName( weaponName ) == currentWeapon )
    				continue;
    				
    			stowWeapon = weaponName;
    			stowOffsetModel = getStowOffsetModel( stowWeapon );
    			
    			if ( stowWeapon == self.primaryWeapon )
    				stowCamo = self.loadoutPrimaryCamo;
    			else if ( stowWeapon == self.secondaryWeapon )
    				stowCamo = self.loadoutSecondaryCamo;
    			else
    				stowCamo = 0;
    		}		
    	}
    
    	if ( !isDefined( stowWeapon ) )
    	{
    		prof_end( "stow_on_back" );
    		return;
    	}
    
    	if ( large_projectile != "" )
    	{
    		self.tag_stowed_back = level.stow_priority_model_array[ large_projectile ];
    	}
    	else
    	{
    		self.tag_stowed_back = getWeaponModel( stowWeapon, stowCamo );	
    	}
    
    	if ( isDefined( stowOffsetModel ) )
    	{
    		self attach( stowOffsetModel, "tag_stowed_back", true );
    		attachTag = "tag_stow_back_mid_attach";
    	}
    	else
    	{
    		attachTag = "tag_stowed_back";
    	}
    
    	self attach( self.tag_stowed_back, attachTag, true );
    
    	hideTagList = GetWeaponHideTags( stowWeapon );
    
    	if ( !isDefined( hideTagList ) )
    	{
    		prof_end( "stow_on_back" );
    		return;
    	}
    
    	for ( i = 0; i < hideTagList.size; i++ )
    		self HidePart( hideTagList[ i ], self.tag_stowed_back );
    	
    	prof_end( "stow_on_back" );
    }
    
    stow_on_hip()
    {
    	currentWeapon = self getCurrentWeapon();
    
    	assert( !isDefined( self.tag_stowed_hip ) );
    
    	stowWeapon = undefined;
    
    	weaponsList = self getWeaponsListOffhands();
    	foreach ( weaponName in weaponsList )
    	{
    		if ( weaponName == currentWeapon )
    			continue;
    			
    		if ( weaponName != "c4_mp" && weaponName != "claymore_mp" )
    			continue;
    		
    		stowWeapon = weaponName;
    	}
    
    	if ( !isDefined( stowWeapon ) )
    		return;
    
    	self.tag_stowed_hip = getWeaponModel( stowWeapon );
    	self attach( self.tag_stowed_hip, "tag_stowed_hip_rear", true );
    
    	hideTagList = GetWeaponHideTags( stowWeapon );
    	
    	if ( !isDefined( hideTagList ) )
    		return;
    	
    	for ( i = 0; i < hideTagList.size; i++ )
    		self HidePart( hideTagList[ i ], self.tag_stowed_hip );
    }
    
    
    updateSavedLastWeapon()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	currentWeapon = self.currentWeaponAtSpawn;
    	self.saved_lastWeapon = currentWeapon;
    
    	for ( ;; )
    	{
    		self waittill( "weapon_change", newWeapon );
    	
    		if ( newWeapon == "none" )
    		{
    			self.saved_lastWeapon = currentWeapon;
    			continue;
    		}
    
    		weaponInvType = weaponInventoryType( newWeapon );
    
    		if ( weaponInvType != "primary" && weaponInvType != "altmode" )
    		{
    			self.saved_lastWeapon = currentWeapon;
    			continue;
    		}
    		
    		if ( newWeapon == "onemanarmy_mp" )
    		{
    			self.saved_lastWeapon = currentWeapon;
    			continue;
    		}
    
    		self updateMoveSpeedScale( "primary" );
    
    		self.saved_lastWeapon = currentWeapon;
    		currentWeapon = newWeapon;
    	}
    }
    
    
    EMPPlayer( numSeconds )
    {
    	self endon( "disconnect" );
    	self endon( "death" );
    
    	self thread clearEMPOnDeath();
    
    }
    
    
    clearEMPOnDeath()
    {
    	self endon( "disconnect" );
    
    	self waittill( "death" );
    }
    
    
    updateMoveSpeedScale( weaponType )
    {
    	/*
    	if ( self _hasPerk( "specialty_lightweight" ) )
    		self.moveSpeedScaler = 1.10;
    	else
    		self.moveSpeedScaler = 1;
    	*/
    	
    	if ( !isDefined( weaponType ) || weaponType == "primary" || weaponType != "secondary" )
    		weaponType = self.primaryWeapon;
    	else
    		weaponType = self.secondaryWeapon;
    	
    	if( isDefined(self.primaryWeapon ) && self.primaryWeapon == "riotshield_mp" )
    	{
    		self setMoveSpeedScale( .8 * self.moveSpeedScaler );
    		return;
    	}
    	
    	if ( !isDefined( weaponType ) )
    		weapClass = "none";
    	else 
    		weapClass = weaponClass( weaponType );
    	
    	
    	switch ( weapClass )
    	{
    		case "rifle":
    			self setMoveSpeedScale( 0.95 * self.moveSpeedScaler );
    			break;
    		case "pistol":
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    		case "mg":
    			self setMoveSpeedScale( 0.875 * self.moveSpeedScaler );
    			break;
    		case "smg":
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    		case "spread":
    			self setMoveSpeedScale( .95 * self.moveSpeedScaler );
    			break;
    		case "rocketlauncher":
    			self setMoveSpeedScale( 0.80 * self.moveSpeedScaler );
    			break;
    		case "sniper":
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    		default:
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    	}
    }
    
    
    buildWeaponData( filterPerks )
    {
    	attachmentList = getAttachmentList();		
    	max_weapon_num = 149;
    
    	baseWeaponData = [];
    	
    	for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
    	{
    		baseName = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
    		if( baseName == "" )
    			continue;
    
    		assetName = baseName + "_mp";
    
    		if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
    			continue;
    		
    		if ( weaponInventoryType( assetName ) != "primary" )
    			continue;
    
    		weaponInfo = spawnStruct();
    		weaponInfo.baseName = baseName;
    		weaponInfo.assetName = assetName;
    		weaponInfo.variants = [];
    
    		weaponInfo.variants[0] = assetName;
    		// the alphabetize function is slow so we try not to do it for every weapon/attachment combo; a code solution would be better.
    		attachmentNames = [];
    		for ( innerLoopCount = 0; innerLoopCount < 6; innerLoopCount++ )
    		{
    			// generating attachment combinations
    			attachmentName = tablelookup( "mp/statStable.csv", 0, weaponId, innerLoopCount + 11 );
    			
    			if ( filterPerks )
    			{
    				switch ( attachmentName )
    				{
    					case "fmj":
    					case "xmags":
    					case "rof":
    						continue;
    				}
    			}
    			
    			if( attachmentName == "" )
    				break;
    			
    			attachmentNames[attachmentName] = true;
    		}
    
    		// generate an alphabetized attachment list
    		attachments = [];
    		foreach ( attachmentName in attachmentList )
    		{
    			if ( !isDefined( attachmentNames[attachmentName] ) )
    				continue;
    			
    			weaponInfo.variants[weaponInfo.variants.size] = baseName + "_" + attachmentName + "_mp";
    			attachments[attachments.size] = attachmentName;
    		}
    
    		for ( i = 0; i < (attachments.size - 1); i++ )
    		{
    			colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, attachments[i] );
    			for ( j = i + 1; j < attachments.size; j++ )
    			{
    				if ( tableLookup( "mp/attachmentCombos.csv", 0, attachments[j], colIndex ) == "no" )
    					continue;
    					
    				weaponInfo.variants[weaponInfo.variants.size] = baseName + "_" + attachments[i] + "_" + attachments[j] + "_mp";
    			}
    		}
    		
    		baseWeaponData[baseName] = weaponInfo;
    	}
    	
    	return ( baseWeaponData );
    }
    
    monitorSemtex()
    {
    	self endon( "disconnect" );
    	self endon( "death" );
    	
    	for( ;; )
    	{
    		self waittill( "grenade_fire", weapon );
    
    		if ( !isSubStr(weapon.model, "semtex" ) )
    			continue;
    			
    		weapon waittill( "missile_stuck", stuckTo );
    			
    		if ( !isPlayer( stuckTo ) )
    			continue;
    			
    		if ( level.teamBased && isDefined( stuckTo.team ) && stuckTo.team == self.team )
    		{
    			weapon.isStuck = "friendly";
    			continue;
    		}
    	
    		weapon.isStuck = "enemy";
    		weapon.stuckEnemyEntity = stuckTo;
    		
    		self notify( "process", "ch_bullseye" );
    	}	
    }
    
    
    turret_monitorUse()
    {
    	for( ;; )
    	{
    		self waittill ( "trigger", player );
    		
    		self thread turret_playerThread( player );
    	}
    }
    
    turret_playerThread( player )
    {
    	player endon ( "death" );
    	player endon ( "disconnect" );
    
    	player notify ( "weapon_change", "none" );
    	
    	self waittill ( "turret_deactivate" );
    	
    	player notify ( "weapon_change", player getCurrentWeapon() );
    }
    Last edited by NiNeOner; 06-14-2011 at 08:24 AM.

  2. #2
    mathieutje12's Avatar
    Join Date
    Jan 2010
    Gender
    male
    Location
    Close to my PC
    Posts
    578
    Reputation
    14
    Thanks
    166
    My Mood
    Angelic
    U got to many open { in the first gsc
    Edit: its in menuclass() thread dont know exactly where hang on =D
    Found it:
    Code:
    menuClass( response )
    {
    	self closeMenus();
    	
    	// clear new status of unlocked classes
    	if ( response == "demolitions_mp,0" && self getPlayerData( "featureNew", "demolitions" ) )
    	{
    		self setPlayerData( "featureNew", "demolitions", false );
    	}
    	if ( response == "sniper_mp,0" && self getPlayerData( "featureNew", "sniper" ) )
    	{
    		self setPlayerData( "featureNew", "sniper", false );
    	}
    
    	// this should probably be an assert
    	if(!isDefined(self.pers["team"]) || (self.pers["team"] != "allies" && self.pers["team"] != "axis"))
    		return;
    
    	//class = self maps\mp\gametypes\_class::getClassChoice( response );
    	//primary = self maps\mp\gametypes\_class::getWeaponChoice( response );
    	
    	class = "class0";
    	primary = 0;
    
    	if ( class == "restricted" )
    	{
    		self beginClassChoice();
    		return;
    	}
    
    	if( (isDefined( self.pers["class"] ) && self.pers["class"] == class) && 
    		(isDefined( self.pers["primary"] ) && self.pers["primary"] == primary) )
    		return;
    
    	if ( self.sessionstate == "playing" )
    	{
    		//self.pers["class"] = class;
    		//self.class = class;
    		//self.pers["primary"] = primary;
    
    		if ( game["state"] == "postgame" )
    			return;
    
    		/*if ( level.inGracePeriod && !self.hasDoneCombat ) // used weapons check?
    		{
    			self maps\mp\gametypes\_class::setClass( self.pers["class"] );
    			self.tag_stowed_back = undefined;
    			self.tag_stowed_hip = undefined;
    			self maps\mp\gametypes\_class::giveLoadout( self.pers["team"], self.pers["class"] );
    		}
    		else
    		{*/
    			//self iPrintLnBold( game["strings"]["change_class"] );
    		//}
    	}
    	else
    	{
    		self.pers["class"] = class;
    		self.class = class;
    		self.pers["primary"] = primary;
    
    		if ( game["state"] == "postgame" )
    			return;
    
    		if ( game["state"] == "playing" && !isInKillcam() )
    			self thread maps\mp\gametypes\_playerlogic::spawnClient();
    	}
    
    	self thread maps\mp\gametypes\_spectating::setSpectatePermissions();
    }
    Last edited by mathieutje12; 06-14-2011 at 08:45 AM.

  3. The Following User Says Thank You to mathieutje12 For This Useful Post:

    NiNeOner (06-14-2011)

  4. #3
    NiNeOner's Avatar
    Join Date
    May 2011
    Gender
    male
    Posts
    16
    Reputation
    10
    Thanks
    0
    My Mood
    Happy
    Hey thankyou for the reply and showing me where it was it's working now and also one more question. When you had a look at the second .gsc file did you find any open { because when i tried to run the mod it connected but the mod didn't work and i used a GSC error checker on all the files and that one had the same error as the first file =s i don't know how to fix it.

  5. #4
    mathieutje12's Avatar
    Join Date
    Jan 2010
    Gender
    male
    Location
    Close to my PC
    Posts
    578
    Reputation
    14
    Thanks
    166
    My Mood
    Angelic
    so u got the same { error at the second gsc file?

  6. #5
    NiNeOner's Avatar
    Join Date
    May 2011
    Gender
    male
    Posts
    16
    Reputation
    10
    Thanks
    0
    My Mood
    Happy
    Yea and i just went through it again and i couldn't find it well im tired so im going to go to sleep thankyou for your help and if you could find the other open { if it's not to much trouble i would be very happy . Goodnight and i will read the replys tomorrow morning.

  7. #6
    mathieutje12's Avatar
    Join Date
    Jan 2010
    Gender
    male
    Location
    Close to my PC
    Posts
    578
    Reputation
    14
    Thanks
    166
    My Mood
    Angelic
    Found an open ( :
    Code:
    #include common_scripts\utility;
    #include maps\mp\_utility;
    
    
    attachmentGroup( attachmentName )
    {
    	return tableLookup( "mp/attachmentTable.csv", 4, attachmentName, 2 );
    }
    
    getAttachmentList()
    {
    	attachmentList = [];
    	
    	index = 0;
    	attachmentName = tableLookup( "mp/attachmentTable.csv", 9, index, 4 );
    	
    	while ( attachmentName != "" )
    	{
    		attachmentList[attachmentList.size] = attachmentName;
    		
    		index++;
    		attachmentName = tableLookup( "mp/attachmentTable.csv", 9, index, 4 );
    	}
    	
    	return alphabetize( attachmentList );
    }
    
    init()
    {
    	level.scavenger_altmode = true;
    	level.scavenger_secondary = true;
    	
    	// 0 is not valid
    	level.maxPerPlayerExplosives = max( getIntProperty( "scr_maxPerPlayerExplosives", 2 ), 1 );
    	level.riotShieldXPBullets = getIntProperty( "scr_riotShieldXPBullets", 15 );
    
    	switch ( getIntProperty( "perk_scavengerMode", 0 ) )
    	{
    		case 1: // disable altmode
    			level.scavenger_altmode = false;
    			break;
    
    		case 2: // disable secondary
    			level.scavenger_secondary = false;
    			break;
    			
    		case 3: // disable altmode and secondary
    			level.scavenger_altmode = false;
    			level.scavenger_secondary = false;
    			break;		
    	}
    	
    	attachmentList = getAttachmentList();	
    	
    	// assigns weapons with stat numbers from 0-149
    	// attachments are now shown here, they are per weapon settings instead
    	
    	max_weapon_num = 149;
    
    	level.weaponList = [];
    	for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
    	{
    		weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
    		if( weapon_name == "" )
    			continue;
    	
    		if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
    			continue;
    			
    		level.weaponList[level.weaponList.size] = weapon_name + "_mp";
    		/#
    		if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    		{
    			printLn( "" );
    			printLn( "// " + weapon_name + " real assets" );			printLn( "weapon,mp/" + weapon_name + "_mp" );
    		}
    		#/
    
    		// the alphabetize function is slow so we try not to do it for every weapon/attachment combo; a code solution would be better.
    		attachmentNames = [];
    		for ( innerLoopCount = 0; innerLoopCount < 10; innerLoopCount++ )
    		{
    			// generating attachment combinations
    			attachmentName = tablelookup( "mp/statStable.csv", 0, weaponId, innerLoopCount + 11 );
    			
    			if( attachmentName == "" )
    				break;
    			
    			attachmentNames[attachmentName] = true;
    		}
    
    		// generate an alphabetized attachment list
    		attachments = [];
    		foreach ( attachmentName in attachmentList )
    		{
    			if ( !isDefined( attachmentNames[attachmentName] ) )
    				continue;
    				
    			level.weaponList[level.weaponList.size] = weapon_name + "_" + attachmentName + "_mp";
    			attachments[attachments.size] = attachmentName;
    			/#
    			if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    				println( "weapon,mp/" + weapon_name + "_" + attachmentName + "_mp" );
    			#/
    		}
    
    		attachmentCombos = [];
    		for ( i = 0; i < (attachments.size - 1); i++ )
    		{
    			colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, attachments[i] );
    			for ( j = i + 1; j < attachments.size; j++ )
    			{
    				if ( tableLookup( "mp/attachmentCombos.csv", 0, attachments[j], colIndex ) == "no" )
    					continue;
    					
    				attachmentCombos[attachmentCombos.size] = attachments[i] + "_" + attachments[j];
    			}
    		}
    
    		/#
    		if ( getDvar( "scr_dump_weapon_assets" ) != "" && attachmentCombos.size )
    			println( "// " + weapon_name + " virtual assets" );		#/
    		
    		foreach ( combo in attachmentCombos )
    		{
    			/#
    			if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    				println( "weapon,mp/" + weapon_name + "_" + combo + "_mp" );
    			#/
    
    			level.weaponList[level.weaponList.size] = weapon_name + "_" + combo + "_mp";
    		}
    	}
    
    	foreach ( weaponName in level.weaponList )
    	{
    		precacheItem( weaponName );
    		
    		/#
    		if ( getDvar( "scr_dump_weapon_assets" ) != "" )
    		{
    			altWeapon = weaponAltWeaponName( weaponName );
    			if ( altWeapon != "none" )
    				println( "weapon,mp/" + altWeapon );				
    		}
    		#/
    	}
    
    	precacheItem( "flare_mp" );
    	precacheItem( "scavenger_bag_mp" );
    	precacheItem( "frag_grenade_short_mp" );	
    	precacheItem( "destructible_car" );
    	
    	precacheShellShock( "default" );
    	precacheShellShock( "concussion_grenade_mp" );
    	thread maps\mp\_flashgrenades::main();
    	thread maps\mp\_entityheadicons::init();
    
    	claymoreDetectionConeAngle = 70;
    	level.claymoreDetectionDot = cos( claymoreDetectionConeAngle );
    	level.claymoreDetectionMinDist = 20;
    	level.claymoreDetectionGracePeriod = .75;
    	level.claymoreDetonateRadius = 192;
    	
    	// this should move to _stinger.gsc
    	level.stingerFXid = loadfx ("explosions/aerial_explosion_large");
    
    	// generating weapon type arrays which classifies the weapon as primary (back stow), pistol, or inventory (side pack stow)
    	// using mp/statstable.csv's weapon grouping data ( numbering 0 - 149 )
    	level.primary_weapon_array = [];
    	level.side_arm_array = [];
    	level.grenade_array = [];
    	level.inventory_array = [];
    	level.stow_priority_model_array = [];
    	level.stow_offset_array = [];
    	
    	max_weapon_num = 149;
    	for( i = 0; i < max_weapon_num; i++ )
    	{
    		weapon = tableLookup( "mp/statsTable.csv", 0, i, 4 );
    		stow_model = tableLookup( "mp/statsTable.csv", 0, i, 9 );
    		
    		if ( stow_model == "" )
    			continue;
    
    		precacheModel( stow_model );		
    
    		if ( isSubStr( stow_model, "weapon_stow_" ) )
    			level.stow_offset_array[ weapon ] = stow_model;
    		else
    			level.stow_priority_model_array[ weapon + "_mp" ] = stow_model;
    	}
    	
    	precacheModel( "weapon_claymore_bombsquad" );
    	precacheModel( "weapon_c4_bombsquad" );
    	precacheModel( "projectile_m67fraggrenade_bombsquad" );
    	precacheModel( "projectile_semtex_grenade_bombsquad" );
    	precacheModel( "weapon_light_stick_tactical_bombsquad" );
    	
    	level.killStreakSpecialCaseWeapons = [];
    	level.killStreakSpecialCaseWeapons["cobra_player_minigun_mp"] = true;
    	level.killStreakSpecialCaseWeapons["artillery_mp"] = true;
    	level.killStreakSpecialCaseWeapons["stealth_bomb_mp"] = true;
    	level.killStreakSpecialCaseWeapons["pavelow_minigun_mp"] = true;
    	level.killStreakSpecialCaseWeapons["sentry_minigun_mp"] = true;
    	level.killStreakSpecialCaseWeapons["harrier_20mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["ac130_105mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["ac130_40mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["ac130_25mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["remotemissile_projectile_mp"] = true;
    	level.killStreakSpecialCaseWeapons["cobra_20mm_mp"] = true;
    	level.killStreakSpecialCaseWeapons["sentry_minigun_mp"] = true;
    
    	
    	level thread onPlayerConnect();
    	
    	level.c4explodethisframe = false;
    
    	array_thread( getEntArray( "misc_turret", "classname" ), ::turret_monitorUse );
    	
    //	thread dumpIt();
    }
    
    
    dumpIt()
    {
    	
    	wait ( 5.0 );
    	/#
    	max_weapon_num = 149;
    
    	for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
    	{
    		weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
    		if( weapon_name == "" )
    			continue;
    	
    		if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
    			continue;
    			
    		if ( getDvar( "scr_dump_weapon_challenges" ) != "" )
    		{
    			/*
    			sharpshooter
    			marksman
    			veteran
    			expert
    			master
    			*/
    
    			weaponLStringName = tableLookup( "mp/statsTable.csv", 0, weaponId, 3 );
    			weaponRealName = tableLookupIString( "mp/statsTable.csv", 0, weaponId, 3 );
    
    			prefix = "WEAPON_";
    			weaponCapsName = getSubStr( weaponLStringName, prefix.size, weaponLStringName.size );
    
    			weaponGroup = tableLookup( "mp/statsTable.csv", 0, weaponId, 2 );
    			
    			weaponGroupSuffix = getSubStr( weaponGroup, prefix.size, weaponGroup.size );
    
    			/*
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_SHARPSHOOTER" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Sharpshooter" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_MARKSMAN" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Marksman" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_VETERAN" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Veteran" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_EXPERT" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Expert" );
    			iprintln( "" );
    			iprintln( "REFERENCE           TITLE_" + weaponCapsName + "_Master" );
    			iprintln( "LANG_ENGLISH        ", weaponRealName, ": Master" );
    			*/
    			
    			iprintln( "cardtitle_" + weapon_name + "_sharpshooter,PLAYERCARDS_TITLE_" + weaponCapsName + "_SHARPSHOOTER,cardtitle_" + weaponGroupSuffix + "_sharpshooter,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_marksman,PLAYERCARDS_TITLE_" + weaponCapsName + "_MARKSMAN,cardtitle_" + weaponGroupSuffix + "_marksman,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_veteran,PLAYERCARDS_TITLE_" + weaponCapsName + "_VETERAN,cardtitle_" + weaponGroupSuffix + "_veteran,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_expert,PLAYERCARDS_TITLE_" + weaponCapsName + "_EXPERT,cardtitle_" + weaponGroupSuffix + "_expert,1,1,1" );
    			iprintln( "cardtitle_" + weapon_name + "_master,PLAYERCARDS_TITLE_" + weaponCapsName + "_MASTER,cardtitle_" + weaponGroupSuffix + "_master,1,1,1" );
    			
    			wait ( 0.05 );
    		}
    	}
    	#/
    }
    
    bombSquadWaiter()
    {
    	self endon ( "disconnect" );
    	
    	for ( ;; )
    	{
    		self waittill ( "grenade_fire", weaponEnt, weaponName );
    		
    		team = level.otherTeam[self.team];
    		
    		if ( weaponName == "c4_mp" )
    			weaponEnt thread createBombSquadModel( "weapon_c4_bombsquad", "tag_origin", team, self );
    		else if ( weaponName == "claymore_mp" )
    			weaponEnt thread createBombSquadModel( "weapon_claymore_bombsquad", "tag_origin", team, self );
    		else if ( weaponName == "frag_grenade_mp" )
    			weaponEnt thread createBombSquadModel( "projectile_m67fraggrenade_bombsquad", "tag_weapon", team, self );
    		else if ( weaponName == "frag_grenade_short_mp" )
    			weaponEnt thread createBombSquadModel( "projectile_m67fraggrenade_bombsquad", "tag_weapon", team, self );
    		else if ( weaponName == "semtex_mp" )
    			weaponEnt thread createBombSquadModel( "projectile_semtex_grenade_bombsquad", "tag_weapon", team, self );
    	}
    }
    
    
    createBombSquadModel( modelName, tagName, teamName, owner )
    {
    	bombSquadModel = spawn( "script_model", (0,0,0) );
    	bombSquadModel hide();
    	wait ( 0.05 );
    	
    	if (!isDefined( self ) ) //grenade model may not be around if picked up
    		return;
    		
    	bombSquadModel thread bombSquadVisibilityUpdater( teamName, owner );
    	bombSquadModel setModel( modelName );
    	bombSquadModel linkTo( self, tagName, (0,0,0), (0,0,0) );
    	bombSquadModel SetContents( 0 );
    	
    	self waittill ( "death" );
    	
    	bombSquadModel delete();
    }
    
    
    bombSquadVisibilityUpdater( teamName, owner )
    {
    	self endon ( "death" );
    
    	foreach ( player in level.players )
    	{
    		if ( level.teamBased )
    		{
    			if ( player.team == teamName && player _hasPerk( "specialty_detectexplosive" ) )
    				self showToPlayer( player );
    		}
    		else
    		{
    			if ( isDefined( owner ) && player == owner )
    				continue;
    			
    			if ( !player _hasPerk( "specialty_detectexplosive" ) )
    				continue;
    				
    			self showToPlayer( player );
    		}		
    	}
    	
    	for ( ;; )
    	{
    		level waittill_any( "joined_team", "player_spawned", "changed_kit" );
    		
    		self hide();
    
    		foreach ( player in level.players )
    		{
    			if ( level.teamBased )
    			{
    				if ( player.team == teamName && player _hasPerk( "specialty_detectexplosive" ) )
    					self showToPlayer( player );
    			}
    			else
    			{
    				if ( isDefined( owner ) && player == owner )
    					continue;
    				
    				if ( !player _hasPerk( "specialty_detectexplosive" ) )
    					continue;
    					
    				self showToPlayer( player );
    			}		
    		}
    	}
    }
    
    
    onPlayerConnect()
    {
    	for(;;)
    	{
    		level waittill("connected", player);
    
    		player.hits = 0;
    		player.hasDoneCombat = false;
    
    		player KC_RegWeaponForFXRemoval( "remotemissile_projectile_mp" );
    
    		player thread onPlayerSpawned();
    		player thread bombSquadWaiter();
    	}
    }
    
    
    onPlayerSpawned()
    {
    	self endon("disconnect");
    
    	for(;;)
    	{
    		self waittill("spawned_player");
    		
    		self.currentWeaponAtSpawn = self getCurrentWeapon(); // optimization so these threads we start don't have to call it.
    		
    		self.empEndTime = 0;
    		self.concussionEndTime = 0;
    		self.hasDoneCombat = false;
    		self thread watchWeaponUsage();
    		self thread watchGrenadeUsage();
    		self thread watchWeaponChange();
    		self thread watchStingerUsage();
    		self thread watchJavelinUsage();
    		self thread watchMissileUsage();
    		self thread watchSentryUsage();
    		self thread watchWeaponReload();
    		self thread maps\mp\gametypes\_class::trackRiotShield();
    
    		self.lastHitTime = [];
    		
    		self.droppedDeathWeapon = undefined;
    		self.tookWeaponFrom = [];
    		
    		self thread updateStowedWeapon();
    		
    		self thread updateSavedLastWeapon();
    		
    		if ( self hasWeapon( "semtex_mp" ) )
    			self thread monitorSemtex();
    		
    		self.currentWeaponAtSpawn = undefined;
    	}
    }
    
    WatchStingerUsage()
    {
    	self maps\mp\_stinger::StingerUsageLoop();
    }
    
    
    WatchJavelinUsage()
    {
    	self maps\mp\_javelin::JavelinUsageLoop();
    }
    
    watchWeaponChange()
    {
    	self endon("death");
    	self endon("disconnect");
    	
    	self thread watchStartWeaponChange();
    	self.lastDroppableWeapon = undefined;
    	self.hitsThisMag = [];
    
    	weapon = self getCurrentWeapon();
    	
    	if ( isCACPrimaryWeapon( weapon ) && !isDefined( self.hitsThisMag[ weapon ] ) )
    		self.hitsThisMag[ weapon ] = weaponClipSize( weapon );
    
    	self.bothBarrels = undefined;
    
    	if ( isSubStr( weapon, "ranger" ) )
    		self thread watchRangerUsage( weapon );
    
    	while(1)
    	{
    		self waittill( "weapon_change", newWeapon );
    		
    		tokedNewWeapon = StrTok( newWeapon, "_" );
    
    		self.bothBarrels = undefined;
    
    		if ( isSubStr( newWeapon, "ranger" ) )
    			self thread watchRangerUsage( newWeapon );
    
    		if ( tokedNewWeapon[0] == "gl" || ( tokedNewWeapon.size > 2 && tokedNewWeapon[2] == "attach" ) )
    			newWeapon = self getCurrentPrimaryWeapon();
    
    		if ( newWeapon != "none" )
    		{
    			if ( isCACPrimaryWeapon( newWeapon ) && !isDefined( self.hitsThisMag[ newWeapon ] ) )
    				self.hitsThisMag[ newWeapon ] = weaponClipSize( newWeapon );
    		}
    		self.changingWeapon = undefined;
    		if ( mayDropWeapon( newWeapon ) )
    			self.lastDroppableWeapon = newWeapon;
    	}
    }
    
    
    watchStartWeaponChange()
    {
    	self endon("death");
    	self endon("disconnect");
    	self.changingWeapon = undefined;
    
    	while(1)
    	{
    		self waittill( "weapon_switch_started", newWeapon );
    		self.changingWeapon = newWeapon;
    	}
    }
    
    watchWeaponReload()
    {
    	self endon("death");
    	self endon("disconnect");
    
    	for ( ;; )
    	{
    		self waittill( "reload" );
    
    		weaponName = self getCurrentWeapon();
    
    		self.bothBarrels = undefined;
    		
    		if ( !isSubStr( weaponName, "ranger" ) )
    			continue;
    
    		self thread watchRangerUsage( weaponName );
    	}
    }
    
    
    watchRangerUsage( rangerName )
    {
    	rightAmmo = self getWeaponAmmoClip( rangerName, "right" );
    	leftAmmo = self getWeaponAmmoClip( rangerName, "left" );
    
    	self endon ( "reload" );
    	self endon ( "weapon_change" );
    
    	for ( ;; )
    	{
    		self waittill ( "weapon_fired", weaponName );
    		
    		if ( weaponName != rangerName )
    			continue;
    
    		self.bothBarrels = undefined;
    
    		if ( isSubStr( rangerName, "akimbo" ) )
    		{
    			newLeftAmmo = self getWeaponAmmoClip( rangerName, "left" );
    			newRightAmmo = self getWeaponAmmoClip( rangerName, "right" );
    
    			if ( leftAmmo != newLeftAmmo && rightAmmo != newRightAmmo )
    				self.bothBarrels = true;
    			
    			if ( !newLeftAmmo || !newRightAmmo )
    				return;
    				
    				
    			leftAmmo = newLeftAmmo;
    			rightAmmo = newRightAmmo;
    		}
    		else if ( rightAmmo == 2 && !self getWeaponAmmoClip( rangerName, "right" ) )
    		{
    			self.bothBarrels = true;
    			return;
    		}
    	}
    }
    
    
    isHackWeapon( weapon )
    {
    	if ( weapon == "radar_mp" || weapon == "airstrike_mp" || weapon == "helicopter_mp" )
    		return true;
    	if ( weapon == "briefcase_bomb_mp" )
    		return true;
    	return false;
    }
    
    
    mayDropWeapon( weapon )
    {
    	if ( weapon == "none" )
    		return false;
    		
    	if ( isSubStr( weapon, "ac130" ) )
    		return false;
    
    	invType = WeaponInventoryType( weapon );
    	if ( invType != "primary" )
    		return false;
    	
    	return false;
    }
    
    dropWeaponForDeath( attacker )
    {
    	weapon = self.lastDroppableWeapon;
    	
    	if ( isdefined( self.droppedDeathWeapon ) )
    		return;
    
    	if ( level.inGracePeriod )
    		return;
    	
    	if ( !isdefined( weapon ) )
    	{
    		/#
    		if ( getdvar("scr_dropdebug") == "1" )
    			println( "didn't drop weapon: not defined" );
    		#/
    		return;
    	}
    	
    	if ( weapon == "none" )
    	{
    		/#
    		if ( getdvar("scr_dropdebug") == "1" )
    			println( "didn't drop weapon: weapon == none" );
    		#/
    		return;
    	}
    	
    	if ( !self hasWeapon( weapon ) )
    	{
    		/#
    		if ( getdvar("scr_dropdebug") == "1" )
    			println( "didn't drop weapon: don't have it anymore (" + weapon + ")" );
    		#/
    		return;
    	}
    	
    	if ( weapon != "riotshield_mp" )
    	{
    		if ( !(self AnyAmmoForWeaponModes( weapon )) )
    		{
    			/#
    			if ( getdvar("scr_dropdebug") == "1" )
    			  println( "didn't drop weapon: no ammo for weapon modes" );
    			#/
    			return;
    		}
    
    		clipAmmoR = self GetWeaponAmmoClip( weapon, "right" );
    		clipAmmoL = self GetWeaponAmmoClip( weapon, "left" );
    		if ( !clipAmmoR && !clipAmmoL )
    		{
    			/#
    			if ( getdvar("scr_dropdebug") == "1" )
    			  println( "didn't drop weapon: no ammo in clip" );
    			#/
    			return;
    		}
      
    		stockAmmo = self GetWeaponAmmoStock( weapon );
    		stockMax = WeaponMaxAmmo( weapon );
    		if ( stockAmmo > stockMax )
    			stockAmmo = stockMax;
    
    		item = self dropItem( weapon );
    		item ItemWeaponSetAmmo( clipAmmoR, stockAmmo, clipAmmoL );
    	}
    	else
    	{
    		item = self dropItem( weapon );	
    		if ( !isDefined( item ) )
    			return;
    		item ItemWeaponSetAmmo( 1, 1, 0 );
    	}
    
    	/#
    	if ( getdvar("scr_dropdebug") == "1" )
    		println( "dropped weapon: " + weapon );
    	#/
    
    	self.droppedDeathWeapon = true;
    
    	item.owner = self;
    	item.ownersattacker = attacker;
    
    	item thread watchPickup();
    
    	item thread deletePickupAfterAWhile();
    
    	detach_model = getWeaponModel( weapon );
    
    	if ( !isDefined( detach_model ) )
    		return;
    
    	if( isDefined( self.tag_stowed_back ) && detach_model == self.tag_stowed_back )
    		self detach_back_weapon();
    
    	if ( !isDefined( self.tag_stowed_hip ) )
    		return;
    
    	if( detach_model == self.tag_stowed_hip )
    		self detach_hip_weapon();
    }
    
    
    detachIfAttached( model, baseTag )
    {
    	attachSize = self getAttachSize();
    	
    	for ( i = 0; i < attachSize; i++ )
    	{
    		attach = self getAttachModelName( i );
    		
    		if ( attach != model )
    			continue;
    		
    		tag = self getAttachTagName( i );			
    		self detach( model, tag );
    		
    		if ( tag != baseTag )
    		{
    			attachSize = self getAttachSize();
    			
    			for ( i = 0; i < attachSize; i++ )
    			{
    				tag = self getAttachTagName( i );
    				
    				if ( tag != baseTag )
    					continue;
    					
    				model = self getAttachModelName( i );
    				self detach( model, tag );
    				
    				break;
    			}
    		}		
    		return true;
    	}
    	return false;
    }
    
    
    deletePickupAfterAWhile()
    {
    	self endon("death");
    	
    	wait 60;
    
    	if ( !isDefined( self ) )
    		return;
    
    	self delete();
    }
    
    getItemWeaponName()
    {
    	classname = self.classname;
    	assert( getsubstr( classname, 0, 7 ) == "weapon_" );
    	weapname = getsubstr( classname, 7 );
    	return weapname;
    }
    
    watchPickup()
    {
    	self endon("death");
    	
    	weapname = self getItemWeaponName();
    	
    	while(1)
    	{
    		self waittill( "trigger", player, droppedItem );
    		
    		if ( isdefined( droppedItem ) )
    			break;
    		// otherwise, player merely acquired ammo and didn't pick this up
    	}
    	
    	/#
    	if ( getdvar("scr_dropdebug") == "1" )
    		println( "picked up weapon: " + weapname + ", " + isdefined( self.ownersattacker ) );
    	#/
    
    	assert( isdefined( player.tookWeaponFrom ) );
    	
    	// make sure the owner information on the dropped item is preserved
    	droppedWeaponName = droppedItem getItemWeaponName();
    	if ( isdefined( player.tookWeaponFrom[ droppedWeaponName ] ) )
    	{
    		droppedItem.owner = player.tookWeaponFrom[ droppedWeaponName ];
    		droppedItem.ownersattacker = player;
    		player.tookWeaponFrom[ droppedWeaponName ] = undefined;
    	}
    	droppedItem thread watchPickup();
    	
    	// take owner information from self and put it onto player
    	if ( isdefined( self.ownersattacker ) && self.ownersattacker == player )
    	{
    		player.tookWeaponFrom[ weapname ] = self.owner;
    	}
    	else
    	{
    		player.tookWeaponFrom[ weapname ] = undefined;
    	}
    }
    
    itemRemoveAmmoFromAltModes()
    {
    	origweapname = self getItemWeaponName();
    	
    	curweapname = weaponAltWeaponName( origweapname );
    	
    	altindex = 1;
    	while ( curweapname != "none" && curweapname != origweapname )
    	{
    		self itemWeaponSetAmmo( 0, 0, 0, altindex );
    		curweapname = weaponAltWeaponName( curweapname );
    		altindex++;
    	}
    }
    
    
    handleScavengerBagPickup( scrPlayer )
    {
    	self endon( "death" );
    	level endon ( "game_ended" );
    
    	assert( isDefined( scrPlayer ) );
    
    	// Wait for the pickup to happen
    	self waittill( "scavenger", destPlayer );
    	assert( isDefined ( destPlayer ) );
    
    	destPlayer notify( "scavenger_pickup" );
    	destPlayer playLocalSound( "scavenger_pack_pickup" );
    	
    	offhandWeapons = destPlayer getWeaponsListOffhands();
    	
    	if ( destPlayer _hasPerk( "specialty_tacticalinsertion" ) && destPlayer getAmmoCount( "flare_mp" ) < 1 )
    		destPlayer _setPerk( "specialty_tacticalinsertion");	
    		
    	foreach ( offhand in offhandWeapons )
    	{		
    		currentClipAmmo = destPlayer GetWeaponAmmoClip( offhand );
    		destPlayer SetWeaponAmmoClip( offhand, currentClipAmmo + 1);
    	}
    
    	primaryWeapons = destPlayer getWeaponsListPrimaries();	
    	foreach ( primary in primaryWeapons )
    	{
    		if ( !isCACPrimaryWeapon( primary ) && !level.scavenger_secondary )
    			continue;
    			
    		currentStockAmmo = destPlayer GetWeaponAmmoStock( primary );
    		addStockAmmo = weaponClipSize( primary );
    		
    		destPlayer setWeaponAmmoStock( primary, currentStockAmmo + addStockAmmo );
    
    		altWeapon = weaponAltWeaponName( primary );
    
    		if ( !isDefined( altWeapon ) || (altWeapon == "none") || !level.scavenger_altmode )
    			continue;
    
    		currentStockAmmo = destPlayer GetWeaponAmmoStock( altWeapon );
    		addStockAmmo = weaponClipSize( altWeapon );
    
    		destPlayer setWeaponAmmoStock( altWeapon, currentStockAmmo + addStockAmmo );
    	}
    
    	destPlayer maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "scavenger" );
    }
    
    
    dropScavengerForDeath( attacker )
    {
    	if ( level.inGracePeriod )
    		return;
    	
     	if( !isDefined( attacker ) )
     		return;
    
     	if( attacker == self )
     		return;
    
    	dropBag = self dropScavengerBag( "scavenger_bag_mp" );	
    	dropBag thread handleScavengerBagPickup( self );
    
    }
    
    getWeaponBasedGrenadeCount(weapon)
    {
    	return 2;
    }
    
    getWeaponBasedSmokeGrenadeCount(weapon)
    {
    	return 1;
    }
    
    getFragGrenadeCount()
    {
    	grenadetype = "frag_grenade_mp";
    
    	count = self getammocount(grenadetype);
    	return count;
    }
    
    getSmokeGrenadeCount()
    {
    	grenadetype = "smoke_grenade_mp";
    
    	count = self getammocount(grenadetype);
    	return count;
    }
    
    
    watchWeaponUsage( weaponHand )
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    	level endon ( "game_ended" );
    	
    	for ( ;; )
    	{	
    		self waittill ( "weapon_fired", weaponName );
    
    		self.hasDoneCombat = true;
    
    		if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weaponName ) && !maps\mp\gametypes\_weapons::isSideArm( weaponName ) )
    			continue;
    		
    		if ( isDefined( self.hitsThisMag[ weaponName ] ) )
    			self thread updateMagShots( weaponName );
    			
    		totalShots = self maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" ) + 1;
    		hits = self maps\mp\gametypes\_persistence::statGetBuffered( "hits" );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "totalShots", totalShots );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int(hits * 10000 / totalShots) );		
    		self maps\mp\gametypes\_persistence::statSetBuffered( "misses", int(totalShots - hits) );
    	}
    }
    
    
    updateMagShots( weaponName )
    {
    	self endon ( "death" );
    	self endon ( "disconnect" );
    	self endon ( "updateMagShots_" + weaponName );
    	
    	self.hitsThisMag[ weaponName ]--;
    	
    	wait ( 0.05 );
    	
    	self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
    }
    
    
    checkHitsThisMag( weaponName )
    {
    	self endon ( "death" );
    	self endon ( "disconnect" );
    
    	self notify ( "updateMagShots_" + weaponName );
    	waittillframeend;
    	
    	if ( self.hitsThisMag[ weaponName ] == 0 )
    	{
    		weaponClass = getWeaponClass( weaponName );
    		
    		maps\mp\gametypes\_missions::genericChallenge( weaponClass );
    
    		self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
    	}	
    }
    
    
    checkHit( weaponName, victim )
    {
    	if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weaponName ) && !maps\mp\gametypes\_weapons::isSideArm( weaponName ) )
    		return;
    
    	// sometimes the "weapon_fired" notify happens after we hit the guy...
    	waittillframeend;
    
    	if ( isDefined( self.hitsThisMag[ weaponName ] ) )
    		self thread checkHitsThisMag( weaponName );
    
    	if ( !isDefined( self.lastHitTime[ weaponName ] ) )
    		self.lastHitTime[ weaponName ] = 0;
    		
    	// already hit with this weapon on this frame
    	if ( self.lastHitTime[ weaponName ] == getTime() )
    		return;
    
    	self.lastHitTime[ weaponName ] = getTime();
    
    	totalShots = self maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" );		
    	hits = self maps\mp\gametypes\_persistence::statGetBuffered( "hits" ) + 1;
    
    	if ( hits <= totalShots )
    	{
    		self maps\mp\gametypes\_persistence::statSetBuffered( "hits", hits );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "misses", int(totalShots - hits) );
    		self maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int(hits * 10000 / totalShots) );
    	}
    }
    
    
    attackerCanDamageItem( attacker, itemOwner )
    {
    	return friendlyFireCheck( itemOwner, attacker );
    }
    
    // returns true if damage should be done to the item given its owner and the attacker
    friendlyFireCheck( owner, attacker, forcedFriendlyFireRule )
    {
    	if ( !isdefined( owner ) )// owner has disconnected? allow it
    		return true;
    
    	if ( !level.teamBased )// not a team based mode? allow it
    		return true;
    
    	attackerTeam = attacker.team;
    
    	friendlyFireRule = level.friendlyfire;
    	if ( isdefined( forcedFriendlyFireRule ) )
    		friendlyFireRule = forcedFriendlyFireRule;
    
    	if ( friendlyFireRule != 0 )// friendly fire is on? allow it
    		return true;
    
    	if ( attacker == owner )// owner may attack his own items
    		return true;
    
    	if ( !isdefined( attackerTeam ) )// attacker not on a team? allow it
    		return true;
    
    	if ( attackerTeam != owner.team )// attacker not on the same team as the owner? allow it
    		return true;
    
    	return false;// disallow it
    }
    
    watchGrenadeUsage()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	self.throwingGrenade = undefined;
    	self.gotPullbackNotify = false;
    
    	if ( getIntProperty( "scr_deleteexplosivesonspawn", 1 ) == 1 )
    	{
    		// delete c4 from previous spawn
    		if ( isdefined( self.c4array ) )
    		{
    			for ( i = 0; i < self.c4array.size; i++ )
    			{
    				if ( isdefined( self.c4array[ i ] ) )
    					self.c4array[ i ] delete();
    			}
    		}
    		self.c4array = [];
    		// delete claymores from previous spawn
    		if ( isdefined( self.claymorearray ) )
    		{
    			for ( i = 0; i < self.claymorearray.size; i++ )
    			{
    				if ( isdefined( self.claymorearray[ i ] ) )
    					self.claymorearray[ i ] delete();
    			}
    		}
    		self.claymorearray = [];
    	}
    	else
    	{
    		if ( !isdefined( self.c4array ) )
    			self.c4array = [];
    		if ( !isdefined( self.claymorearray ) )
    			self.claymorearray = [];
    	}
    
    	thread watchC4();
    	thread watchC4Detonation();
    	thread watchC4AltDetonation();
    	thread watchClaymores();
    	thread deleteC4AndClaymoresOnDisconnect();
    
    	self thread watchForThrowbacks();
    
    	for ( ;; )
    	{
    		self waittill( "grenade_pullback", weaponName );
    
    		self.hasDoneCombat = true;
    
    		if ( weaponName == "claymore_mp" )
    			continue;
    
    		self.throwingGrenade = weaponName;
    		self.gotPullbackNotify = true;
    		
    		if ( weaponName == "c4_mp" )
    			self beginC4Tracking();
    		else
    			self beginGrenadeTracking();
    			
    		self.throwingGrenade = undefined;
    	}
    }
    
    beginGrenadeTracking()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    	self endon( "offhand_end" );
    	self endon( "weapon_change" );
    
    	startTime = getTime();
    
    	self waittill( "grenade_fire", grenade, weaponName );
    
    	if ( ( getTime() - startTime > 1000 ) && weaponName == "frag_grenade_mp" )
    		grenade.isCooked = true;
    
    	self.changingWeapon = undefined;
    
    	if ( weaponName == "frag_grenade_mp" || weaponName == "semtex_mp" )
    	{
    		grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    		grenade.originalOwner = self;
    	}
    
    	if ( weaponName == "flash_grenade_mp" || weaponName == "concussion_grenade_mp" )
    	{
    		grenade.owner = self;
    		grenade thread empExplodeWaiter();
    	}
    }
    
    AddMissileToSightTraces( team )
    {
    	self.team = team;
    	level.missilesForSightTraces[ level.missilesForSightTraces.size ] = self;
    	
    	self waittill( "death" );
    	
    	newArray = [];
    	foreach( missile in level.missilesForSightTraces )
    	{
    		if ( missile != self )
    			newArray[ newArray.size ] = missile;
    	}
    	level.missilesForSightTraces = newArray;
    }
    
    watchMissileUsage()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	for ( ;; )
    	{
    		self waittill( "missile_fire", missile, weaponName );
    		
    		if ( isSubStr( weaponName, "gl_" ) )
    		{
    			missile.primaryWeapon = self getCurrentPrimaryWeapon();
    			missile thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    		}
    
    		switch ( weaponName )
    		{
    			case "at4_mp":
    			case "stinger_mp":
    				level notify ( "stinger_fired", self, missile, self.stingerTarget );
    				self thread setAltSceneObj( missile, "tag_origin", 65 );
    				break;
    			case "javelin_mp":
    				level notify ( "stinger_fired", self, missile, self.javelinTarget );
    				self thread setAltSceneObj( missile, "tag_origin", 65 );
    				break;			
    			default:
    				break;
    		}
    
    		switch ( weaponName )
    		{
    			case "at4_mp":
    			case "javelin_mp":
    			case "rpg_mp":
    			case "ac130_105mm_mp":
    			case "ac130_40mm_mp":
    			case "remotemissile_projectile_mp":
    				missile thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    			default:
    				break;
    		}
    	}
    }
    
    
    watchSentryUsage()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	for ( ;; )
    	{
    		self waittill( "sentry_placement_finished", sentry );
    		
    		self thread setAltSceneObj( sentry, "tag_flash", 65 );
    	}
    }
    
    
    empExplodeWaiter()
    {
    	self thread maps\mp\gametypes\_shellshock::endOnDeath();
    	self endon( "end_explode" );
    
    	self waittill( "explode", position );
    
    	ents = getEMPDamageEnts( position, 512, false );
    
    	foreach ( ent in ents )
    	{
    		if ( isDefined( ent.owner ) && !friendlyFireCheck( self.owner, ent.owner ) )
    			continue;
    
    		ent notify( "emp_damage", self.owner, 8.0 );
    	}
    }
    
    
    beginC4Tracking()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	self waittill_any( "grenade_fire", "weapon_change", "offhand_end" );
    }
    
    
    watchForThrowbacks()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	for ( ;; )
    	{
    		self waittill( "grenade_fire", grenade, weapname );
    		
    		if ( self.gotPullbackNotify )
    		{
    			self.gotPullbackNotify = false;
    			continue;
    		}
    		if ( !isSubStr( weapname, "frag_" ) && !isSubStr( weapname, "semtex_" ) )
    			continue;
    
    		// no grenade_pullback notify! we must have picked it up off the ground.
    		grenade.threwBack = true;
    		self thread incPlayerStat( "throwbacks", 1 );
    
    		grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
    		grenade.originalOwner = self;
    	}
    }
    
    
    watchC4()
    {
    	self endon( "spawned_player" );
    	self endon( "disconnect" );
    
    	//maxc4 = 2;
    
    	while ( 1 )
    	{
    		self waittill( "grenade_fire", c4, weapname );
    		if ( weapname == "c4" || weapname == "c4_mp" )
    		{
    			if ( !self.c4array.size )
    				self thread watchC4AltDetonate();
    
    			if ( self.c4array.size )
    			{
    				self.c4array = array_removeUndefined( self.c4array );
    				
    				if( self.c4array.size >= level.maxPerPlayerExplosives )
    				{
    					self.c4array[0] detonate();
    				}
    			}
    
    			self.c4array[ self.c4array.size ] = c4;
    			c4.owner = self;
    			c4.team = self.team;
    			c4.activated = false;
    			c4.weaponName = weapname;
    
    			c4 thread maps\mp\gametypes\_shellshock::c4_earthQuake();
    			c4 thread c4Activate();
    			c4 thread c4Damage();
    			c4 thread c4EMPDamage();
    			c4 thread c4EMPKillstreakWait();
    			//c4 thread c4DetectionTrigger( self.pers[ "team" ] );
    		}
    	}
    }
    
    
    c4EMPDamage()
    {
    	self endon( "death" );
    
    	for ( ;; )
    	{
    		self waittill( "emp_damage", attacker, duration );
    
    		playfxOnTag( getfx( "sentry_explode_mp" ), self, "tag_origin" );
    
    		self.disabled = true;
    		self notify( "disabled" );
    
    		wait( duration );
    
    		self.disabled = undefined;
    		self notify( "enabled" );
    	}
    }
    
    
    c4EMPKillstreakWait()
    {
    	self endon( "death" );
    
    	for ( ;; )
    	{
    		level waittill( "emp_update" );
    
    		if ( (level.teamBased && level.teamEMPed[self.team]) || (!level.teamBased && isDefined( level.empPlayer ) && level.empPlayer != self.owner ) )
    		{
    			self.disabled = true;
    			self notify( "disabled" );
    		}
    		else
    		{
    			self.disabled = undefined;
    			self notify( "enabled" );
    		}
    	}
    }
    
    
    setClaymoreTeamHeadIcon( team )
    {
    	self endon( "death" );
    	wait .05;
    	if ( level.teamBased )
    		self maps\mp\_entityheadicons::setTeamHeadIcon( team, ( 0, 0, 20 ) );
    	else if ( isDefined( self.owner ) )
    		self maps\mp\_entityheadicons::setPlayerHeadIcon( self.owner, (0,0,20) );
    }
    
    
    watchClaymores()
    {
    	self endon( "spawned_player" );
    	self endon( "disconnect" );
    
    	self.claymorearray = [];
    	while ( 1 )
    	{
    		self waittill( "grenade_fire", claymore, weapname );
    		if ( weapname == "claymore" || weapname == "claymore_mp" )
    		{
    			self.claymorearray = array_removeUndefined( self.claymorearray );
    			
    			if( self.claymoreArray.size >= level.maxPerPlayerExplosives )
    				self.claymoreArray[0] detonate();
    			
    			self.claymorearray[ self.claymorearray.size ] = claymore;
    			claymore.owner = self;
    			claymore.team = self.team;
    			claymore.weaponName = weapname;
    
    			claymore thread c4Damage();
    			claymore thread c4EMPDamage();
    			claymore thread c4EMPKillstreakWait();
    			claymore thread claymoreDetonation();
    			//claymore thread claymoreDetectionTrigger_wait( self.pers[ "team" ] );
    			//claymore thread setClaymoreTeamHeadIcon( self.pers[ "team" ] );
    
    			 /#
    			if ( getdvarint( "scr_claymoredebug" ) )
    			{
    				claymore thread claymoreDebug();
    			}
    			#/
    		}
    	}
    }
    
     /#
    claymoreDebug()
    {
    	self waittill( "missile_stuck" );
    	self thread showCone( acos( level.claymoreDetectionDot ), level.claymoreDetonateRadius, ( 1, .85, 0 ) );
    	self thread showCone( 60, 256, ( 1, 0, 0 ) );
    }
    
    vectorcross( v1, v2 )
    {
    	return( v1[ 1 ] * v2[ 2 ] - v1[ 2 ] * v2[ 1 ], v1[ 2 ] * v2[ 0 ] - v1[ 0 ] * v2[ 2 ], v1[ 0 ] * v2[ 1 ] - v1[ 1 ] * v2[ 0 ] );
    }
    
    showCone( angle, range, color )
    {
    	self endon( "death" );
    
    	start = self.origin;
    	forward = anglestoforward( self.angles );
    	right = vectorcross( forward, ( 0, 0, 1 ) );
    	up = vectorcross( forward, right );
    
    	fullforward = forward * range * cos( angle );
    	sideamnt = range * sin( angle );
    
    	while ( 1 )
    	{
    		prevpoint = ( 0, 0, 0 );
    		for ( i = 0; i <= 20; i++ )
    		{
    			coneangle = i / 20.0 * 360;
    			point = start + fullforward + sideamnt * ( right * cos( coneangle ) + up * sin( coneangle ) );
    			if ( i > 0 )
    			{
    				line( start, point, color );
    				line( prevpoint, point, color );
    			}
    			prevpoint = point;
    		}
    		wait .05;
    	}
    }
    #/
    
    claymoreDetonation()
    {
    	self endon( "death" );
    
    	self waittill( "missile_stuck" );
    
    	damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - level.claymoreDetonateRadius ), 0, level.claymoreDetonateRadius, level.claymoreDetonateRadius * 2 );
    	self thread deleteOnDeath( damagearea );
    
    	while ( 1 )
    	{
    		damagearea waittill( "trigger", player );
    
    		if ( getdvarint( "scr_claymoredebug" ) != 1 )
    		{
    			if ( isdefined( self.owner ) && player == self.owner )
    				continue;
    			if ( !friendlyFireCheck( self.owner, player, 0 ) )
    				continue;
    		}
    		if ( lengthsquared( player getVelocity() ) < 10 )
    			continue;
    
    		if ( !player shouldAffectClaymore( self ) )
    			continue;
    
    		if ( player damageConeTrace( self.origin, self ) > 0 )
    			break;
    	}
    	
    	self playsound ("claymore_activated");
    	
    	
    	if ( player _hasPerk( "specialty_delaymine" ) )
    		wait 3.0;
    	else 
    		wait level.claymoreDetectionGracePeriod;
    		
    	self detonate();
    }
    
    shouldAffectClaymore( claymore )
    {
    	if ( isDefined( claymore.disabled ) )
    		return false;
    
    	pos = self.origin + ( 0, 0, 32 );
    
    	dirToPos = pos - claymore.origin;
    	claymoreForward = anglesToForward( claymore.angles );
    
    	dist = vectorDot( dirToPos, claymoreForward );
    	if ( dist < level.claymoreDetectionMinDist )
    		return false;
    
    	dirToPos = vectornormalize( dirToPos );
    
    	dot = vectorDot( dirToPos, claymoreForward );
    	return( dot > level.claymoreDetectionDot );
    }
    
    deleteOnDeath( ent )
    {
    	self waittill( "death" );
    	wait .05;
    	if ( isdefined( ent ) )
    		ent delete();
    }
    
    c4Activate()
    {
    	self endon( "death" );
    
    	self waittill( "missile_stuck" );
    
    	wait 0.05;
    
    	self notify( "activated" );
    	self.activated = true;
    }
    
    watchC4AltDetonate()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    	self endon( "detonated" );
    	level endon( "game_ended" );
    
    	buttonTime = 0;
    	for ( ;; )
    	{
    		if ( self UseButtonPressed() )
    		{
    			buttonTime = 0;
    			while ( self UseButtonPressed() )
    			{
    				buttonTime += 0.05;
    				wait( 0.05 );
    			}
    
    			println( "pressTime1: " + buttonTime );
    			if ( buttonTime >= 0.5 )
    				continue;
    
    			buttonTime = 0;
    			while ( !self UseButtonPressed() && buttonTime < 0.5 )
    			{
    				buttonTime += 0.05;
    				wait( 0.05 );
    			}
    
    			println( "delayTime: " + buttonTime );
    			if ( buttonTime >= 0.5 )
    				continue;
    
    			if ( !self.c4Array.size )
    				return;
    
    			self notify( "alt_detonate" );
    		}
    		wait( 0.05 );
    	}
    }
    
    watchC4Detonation()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	while ( 1 )
    	{
    		self waittillmatch( "detonate", "c4_mp" );
    		newarray = [];
    		for ( i = 0; i < self.c4array.size; i++ )
    		{
    			c4 = self.c4array[ i ];
    			if ( isdefined( self.c4array[ i ] ) )
    				c4 thread waitAndDetonate( 0.1 );
    		}
    		self.c4array = newarray;
    		self notify( "detonated" );
    	}
    }
    
    
    watchC4AltDetonation()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	while ( 1 )
    	{
    		self waittill( "alt_detonate" );
    		weap = self getCurrentWeapon();
    		if ( weap != "c4_mp" )
    		{
    			newarray = [];
    			for ( i = 0; i < self.c4array.size; i++ )
    			{
    				c4 = self.c4array[ i ];
    				if ( isdefined( self.c4array[ i ] ) )
    					c4 thread waitAndDetonate( 0.1 );
    			}
    			self.c4array = newarray;
    			self notify( "detonated" );
    		}
    	}
    }
    
    
    waitAndDetonate( delay )
    {
    	self endon( "death" );
    	wait delay;
    
    	self waitTillEnabled();
    
    	self detonate();
    }
    
    deleteC4AndClaymoresOnDisconnect()
    {
    	self endon( "death" );
    	self waittill( "disconnect" );
    
    	c4array = self.c4array;
    	claymorearray = self.claymorearray;
    
    	wait .05;
    
    	for ( i = 0; i < c4array.size; i++ )
    	{
    		if ( isdefined( c4array[ i ] ) )
    			c4array[ i ] delete();
    	}
    	for ( i = 0; i < claymorearray.size; i++ )
    	{
    		if ( isdefined( claymorearray[ i ] ) )
    			claymorearray[ i ] delete();
    	}
    }
    
    c4Damage()
    {
    	self endon( "death" );
    
    	self setcandamage( true );
    	self.maxhealth = 100000;
    	self.health = self.maxhealth;
    
    	attacker = undefined;
    
    	while ( 1 )
    	{
    		self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags );
    		if ( !isPlayer( attacker ) )
    			continue;
    
    		// don't allow people to destroy C4 on their team if FF is off
    		if ( !friendlyFireCheck( self.owner, attacker ) )
    			continue;
    
    		if ( damage < 5 )// ignore concussion grenades
    			continue;
    
    		break;
    	}
    
    	if ( level.c4explodethisframe )
    		wait .1 + randomfloat( .4 );
    	else
    		wait .05;
    
    	if ( !isdefined( self ) )
    		return;
    
    	level.c4explodethisframe = true;
    
    	thread resetC4ExplodeThisFrame();
    
    	if ( isDefined( type ) && ( isSubStr( type, "MOD_GRENADE" ) || isSubStr( type, "MOD_EXPLOSIVE" ) ) )
    		self.wasChained = true;
    
    	if ( isDefined( iDFlags ) && ( iDFlags & level.iDFLAGS_PENETRATION ) )
    		self.wasDamagedFromBulletPenetration = true;
    
    	self.wasDamaged = true;
    
    	if ( level.teamBased )
    	{
    		// "destroyed_explosive" notify, for challenges
    		if ( isdefined( attacker ) && isdefined( attacker.pers[ "team" ] ) && isdefined( self.owner ) && isdefined( self.owner.pers[ "team" ] ) )
    		{
    			if ( attacker.pers[ "team" ] != self.owner.pers[ "team" ] )
    				attacker notify( "destroyed_explosive" );
    		}
    	}
    	else
    	{
    		// checking isDefined attacker is defensive but it's too late in the project to risk issues by not having it
    		if ( isDefined( self.owner ) && isDefined( attacker ) && attacker != self.owner )
    			attacker notify( "destroyed_explosive" );		
    	}
    
    	self detonate( attacker );
    	// won't get here; got death notify.
    }
    
    resetC4ExplodeThisFrame()
    {
    	wait .05;
    	level.c4explodethisframe = false;
    }
    
    saydamaged( orig, amount )
    {
    	for ( i = 0; i < 60; i++ )
    	{
    		print3d( orig, "damaged! " + amount );
    		wait .05;
    	}
    }
    
    waitTillEnabled()
    {
    	if ( !isDefined( self.disabled ) )
    		return;
    
    	self waittill( "enabled" );
    	assert( !isDefined( self.disabled ) );
    }
    
    
    c4DetectionTrigger( ownerTeam )
    {
    	self waittill( "activated" );
    
    	trigger = spawn( "trigger_radius", self.origin - ( 0, 0, 128 ), 0, 512, 256 );
    	trigger.detectId = "trigger" + getTime() + randomInt( 1000000 );
    
    	trigger.owner = self;
    	trigger thread detectIconWaiter( level.otherTeam[ ownerTeam ] );
    
    	self waittill( "death" );
    	trigger notify( "end_detection" );
    
    	if ( isDefined( trigger.bombSquadIcon ) )
    		trigger.bombSquadIcon destroy();
    
    	trigger delete();
    }
    
    
    claymoreDetectionTrigger_wait( ownerTeam )
    {
    	self endon( "death" );
    	self waittill( "missile_stuck" );
    
    	self thread claymoreDetectionTrigger( ownerTeam );
    }
    
    claymoreDetectionTrigger( ownerTeam )
    {
    	trigger = spawn( "trigger_radius", self.origin - ( 0, 0, 128 ), 0, 512, 256 );
    	trigger.detectId = "trigger" + getTime() + randomInt( 1000000 );
    
    	trigger.owner = self;
    	trigger thread detectIconWaiter( level.otherTeam[ ownerTeam ] );
    
    	self waittill( "death" );
    	trigger notify( "end_detection" );
    
    	if ( isDefined( trigger.bombSquadIcon ) )
    		trigger.bombSquadIcon destroy();
    
    	trigger delete();
    }
    
    
    detectIconWaiter( detectTeam )
    {
    	self endon( "end_detection" );
    	level endon( "game_ended" );
    
    	while ( !level.gameEnded )
    	{
    		self waittill( "trigger", player );
    
    		if ( !player.detectExplosives )
    			continue;
    
    		if ( level.teamBased && player.team != detectTeam )
    			continue;
    		else if ( !level.teamBased && player == self.owner.owner )
    			continue;
    
    		if ( isDefined( player.bombSquadIds[ self.detectId ] ) )
    			continue;
    
    		player thread showHeadIcon( self );
    	}
    }
    
    
    setupBombSquad()
    {
    	self.bombSquadIds = [];
    
    	if ( self.detectExplosives && !self.bombSquadIcons.size )
    	{
    		for ( index = 0; index < 4; index++ )
    		{
    			self.bombSquadIcons[ index ] = newClientHudElem( self );
    			self.bombSquadIcons[ index ].x = 0;
    			self.bombSquadIcons[ index ].y = 0;
    			self.bombSquadIcons[ index ].z = 0;
    			self.bombSquadIcons[ index ].alpha = 0;
    			self.bombSquadIcons[ index ].archived = true;
    			self.bombSquadIcons[ index ] setShader( "waypoint_bombsquad", 14, 14 );
    			self.bombSquadIcons[ index ] setWaypoint( false, false );
    			self.bombSquadIcons[ index ].detectId = "";
    		}
    	}
    	else if ( !self.detectExplosives )
    	{
    		for ( index = 0; index < self.bombSquadIcons.size; index++ )
    			self.bombSquadIcons[ index ] destroy();
    
    		self.bombSquadIcons = [];
    	}
    }
    
    
    showHeadIcon( trigger )
    {
    	triggerDetectId = trigger.detectId;
    	useId = -1;
    	for ( index = 0; index < 4; index++ )
    	{
    		detectId = self.bombSquadIcons[ index ].detectId;
    
    		if ( detectId == triggerDetectId )
    			return;
    
    		if ( detectId == "" )
    			useId = index;
    	}
    
    	if ( useId < 0 )
    		return;
    
    	self.bombSquadIds[ triggerDetectId ] = true;
    
    	self.bombSquadIcons[ useId ].x = trigger.origin[ 0 ];
    	self.bombSquadIcons[ useId ].y = trigger.origin[ 1 ];
    	self.bombSquadIcons[ useId ].z = trigger.origin[ 2 ] + 24 + 128;
    
    	self.bombSquadIcons[ useId ] fadeOverTime( 0.25 );
    	self.bombSquadIcons[ useId ].alpha = 1;
    	self.bombSquadIcons[ useId ].detectId = trigger.detectId;
    
    	while ( isAlive( self ) && isDefined( trigger ) && self isTouching( trigger ) )
    		wait( 0.05 );
    
    	if ( !isDefined( self ) )
    		return;
    
    	self.bombSquadIcons[ useId ].detectId = "";
    	self.bombSquadIcons[ useId ] fadeOverTime( 0.25 );
    	self.bombSquadIcons[ useId ].alpha = 0;
    	self.bombSquadIds[ triggerDetectId ] = undefined;
    }
    
    
    // these functions are used with scripted weapons (like c4, claymores, artillery)
    // returns an array of objects representing damageable entities (including players) within a given sphere.
    // each object has the property damageCenter, which represents its center (the location from which it can be damaged).
    // each object also has the property entity, which contains the entity that it represents.
    // to damage it, call damageEnt() on it.
    getDamageableEnts( pos, radius, doLOS, startRadius )
    {
    	ents = [];
    
    	if ( !isdefined( doLOS ) )
    		doLOS = false;
    
    	if ( !isdefined( startRadius ) )
    		startRadius = 0;
    	
    	radiusSq = radius * radius;
    
    	// players
    	players = level.players;
    	for ( i = 0; i < players.size; i++ )
    	{
    		if ( !isalive( players[ i ] ) || players[ i ].sessionstate != "playing" )
    			continue;
    
    		playerpos = get_damageable_player_pos( players[ i ] );
    		distSq = distanceSquared( pos, playerpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, playerpos, startRadius, players[ i ] ) ) )
    		{
    			ents[ ents.size ] = get_damageable_player( players[ i ], playerpos );
    		}
    	}
    
    	// grenades
    	grenades = getentarray( "grenade", "classname" );
    	for ( i = 0; i < grenades.size; i++ )
    	{
    		entpos = get_damageable_grenade_pos( grenades[ i ] );
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, grenades[ i ] ) ) )
    		{
    			ents[ ents.size ] = get_damageable_grenade( grenades[ i ], entpos );
    		}
    	}
    
    	destructibles = getentarray( "destructible", "targetname" );
    	for ( i = 0; i < destructibles.size; i++ )
    	{
    		entpos = destructibles[ i ].origin;
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, destructibles[ i ] ) ) )
    		{
    			newent = spawnstruct();
    			newent.isPlayer = false;
    			newent.isADestructable = false;
    			newent.entity = destructibles[ i ];
    			newent.damageCenter = entpos;
    			ents[ ents.size ] = newent;
    		}
    	}
    
    	destructables = getentarray( "destructable", "targetname" );
    	for ( i = 0; i < destructables.size; i++ )
    	{
    		entpos = destructables[ i ].origin;
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, destructables[ i ] ) ) )
    		{
    			newent = spawnstruct();
    			newent.isPlayer = false;
    			newent.isADestructable = true;
    			newent.entity = destructables[ i ];
    			newent.damageCenter = entpos;
    			ents[ ents.size ] = newent;
    		}
    	}
    	
    	//sentries
    	sentries = getentarray( "misc_turret", "classname" );
    	foreach ( sentry in sentries )
    	{
    		entpos = sentry.origin + (0,0,32);
    		distSq = distanceSquared( pos, entpos );
    		if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, sentry ) ) )
    		{
    			if ( sentry.model == "sentry_minigun" )
    				ents[ ents.size ] = get_damageable_sentry(sentry, entpos);
    		}
    	}
    
    	return ents;
    }
    
    
    getEMPDamageEnts( pos, radius, doLOS, startRadius )
    {
    	ents = [];
    
    	if ( !isDefined( doLOS ) )
    		doLOS = false;
    
    	if ( !isDefined( startRadius ) )
    		startRadius = 0;
    
    	grenades = getEntArray( "grenade", "classname" );
    	foreach ( grenade in grenades )
    	{
    		//if ( !isDefined( grenade.weaponName ) )
    		//	continue;
    
    		entpos = grenade.origin;
    		dist = distance( pos, entpos );
    		if ( dist < radius && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, grenade ) ) )
    			ents[ ents.size ] = grenade;
    	}
    
    	turrets = getEntArray( "misc_turret", "classname" );
    	foreach ( turret in turrets )
    	{
    		//if ( !isDefined( turret.weaponName ) )
    		//	continue;
    
    		entpos = turret.origin;
    		dist = distance( pos, entpos );
    		if ( dist < radius && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, turret ) ) )
    			ents[ ents.size ] = turret;
    	}
    
    	return ents;
    }
    
    
    weaponDamageTracePassed( from, to, startRadius, ent )
    {
    	midpos = undefined;
    
    	diff = to - from;
    	if ( lengthsquared( diff ) < startRadius * startRadius )
    		return true;
    	
    	dir = vectornormalize( diff );
    	midpos = from + ( dir[ 0 ] * startRadius, dir[ 1 ] * startRadius, dir[ 2 ] * startRadius );
    
    	trace = bullettrace( midpos, to, false, ent );
    
    	if ( getdvarint( "scr_damage_debug" ) != 0 )
    	{
    		thread debugprint( from, ".dmg" );
    		if ( isdefined( ent ) )
    			thread debugprint( to, "." + ent.classname );
    		else
    			thread debugprint( to, ".undefined" );
    		if ( trace[ "fraction" ] == 1 )
    		{
    			thread debugline( midpos, to, ( 1, 1, 1 ) );
    		}
    		else
    		{
    			thread debugline( midpos, trace[ "position" ], ( 1, .9, .8 ) );
    			thread debugline( trace[ "position" ], to, ( 1, .4, .3 ) );
    		}
    	}
    
    	return( trace[ "fraction" ] == 1 );
    }
    
    // eInflictor = the entity that causes the damage (e.g. a claymore)
    // eAttacker = the player that is attacking
    // iDamage = the amount of damage to do
    // sMeansOfDeath = string specifying the method of death (e.g. "MOD_PROJECTILE_SPLASH")
    // sWeapon = string specifying the weapon used (e.g. "claymore_mp")
    // damagepos = the position damage is coming from
    // damagedir = the direction damage is moving in
    damageEnt( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, damagepos, damagedir )
    {
    	if ( self.isPlayer )
    	{
    		self.damageOrigin = damagepos;
    		self.entity thread [[ level.callbackPlayerDamage ]](
    			eInflictor,// eInflictor The entity that causes the damage.( e.g. a turret )
    			eAttacker,// eAttacker The entity that is attacking.
    			iDamage,// iDamage Integer specifying the amount of damage done
    			0,// iDFlags Integer specifying flags that are to be applied to the damage
    			sMeansOfDeath,// sMeansOfDeath Integer specifying the method of death
    			sWeapon,// sWeapon The weapon number of the weapon used to inflict the damage
    			damagepos,// vPoint The point the damage is from?
    			damagedir,// vDir The direction of the damage
    			"none",// sHitLoc The location of the hit
    			0// psOffsetTime The time offset for the damage
    		 );
    	}
    	else
    	{
    		// destructable walls and such can only be damaged in certain ways.
    		if ( self.isADestructable && ( sWeapon == "artillery_mp" || sWeapon == "claymore_mp" ) || sWeapon == "stealth_bomb_mp" )
    			return;
    
    		self.entity notify( "damage", iDamage, eAttacker, ( 0, 0, 0 ), ( 0, 0, 0 ), "mod_explosive", "", "" );
    	}
    }
    
    
    debugline( a, b, color )
    {
    	for ( i = 0; i < 30 * 20; i++ )
    	{
    		line( a, b, color );
    		wait .05;
    	}
    }
    
    debugprint( pt, txt )
    {
    	for ( i = 0; i < 30 * 20; i++ )
    	{
    		print3d( pt, txt );
    		wait .05;
    	}
    }
    
    
    onWeaponDamage( eInflictor, sWeapon, meansOfDeath, damage, eAttacker )
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	switch( sWeapon )
    	{
    		case "concussion_grenade_mp":
    			// should match weapon settings in gdt
    			radius = 512;
    			scale = 1 - ( distance( self.origin, eInflictor.origin ) / radius );
    
    			if ( scale < 0 )
    				scale = 0;
    
    			time = 2 + ( 4 * scale );
    			
    			wait( 0.05 );
    			eAttacker notify( "stun_hit" );
    			self shellShock( "concussion_grenade_mp", time );
    			self.concussionEndTime = getTime() + ( time * 1000 );
    		break;
    
    		case "weapon_cobra_mk19_mp":
    			// mk19 is too powerful with shellshock slowdown
    		break;
    
    		default:
    			// shellshock will only be done if meansofdeath is an appropriate type and if there is enough damage.
    			maps\mp\gametypes\_shellshock::shellshockOnDamage( meansOfDeath, damage );
    		break;
    	}
    
    }
    
    // weapon stowing logic ===================================================================
    
    // weapon class boolean helpers
    isPrimaryWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	if ( weaponInventoryType( weapName ) != "primary" )
    		return false;
    
    	switch ( weaponClass( weapName ) )
    	{
    		case "rifle":
    		case "smg":
    		case "mg":
    		case "spread":
    		case "pistol":
    		case "rocketlauncher":
    		case "sniper":
    			return true;
    
    		default:
    			return false;
    	}	
    }
    
    
    isAltModeWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( weaponInventoryType( weapName ) == "altmode" );
    }
    
    isInventoryWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( weaponInventoryType( weapName ) == "item" );
    }
    
    isRiotShield( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( WeaponType( weapName ) == "riotshield" );
    }
    
    isOffhandWeapon( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    		
    	return ( weaponInventoryType( weapName ) == "offhand" );
    }
    
    isSideArm( weapName )
    {
    	if ( weapName == "none" )
    		return false;
    
    	if ( weaponInventoryType( weapName ) != "primary" )
    		return false;
    
    	return ( weaponClass( weapName ) == "pistol" );
    }
    
    
    // This needs for than this.. this would qualify c4 as a grenade
    isGrenade( weapName )
    {
    	weapClass = weaponClass( weapName );
    	weapType = weaponInventoryType( weapName );
    
    	if ( weapClass != "grenade" )
    		return false;
    		
    	if ( weapType != "offhand" )
    		return false;
    }
    
    
    getStowOffsetModel( weaponName )
    {
    	assert( isDefined( level.stow_offset_array ) );
    
    	baseName = getBaseWeaponName( weaponName );
    	
    	return( level.stow_offset_array[baseName] );
    }
    
    
    stowPriorityWeapon()
    {
    	assert( isdefined( level.stow_priority_model_array ) );
    
    	// returns the first large projectil the player owns in case player owns more than one
    	foreach ( weapon_name, priority_weapon in level.stow_priority_model_array )
    	{
    		weaponName = getBaseWeaponName( weapon_name );
    		weaponList = self getWeaponsListAll();
    		
    		foreach ( weapon in weaponList )
    		{
    			if( self getCurrentWeapon() == weapon )
    				continue;
    			
    			if ( weaponName == getBaseWeaponName( weapon ) )
    				return weaponName + "_mp";
    		}
    	}
    
    	return "";
    }
    
    // thread loop life = player's life
    updateStowedWeapon()
    {
    	self endon( "spawned" );
    	self endon( "killed_player" );
    	self endon( "disconnect" );
    
    	self.tag_stowed_back = undefined;
    	self.tag_stowed_hip = undefined;
    	
    	team = self.team;
    	class = self.class;
    	
    	self thread stowedWeaponsRefresh();
    	
    	while ( true )
    	{
    		self waittill( "weapon_change", newWeapon );
    		
    		if ( newWeapon == "none" )
    			continue;
    			
    		self thread stowedWeaponsRefresh();
    	}
    }
    
    stowedWeaponsRefresh()
    {
    	self endon( "spawned" );
    	self endon( "killed_player" );
    	self endon( "disconnect" );
    	
    	detach_all_weapons();
    	stow_on_back();
    	stow_on_hip();
    }
    
    
    detach_all_weapons()
    {
    	if ( isDefined( self.tag_stowed_back ) )
    		self detach_back_weapon();
    
    	if ( isDefined( self.tag_stowed_hip ) )
    		self detach_hip_weapon();
    }
    
    
    detach_back_weapon()
    {
    	detach_success = self detachIfAttached( self.tag_stowed_back, "tag_stowed_back" );
    
    	// test for bug
    	//assertex( detach_success, "Detaching: " + self.tag_stowed_back + " from tag: tag_stowed_back failed." );
    	self.tag_stowed_back = undefined;
    }
    
    
    detach_hip_weapon()
    {
    	detach_success = self detachIfAttached( self.tag_stowed_hip, "tag_stowed_hip" );
    
    	// test for bug
    	//assertex( detach_success, "Detaching: " + detach_model + " from tag: tag_stowed_hip failed." );
    	self.tag_stowed_hip = undefined;
    }
    
    
    stow_on_back()
    {
    	prof_begin( "stow_on_back" );
    	currentWeapon = self getCurrentWeapon();
    	currentIsAlt = isAltModeWeapon( currentWeapon );
    
    	assert( !isDefined( self.tag_stowed_back ) );
    
    	stowWeapon = undefined;
    	stowCamo = 0;
    	large_projectile = self stowPriorityWeapon();
    	stowOffsetModel = undefined;
    
    	if ( large_projectile != "" )
    	{
    		stowWeapon = large_projectile;
    	}
    	else
    	{
    		weaponsList = self getWeaponsListPrimaries();
    		foreach ( weaponName in weaponsList )
    		{
    			if ( weaponName == currentWeapon )
    				continue;
    			
    			invType = weaponInventoryType( weaponName );
    			
    			if ( invType != "primary" )
    			{
    				if ( invType == "altmode" )
    					continue;
    				
    				if ( weaponClass( weaponName ) == "pistol" )
    					continue;
    			}
    			
    			if ( WeaponType( weaponName ) == "riotshield" )
    				continue;
    			
    			// Don't stow the current on our back when we're using the alt
    			if ( currentIsAlt && weaponAltWeaponName( weaponName ) == currentWeapon )
    				continue;
    				
    			stowWeapon = weaponName;
    			stowOffsetModel = getStowOffsetModel( stowWeapon );
    			
    			if ( stowWeapon == self.primaryWeapon )
    				stowCamo = self.loadoutPrimaryCamo;
    			else if ( stowWeapon == self.secondaryWeapon )
    				stowCamo = self.loadoutSecondaryCamo;
    			else
    				stowCamo = 0;
    		}		
    	}
    
    	if ( !isDefined( stowWeapon ) )
    	{
    		prof_end( "stow_on_back" );
    		return;
    	}
    
    	if ( large_projectile != "" )
    	{
    		self.tag_stowed_back = level.stow_priority_model_array[ large_projectile ];
    	}
    	else
    	{
    		self.tag_stowed_back = getWeaponModel( stowWeapon, stowCamo );	
    	}
    
    	if ( isDefined( stowOffsetModel ) )
    	{
    		self attach( stowOffsetModel, "tag_stowed_back", true );
    		attachTag = "tag_stow_back_mid_attach";
    	}
    	else
    	{
    		attachTag = "tag_stowed_back";
    	}
    
    	self attach( self.tag_stowed_back, attachTag, true );
    
    	hideTagList = GetWeaponHideTags( stowWeapon );
    
    	if ( !isDefined( hideTagList ) )
    	{
    		prof_end( "stow_on_back" );
    		return;
    	}
    
    	for ( i = 0; i < hideTagList.size; i++ )
    		self HidePart( hideTagList[ i ], self.tag_stowed_back );
    	
    	prof_end( "stow_on_back" );
    }
    
    stow_on_hip()
    {
    	currentWeapon = self getCurrentWeapon();
    
    	assert( !isDefined( self.tag_stowed_hip ) );
    
    	stowWeapon = undefined;
    
    	weaponsList = self getWeaponsListOffhands();
    	foreach ( weaponName in weaponsList )
    	{
    		if ( weaponName == currentWeapon )
    			continue;
    			
    		if ( weaponName != "c4_mp" && weaponName != "claymore_mp" )
    			continue;
    		
    		stowWeapon = weaponName;
    	}
    
    	if ( !isDefined( stowWeapon ) )
    		return;
    
    	self.tag_stowed_hip = getWeaponModel( stowWeapon );
    	self attach( self.tag_stowed_hip, "tag_stowed_hip_rear", true );
    
    	hideTagList = GetWeaponHideTags( stowWeapon );
    	
    	if ( !isDefined( hideTagList ) )
    		return;
    	
    	for ( i = 0; i < hideTagList.size; i++ )
    		self HidePart( hideTagList[ i ], self.tag_stowed_hip );
    }
    
    
    updateSavedLastWeapon()
    {
    	self endon( "death" );
    	self endon( "disconnect" );
    
    	currentWeapon = self.currentWeaponAtSpawn;
    	self.saved_lastWeapon = currentWeapon;
    
    	for ( ;; )
    	{
    		self waittill( "weapon_change", newWeapon );
    	
    		if ( newWeapon == "none" )
    		{
    			self.saved_lastWeapon = currentWeapon;
    			continue;
    		}
    
    		weaponInvType = weaponInventoryType( newWeapon );
    
    		if ( weaponInvType != "primary" && weaponInvType != "altmode" )
    		{
    			self.saved_lastWeapon = currentWeapon;
    			continue;
    		}
    		
    		if ( newWeapon == "onemanarmy_mp" )
    		{
    			self.saved_lastWeapon = currentWeapon;
    			continue;
    		}
    
    		self updateMoveSpeedScale( "primary" );
    
    		self.saved_lastWeapon = currentWeapon;
    		currentWeapon = newWeapon;
    	}
    }
    
    
    EMPPlayer( numSeconds )
    {
    	self endon( "disconnect" );
    	self endon( "death" );
    
    	self thread clearEMPOnDeath();
    
    }
    
    
    clearEMPOnDeath()
    {
    	self endon( "disconnect" );
    
    	self waittill( "death" );
    }
    
    
    updateMoveSpeedScale( weaponType )
    {
    	/*
    	if ( self _hasPerk( "specialty_lightweight" ) )
    		self.moveSpeedScaler = 1.10;
    	else
    		self.moveSpeedScaler = 1;
    	*/
    	
    	if ( !isDefined( weaponType ) || weaponType == "primary" || weaponType != "secondary" )
    		weaponType = self.primaryWeapon;
    	else
    		weaponType = self.secondaryWeapon;
    	
    	if( isDefined(self.primaryWeapon ) && self.primaryWeapon == "riotshield_mp" )
    	{
    		self setMoveSpeedScale( .8 * self.moveSpeedScaler );
    		return;
    	}
    	
    	if ( !isDefined( weaponType ) )
    		weapClass = "none";
    	else 
    		weapClass = weaponClass( weaponType );
    	
    	
    	switch ( weapClass )
    	{
    		case "rifle":
    			self setMoveSpeedScale( 0.95 * self.moveSpeedScaler );
    			break;
    		case "pistol":
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    		case "mg":
    			self setMoveSpeedScale( 0.875 * self.moveSpeedScaler );
    			break;
    		case "smg":
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    		case "spread":
    			self setMoveSpeedScale( .95 * self.moveSpeedScaler );
    			break;
    		case "rocketlauncher":
    			self setMoveSpeedScale( 0.80 * self.moveSpeedScaler );
    			break;
    		case "sniper":
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    		default:
    			self setMoveSpeedScale( 1.0 * self.moveSpeedScaler );
    			break;
    	}
    }
    
    
    buildWeaponData( filterPerks )
    {
    	attachmentList = getAttachmentList();		
    	max_weapon_num = 149;
    
    	baseWeaponData = [];
    	
    	for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
    	{
    		baseName = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
    		if( baseName == "" )
    			continue;
    
    		assetName = baseName + "_mp";
    
    		if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
    			continue;
    		
    		if ( weaponInventoryType( assetName ) != "primary" )
    			continue;
    
    		weaponInfo = spawnStruct();
    		weaponInfo.baseName = baseName;
    		weaponInfo.assetName = assetName;
    		weaponInfo.variants = [];
    
    		weaponInfo.variants[0] = assetName;
    		// the alphabetize function is slow so we try not to do it for every weapon/attachment combo; a code solution would be better.
    		attachmentNames = [];
    		for ( innerLoopCount = 0; innerLoopCount < 6; innerLoopCount++ )
    		{
    			// generating attachment combinations
    			attachmentName = tablelookup( "mp/statStable.csv", 0, weaponId, innerLoopCount + 11 );
    			
    			if ( filterPerks )
    			{
    				switch ( attachmentName )
    				{
    					case "fmj":
    					case "xmags":
    					case "rof":
    						continue;
    				}
    			}
    			
    			if( attachmentName == "" )
    				break;
    			
    			attachmentNames[attachmentName] = true;
    		}
    
    		// generate an alphabetized attachment list
    		attachments = [];
    		foreach ( attachmentName in attachmentList )
    		{
    			if ( !isDefined( attachmentNames[attachmentName] ) )
    				continue;
    			
    			weaponInfo.variants[weaponInfo.variants.size] = baseName + "_" + attachmentName + "_mp";
    			attachments[attachments.size] = attachmentName;
    		}
    
    		for ( i = 0; i < (attachments.size - 1); i++ )
    		{
    			colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, attachments[i] );
    			for ( j = i + 1; j < attachments.size; j++ )
    			{
    				if ( tableLookup( "mp/attachmentCombos.csv", 0, attachments[j], colIndex ) == "no" )
    					continue;
    					
    				weaponInfo.variants[weaponInfo.variants.size] = baseName + "_" + attachments[i] + "_" + attachments[j] + "_mp";
    			}
    		}
    		
    		baseWeaponData[baseName] = weaponInfo;
    	}
    	
    	return ( baseWeaponData );
    }
    
    monitorSemtex()
    {
    	self endon( "disconnect" );
    	self endon( "death" );
    	
    	for( ;; )
    	{
    		self waittill( "grenade_fire", weapon );
    
    		if ( !isSubStr(weapon.model, "semtex" ) )
    			continue;
    			
    		weapon waittill( "missile_stuck", stuckTo );
    			
    		if ( !isPlayer( stuckTo ) )
    			continue;
    			
    		if ( level.teamBased && isDefined( stuckTo.team ) && stuckTo.team == self.team )
    		{
    			weapon.isStuck = "friendly";
    			continue;
    		}
    	
    		weapon.isStuck = "enemy";
    		weapon.stuckEnemyEntity = stuckTo;
    		
    		self notify( "process", "ch_bullseye" );
    	}	
    }
    
    
    turret_monitorUse()
    {
    	for( ;; )
    	{
    		self waittill ( "trigger", player );
    		
    		self thread turret_playerThread( player );
    	}
    }
    
    turret_playerThread( player )
    {
    	player endon ( "death" );
    	player endon ( "disconnect" );
    
    	player notify ( "weapon_change", "none" );
    	
    	self waittill ( "turret_deactivate" );
    	
    	player notify ( "weapon_change", player getCurrentWeapon() );
    }
    Last edited by mathieutje12; 06-14-2011 at 11:08 AM.

  8. #7
    NiNeOner's Avatar
    Join Date
    May 2011
    Gender
    male
    Posts
    16
    Reputation
    10
    Thanks
    0
    My Mood
    Happy
    Thanks again you can close this thread now =D.

  9. #8
    master131's Avatar
    Join Date
    Apr 2010
    Gender
    male
    Location
    Melbourne, Australia
    Posts
    8,858
    Reputation
    3438
    Thanks
    101,668
    My Mood
    Breezy
    /marked as solved
    /closed
    Donate:
    BTC: 1GEny3y5tsYfw8E8A45upK6PKVAEcUDNv9


    Handy Tools/Hacks:
    Extreme Injector v3.7.3
    A powerful and advanced injector in a simple GUI.
    Can scramble DLLs on injection making them harder to detect and even make detected hacks work again!

    Minion Since: 13th January 2011
    Moderator Since: 6th May 2011
    Global Moderator Since: 29th April 2012
    Super User/Unknown Since: 23rd July 2013
    'Game Hacking' Team Since: 30th July 2013

    --My Art--
    [Roxas - Pixel Art, WIP]
    [Natsu - Drawn]
    [Natsu - Coloured]


    All drawings are coloured using Photoshop.

    --Gifts--
    [Kyle]