#using scripts\mp\_teamops;
#using scripts\mp\_util;
#using scripts\mp\gametypes\_dogtags;
#using scripts\mp\gametypes\_globallogic;
#using scripts\mp\gametypes\_globallogic_audio;
#using scripts\mp\gametypes\_globallogic_score;
#using scripts\mp\gametypes\_globallogic_spawn;
#using scripts\mp\gametypes\_globallogic_utils;
#using scripts\mp\gametypes\_prop_controls;
#using scripts\mp\gametypes\_spawning;
#using scripts\mp\gametypes\_spawnlogic;
#using scripts\mp\gametypes\prop;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\shared\gameobjects_shared;
#using scripts\shared\hostmigration_shared;
#using scripts\shared\hud_util_shared;
#using scripts\shared\math_shared;
#using scripts\shared\util_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\math_shared;
#using scripts\shared\bots\_bot;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
           	               	           	                                                    	      	       

#namespace prop_dev;

/*
	Prop Hunt
*/

/#
function AddDevguiCommand( path, executeCmd )
{
	pathStr = "\"" + path + "\"";
	cmdStr = "\"" + executeCmd + "\"\n";
	debugCommand = "devgui_cmd " + pathStr + " " + cmdStr;
	AddDebugCommand( debugCommand );
}

function propDevGui()
{
	REMOVE_UPPER_RIGHT_PRINTS_DEBUG = 0;
	PLACEMENT_MODE = 0;
	MORE_CHANGES = 0;
	MORE_CLONES = 0;
	MORE_FLASHES = 0;
	MORE_BOOST = 0;
	MORE_PINGS = 0;
	MINIGAME_FORCE_TYPE = 0;
	MINIGAME_ON = GetDvarInt( "scr_prop_minigame", 1 );
	SERVER_HUD = GetDvarInt( "scr_ph_usePropHudServer", true );
	
	CONST_SWIM_DAMAGE = GetDvarFloat( "player_swimDamage" );;
		
	util::set_dvar_int_if_unset( "scr_ph_moreChanges", 0 );
	util::set_dvar_int_if_unset( "scr_ph_moreClones", 0 );
	util::set_dvar_int_if_unset( "scr_ph_moreFlashes", 0 );
	util::set_dvar_int_if_unset( "scr_ph_morePings", 0 );
	util::set_dvar_int_if_unset( "scr_ph_moreBoost", 0 );
	util::set_dvar_int_if_unset( "scr_ph_removeDebugUR", 0 );
	util::set_dvar_int_if_unset( "scr_ph_holdTimelimitZero", 0 );
	util::set_dvar_int_if_unset( "scr_ph_allowTeamChange", 0 );
	util::set_dvar_int_if_unset( "scr_ph_alwaysSpawn", 0 );
	util::set_dvar_int_if_unset( "scr_ph_showHealth", 0 );
	util::set_dvar_int_if_unset( "scr_ph_debugGroundTrace", 0 );
	util::set_dvar_int_if_unset( "scr_ph_useBoundsForGroundNormal", 1 );
	util::set_dvar_int_if_unset( "scr_ph_usePropHudServer", true );
	util::set_dvar_int_if_unset( "scr_ph_debugLastLock", 0 );
	util::set_dvar_int_if_unset( "scr_ph_debugCanLock", 0 );
	util::set_dvar_int_if_unset( "scr_ph_cancelCountdown", 0 );
	util::set_dvar_int_if_unset( "scr_ph_pauseCountdown", 0 );
	util::set_dvar_int_if_unset( "scr_ph_debugSpeed", 0 );
	util::set_dvar_int_if_unset( "scr_ph_debugShowPlayers", 0 );
	util::set_dvar_int_if_unset( "scr_ph_debugShowTargets", 0 );
	util::set_dvar_int_if_unset( "scr_ph_debugDoMinigameType", 0 );
	SetDvar( "scr_ph_showModels", 0 );
	SetDvar( "scr_ph_placementMode", 0 );
	SetDvar( "scr_ph_placementWrite", 0 );
	SetDvar( "scr_ph_placementWriteGSH", 0 );
	SetDvar( "scr_ph_placementWriteEmpty", 0 );
	SetDvar( "scr_ph_makeClone", 0 );
	SetDvar( "scr_ph_makeClones", 0 );
	SetDvar( "scr_ph_debugPlayerCard", 0 );
	
	if ( GetDvarInt( "scr_ph_holdTimelimitZero", 0 ) != 0 )
		AddDebugCommand( "gametype_setting timelimit 0" );
	
	AddDevguiCommand( "Prop/Remove Debug Upper Right:1", "toggle scr_ph_removeDebugUR 1 0" );
	AddDevguiCommand( "Prop/Timelimit:2/Clear:1", "gametype_setting timelimit 0; set scr_ph_holdTimelimitZero 1" );
	AddDevguiCommand( "Prop/Timelimit:2/Reset:2", "gametype_setting timelimit " + 4 + "; set scr_ph_holdTimelimitZero 0" );
	AddDevguiCommand( "Prop/Timelimit:2/15 Sec:3", "gametype_setting timelimit " + 0.25 + "; set scr_ph_holdTimelimitZero 0" );
	AddDevguiCommand( "Prop/Timelimit:2/Cancel Prop Hide:4", "set scr_ph_cancelCountdown 1" );
	AddDevguiCommand( "Prop/Timelimit:2/Pause Prop Hide:5", "toggle scr_ph_pauseCountdown 1 0" );
	AddDevguiCommand( "Prop/Toggle Unlimited:3/Clones:1", "toggle scr_ph_moreClones 1 0" );	
	AddDevguiCommand( "Prop/Toggle Unlimited:3/Flashes:2", "toggle scr_ph_moreFlashes 1 0" );	
	AddDevguiCommand( "Prop/Toggle Unlimited:3/Changes:3", "toggle scr_ph_moreChanges 1 0" );
	AddDevguiCommand( "Prop/Toggle Unlimited:3/Boost:4", "toggle scr_ph_moreBoost 1 0" );
	AddDevguiCommand( "Prop/Toggle Unlimited:3/Pings:5", "toggle scr_ph_morePings 1 0" );
	AddDevguiCommand( "Prop/Team Change:4/Allow", "set scr_ph_allowTeamChange 1" );
	AddDevguiCommand( "Prop/Team Change:4/Block", "set scr_ph_allowTeamChange 0" );
	AddDevguiCommand( "Prop/Spawning:5/Allow", "set scr_ph_alwaysSpawn 1" );
	AddDevguiCommand( "Prop/Spawning:5/Block", "set scr_ph_alwaysSpawn 0" );
	AddDevguiCommand( "Prop/Find Models:6", "toggle r_showSModelNames 200 0; toggle r_drawInfo 3 0; toggle ui_enabled 0 1" );	
	AddDevguiCommand( "Prop/Debug:8/Health:1", "toggle scr_ph_showHealth 1 0" );	
	AddDevguiCommand( "Prop/Debug:8/Speed:2", "toggle scr_ph_debugSpeed 1 0" );	
	AddDevguiCommand( "Prop/Debug:8/Models:3", "set scr_ph_showModels 1" );	
	AddDevguiCommand( "Prop/Debug:8/Make All Clones:4", "set scr_ph_makeClones 1" );	
	AddDevguiCommand( "Prop/Debug:8/Make One Clone:5", "set scr_ph_makeClone 1" );	
	AddDevguiCommand( "Prop/Debug:8/Last Lock:5", "toggle scr_ph_debugLastLock 1 0" );	
	AddDevguiCommand( "Prop/Debug:8/Can Lock:6", "toggle scr_ph_debugCanLock 1 0" );	
	AddDevguiCommand( "Prop/Debug:8/Player Boxes:7", "toggle scr_ph_debugShowPlayers 1 0" );	
	AddDevguiCommand( "Prop/Debug:8/Targets:8", "toggle scr_ph_debugShowTargets 1 0" );	
	AddDevguiCommand( "Prop/Debug:8/Player Card:9", "set scr_ph_debugPlayerCard 1" );
	AddDevguiCommand( "Prop/Prop Setup:9/Toggle Placement Mode:1", "toggle scr_ph_placementMode 1 0" );
	AddDevguiCommand( "Prop/Prop Setup:9/Write Prop Data CSV File:2", "set scr_ph_placementWrite 1" );
	AddDevguiCommand( "Prop/Prop Setup:9/Write Ordered Prop GSH File:3", "set scr_ph_placementWriteGSH 1" );
	AddDevguiCommand( "Prop/Prop Setup:9/Write Empty Prop Files:4", "set scr_ph_placementWriteEmpty 1" );
	AddDevguiCommand( "Prop/Toggle Server Hud:10", "toggle scr_ph_usePropHudServer 1 0" );
	AddDevguiCommand( "Prop/Minigame:8/Toggle:1", "toggle scr_prop_minigame 1 0" );	
	AddDevguiCommand( "Prop/Minigame:8/Toggle Force Type:2", "toggle scr_ph_debugDoMinigameType 2 1 0" );		
	while ( true )
	{
		if ( ( isdefined( level.prematch_over ) && level.prematch_over ) )
		{
			level.allow_teamchange = "" + GetDvarInt( "scr_ph_allowTeamChange", 0 );
			level.alwaysAllowSpawn = GetDvarInt( "scr_ph_alwaysSpawn", 0 ) != 0;
		}
		
		if ( GetDvarInt( "scr_ph_usePropHudServer", 0 ) != SERVER_HUD && IsDefined( level.players ) )
		{
			SERVER_HUD = GetDvarInt( "scr_ph_usePropHudServer", 0 );
			if ( !IsDefined( level.players[0].changePropKey ) )
			{
				IPrintLnBold( "Map Restart to show hud" );
			}
			else
			{
				foreach ( player in level.players )
				{
					if ( IsDefined( player.team ) && player util::isProp() )
						player prop_controls::propAbilityKeysVisible( SERVER_HUD, true );
				}
				level.elim_hud.alpha = SERVER_HUD;
			}
		}
		
		if ( GetDvarInt( "scr_ph_moreChanges", 0 ) != MORE_CHANGES && IsDefined( level.players ) )
		{
			foreach ( player in level.players )
			{
				if ( player util::isProp() )
				{
					MORE_CHANGES = GetDvarInt( "scr_ph_moreChanges", 0 );
					player.unlimitedChanges = !( isdefined( player.unlimitedChanges ) && player.unlimitedChanges );
					player IPrintLnBold( (player.unlimitedChanges ? "Unlimited changes" : "Finite changes") );
				}
			}
		}
		
		if ( GetDvarInt( "scr_ph_moreClones", 0 ) != MORE_CLONES && IsDefined( level.players ) )
		{
			foreach ( player in level.players )
			{
				if ( player util::isProp() )
				{
					MORE_CLONES = GetDvarInt( "scr_ph_moreClones", 0 );
					player.unlimitedClones = !( isdefined( player.unlimitedClones ) && player.unlimitedClones );
					player IPrintLnBold( (player.unlimitedClones ? "Unlimited clones" : "Finite clones") );
				}
			}
		}
		
		if ( GetDvarInt( "scr_ph_moreFlashes", 0 ) != MORE_FLASHES && IsDefined( level.players ) )
		{
			foreach ( player in level.players )
			{
				if ( player util::isProp() )
				{
					MORE_FLASHES = GetDvarInt( "scr_ph_moreFlashes", 0 );
					player.unlimitedFlashes = !( isdefined( player.unlimitedFlashes ) && player.unlimitedFlashes );
					player IPrintLnBold( (player.unlimitedFlashes ? "Unlimited flashes" : "Finite flashes") );
				}
			}
		}

		if ( GetDvarInt( "scr_ph_moreBoost", 0 ) != MORE_BOOST )
		{
			MORE_BOOST = GetDvarInt( "scr_ph_moreBoost", 0 );
			if ( MORE_BOOST )
			{
				SetDvar( "doublejump_time_before_recharge", 1 );
				SetDvar( "doublejump_time_before_recharge_fast", 1 );
				SetDvar( "playerEnergy_restRate", 10000 );
			}
			else
			{
				SetDvar( "doublejump_time_before_recharge", 1600 );
				SetDvar( "doublejump_time_before_recharge_fast", 1000 );
				SetDvar( "playerEnergy_restRate", 400 );
				IPrintLnBold( (MORE_BOOST ? "Unlimited boost" : "Finite boost") );
			}
		}
		
		if ( GetDvarInt( "scr_ph_morePings", 0 ) != MORE_PINGS && IsDefined( level.players ) )
		{
			foreach ( player in level.players )
			{
				if ( player prop::isHunter() )
				{
					MORE_PINGS = GetDvarInt( "scr_ph_morePings", 0 );
					player.unlimitedPings = !( isdefined( player.unlimitedPings ) && player.unlimitedPings );
					player IPrintLnBold( (player.unlimitedPings ? "Unlimited pings" : "Finite pings") );
				}
			}
		}
		
		isRemoved = GetDvarInt( "scr_ph_removeDebugUR", 0 );
		if ( isRemoved != REMOVE_UPPER_RIGHT_PRINTS_DEBUG )
		{
			REMOVE_UPPER_RIGHT_PRINTS_DEBUG = isRemoved;
			
			toggleDebugUpperRight( !isRemoved );
		}
		
		inPlacementMode = GetDvarInt( "scr_ph_placementMode", 0 );
		if ( inPlacementMode != PLACEMENT_MODE )
		{
			PLACEMENT_MODE = inPlacementMode;
			
			result = toggleDebugPlacmentMode( inPlacementMode );
			if ( !result )
				PLACEMENT_MODE = !inPlacementMode;
			
			if ( PLACEMENT_MODE )
				level.drown_damage = 0;
			else
				level.drown_damage = CONST_SWIM_DAMAGE;
		}
		
		if ( GetDvarInt( "scr_ph_placementWrite", 0 ) != 0 )
		{
			writePlacementFile();
			
			SetDvar( "scr_ph_placementWrite", 0 );
		}
		
		if ( GetDvarInt( "scr_ph_placementWriteGSH", 0 ) != 0 )
		{
			writePlacementGSHFile();
			
			SetDvar( "scr_ph_placementWriteGSH", 0 );
		}
		
		if ( GetDvarInt( "scr_ph_placementWriteEmpty", 0 ) != 0 )
		{
			writeEmptyPlacementFiles();
			
			SetDvar( "scr_ph_placementWriteEmpty", 0 );
		}
		
		if ( GetDvarInt( "scr_ph_debugPlayerCard", 0 ) != 0 )
		{
			if ( isdefined( level.players ) && isdefined( level.players[0] ) )
				level thread prop::playerCardSplash( &"SCORE_LAST_ALIVE", level.players[0] );
			
			SetDvar( "scr_ph_debugPlayerCard", 0 );
		}
		
		if ( GetDvarInt( "scr_ph_showHealth", 0 ) != 0 )
		{
			showHealth();
		}
		
		if ( GetDvarInt( "scr_ph_debugGroundTrace", 0) )
		{
			debugGroundTrace();
		}
		
		if ( GetDvarInt( "scr_ph_showModels", 0 ) != 0 )
		{
			showModels();
			
			SetDvar( "scr_ph_showModels", 0 );
		}
		
		if ( GetDvarInt( "scr_ph_debugCanLock", 0 ) != 0 )
		{
			if ( isdefined( level.players ) && isdefined( level.players[0] ) )
				level.players[0] prop_controls::canLock();
		}
		
		if ( GetDvarInt( "scr_ph_debugLastLock", 0 ) != 0 || GetDvarInt( "scr_ph_debugCanLock", 0 ) != 0 )
		{
			debugDrawLastLock();
		}
		
		if ( GetDvarInt( "scr_ph_makeClone", 0 ) != 0 )
		{
			makeClone();
			
			SetDvar( "scr_ph_makeClone", 0 );
		}

		if ( GetDvarInt( "scr_ph_makeClones", 0 ) != 0 )
		{
			makeClones();
			
			SetDvar( "scr_ph_makeClones", 0 );
		}
		
		if ( GetDvarInt( "scr_ph_cancelCountdown", 0 ) != 0 && IsDefined( level.players ) )
		{
			foreach ( player in level.players )
				player notify( "cancelCountdown" );
			
			SetDvar( "scr_ph_cancelCountdown", 0 );
		}	

		if ( GetDvarInt( "scr_ph_debugSpeed", 0 ) != 0 )
		{
			showPlayerSpeed();
		}
		
		if ( GetDvarInt( "scr_ph_debugShowPlayers", 0 ) != 0 )
		{
			showPlayers();
		}
		
		if ( GetDvarInt( "scr_ph_debugShowTargets", 0 ) != 0 )
		{
			showTargets();
		}
		
		if ( GetDvarInt( "scr_prop_minigame", 1 ) != MINIGAME_ON && IsDefined( level.players ) && level.players.size > 0 )
		{
			MINIGAME_ON = GetDvarInt( "scr_prop_minigame", 1 );
			IPrintLnBold( (MINIGAME_ON ? "Minigame On" : "Minigame Off") );
		}

		if ( GetDvarInt( "scr_ph_debugDoMinigameType", 0 ) != MINIGAME_FORCE_TYPE && IsDefined( level.players ) && level.players.size > 0 )
		{
			MINIGAME_FORCE_TYPE = GetDvarInt( "scr_ph_debugDoMinigameType", 0 );
			if ( MINIGAME_FORCE_TYPE == 2 )
				IPrintLnBold( "Minigame Type Hunt" );
			else if ( MINIGAME_FORCE_TYPE == 1 )
				IPrintLnBold( "Minigame Type Chase" );
			else
				IPrintLnBold( "Minigame Type Random" );
		}
		
		{wait(.05);};
	}
}

function toggleDebugUpperRight( enabled )
{
	SetDvar( "com_statmon", enabled );
	SetDvar( "con_minicon", enabled );
	SetDvar( "cg_drawfps", enabled );
	SetDvar( "cg_drawTime", enabled );
	SetDvar( "cg_drawviewpos", enabled );
	SetDvar( "cg_drawBuildname", enabled );
	SetDvar( "cg_drawLimits", enabled );
}

function toggleDebugPlacmentMode( enabled )
{
	if ( !IsDefined( level.players ) || level.players.size == 0 )
		return false;
	
	player = level.players[0];
	
	if ( !IsDefined( player ) || !IsAlive( player ) || IsDefined( player.placementOffset ) || !IsDefined( player.prop ) )
		return false;
	
	if ( enabled )
	{
		player addPlacementHud();
	}
	else
	{
		player removePlacementHud();
	}
	
	return true;
}

function addUpperRightHudElemDebug( color, label, value, text, textPC )
{
	hudElem = prop_controls::addUpperRightHudElem( label, value, text, textPC );
	hudElem.alpha = 0.5;
	hudElem.color = color;
	
	return hudElem;
}

function addPlacementHud()
{
	self prop_controls::cleanupPropControlsHUD();
	self prop_controls::cleanupPropKeyBindings();
	
	if ( self IsSplitscreen() )
		self.currentHudY = -10;
	else
		self.currentHudY = -80;
	
	self.currentPropIndex = getPropIndex(self.prop.info.modelName);
	
	white = ( 1, 1, 1 );
	red = ( 1, 0, 0 );
	green = ( 0, 1, 0 );
	blue = ( 0, 0.5, 1 );
	
	self.placementRange = addUpperRightHudElemDebug( white, &"Range:  &&1", self.prop.info.propRange );
	self.placementHeight = addUpperRightHudElemDebug( white, &"Height:  &&1", self.prop.info.propHeight );
	self.placementOffsetAngR = addUpperRightHudElemDebug( white, &"Angle Offset Roll: &&1", self.prop.info.anglesOffset[2] );
	self.placementOffsetAngY = addUpperRightHudElemDebug( white, &"Angle Offset Yaw: &&1", self.prop.info.anglesOffset[1] );
	self.placementOffsetAngP = addUpperRightHudElemDebug( white, &"Angle Offset Pitch: &&1", self.prop.info.anglesOffset[0] );
	self.placementOffsetOrgZ = addUpperRightHudElemDebug( blue, &"Origin Offset Z: &&1", self.prop.info.xyzOffset[2] );
	self.placementOffsetOrgY = addUpperRightHudElemDebug( green, &"Origin Offset Y: &&1", self.prop.info.xyzOffset[1] );
	self.placementOffsetOrgX = addUpperRightHudElemDebug( red, &"Origin Offset X: &&1", self.prop.info.xyzOffset[0] );
	self.placementScale = addUpperRightHudElemDebug( white, &"Scale: &&1", self.prop.info.propScale );
	self.placementHealth = addUpperRightHudElemDebug( white, &"Health: &&1", self.prop.info.propSize );
	self.placementSize = addUpperRightHudElemDebug( white, undefined, undefined, "Size: " + self.prop.info.propSizeText );
	self.placementModel = addUpperRightHudElemDebug( white, undefined, undefined, "Model [" + self.currentPropIndex + "]" + self.prop.info.modelName );
	
	self.placementHud = Array( self.placementModel, self.placementSize, self.placementHealth, self.placementScale, self.placementOffsetOrgX, self.placementOffsetOrgY, self.placementOffsetOrgZ, self.placementOffsetAngP, self.placementOffsetAngY, self.placementOffsetAngR, self.placementHeight, self.placementRange );
	self.placementIndex = 0;
	
	self setupPlacementBindings();
	self thread drawPlacementDebug();
	self thread handlePlacementInput();
	self thread removePlacementHudOnDeath();
}

function removePlacementHud()
{
	self notify( "removePlacementHud" );
	
	prop_controls::safeDestroy( self.placementModel );
	prop_controls::safeDestroy( self.placementSize );
	prop_controls::safeDestroy( self.placementHealth );
	prop_controls::safeDestroy( self.placementScale );
	prop_controls::safeDestroy( self.placementOffsetOrgX );
	prop_controls::safeDestroy( self.placementOffsetOrgY );
	prop_controls::safeDestroy( self.placementOffsetOrgZ );
	prop_controls::safeDestroy( self.placementOffsetAngP );
	prop_controls::safeDestroy( self.placementOffsetAngY );
	prop_controls::safeDestroy( self.placementOffsetAngR );
	prop_controls::safeDestroy( self.placementHeight );
	prop_controls::safeDestroy( self.placementRange );
		
	self cleanupPlacementBindings();
	self prop_controls::propControlsHUD();
	self prop_controls::setupKeyBindings();
}

function removePlacementHudOnDeath()
{
	self endon( "game_ended" );
	self endon( "disconnect" );
	self endon( "removePlacementHud" );
		
	self waittill( "death" );
	
	SetDvar( "scr_ph_placementMode", 0 );
}

function debugAxis( origin, angles, size, alpha, depthTest, duration )
{
	axisX = AnglesToForward( angles ) * size;
	axisY = AnglesToRight( angles ) * size;
	axisZ = AnglesToUp( angles ) * size;

	Line( origin, origin + axisX, ( 1, 0, 0 ), alpha, false, duration );
	Line( origin, origin + axisY, ( 0, 1, 0 ), alpha, false, duration );
	Line( origin, origin + axisZ, ( 0, 0, 1 ), alpha, false, duration );
}

function drawPlacementDebug()
{
	self endon( "removePlacementHud" );
	
	while ( true )
	{
		debugAxis( self.origin, self.angles, 100, 1, false, 1 );
		Box( self.origin, self GetMins(), self GetMaxs(), self.angles[1], ( 1, 0, 1 ), 1, false, 1 );
		{wait(.05);};
	}
}

function handlePlacementInput()
{
	self endon( "removePlacementHud" );
	
	self changeSelectedPlacementOption( 0 );
	
	while ( 1 )
	{
		msg = self util::waittill_any_return( "up", "down", "left", "right", "shot" );
		
		if ( !IsDefined( msg ) )
			continue;
		
		if ( msg == "up" )
			self changeSelectedPlacementOptionHold( -1 );
		else if ( msg == "down" )
			self changeSelectedPlacementOptionHold( 1 );
		else if ( msg == "right" )
			self adjustSelectedPlacementOptionHold( 1 );
		else if ( msg == "left" )
			self adjustSelectedPlacementOptionHold( -1 );
		else if ( msg == "shot" )
			debugShotTest();
	}
}

function changeSelectedPlacementOptionHold( val )
{
	self endon( "letgo" );
	
	changeSelectedPlacementOption( val );
	
	wait 0.5;
	
	while ( true )
	{
		changeSelectedPlacementOption( val );
		
		wait 0.05;
	}
}

function changeSelectedPlacementOption( val )
{	
	hudElem = self.placementHud[self.placementIndex];
	hudElem.alpha = 0.5;
	hudElem.fontscale = 1;
	
	self.placementIndex += val;
	if ( self.placementIndex >= self.placementHud.size )
		self.placementIndex = 0;
	else if ( self.placementIndex < 0 )
		self.placementIndex = self.placementHud.size - 1;

	hudElem = self.placementHud[self.placementIndex];
	hudElem.alpha = 1;
	hudElem.fontscale = 1.3;
}

function adjustSelectedPlacementOptionHold( val )
{
	self endon( "letgo" );
	
	adjustSelectedPlacementOption( val );
	
	wait 0.5;
	
	while ( true )
	{
		adjustSelectedPlacementOption( val );
		
		wait 0.05;
	}
}

function setCurrentPropIndex(inVal)
{
	tempIndex = self.currentPropIndex + inVal;
	
	if (tempIndex >= level.propIndex.size)
		tempIndex = 0;
	else if (tempIndex < 0)
		tempIndex = (level.propIndex.size-1);
	
	self.currentPropIndex = tempIndex;
}

function getPropIndex(inModelName)
{
	for (index = 0; index < level.propIndex.size; index++)
	{
		if ( level.propList[level.propIndex[index][0]][level.propIndex[index][1]].modelName == inModelName )
			return index;
	}
}

function adjustSelectedPlacementOption( val )
{
	hudElem = self.placementHud[self.placementIndex];
	
	if ( hudElem == self.placementModel )
	{		
		setCurrentPropIndex(val);
		
		self.prop.info = level.propList[level.propIndex[self.currentPropIndex][0]][level.propIndex[self.currentPropIndex][1]];

		prop_controls::propChangeTo( self.prop.info );
		
		self.placementModel SetText( "Model (" + self.currentPropIndex + "): " + self.prop.info.modelName );
		self.placementSize SetText( "Size: " + self.prop.info.propSizeText );
		self.placementHealth SetValue( self.prop.info.propSize );
		self.placementScale SetValue( self.prop.info.propScale );
		self.placementOffsetOrgX SetValue( self.prop.info.xyzOffset[0] );
		self.placementOffsetOrgY SetValue( self.prop.info.xyzOffset[1] );
		self.placementOffsetOrgZ SetValue( self.prop.info.xyzOffset[2] );
		self.placementOffsetAngP SetValue( self.prop.info.anglesOffset[0] );
		self.placementOffsetAngY SetValue( self.prop.info.anglesOffset[1] );
		self.placementOffsetAngR SetValue( self.prop.info.anglesOffset[2] );
		self.placementHeight SetValue( self.prop.info.propHeight );
		self.placementRange SetValue( self.prop.info.propRange );
	}
	else if ( hudElem == self.placementSize || hudElem == self.placementHealth )
	{
		sizes = Array( "xsmall", "small", "medium", "large", "xlarge", "remove" );
		index = 0;
		for ( i = 0; i < sizes.size; i++ )
		{
			if ( sizes[i] == self.prop.info.propSizeText )
			{
				index = i;
				break;
			}
		}
		
		index += val;
		if ( index < 0 )
			index = sizes.size -1;
		else if ( index >= sizes.size )
			index = 0;
		
		self.prop.info.propSizeText = sizes[index];
		self.prop.info.propSize = prop::getPropSize( self.prop.info.propSizeText );
		
		self.placementSize SetText( "Size: " + self.prop.info.propSizeText );
		self.placementHealth SetValue( self.prop.info.propSize );
		self.health = self.prop.info.propSize;
		self.maxhealth = self.health;
	}
	else if ( hudElem == self.placementScale )
	{
		CONST_MIN_SCALE = 0.1;
		CONST_MAX_SCALE = 10.0;
		scaleAdjust = 0.01;
		
		self.prop.info.propScale += (scaleadjust * val);
		self.prop.info.propScale = math::clamp( self.prop.info.propScale, CONST_MIN_SCALE, CONST_MAX_SCALE );
		self.prop SetScale( self.prop.info.propScale, true );
		self.placementScale SetValue( self.prop.info.propScale );
	}
	else if ( hudElem == self.placementOffsetOrgX )
	{
		self.prop Unlink();
		self.prop.info.xyzOffset = ( self.prop.info.xyzOffset[0] + val, self.prop.info.xyzOffset[1], self.prop.info.xyzOffset[2] );
		self.prop.xyzOffset = self.prop.info.xyzOffset;
		self.placementOffsetOrgX SetValue( self.prop.info.xyzOffset[0] );
		linkAndApply();
	}
	else if ( hudElem == self.placementOffsetOrgY )
	{
		self.prop Unlink();
		self.prop.info.xyzOffset = ( self.prop.info.xyzOffset[0], self.prop.info.xyzOffset[1] + val, self.prop.info.xyzOffset[2] );
		self.prop.xyzOffset = self.prop.info.xyzOffset;
		self.placementOffsetOrgY SetValue( self.prop.info.xyzOffset[1] );
		linkAndApply();
	}
	else if ( hudElem == self.placementOffsetOrgZ )
	{
		self.prop Unlink();
		self.prop.info.xyzOffset = ( self.prop.info.xyzOffset[0], self.prop.info.xyzOffset[1], self.prop.info.xyzOffset[2] + val );
		self.prop.xyzOffset = self.prop.info.xyzOffset;
		self.placementOffsetOrgZ SetValue( self.prop.info.xyzOffset[2] );
		linkAndApply();
	}
	else if ( hudElem == self.placementOffsetAngP )
	{
		self.prop Unlink();
		self.prop.info.anglesOffset = ( self.prop.info.anglesOffset[0] + val, self.prop.info.anglesOffset[1], self.prop.info.anglesOffset[2] );
		self.prop.anglesOffset = self.prop.info.anglesOffset;
		self.placementOffsetAngP SetValue( self.prop.info.anglesOffset[0] );
		linkAndApply();
	}
	else if ( hudElem == self.placementOffsetAngY )
	{
		self.prop Unlink();
		self.prop.info.anglesOffset = ( self.prop.info.anglesOffset[0], self.prop.info.anglesOffset[1] + val, self.prop.info.anglesOffset[2] );
		self.prop.anglesOffset = self.prop.info.anglesOffset;
		self.placementOffsetAngY SetValue( self.prop.info.anglesOffset[1] );
		linkAndApply();
	}
	else if ( hudElem == self.placementOffsetAngR )
	{
		self.prop Unlink();
		self.prop.info.anglesOffset = ( self.prop.info.anglesOffset[0], self.prop.info.anglesOffset[1], self.prop.info.anglesOffset[2] + val );
		self.prop.anglesOffset = self.prop.info.anglesOffset;
		self.placementOffsetAngR SetValue( self.prop.info.anglesOffset[2] );
		linkAndApply();
	}
	else if ( hudElem == self.placementHeight )
	{
		adjust = 10;
		
		self.prop.info.propHeight += (adjust * val);
		self.prop.info.propHeight = math::clamp( self.prop.info.propHeight, -30, 40 );
		self.thirdPersonHeightOffset = self.prop.info.propHeight;
		self SetClientThirdPerson( true, self.thirdPersonRange, self.thirdPersonHeightOffset );
		self.placementHeight SetValue( self.prop.info.propHeight );
	}
	else if ( hudElem == self.placementRange )
	{
		adjust = 10;
		
		self.prop.info.propRange += (adjust * val);
		self.prop.info.propRange = math::clamp( self.prop.info.propRange, 50, 360 );
		self.thirdPersonRange = self.prop.info.propRange;
		self SetClientThirdPerson( true, self.thirdPersonRange, self.thirdPersonHeightOffset );
		self.placementRange SetValue( self.prop.info.propRange );
	}
}

function linkAndApply()
{
	self.prop.origin = self.propEnt.origin;
	self prop::applyXYZOffset();
	self prop::applyAnglesOffset();
	self.prop LinkTo( self.propEnt );
}

function setupPlacementBindings() // self == player
{
	self prop_controls::NotifyOnPlayerCommand( "up", "+actionslot 1" );
	self prop_controls::NotifyOnPlayerCommand( "down", "+actionslot 2" );
	self prop_controls::NotifyOnPlayerCommand( "left", "+actionslot 3" );
	self prop_controls::NotifyOnPlayerCommand( "right", "+actionslot 4" );
	self prop_controls::NotifyOnPlayerCommand( "letgo", "-actionslot 1" );
	self prop_controls::NotifyOnPlayerCommand( "letgo", "-actionslot 2" );
	self prop_controls::NotifyOnPlayerCommand( "letgo", "-actionslot 3" );
	self prop_controls::NotifyOnPlayerCommand( "letgo", "-actionslot 4" );
	self prop_controls::NotifyOnPlayerCommand( "shot", "+attack" );
	self prop_controls::NotifyOnPlayerCommand( "zoomOut", "weapnext" );
	self prop_controls::NotifyOnPlayerCommand( "zoomIn", "+usereload" );
	self prop_controls::NotifyOnPlayerCommand( "zoomIn", "+activate" );
}

function cleanupPlacementBindings() // self == player
{
	self prop_controls::NotifyOnPlayerCommandRemove( "up", "+actionslot 1" );
	self prop_controls::NotifyOnPlayerCommandRemove( "down", "+actionslot 2" );
	self prop_controls::NotifyOnPlayerCommandRemove( "left", "+actionslot 3" );
	self prop_controls::NotifyOnPlayerCommandRemove( "right", "+actionslot 4" );
	self prop_controls::NotifyOnPlayerCommandRemove( "letgo", "-actionslot 1" );
	self prop_controls::NotifyOnPlayerCommandRemove( "letgo", "-actionslot 2" );
	self prop_controls::NotifyOnPlayerCommandRemove( "letgo", "-actionslot 3" );
	self prop_controls::NotifyOnPlayerCommandRemove( "letgo", "-actionslot 4" );
	self prop_controls::NotifyOnPlayerCommandRemove( "shot", "+attack" );
	self prop_controls::NotifyOnPlayerCommandRemove( "zoomOut", "weapnext" );
	self prop_controls::NotifyOnPlayerCommandRemove( "zoomIn", "+usereload" );
	self prop_controls::NotifyOnPlayerCommandRemove( "zoomIn", "+activate" );
}

function offsetIsDefined( vec )
{
	return isDefined( vec ) && ( vec[0] != 0 || vec[1] != 0 || vec[2] != 0 );
}

function heightIsDefined( propInfo )
{
	return isdefined( propInfo.propHeight ) && propInfo.propHeight != prop::getThirdPersonHeightOffsetForSize( propInfo.propSize );
}

function rangeIsDefined( propInfo )
{
	return isdefined( propInfo.propRange ) && propInfo.propRange != prop::getThirdPersonRangeForSize( propInfo.propSize );
}

function propFPrintLn( file, propInfo )
{
	propStr = "" + propInfo.modelName + "," + propInfo.propSizeText + "," + propInfo.propScale;
	
	if ( offsetIsDefined( propInfo.xyzOffset ) )
		propStr += "," + propInfo.xyzOffset[0] + "," + propInfo.xyzOffset[1] + "," + propInfo.xyzOffset[2];
	else
		propStr += ",0,0,0";
	
	if ( offsetIsDefined( propInfo.anglesOffset ) )
		propStr += "," + propInfo.anglesOffset[0] + "," + propInfo.anglesOffset[1] + "," + propInfo.anglesOffset[2];
	else
		propStr += ",0,0,0";
	
	if ( heightisDefined( propInfo ) )
		propStr += "," + propInfo.propHeight;
	else
		propStr += "," + prop::getThirdPersonHeightOffsetForSize( propInfo.propSize );
	
	if ( rangeIsDefined( propInfo ) )
		propStr += "," + propInfo.propRange;
	else
		propStr += "," + prop::getThirdPersonRangeForSize( propInfo.propSize );		
	
	FPrintLn( file, propStr );
}

function propGSHFPrintLn( file, propInfo )
{
	propStr = "#precache( \"model\", \"" + propInfo.modelName + "\" );";
		
	FPrintLn( file, propStr );
}

function FPrintPropsOfSize( file, propSizeText )
{
	foreach ( sizeType in level.propList )
	{
		foreach ( propInfo in sizeType )
		{
			if ( propInfo.propSizeText == propSizeText )
				propFPrintLn( file, propInfo );
		}
	}
}

function FPrintPropsOfSizeGSH( file, propSizeText )
{
	foreach ( sizeType in level.propList )
	{
		foreach ( propInfo in sizeType )
		{
			if ( propInfo.propSizeText == propSizeText )
				propGSHFPrintLn( file, propInfo );
		}
	}
}

function writePlacementFileHeader( file, filename_base )
{
	filename_stringtable = filename_base + ".csv";
	filename_header = filename_base + ".gsh";
	filename_zpkg = filename_base + ".zpkg";
	
	filename_zone = level.script + ".zone";
	filename_gsc = level.script + ".gsc";
	
	dir_zone = "\\game\\share\\zone_source\\";
	dir_gsc = "\\game\\share\\raw\\scripts\\mp\\";
	dir_csv = "\\game\\share\\raw\\gamedata\\tables\\mp\\";
	
	FPrintLn( file, "#prop name,#prop size,#scale,#origin offset x,#origin offset y,#origin offset z,#angle offset pitch,#angle offset yaw,#angle offset roll,#height offset,#range offset" );
	FPrintLn( file, "" );
	FPrintLn( file, "#SETUP:" );
	FPrintLn( file, "# 1) Fill in the file " + filename_stringtable + " with model names" );
	FPrintLn( file, "# 2) Fill in the file " + filename_header + " with model names" );
	FPrintLn( file, "# 3) Put the file " + filename_zpkg + " in " + dir_zone );
	FPrintLn( file, "# 4) Put the file " + filename_stringtable + " in " + dir_csv );
	FPrintLn( file, "# 5) Put the file " + filename_header + " in " + dir_gsc );
	FPrintLn( file, "# 6) Add the 3 files to perforce" );
	FPrintLn( file, "# 7) Add the following to " + filename_zone + ": include," + filename_base );
	FPrintLn( file, "# 8) Add the following to " + filename_gsc + ": #insert scripts\\mp\\" + filename_header + ";" );
	FPrintLn( file, "" );
	FPrintLn( file, "#NOTE: prop size correlates to amount of health" );
	FPrintLn( file, "" );
}

function writePlacementFile()
{
	platform = "pc";
	if ( level.orbis )
		platform = "orbis";
	else if ( level.durango )
		platform = "durango";
	
	filename_base = level.script + "_ph";
	filename_stringtable = filename_base + ".csv";

	dir_scriptdata = "game\\" + platform + "\\scriptdata\\";
	dir_csv = "\\game\\share\\raw\\gamedata\\tables\\mp\\";

	file = OpenFile( filename_stringtable, "write" );
	if ( file == -1 )
	{
		iprintlnbold( "Error: can't open " + dir_scriptdata + filename_stringtable + " for writing" );
		Println( "Error: can't open " + dir_scriptdata + filename_stringtable + " for writing" );
		return;
	}
	
	writePlacementFileHeader( file, filename_base );
		
	FPrintLn( file, "#Extra Small Props" );
	FPrintPropsOfSize( file, "xsmall" );	
	FPrintLn( file, "" );

	FPrintLn( file, "#Small Props" );
	FPrintPropsOfSize( file, "small" );
	FPrintLn( file, "" );

	FPrintLn( file, "#Medium Props" );
	FPrintPropsOfSize( file, "medium" );
	FPrintLn( file, "" );

	FPrintLn( file, "#Large Props" );
	FPrintPropsOfSize( file, "large" );
	FPrintLn( file, "" );
	
	FPrintLn( file, "#Extra Large Props" );
	FPrintPropsOfSize( file, "xlarge" );
	
	iprintlnbold( "Wrote " + dir_scriptdata + filename_stringtable + "; move to " + dir_csv );
	PrintLn( "Wrote " + dir_scriptdata + filename_stringtable + "; move to " + dir_csv );
	
	CloseFile( file );
}

function writePlacementGSHFile()
{
	platform = "pc";
	if ( level.orbis )
		platform = "orbis";
	else if ( level.durango )
		platform = "durango";
	
	filename_base = level.script + "_ph";
	filename_stringtable = filename_base + ".gsh";

	dir_scriptdata = "game\\" + platform + "\\scriptdata\\";
	dir_csv = "\\game\\share\\raw\\scripts\\mp\\";

	file = OpenFile( filename_stringtable, "write" );
	if ( file == -1 )
	{
		iprintlnbold( "Error: can't open " + dir_scriptdata + filename_stringtable + " for writing" );
		Println( "Error: can't open " + dir_scriptdata + filename_stringtable + " for writing" );
		return;
	}
			
	FPrintLn( file, "// Extra Small Props" );
	FPrintPropsOfSizeGSH( file, "xsmall" );	
	FPrintLn( file, "" );

	FPrintLn( file, "// Small Props" );
	FPrintPropsOfSizeGSH( file, "small" );
	FPrintLn( file, "" );

	FPrintLn( file, "// Medium Props" );
	FPrintPropsOfSizeGSH( file, "medium" );
	FPrintLn( file, "" );

	FPrintLn( file, "// Large Props" );
	FPrintPropsOfSizeGSH( file, "large" );
	FPrintLn( file, "" );
	
	FPrintLn( file, "// Extra Large Props" );
	FPrintPropsOfSizeGSH( file, "xlarge" );
	
	iprintlnbold( "Wrote " + dir_scriptdata + filename_stringtable + "; move to " + dir_csv );
	PrintLn( "Wrote " + dir_scriptdata + filename_stringtable + "; move to " + dir_csv );
	
	CloseFile( file );
}

function writeEmptyPlacementFiles()
{
	platform = "pc";
	if ( level.orbis )
		platform = "orbis";
	else if ( level.durango )
		platform = "durango";
	
	filename_base = level.script + "_ph";
	filename_stringtable = filename_base + ".csv";
	filename_header = filename_base + ".gsh";
	filename_zpkg = filename_base + ".zpkg";
	
	filename_zone = level.script + ".zone";
	filename_gsc = level.script + ".gsc";
	
	dir_scriptdata = "game\\" + platform + "\\scriptdata\\";
	dir_zone = "\\game\\share\\zone_source\\";
	dir_gsc = "\\game\\share\\raw\\scripts\\mp\\";
	dir_csv = "\\game\\share\\raw\\gamedata\\tables\\mp\\";
	
	// <mapname>_ph.csv	
	file = OpenFile( filename_stringtable, "write" );
	if ( file == -1 )
	{
		iprintlnbold( "Error: can't open " + dir_scriptdata + filename_stringtable + " for writing" );
		Println( "Error: can't open " + dir_scriptdata + filename_stringtable + " for writing" );
		return;
	}
	
	writePlacementFileHeader( file, filename_base );
	
	FPrintLn( file, "#Extra Small Props" );
	FPrintLn( file, "some_xsmall_model,xsmall" );
	FPrintLn( file, "some_xsmall_model,xsmall" );
	FPrintLn( file, "some_xsmall_model,xsmall" );	
	FPrintLn( file, "" );

	FPrintLn( file, "#Small Props" );
	FPrintLn( file, "some_small_model,small" );
	FPrintLn( file, "some_small_model,small" );
	FPrintLn( file, "some_small_model,small" );
	FPrintLn( file, "some_small_model,small" );
	FPrintLn( file, "some_small_model,small" );
	FPrintLn( file, "some_small_model,small" );
	FPrintLn( file, "" );

	FPrintLn( file, "#Medium Props" );
	FPrintLn( file, "some_medium_model,medium" );
	FPrintLn( file, "some_medium_model,medium" );
	FPrintLn( file, "some_medium_model,medium" );
	FPrintLn( file, "some_medium_model,medium" );
	FPrintLn( file, "some_medium_model,medium" );
	FPrintLn( file, "some_medium_model,medium" );
	FPrintLn( file, "" );

	FPrintLn( file, "#Large Props" );
	FPrintLn( file, "some_large_model,large" );
	FPrintLn( file, "some_large_model,large" );
	FPrintLn( file, "some_large_model,large" );
	FPrintLn( file, "some_large_model,large" );
	FPrintLn( file, "some_large_model,large" );
	FPrintLn( file, "some_large_model,large" );
	FPrintLn( file, "" );
	
	FPrintLn( file, "#Extra Large Props" );
	FPrintLn( file, "some_extra_large_model,xlarge" );
	FPrintLn( file, "some_extra_large_model,xlarge" );
	FPrintLn( file, "some_extra_large_model,xlarge" );
		
	CloseFile( file );
	
	
	// <mapname>_ph.gsh
	file = OpenFile( filename_header, "write" );
	if ( file == -1 )
	{
		iprintlnbold( "Error: can't open " + dir_scriptdata + filename_header + " for writing" );
		Println( "Error: can't open " + dir_scriptdata + filename_header + " for writing" );
		return;
	}
	
	FPrintLn( file, "// Extra Small Props" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "" );

	FPrintLn( file, "// Small Props" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "" );

	FPrintLn( file, "// Medium Props" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "" );

	FPrintLn( file, "// Large Props" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "" );
	
	FPrintLn( file, "// Extra Large Props" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );
	FPrintLn( file, "#precache( \"model\", \"\" );" );	
		
	CloseFile( file );
	
	
	// <mapname>_ph.zpkg
	file = OpenFile( filename_zpkg, "write" );
	if ( file == -1 )
	{
		iprintlnbold( "Error: can't open " + dir_scriptdata + filename_zpkg + " for writing" );
		Println( "Error: can't open " + dir_scriptdata + filename_zpkg + " for writing" );
		return;
	}

	FPrintLn( file, "stringtable,gamedata/tables/mp/" + filename_stringtable );
	FPrintLn( file, "rawfile,scripts/mp/" + filename_header );
	
	CloseFile( file );
	
	iprintlnbold( "Wrote empty files in: " + dir_scriptdata );
	PrintLn( "Wrote empty files in: " + dir_scriptdata );
}

function debugShotTest()
{
	player = level.players[0];
	if ( !IsDefined( player ) || !IsAlive( player ) || !( isdefined( player.hasSpawned ) && player.hasSpawned ) )
		return;
	
	if ( IsDefined( level.players[1] ) )
		enemyBot = level.players[1];
	else
		enemyBot = bot::add_bot( util::getotherteam( player.team ) );
	
	if ( !isdefined( enemyBot.pers["participation"] ) )
		enemyBot.pers["participation"] = 0;
	
	if ( !isdefined( enemyBot.hits ) )
		enemyBot.hits = 0;
	
	SetDvar( "bot_AllowAttack", 0 );
	SetDvar( "bot_AllowMovement", 0 );
	
	player.health = player.maxhealth;
	
	weapon = GetWeapon( "smg_standard" );
	end = player.origin;
	
	dir = AnglesToForward( player.angles );
	start = end + ( dir * 100 ) + ( 0, 0, 30 );
	MagicBullet( weapon, start, end, enemyBot );
	
	dirBack = -1 * dir;
	start = end + ( dirBack * 100 ) + ( 0, 0, 30 );
	MagicBullet( weapon, start, end, enemyBot );

	dirRight = AnglesToRight( player.angles );
	start = end + ( dirRight * 100 ) + ( 0, 0, 30 );
	MagicBullet( weapon, start, end, enemyBot );

	dirLeft = -1 * dirRight;
	start = end + ( dirLeft * 100 ) + ( 0, 0, 30 );
	MagicBullet( weapon, start, end, enemyBot );

	start = end + ( 0, 0, 100 );
	MagicBullet( weapon, start, end, enemyBot );
	
	player util::waittill_notify_or_timeout( "damage", 0.3 );
	
	wait 0.5;
	
	player.health = player.maxhealth;
}

function showHealth()
{
	if ( !IsDefined( level.players ) )
		return;
	
	foreach ( player in level.players )
	{
		if ( IsDefined( player ) && IsDefined( player.team ) && player.team == game[ "defenders" ] )
			Print3D( player.origin + ( 0, 0, 50 ), "" + player.health );
	}
}

function showPlayerSpeed()
{
	if ( !IsDefined( level.players ) )
		return;
	
	foreach ( player in level.players )
	{
		velocity = player GetVelocity();
		velocity2d = ( velocity[0], velocity[1], 0 );
		speed = Length( velocity2d );
		Print3D( player.origin + ( 0, 0, 50 ), "" + speed );
	}
}

function debugGroundTrace()
{
	if ( !IsDefined( level.players ) )
		return;
	
	foreach ( player in level.players )
	{
		if ( IsDefined( player ) && IsDefined( player.prop ) )
			player prop_controls::get_ground_normal( player.prop, true );
	}
}

function createFakeModel( propInfo, origin, angles )
{
	propEnt = Spawn( "script_model", origin );
	propEnt SetContents( 0 );
	propEnt NotSolid();
	propEnt SetPlayerCollision( false );

	prop = Spawn("script_model", propEnt.origin);
	prop.angles = angles;
	prop setModel( propInfo.modelName );
	prop SetScale( propInfo.propScale, true );
	prop SetCanDamage( true );
	prop.xyzOffset = propInfo.xyzOffset;
	prop.anglesOffset = propInfo.anglesOffset;
	prop.health = 1;
	prop SetPlayerCollision( false );
		
	forward = AnglesToForward( angles ) * prop.xyzOffset[0];
	right = AnglesToRight( angles ) * prop.xyzOffset[1];
	up = AnglesToUp( angles ) * prop.xyzOffset[2];
	prop.origin += forward;
	prop.origin += right;
	prop.origin += up;
	prop.angles += prop.anglesOffset;

	prop LinkTo( propEnt );
	
	propEnt.prop = prop;
	propEnt.propInfo = propInfo;
	
	return propEnt;
}

function showModels()
{
	player = level.players[0];
	angles = player.angles;
	dir = AnglesToForward( angles );
	origin = player.origin + ( 0, 0, 100 );
	
	if ( !isdefined( level.propDebugModels ) )
	{
		level.propDebugModels = [];
		
		foreach ( category in level.propList )
		{
			foreach ( propInfo in category )
			{
				level.propDebugModels[level.propDebugModels.size] = createFakeModel( propInfo, origin, angles );
				origin = origin + dir * 60;
			}
		}
	}
	else
	{
		foreach ( propEnt in level.propDebugModels )
		{
			propEnt.origin = origin;
			origin = origin + dir * 60;
		}
	}
}

function debugDrawLastLock()
{
	if ( !isdefined( level.phLockDebug ) )
		return;
	
	color = ( 0, 1, 0 );
	if ( !level.phLockDebug.success )
		color = ( 1, 0, 0 );
	
	Print3D( level.phLockDebug.playerOrg + ( 0, 0, 50 ), level.phLockDebug.type );
	Box( level.phLockDebug.playerOrg, level.phLockDebug.playerMins, level.phLockDebug.playerMaxs, level.phLockDebug.playerAngles[1], color );
	
	if ( isdefined( level.phLockDebug.origin1 ) )
	{
		Sphere( level.phLockDebug.origin1, 5, color );
		Line( level.phLockDebug.playerOrg, level.phLockDebug.origin1 );
		if ( isdefined( level.phLockDebug.text1 ) )
			Print3D( level.phLockDebug.origin1 + ( 0, 0, -10 ), level.phLockDebug.text1 );
	}
	
	if ( isdefined( level.phLockDebug.origin2 ) )
	{
		Sphere( level.phLockDebug.origin2, 5, color );
		Line( level.phLockDebug.playerOrg, level.phLockDebug.origin2 );
		if ( isdefined( level.phLockDebug.text2 ) )
			Print3D( level.phLockDebug.origin2 + ( 0, 0, 10 ), level.phLockDebug.text2 );
	}
	
	if ( isdefined( level.phLockDebug.origin3 ) )
	{
		Sphere( level.phLockDebug.origin3, 5, color );
		Line( level.phLockDebug.playerOrg, level.phLockDebug.origin3 );
		if ( isdefined( level.phLockDebug.text3 ) )
			Print3D( level.phLockDebug.origin3 + ( 0, 0, 30 ), level.phLockDebug.text3 );
	}
}

function makeFakeClone( propInfo, origin, angles, team )
{
	newClone = Spawn( "script_model", origin );
    newClone.targetname = "propClone";
    newClone setModel( propInfo.modelname );
    newClone SetScale( propInfo.propScale, true );
    newClone.angles = angles;
    newClone SetCanDamage( true );
    newClone.fakeHealth = 50;
	newClone.health = 99999;
	newClone.maxhealth = 99999;
	newClone thread prop::entityDamageWatcher( &prop_controls::damageCloneWatch );
	newClone SetPlayerCollision( false );
	newClone MakeSentient();
	newClone NotSolidCapsule();
	newClone SetTeam( team );
}

function makeClones()
{
	player = level.players[0];
	angles = player.angles;
	dir = AnglesToForward( angles );
	origin = player.origin + ( 0, 0, 100 );
	
	if ( isdefined( level.propDebugClones ) )
	{
		foreach ( clone in level.propDebugClones )
		{
			clone prop_controls::deleteClone();
		}
	}
	
	level.propDebugClones = [];
	
	foreach ( category in level.propList )
	{
		foreach ( propInfo in category )
		{
			level.propDebugClones[level.propDebugClones.size] = makeFakeClone( propInfo, origin, angles, util::getotherteam( player.team ) );
			origin = origin + dir * 60;
		}
	}
}

function makeClone()
{
	player = level.players[0];
	angles = player.angles;
	dir = AnglesToForward( angles );
	origin = player.origin + dir * ( 0, 0, 100 );
	
	propInfo = prop::getNextProp( player );
	
	if ( !isdefined( level.propDebugClones ) )
		level.propDebugClones = [];
	
	level.propDebugClones[level.propDebugClones.size] = makeFakeClone( propInfo, origin, angles, util::getotherteam( player.team ) );
}

function showPlayers()
{
	if ( !IsDefined( level.players ) )
		return;
	
	foreach ( player in level.players )
	{
		Box( player.origin, player GetMins(), player GetMaxs(), player.angles[1], ( 1, 0, 1 ), 1, false, 1 );
	}
}

function showTargets()
{
	if ( !isdefined( level.ph_minigame ) || !isdefined( level.ph_minigame.targets ) )
		return;
	
	for ( i = 0; i < level.ph_minigame.targets.size; i++ )
	{
		target = level.ph_minigame.targets[i];
		if ( isdefined( target ) )
			Print3D( target.origin + ( 0, 0, 30 ), "" + target.fakehealth );
	}
}
#/