#include maps\_utility;
#include common_scripts\utility;
main()
{
	// -- -- -- -- -- -- -- -- -- 
	// EFECTS DEFINITIONS
	// -- -- -- -- -- -- -- -- -- 

	flag_init( "no_ai_tv_damage" );
	qBarrels = false;

	barrels = getentarray( "explodable_barrel", "targetname" );
	if ( barrels.size )
		qBarrels = true;
		
	barrels = getentarray( "explodable_barrel", "script_noteworthy" );
	if ( barrels.size > 0 )
		qBarrels = true;

	if ( qBarrels )
	{
		level._breakables_fx[ "barrel" ][ "explode" ] 	 = loadfx( "props/barrelExp" );
		level._breakables_fx[ "barrel" ][ "burn_start" ]	 = loadfx( "props/barrel_ignite" );
		level._breakables_fx[ "barrel" ][ "burn" ]	 	 = loadfx( "props/barrel_fire_top" );
	}

	oilspill = getentarray( "oil_spill", "targetname" );
	if ( oilspill.size )
	{
		level._breakables_fx[ "oilspill" ][ "burn" ]		 = loadfx( "props/barrel_fire" );
		level._breakables_fx[ "oilspill" ][ "spark" ]	 = loadfx( "impacts/small_metalhit_1" );
	}

	tincans = getentarray( "tincan", "targetname" );
	if ( tincans.size )
		level._breakables_fx[ "tincan" ] 				 = loadfx( "props/tincan_bounce" );

	qBreakables = false;
	breakables = getentarray( "breakable", "targetname" );
	if ( breakables.size )
		qBreakables = true;
		
	breakables = getentarray( "breakable_vase", "targetname" );
	if ( breakables.size )
		qBreakables = true;
		
	breakables = getentarray( "breakable box", "targetname" );
	if ( barrels.size )
		qBreakables = true;
		
	breakables = getentarray( "breakable box", "script_noteworthy" );
	if ( barrels.size )
		qBreakables = true;
		
	if ( qBreakables )
	{
		level._breakables_fx[ "vase" ] 					 = loadfx( "props/vase_water" );
		level._breakables_fx[ "bottle" ] 				 = loadfx( "props/wine_bottle" );
		level._breakables_fx[ "box" ][ 0 ] 				 = loadfx( "props/crateExp_dust" );
		level._breakables_fx[ "box" ][ 1 ] 				 = loadfx( "props/crateExp_dust" );
		level._breakables_fx[ "box" ][ 2 ] 				 = loadfx( "props/crateExp_dust" );
		level._breakables_fx[ "box" ][ 3 ] 				 = loadfx( "props/crateExp_ammo" );
	}

	glassarray = getentarray( "glass", "targetname" );
	glassarray = array_combine( glassarray, getentarray( "glass", "script_noteworthy" ) );
	if ( glassarray.size )
	{
		level._glass_info = [];

		level._glass_info[ "glass_large" ][ "breakfx" ] = loadfx( "props/car_glass_large" );
		level._glass_info[ "glass_large" ][ "breaksnd" ] = "veh_glass_break_large";

		level._glass_info[ "glass_med" ][ "breakfx" ] = loadfx( "props/car_glass_med" );
		level._glass_info[ "glass_med" ][ "breaksnd" ] = "veh_glass_break_small";

		level._glass_info[ "glass_small" ][ "breakfx" ] = loadfx( "props/car_glass_headlight" );
		level._glass_info[ "glass_small" ][ "breaksnd" ] = "veh_glass_break_small";
	}

	tv_array = getentarray( "interactive_tv", "targetname" );
	if ( tv_array.size )
	{
		precachemodel( "com_tv2_d" );
		precachemodel( "com_tv1" );
		precachemodel( "com_tv2" );
		precachemodel( "com_tv1_testpattern" );
		precachemodel( "com_tv2_testpattern" );

		level._breakables_fx[ "tv_explode" ] = loadfx( "explosions/tv_explosion" );
	}
	level._tv_lite_array = getentarray( "interactive_tv_light", "targetname" );

	security_camera_array = getentarray( "destroyable_security_camera", "script_noteworthy" );
	if ( security_camera_array.size )
	{
		precachemodel( "com_security_camera" );
		precachemodel( "com_security_camera_destroyed" );

		level._breakables_fx[ "security_camera_explode" ] = loadfx( "props/securitycamera_explosion" );
	}

	// -- -- -- -- -- -- -- -- -- 
	// -- -- -- -- -- -- -- -- -- 


	// -- -- -- -- -- -- -- -- - 
	// SOUND DEFINITIONS
	// -- -- -- -- -- -- -- -- - 
	level._barrelExpSound = "barrel_mtl_explode";
	// -- -- -- -- -- -- -- -- - 
	// -- -- -- -- -- -- -- -- - 

	// -- -- -- -- -- -- - 
	// MISC SETTINGS
	// -- -- -- -- -- -- - 
	maxBrokenPieces = 25;
	level._breakables_peicesCollide[ "orange vase" ] = true;
	level._breakables_peicesCollide[ "green vase" ] = true;
	level._breakables_peicesCollide[ "bottle" ] = true;
	//* * * * * * * * * * * * * IF YOU PUT THIS BACK IN - SEARCH FOR "PLATE WAIT" AND PUT THAT BACK IN TOO * * * * * * * * * * * * * 
	// 	level.breakables_peicesCollide[ "plate" ] = true;
	//* * * * * * * * * * * * * IF YOU PUT THIS BACK IN - SEARCH FOR "PLATE WAIT" AND PUT THAT BACK IN TOO * * * * * * * * * * * * * 
	
	
	level._barrelHealth = 150;
	// -- -- -- -- -- -- - 
	// -- -- -- -- -- -- - 
	
	level._precachemodeltype = [];
	level._barrelExplodingThisFrame = false;
	level._breakables_clip = [];
	level._breakables_clip = getentarray( "vase_break_remove", "targetname" );
	level._console_auto_aim = [];
	
	
	level._console_auto_aim = getentarray( "xenon_auto_aim", "targetname" );
	level._console_auto_aim_2nd = getentarray( "xenon_auto_aim_secondary", "targetname" );
	
	for ( i = 0;i < level._console_auto_aim.size;i++ )
		level._console_auto_aim[ i ] notsolid();
		
	for ( i = 0;i < level._console_auto_aim_2nd.size;i++ )
		level._console_auto_aim_2nd[ i ] notsolid();
		
	maps\_utility::set_console_status();
	if ( level._console )
	{
		level._console_auto_aim = undefined;
		level._console_auto_aim_2nd = undefined;
	}

	temp = getentarray( "breakable clip", "targetname" );
	for ( i = 0;i < temp.size;i++ )
		level._breakables_clip[ level._breakables_clip.size ] = temp[ i ];
		
	level._breakable_utility_modelarray = [];
	level._breakable_utility_modelindex = 0;
	level._breakable_utility_maxnum = maxBrokenPieces;
	
	array_thread( getentarray( "tincan", "targetname" ), ::tincan_think );
	array_thread( getentarray( "helmet_pop", "targetname" ), ::helmet_pop );
	array_thread( getentarray( "explodable_barrel", "targetname" ), ::explodable_barrel_think );
	array_thread( getentarray( "explodable_barrel", "script_noteworthy" ), ::explodable_barrel_think );
	array_thread( getentarray( "shuddering_entity", "targetname" ), ::shuddering_entity_think );
	array_thread( getentarray( "breakable box", "targetname" ), ::breakable_think );
	array_thread( getentarray( "breakable box", "script_noteworthy" ), ::breakable_think );
	array_thread( getentarray( "breakable", "targetname" ), ::breakable_think );
	array_thread( getentarray( "breakable_vase", "targetname" ), ::breakable_think );
	array_thread( getentarray( "oil_spill", "targetname" ), ::oil_spill_think );
	array_thread( getentarray( "glass", "targetname" ), ::glass_logic );
	array_thread( getentarray( "interactive_tv", "targetname" ), ::tv_logic );
	array_thread( getentarray( "destroyable_security_camera", "script_noteworthy" ), ::security_camera_logic );
}

security_camera_logic()
{
	self setcandamage( true );
	damagemodel = undefined;
	
	switch( self.model )
	{
		case "com_security_camera":
			damagemodel = "com_security_camera_destroyed";
			break;
	}

	self waittill( "damage", damage, other, direction_vec, P, type );
	
	self setmodel( damagemodel );

	// nice to play a sound here to acompany the effect
	
	playfxontag( level._breakables_fx[ "security_camera_explode" ], self, "tag_deathfx" );
	
}
	
tv_logic()
{
	self setcandamage( true );
	self.damagemodel = undefined;
	self.offmodel = undefined;
	
	self.damagemodel = "com_tv2_d";
	self.offmodel = "com_tv2";
	self.onmodel = "com_tv2_testpattern";
	if ( issubstr( self.model, "1" ) )
	{
		self.offmodel = "com_tv1";
		self.onmodel = "com_tv1_testpattern";
	}

	if ( isdefined( self.target ) )
	{
		if ( isdefined( level._disable_interactive_tv_use_triggers ) )
		{
			usetrig = getent( self.target, "targetname" );
			if ( isdefined( usetrig ) )
				usetrig delete();
		}
		else
		{
			self.usetrig = getent( self.target, "targetname" );
			self.usetrig usetriggerrequirelookat();
			self.usetrig setcursorhint( "HINT_NOICON" );
		}
	}
		
	array = get_array_of_closest( self.origin, level._tv_lite_array, undefined, undefined, 64 );
	
	if ( array.size )
	{
		self.lite = array[ 0 ];
		level._tv_lite_array = array_remove( level._tv_lite_array, self.lite );
		self.liteintensity = self.lite getLightIntensity();
	}	
	
	self thread tv_damage();

	if ( isdefined( self.usetrig ) )
		self thread tv_off();
}

tv_off()
{
	self.usetrig endon( "death" );
	
	while ( 1 )
	{		
		wait .2;
		self.usetrig waittill( "trigger" );
		// it would be nice to play a sound here
		
		self notify( "off" );
		
		if ( self.model == self.offmodel )
		{
			self setmodel( self.onmodel );
			if ( isdefined( self.lite ) )
				self.lite setLightIntensity( self.liteintensity );
		}
		else
		{
			self setmodel( self.offmodel );
			if ( isdefined( self.lite ) )
				self.lite setLightIntensity( 0 );
		}
	}
}

tv_damage()
{
	for ( ;; )
	{
		self waittill( "damage", damage, other, direction_vec, P, type );

		if ( flag( "no_ai_tv_damage" ) )
		{
			if ( !isalive( other ) )
				continue;

			if ( !isplayer( other ) )
				continue;
		}

		break;			
	}
		
	if ( isdefined( level._tvhook ) )
		[[ level._tvhook ]]();
	
	self notify( "off" );
	if ( isdefined( self.usetrig ) )
		self.usetrig notify( "death" );
		
		
	self setmodel( self.damagemodel );
	
	if ( isdefined( self.lite ) )
		self.lite setLightIntensity( 0 );

	playfxontag( level._breakables_fx[ "tv_explode" ], self, "tag_fx" );
	self playsound( "tv_shot_burst" );

	if ( isdefined( self.usetrig ) )
		self.usetrig delete();
}

glass_logic()
{	
	direction_vec 	 = undefined;
	crackedContents = undefined;
	cracked 		 = undefined;
	glasshealth		 = 0;

// setup	
	if ( isdefined( self.target ) )
	{
		cracked = getent( self.target, "targetname" ); 
		assertex( isdefined( cracked ), "Destructible glass at origin( " + self.origin + " ) has a target but the cracked version doesn't exist" );
	}
	
	if ( isdefined( self.script_linkTo ) )
	{
		links = self get_links();
		assert( isdefined( links ) );
		object = getent( links[ 0 ], "script_linkname" );
		self linkto( object );
	}
	
	assertex( isdefined( self.destructible_type ), "Destructible glass at origin( " + self.origin + " ) doesnt have a destructible_type" );
	switch( self.destructible_type )
	{
		case "glass_large":
			
			break;
		case "glass_med":
			
			break;
		case "glass_small":
			
			break;
		default:
			assertMsg( "Destructible glass 'destructible_type' key / value of '" + self.destructible_type + "' is not valid" );
			break;
	}
	
	if ( isdefined( cracked ) )
	{
		glasshealth = 99;
		cracked linkto( self );
		cracked hide();
		// Set the contents to 0 to make it non - solid.
		// Note "notSolid()" won't work since it forgets the contents.
		crackedContents = cracked setContents( 0 );
	}
	
	if ( isdefined( self.script_health ) )
		glasshealth = self.script_health;
	else if ( isdefined( cracked ) )
		glasshealth = 99;
	else
		glasshealth = 250;
	
// break	
	self setcandamage( true );
	while ( glasshealth > 0 )
	{
		self waittill( "damage", damage, attacker, direction_vec, point, damageType );
		
		if ( !isdefined( direction_vec ) )
				direction_vec = ( 0, 0, 1 );		
		if ( !isdefined( damageType ) )
			damage = 100000;// scripted calls to break the glass
		else if ( damageType == "MOD_GRENADE_SPLASH" )
			damage = damage * 1.75;
		else if ( damageType == "MOD_IMPACT" )
			damage = 100000;
		
		glasshealth -= damage;		
	}
	
	prevdamage = glasshealth * - 1;
		
	self hide();
	self notsolid();
	
	if ( isdefined( cracked ) )
	{
		cracked show();
		cracked setcandamage( true );
				
		glasshealth = ( 200 ) - prevdamage;
	
		// Set the contents back so that it's solid
		cracked setContents( crackedContents );
	
		while ( glasshealth > 0 )
		{
			cracked waittill( "damage", damage, other, direction_vec, point, damageType );
			
			if ( !isdefined( direction_vec ) )
				direction_vec = ( 0, 0, 1 );		
			if ( !isdefined( damageType ) )
				damage = 100000;// scripted calls to break the glass
			else if ( damageType == "MOD_GRENADE_SPLASH" )
				damage = damage * 1.75;
			else if ( damageType == "MOD_IMPACT" )
				break;
			
			glasshealth -= damage;		
		}
	
		cracked delete();
	}	
	
	glass_play_break_fx( self getorigin(), self.destructible_type, direction_vec );
	
	self delete();
}

glass_play_break_fx( origin, info, direction_vec )
{

	thread play_sound_in_space( level._glass_info[ info ][ "breaksnd" ], origin );
	playfx( level._glass_info[ info ][ "breakfx" ], origin, direction_vec );
	level notify( "glass_shatter" );
}

oil_spill_think()
{
	self.end = getstruct( self.target, "targetname" );
	self.start = getstruct( self.end.target, "targetname" );
	self.barrel = getClosestEnt( self.start.origin, getentarray( "explodable_barrel", "targetname" ) );
	
	if ( isdefined( self.barrel ) )
	{
		self.barrel.oilspill = true;
		self thread oil_spill_burn_after();
	}
	
	self.extra = getent( self.target, "targetname" );
	self setcandamage( true );
	
	while ( 1 )
	{
		self waittill( "damage", amount, attacker, direction_vec, P, type );
		if ( type == "MOD_MELEE" || type == "MOD_IMPACT" )
			continue;
		
		self.damageOwner = attacker;
		
		playfx( level._breakables_fx[ "oilspill" ][ "spark" ], P, direction_vec );
		P = pointOnSegmentNearestToPoint( self.start.origin, self.end.origin, P );
		thread oil_spill_burn_section( P );
		self thread oil_spill_burn( P, self.start.origin );
		self thread oil_spill_burn( P, self.end.origin );
		break;
	}
	if ( isdefined( self.barrel ) )
		self.barrel waittill( "exploding" );
	
	self.extra delete();
	self hide();
	
	wait 10;
	self delete();
}

oil_spill_burn_after()
{
	while ( 1 )
	{
		self.barrel waittill( "damage", amount, attacker, direction_vec, P, type );
		if ( type == "MOD_MELEE" || type == "MOD_IMPACT" )
			continue;
		self.damageOwner = attacker;
		break;
	}
	self radiusdamage( self.start.origin, 4, 10, 10, self.damageOwner );
}


OIL_SPILL_COUNT = 4;
OIL_SPILL_WAIT_TIME = 0.1;
OIL_SPILL_BAD_PLACE_DURATION = 0.5;

oil_spill_burn( P, dest )
{
	forward = vectornormalize( dest - P );
	dist = distance( p, dest );
	range = 8;
	interval = vector_multiply( forward, range );	
	angle = vectortoangles( forward );
	right = anglestoright( angle );
	
	barrels = getentarray( "explodable_barrel", "targetname" );
	distsqr = 22 * 22;
	
	test = spawn( "script_origin", P );
	
	assert( OIL_SPILL_BAD_PLACE_DURATION > OIL_SPILL_COUNT * OIL_SPILL_WAIT_TIME );
	
	num = 0;
	while ( 1 )
	{
		dist -= range;
		if ( dist < range * .1 )
			break;
			
		p += ( interval + vector_multiply( right, randomfloatrange( -6, 6 ) ) );		
		
		thread oil_spill_burn_section( P );
		num++ ;
		if ( num == OIL_SPILL_COUNT )
		{
			badplace_cylinder( "", OIL_SPILL_BAD_PLACE_DURATION, P, 64, 64 );	
			num = 0;
		}
		
		test.origin = P;
		
		remove = [];
		barrels = array_removeUndefined( barrels );
		for ( i = 0; i < barrels.size; i++ )
		{
			vec = anglestoup( barrels[ i ].angles );
			start = barrels[ i ].origin + ( vector_multiply( vec, 22 ) );
			pos = physicstrace( start, start + ( 0, 0, -64 ) );
			
			if ( distancesquared( P, pos ) < distsqr ) 
			{
				remove[ remove.size ] = barrels[ i ];
				barrels[ i ] dodamage( ( 80 + randomfloat( 10 ) ), P );
			}
		}
		for ( i = 0; i < remove.size; i++ )
			barrels = array_remove( barrels, remove[ i ] );	
		wait OIL_SPILL_WAIT_TIME;
	}		
	
	if ( !isdefined( self.barrel ) )
		return;
	if ( distance( P, self.start.origin ) < 32 )
		self.barrel dodamage( ( 80 + randomfloat( 10 ) ), P );
}

oil_spill_burn_section( P )
{
	count = 0;
	time = 0;
	playfx( level._breakables_fx[ "oilspill" ][ "burn" ], P );
	/* 
	while ( time < 5 )
	{
		attacker = undefined;
		if ( isdefined( self.damageOwner ) )
			attacker = self.damageOwner;
		
		self radiusdamage( P, 32, 5, 1, attacker );
		time += 1;
		wait 1;
	}*/ 
}

explodable_barrel_think()
{
	if ( self.classname != "script_model" )
		return;
	// if ( ( self.model != "com_barrel_benzin" ) && ( self.model != "com_barrel_benzin_snow" ) )
	// 	return;
	if ( !isdefined( level._precachemodeltype[ "com_barrel_benzin" ] ) )
	{
		level._precachemodeltype[ "com_barrel_benzin" ] = true;
		precacheModel( "com_barrel_piece" );
		precacheModel( "com_barrel_piece2" );
	}
	self endon( "exploding" );

	self breakable_clip();
	self xenon_auto_aim();
	self.damageTaken = 0;
	self setcandamage( true );
	for ( ;; )
	{
		self waittill( "damage", amount, attacker, direction_vec, P, type );
		if ( type == "MOD_MELEE" || type == "MOD_IMPACT" )
			continue;

		self.damageOwner = attacker;

		if ( level._barrelExplodingThisFrame )
			wait randomfloat( 1 );
		self.damageTaken += amount;
		if ( self.damageTaken == amount )
			self thread explodable_barrel_burn();
	}
}

MAX_COUNT = 19;
WAIT_TIME = 0.05;
BAD_PLACE_DURATION = 1;

explodable_barrel_burn()
{
	count = 0;
	startedfx = false;

	up = anglestoup( self.angles );
	worldup = anglestoup( ( 0, 90, 0 ) );
	dot = vectordot( up, worldup );

	offset1 = ( 0, 0, 0 );
	offset2 =  vector_multiply( up, 44 );

	// if this isn't true, bad place will turn on and off on the barrel
	assert( BAD_PLACE_DURATION > MAX_COUNT * WAIT_TIME );
	
	if ( dot < .5 )
	{
		offset1 = vector_multiply( up, 22 ) - ( 0, 0, 30 );
		offset2 = vector_multiply( up, 22 ) + ( 0, 0, 14 );
	}
	while ( self.damageTaken < level._barrelHealth )
	{
		if ( !startedfx )
		{
			playfx( level._breakables_fx[ "barrel" ][ "burn_start" ], self.origin + offset1 );
			startedfx = true;
		}
		if ( count > MAX_COUNT )
			count = 0;

		playfx( level._breakables_fx[ "barrel" ][ "burn" ], self.origin + offset2 );

		if ( count == 0 )
		{
			self.damageTaken += ( 10 + randomfloat( 10 ) );
			badplace_cylinder( "", BAD_PLACE_DURATION, self.origin, 128, 250 );
		}
		count++;
		wait WAIT_TIME;
		
		if( !isdefined( self ) )
			return;  // support deleting explodable barrels.
	}
	self thread explodable_barrel_explode();
}

explodable_barrel_explode()
{
	self notify( "exploding" );
	self notify( "death" );

	up = anglestoup( self.angles );
	worldup = anglestoup( ( 0, 90, 0 ) );
	dot = vectordot( up, worldup );

	offset = ( 0, 0, 0 );
	if ( dot < .5 )
	{
		start = ( self.origin + vector_multiply( up, 22 ) );
		end  = physicstrace( start, ( start + ( 0, 0, -64 ) ) );
		offset = end - self.origin;
	}
	offset += ( 0, 0, 4 );

	level thread play_sound_in_space( level._barrelExpSound, self.origin );
	playfx( level._breakables_fx[ "barrel" ][ "explode" ], self.origin + offset );
	physicsexplosionsphere( self.origin + offset, 100, 80, 1 );

	level._barrelExplodingThisFrame = true;

	if ( isdefined( self.remove ) )
	{
		self.remove connectpaths();
		self.remove delete();
	}

	minDamage = 1;
	maxDamage = 250;
	blastRadius = 250;
	if ( isdefined( self.radius ) )
		blastRadius = self.radius;
	// radiusDamage( self.origin + ( 0, 0, 56 ), blastRadius, maxDamage, minDamage );

	attacker = undefined;

	if ( isdefined( self.damageOwner ) )
	{
		attacker = self.damageOwner;
		if ( isplayer( attacker ) )
			arcadeMode_kill( self.origin, "rifle", 150 );
	}

	level._lastExplodingBarrel[ "time" ] = getTime();
	level._lastExplodingBarrel[ "origin" ] = self.origin + ( 0, 0, 30 );
	level._lastExplodingBarrel[ "radius" ] = blastRadius;
	self radiusDamage( self.origin + ( 0, 0, 30 ), blastRadius, maxDamage, minDamage, attacker );

	if ( randomint( 2 ) == 0 )
		self setModel( "com_barrel_piece" );
	else
		self setModel( "com_barrel_piece2" );


	if ( dot < .5 )
	{
		start = ( self.origin + vector_multiply( up, 22 ) );
		pos = physicstrace( start, ( start + ( 0, 0, -64 ) ) );

		self.origin = pos;
		self.angles += ( 0, 0, 90 );

	}
	wait 0.05;
	level._barrelExplodingThisFrame = false;
}

shuddering_entity_think()
{
	assert( self.classname == "script_model" );
	helmet = false;
	if ( self.model == "prop_helmet_german_normandy" )
		helmet = true;
	self setcandamage( true );
	for ( ;; )
	{
        self waittill( "damage", other, damage, direction_vec, point );
        if ( helmet )
        	self vibrate( direction_vec, 20, 0.6, 0.75 );
        else
        	self vibrate( direction_vec, 0.4, 0.4, 0.4 );
        self waittill( "rotatedone" );
    }
}

tincan_think()
{
	if ( self.classname != "script_model" )
		return;

	self setcandamage( true );
	self waittill( "damage", damage, ent );

	if ( isAI( ent ) || isPlayer( ent ) )
		direction_org = ( ( ent getEye() ) - ( 0, 0, ( randomint( 50 ) + 50 ) ) );
	else
		direction_org = ent.origin;

	direction_vec = vectornormalize( self.origin - direction_org );
	direction_vec = vector_multiply( direction_vec, .5 + randomfloat( 1 ) );

	self notify( "death" );
	playfx( level._breakables_fx[ "tincan" ], self.origin, direction_vec );
	self delete();
}

helmet_pop()
{
	if ( self.classname != "script_model" )
		return;
	self xenon_auto_aim();

	self setcandamage( true );
	self thread helmet_logic();
}

helmet_logic()
{
	self waittill( "damage", damage, ent );

	if ( isAI( ent ) )
		direction_org = ent getEye();
	else
		direction_org = ent.origin;

	direction_vec = vectornormalize( self.origin - direction_org );

	if ( !isdefined( self.dontremove ) && isplayer( ent ) )
	{
		self thread animscripts\death::helmetLaunch( direction_vec );
		return;
	}

	self notsolid();
	self hide();
	model = spawn( "script_model", self.origin + ( 0, 0, 5 ) );
	model.angles = self.angles;
	model setmodel( self.model );
	model thread animscripts\death::helmetLaunch( direction_vec );

	self.dontremove = false;
	self notify( "ok_remove" );
}

allowBreak( ent )
{
	if ( !isdefined( level._breakingEnts ) )
		return true;

	if ( level._breakingEnts.size == 0 )
		return false;
	else
	{
		for ( i = 0;i < level._breakingEnts.size;i++ )
		{
			if ( ent == level._breakingEnts[ i ] )
				return true;
		}
		return false;
	}
	return true;
}

breakable_think_triggered( eBreakable )
{
	for ( ;; )
	{
		self waittill( "trigger", other );
		eBreakable notify( "damage", 100, other );
	}
}

breakable_think()
{
	if ( self.classname != "script_model" )
		return;
	if ( !isdefined( self.model ) )
		return;

	type = undefined;

	if ( self.model == "egypt_prop_vase1" || self.model == "egypt_prop_vase3" || self.model == "egypt_prop_vase4" )
	{
		if ( !isdefined( level._precachemodeltype[ "egypt_prop_vase_o" ] ) )
		{
			level._precachemodeltype[ "egypt_prop_vase_o" ]	 = true;
			precacheModel( "egypt_prop_vase_br2" );
			precacheModel( "egypt_prop_vase_br5" );
			precacheModel( "egypt_prop_vase_br7" );
		}
		type = "orange vase";
		self breakable_clip();
		self xenon_auto_aim();
	}
	else if ( self.model == "egypt_prop_vase2" || self.model == "egypt_prop_vase5" || self.model == "egypt_prop_vase6" )
	{
		if ( !isdefined( level._precachemodeltype[ "egypt_prop_vase_g" ] ) )
		{
			level._precachemodeltype[ "egypt_prop_vase_g" ]	 = true;
			precacheModel( "egypt_prop_vase_br1" );
			precacheModel( "egypt_prop_vase_br3" );
			precacheModel( "egypt_prop_vase_br4" );
			precacheModel( "egypt_prop_vase_br6" );
		}
		type = "green vase";
		self breakable_clip();
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_crate_dak1" || self.model == "prop_crate_dak2" || self.model == "prop_crate_dak3" || self.model == "prop_crate_dak4" || self.model == "prop_crate_dak5" || self.model == "prop_crate_dak6" || self.model == "prop_crate_dak7" || self.model == "prop_crate_dak8" || self.model == "prop_crate_dak9" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_crate_dak_shard" ] ) )
		{
			level._precachemodeltype[ "prop_crate_dak_shard" ] = true;
			precacheModel( "prop_crate_dak_shard" );
		}
		type = "wood box";
		self breakable_clip();
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_winebottle_breakable" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_winebottle" ] ) )
		{
			level._precachemodeltype[ "prop_winebottle" ] = true;
			precacheModel( "prop_winebottle_broken_top" );
			precacheModel( "prop_winebottle_broken_bot" );
		}
		type = "bottle";
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_diningplate_roundfloral" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenfloral" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenfloral" ] = true;
			precacheModel( "prop_diningplate_brokenfloral1" );
			precacheModel( "prop_diningplate_brokenfloral2" );
			precacheModel( "prop_diningplate_brokenfloral3" );
			precacheModel( "prop_diningplate_brokenfloral4" );
		}
		type = "plate";
		self.plate = "round_floral";
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_diningplate_roundplain" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenplain" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenplain" ] = true;
			precacheModel( "prop_diningplate_brokenplain1" );
			precacheModel( "prop_diningplate_brokenplain2" );
			precacheModel( "prop_diningplate_brokenplain3" );
			precacheModel( "prop_diningplate_brokenplain4" );
		}
		type = "plate";
		self.plate = "round_plain";
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_diningplate_roundstack" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenplain" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenplain" ] = true;
			precacheModel( "prop_diningplate_brokenplain1" );
			precacheModel( "prop_diningplate_brokenplain2" );
			precacheModel( "prop_diningplate_brokenplain3" );
			precacheModel( "prop_diningplate_brokenplain4" );
		}
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenfloral" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenfloral" ] = true;
			precacheModel( "prop_diningplate_brokenfloral1" );
			precacheModel( "prop_diningplate_brokenfloral2" );
			precacheModel( "prop_diningplate_brokenfloral3" );
			precacheModel( "prop_diningplate_brokenfloral4" );
		}
		type = "plate";
		self.plate = "round_stack";
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_diningplate_ovalfloral" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenfloral" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenfloral" ] = true;
			precacheModel( "prop_diningplate_brokenfloral1" );
			precacheModel( "prop_diningplate_brokenfloral2" );
			precacheModel( "prop_diningplate_brokenfloral3" );
			precacheModel( "prop_diningplate_brokenfloral4" );
		}
		type = "plate";
		self.plate = "oval_floral";
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_diningplate_ovalplain" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenplain" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenplain" ] = true;
			precacheModel( "prop_diningplate_brokenplain1" );
			precacheModel( "prop_diningplate_brokenplain2" );
			precacheModel( "prop_diningplate_brokenplain3" );
			precacheModel( "prop_diningplate_brokenplain4" );
		}
		type = "plate";
		self.plate = "oval_plain";
		self xenon_auto_aim();
	}
	else if ( self.model == "prop_diningplate_ovalstack" )
	{
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenplain" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenplain" ] = true;
			precacheModel( "prop_diningplate_brokenplain1" );
			precacheModel( "prop_diningplate_brokenplain2" );
			precacheModel( "prop_diningplate_brokenplain3" );
			precacheModel( "prop_diningplate_brokenplain4" );
		}
		if ( !isdefined( level._precachemodeltype[ "prop_diningplate_brokenfloral" ] ) )
		{
			level._precachemodeltype[ "prop_diningplate_brokenfloral" ] = true;
			precacheModel( "prop_diningplate_brokenfloral1" );
			precacheModel( "prop_diningplate_brokenfloral2" );
			precacheModel( "prop_diningplate_brokenfloral3" );
			precacheModel( "prop_diningplate_brokenfloral4" );
		}
		type = "plate";
		self.plate = "oval_stack";
		self xenon_auto_aim();
	}
	if ( !isdefined( type ) )
	{
		println( "Entity ", self.targetname, " at ", self.origin, " is not a valid breakable object." );
		return;
	}

	if ( isdefined( self.target ) )
	{
		trig = getent( self.target, "targetname" );
		if ( ( isdefined( trig ) ) && ( trig.classname == "trigger_multiple" ) )
			trig thread breakable_think_triggered( self );
	}

	self setcandamage( true );
	self thread breakable_logic( type );
}

breakable_logic( type )
{
	ent = undefined;
	for ( ;; )
	{
		self waittill( "damage", amount, ent );
		if ( isdefined( ent ) && ent.code_classname == "script_vehicle" )
			ent joltbody( self.origin + ( 0, 0, -90 ), .2 );
		if ( type == "wood box" )
		{
			if ( !allowBreak( ent ) )
				continue;
			if ( ( !isdefined( level._flags ) ) || ( !isdefined( level._flags[ "Breakable Boxes" ] ) ) )
				break;
			if ( ( isdefined( level._flags[ "Breakable Boxes" ] ) ) && ( level._flags[ "Breakable Boxes" ] == true ) )
				break;
			continue;
		}
		break;
	}

	self notify( "death" );

	soundAlias = undefined;
	fx = undefined;
	hasDependant = false;
	switch( type )
	{
		case "orange vase":
		case "green vase":
			soundAlias = "bullet_large_vase";
			fx = level._breakables_fx[ "vase" ];
			break;
		case "wood box":
			if ( isdefined( level._crateImpactSound ) )
				soundAlias = level._crateImpactSound;
			else
				soundAlias = "bullet_large_vase";
			fx = level._breakables_fx[ "box" ][ randomint( level._breakables_fx[ "box" ].size ) ];
			hasDependant = true;
			break;
		case "bottle":
			soundAlias = "bullet_small_bottle";
			fx = level._breakables_fx[ "bottle" ];
			break;
		case "plate":
			soundAlias = "bullet_small_plate";
			break;
	}
	thread play_sound_in_space( soundAlias, self.origin );
	self thread make_broken_peices( self, type );
	if ( isdefined( fx ) )
		playfx( fx, self.origin );

	// certain types should destroy objects sitting on top of them
	if ( hasDependant )
	{
		others = getentarray( "breakable", "targetname" );
		for ( i = 0;i < others.size;i++ )
		{
			other = others[ i ];
			// see if it's within 40 units from this box on X or Y
			diffX = abs( self.origin[ 0 ] - other.origin[ 0 ] );
			diffY = abs( self.origin[ 1 ] - other.origin[ 1 ] );

			if ( ( diffX <= 20 ) && ( diffY <= 20 ) )
			{
				// see if it's above the box( would probably be resting on it )
				diffZ = ( self.origin[ 2 ] - other.origin[ 2 ] );
				if ( diffZ <= 0 )
					other notify( "damage", amount, ent );
			}
		}
	}

	if ( isdefined( self.remove ) )
	{
		self.remove connectpaths();
		self.remove delete();
	}

	if ( !isdefined( self.dontremove ) )
		self delete();

	else
		self.dontremove = false;
		self notify( "ok_remove" );
}

xenon_auto_aim()
{
	if ( 	( isdefined( level._console_auto_aim ) ) && ( level._console_auto_aim.size > 0 ) )
		self.autoaim = getClosestAccurantEnt( self.origin, level._console_auto_aim );

	if ( isdefined( self.autoaim ) )
	{
		level._console_auto_aim = array_remove( level._console_auto_aim, self.autoaim );
		self thread xenon_remove_auto_aim();
	}
}

xenon_auto_aim_stop_logic()
{
	self notify( "entered_xenon_auto_aim_stop_logic" );
	self endon( "entered_xenon_auto_aim_stop_logic" );

	self.autoaim waittill( "xenon_auto_aim_stop_logic" );
	self.dontremove = undefined;
}

xenon_remove_auto_aim( wait_message )
{
	self thread xenon_auto_aim_stop_logic();
	self endon( "xenon_auto_aim_stop_logic" );
	self.autoaim endon( "xenon_auto_aim_stop_logic" );

	self notify( "xenon_remove_auto_aim" );
	self.autoaim thread xenon_enable_auto_aim( wait_message );
	self.dontremove = true;
	self waittill( "damage", amount, ent );


	self.autoaim disableAimAssist();

	self.autoaim delete();
	if ( self.dontremove )
		self waittill( "ok_remove" );
	self delete();

}

xenon_enable_auto_aim( wait_message )
{
	self endon( "xenon_auto_aim_stop_logic" );
	self endon( "death" );
	if ( !isdefined( wait_message ) )
		wait_message = true;

	if ( isdefined( self.script_noteworthy ) && wait_message )
	{
		string = "enable_xenon_autoaim_" + self.script_noteworthy;
		level waittill( string );
	}

	self.wait_message = false;
	if ( isdefined( self.recreate ) && self.recreate == true )
		self waittill( "recreate" );
	self enableAimAssist();
}

breakable_clip()
{
	// targeted brushmodels take priority over proximity based breakables - nate
	if ( isdefined( self.target ) )
	{
		targ = getent( self.target, "targetname" );
		if ( targ.classname == "script_brushmodel" )
		{
			self.remove = targ;
			return;
		}
	}
	// setup it's removable clip part
	if ( ( isdefined( level._breakables_clip ) ) && ( level._breakables_clip.size > 0 ) )
		self.remove = getClosestEnt( self.origin, level._breakables_clip );
	if ( isdefined( self.remove ) )
		level._breakables_clip = array_remove( level._breakables_clip, self.remove );
}

make_broken_peices( wholepiece, type )
{
	rt		 = anglesToRight( wholepiece.angles );
	fw		 = anglesToForward( wholepiece.angles );
	up	 	 = anglesToUp( wholepiece.angles );

	piece = [];
	switch( type )
	{
		case "orange vase":
			piece[ piece.size ] = addpiece( rt, fw, up, -7, 0, 22, wholepiece, ( 0, 0, 0 ), "egypt_prop_vase_br2" );
			piece[ piece.size ] = addpiece( rt, fw, up, 13, -6, 28, wholepiece, ( 0, 245.1, 0 ), "egypt_prop_vase_br7" );
			piece[ piece.size ] = addpiece( rt, fw, up, 12, 10, 27, wholepiece, ( 0, 180, 0 ), "egypt_prop_vase_br7" );
			piece[ piece.size ] = addpiece( rt, fw, up, 3, 2, 0, wholepiece, ( 0, 0, 0 ), "egypt_prop_vase_br5" );
			break;
		case "green vase":
			piece[ piece.size ] = addpiece( rt, fw, up, -6, -1, 26, wholepiece, ( 0, 0, 0 ), "egypt_prop_vase_br1" );
			piece[ piece.size ] = addpiece( rt, fw, up, 12, 1, 31, wholepiece, ( 0, 348.5, 0 ), "egypt_prop_vase_br3" );
			piece[ piece.size ] = addpiece( rt, fw, up, 6, 13, 29, wholepiece, ( 0, 153.5, 0 ), "egypt_prop_vase_br6" );
			piece[ piece.size ] = addpiece( rt, fw, up, 3, 1, 0, wholepiece, ( 0, 0, 0 ), "egypt_prop_vase_br4" );
			break;
		case "wood box":
			piece[ piece.size ] = addpiece( rt, fw, up, -10, 10, 25, wholepiece, ( 0, 0, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, 10, 10, 25, wholepiece, ( 0, 90, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, 10, -10, 25, wholepiece, ( 0, 180, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, -10, -10, 25, wholepiece, ( 0, 270, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, 10, 10, 5, wholepiece, ( 180, 0, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, 10, -10, 5, wholepiece, ( 180, 90, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, -10, -10, 5, wholepiece, ( 180, 180, 0 ), "prop_crate_dak_shard" );
			piece[ piece.size ] = addpiece( rt, fw, up, -10, 10, 5, wholepiece, ( 180, 270, 0 ), "prop_crate_dak_shard" );
			break;
		case "bottle":
			piece[ piece.size ] = addpiece( rt, fw, up, 0, 0, 10, wholepiece, ( 0, 0, 0 ), "prop_winebottle_broken_top" );		piece[ piece.size - 1 ].type = "bottle_top";
			piece[ piece.size ] = addpiece( rt, fw, up, 0, 0, 0, wholepiece, ( 0, 0, 0 ), "prop_winebottle_broken_bot" );		piece[ piece.size - 1 ].type = "bottle_bot";
			break;
		case "plate":
		{
			switch( wholepiece.plate )
			{
				case "round_floral":
					piece[ piece.size ] = addpiece( rt, fw, up, -3, -4, .5, wholepiece, ( 0, 150, 0 ), "prop_diningplate_brokenfloral1" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 3, -2, .5, wholepiece, ( 0, 149.8, 0 ), "prop_diningplate_brokenfloral2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 1, 2, .5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenfloral3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -4, 2, .5, wholepiece, ( 0, 146.8, 0 ), "prop_diningplate_brokenfloral4" );		piece[ piece.size - 1 ].type = "plate";
					break;
				case "round_plain":
					piece[ piece.size ] = addpiece( rt, fw, up, -3, -4, .5, wholepiece, ( 0, 150, 0 ), "prop_diningplate_brokenplain1" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 3, -2, .5, wholepiece, ( 0, 149.8, 0 ), "prop_diningplate_brokenplain2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 1, 2, .5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenplain3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -4, 2, .5, wholepiece, ( 0, 146.8, 0 ), "prop_diningplate_brokenplain4" );		piece[ piece.size - 1 ].type = "plate";
					break;
				case "round_stack":
					piece[ piece.size ] = addpiece( rt, fw, up, -3, -4, .5, wholepiece, ( 0, 150, 0 ), "prop_diningplate_brokenfloral1" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 3, -2, .5, wholepiece, ( 0, 149.8, 0 ), "prop_diningplate_brokenfloral2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 1, 2, .5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenfloral3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -4, 2, .5, wholepiece, ( 0, 146.8, 0 ), "prop_diningplate_brokenfloral4" );		piece[ piece.size - 1 ].type = "plate";

					piece[ piece.size ] = addpiece( rt, fw, up, -4, 3, 2.5, wholepiece, ( 0, 60, 0 ), "prop_diningplate_brokenplain1" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -1, -3, 2.5, wholepiece, ( 0, 59.8, 0 ), "prop_diningplate_brokenplain2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 2, -1, 2.5, wholepiece, ( 0, 60.2, 0 ), "prop_diningplate_brokenplain3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 2, 4, 2.5, wholepiece, ( 0, 56.8, 0 ), "prop_diningplate_brokenplain4" );		piece[ piece.size - 1 ].type = "plate";

					piece[ piece.size ] = addpiece( rt, fw, up, -3, -4, 4.5, wholepiece, ( 0, 150, 0 ), "prop_diningplate_brokenfloral1" );	piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 3, -2, 4.5, wholepiece, ( 0, 149.8, 0 ), "prop_diningplate_brokenfloral2" );	piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 1, 2, 4.5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenfloral3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -4, 2, 4.5, wholepiece, ( 0, 146.8, 0 ), "prop_diningplate_brokenfloral4" );	piece[ piece.size - 1 ].type = "plate";
					break;
				case "oval_floral":
					piece[ piece.size ] = addpiece( rt, fw, up, 4, -4, .5, wholepiece, ( 0, 205.9, 0 ), "prop_diningplate_brokenfloral1" );	piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -6, 1, .5, wholepiece, ( 0, 352.2, 0 ), "prop_diningplate_brokenfloral2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 4, 2, .5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenfloral3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -2, 5, .5, wholepiece, ( 0, 102.3, 0 ), "prop_diningplate_brokenfloral4" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -3, -3, .5, wholepiece, ( 0, 246.7, 0 ), "prop_diningplate_brokenfloral4" );	piece[ piece.size - 1 ].type = "plate";
					break;
				case "oval_plain":
					piece[ piece.size ] = addpiece( rt, fw, up, 4, -4, .5, wholepiece, ( 0, 205.9, 0 ), "prop_diningplate_brokenplain1" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -6, 1, .5, wholepiece, ( 0, 352.2, 0 ), "prop_diningplate_brokenplain2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 4, 2, .5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenplain3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -2, 5, .5, wholepiece, ( 0, 102.3, 0 ), "prop_diningplate_brokenplain4" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -3, -3, .5, wholepiece, ( 0, 246.7, 0 ), "prop_diningplate_brokenplain4" );		piece[ piece.size - 1 ].type = "plate";
					break;
				case "oval_stack":
					piece[ piece.size ] = addpiece( rt, fw, up, 4, -4, .5, wholepiece, ( 0, 205.9, 0 ), "prop_diningplate_brokenfloral1" );	piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -6, 1, .5, wholepiece, ( 0, 352.2, 0 ), "prop_diningplate_brokenfloral2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 4, 2, .5, wholepiece, ( 0, 150.2, 0 ), "prop_diningplate_brokenfloral3" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -2, 5, .5, wholepiece, ( 0, 102.3, 0 ), "prop_diningplate_brokenfloral4" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -3, -3, .5, wholepiece, ( 0, 246.7, 0 ), "prop_diningplate_brokenfloral4" );	piece[ piece.size - 1 ].type = "plate";

					piece[ piece.size ] = addpiece( rt, fw, up, -4, 5, 2.5, wholepiece, ( 0, 25.9, 0 ), "prop_diningplate_brokenplain1" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 6, 0, 2.5, wholepiece, ( 0, 172.2, 0 ), "prop_diningplate_brokenplain2" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, -4, -1, 2.5, wholepiece, ( 0, 330.2, 0 ), "prop_diningplate_brokenplain3" );	piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 2, -4, 2.5, wholepiece, ( 0, 282.3, 0 ), "prop_diningplate_brokenplain4" );		piece[ piece.size - 1 ].type = "plate";
					piece[ piece.size ] = addpiece( rt, fw, up, 3, 4, 2.5, wholepiece, ( 0, 66.7, 0 ), "prop_diningplate_brokenplain4" );		piece[ piece.size - 1 ].type = "plate";
					break;
			}
		}break;
		default:
			return;
	}
	array_thread( piece, ::pieces_move, wholepiece.origin );

	if ( ( isdefined( level._breakables_peicesCollide[ type ] ) ) && ( level._breakables_peicesCollide[ type ] == true ) )
	{
		height = piece[ 0 ].origin[ 2 ];
		for ( i = 0; i < piece.size; i++ )
		{
			if ( height > piece[ i ].origin[ 2 ] )
				height = piece[ i ].origin[ 2 ];
		}
		array_thread( piece, ::pieces_collision, height );
	}
	else
	{
		wait 2;
		for ( i = 0;i < piece.size;i++ )
		{
			if ( isdefined( piece[ i ] ) )
				piece[ i ] delete();
		}
	}
}

list_add( model )
{
	if ( isdefined( level._breakable_utility_modelarray[ level._breakable_utility_modelindex ] ) )
		level._breakable_utility_modelarray[ level._breakable_utility_modelindex ] delete();
	level._breakable_utility_modelarray[ level._breakable_utility_modelindex ] = model;
	level._breakable_utility_modelindex++ ;

	if ( !( level._breakable_utility_modelindex < level._breakable_utility_maxnum ) )
		level._breakable_utility_modelindex = 0;
}

pieces_move( origin )
{
	self endon( "do not kill" );
	if ( isdefined( self.type ) && self.type == "bottle_bot" )
		return;

	org = spawn( "script_origin", self.origin );
	self linkto( org );
	end = self.origin + ( randomfloat( 10 ) - 5, randomfloat( 10 ) - 5, randomfloat( 10 ) + 5 );
	// end = self.origin + ( randomfloat( 50 ) - 25, randomfloat( 50 ) - 25, randomfloat( 50 ) + 25 );

	vec = undefined;
	if ( isdefined( self.type ) && self.type == "bottle_top" )
	{
		vec = ( randomfloat( 40 ) - 20, randomfloat( 40 ) - 20, 70 + randomfloat( 15 ) );
		x = 1;
		y = 1;
		z = 1;
		if ( randomint( 100 ) > 50 )
			x = -1;
		if ( randomint( 100 ) > 50 )
			y = -1;
		if ( randomint( 100 ) > 50 )
			z = -1;

			org rotatevelocity( ( 250 * x, 250 * y, randomfloat( 100 ) * z ), 2, 0, .5 );
	}
	else if ( isdefined( self.type ) && self.type == "plate" )
	{
		vec = vectornormalize( end - origin );
		vec = vector_multiply( vec, 125 + randomfloat( 25 ) );
		if ( randomint( 100 ) > 50 )
			org rotateroll( ( 800 + randomfloat( 4000 ) ) * - 1, 5, 0, 0 );
		else
			org rotateroll( 800 + randomfloat( 4000 ), 5, 0, 0 );
	}
	else
	{
		vec = vectornormalize( end - origin );
		vec = vector_multiply( vec, 60 + randomfloat( 50 ) );
		if ( randomint( 100 ) > 50 )
			org rotateroll( ( 800 + randomfloat( 1000 ) ) * - 1, 5, 0, 0 );
		else
			org rotateroll( 800 + randomfloat( 1000 ), 5, 0, 0 );
	}



	org moveGravity( vec, 5 );

	wait 5;
	if ( isdefined( self ) )
		self unlink();
	org delete();
}

pieces_collision( height )
{
	self endon( "death" );

//* * * * * * * * * * * * * IF YOU PUT THIS BACK IN - SEARCH FOR "PLATE WAIT" AND PUT THAT BACK IN TOO * * * * * * * * * * * * * 	
// 	if ( isdefined( self.type ) && self.type == "plate" )
// 		wait .35;
// 	else
//* * * * * * * * * * * * * IF YOU PUT THIS BACK IN - SEARCH FOR "PLATE WAIT" AND PUT THAT BACK IN TOO * * * * * * * * * * * * * 
		wait .1;
	trace = bullettrace( self.origin, self.origin - ( 0, 0, 50000 ), false, undefined );
	vec = trace[ "position" ];
		
	while ( 	self.origin[ 2 ] > vec[ 2 ] )
		wait .05;
	
	self unlink();
	
	self.origin = ( self.origin[ 0 ], self.origin[ 1 ], vec[ 2 ] );
	
	self notify( "do not kill" );
	self unlink();
}

addpiece( rt, fw, up, xs, ys, zs, wholepiece, angles, model )
{
	scale = 1;
// 	if ( isdefined( wholepiece.modelscale ) )
// 		scale = wholepiece.modelscale;
		
	x 		 = rt;
	y 		 = fw;
	z 		 = up;
	x	 	 = vector_multiply( x, ys * scale );
	y 		 = vector_multiply( y, xs * scale );
	z		 = vector_multiply( z, zs * scale );
	origin 		 = wholepiece.origin + x + y + z;
	part 		 = spawn( "script_model", origin );
	part 		setmodel( model );
	part.modelscale =  scale;
	part.angles	 = wholepiece.angles + angles;	
	
	list_add( part );
	
	return part;
}

getFurthestEnt( org, array )
{
	if ( array.size < 1 )
		return;
		
	dist = distance( array[ 0 ] getorigin(), org );
	ent = array[ 0 ];
// 	dist = 256;
// 	ent = undefined;
	for ( i = 0;i < array.size;i++ )
	{
		newdist = distance( array[ i ] getorigin(), org );
		if ( newdist < dist )
			continue;
		dist = newdist;
		ent = array[ i ];
	}
	return ent;
}

getClosestEnt( org, array )
{
	if ( array.size < 1 )
		return;
		
// 	dist = distance( array[ 0 ] getorigin(), org );
// 	ent = array[ 0 ];
	dist = 256;
	ent = undefined;
	for ( i = 0;i < array.size;i++ )
	{
		newdist = distance( array[ i ] getorigin(), org );
		if ( newdist >= dist )
			continue;
		dist = newdist;
		ent = array[ i ];
	}
	return ent;
}

getClosestAccurantEnt( org, array )
{
	if ( array.size < 1 )
		return;
		
// 	dist = distance( array[ 0 ] getorigin(), org );
// 	ent = array[ 0 ];
	dist = 8;
	ent = undefined;
	for ( i = 0;i < array.size;i++ )
	{
		newdist = distance( array[ i ] getorigin(), org );
		if ( newdist >= dist )
			continue;
		dist = newdist;
		ent = array[ i ];
	}
	return ent;
}

getClosestAimEnt( org, array )
{
	if ( array.size < 1 )
		return;
		
// 	dist = distance( array[ 0 ] getorigin(), org );
// 	ent = array[ 0 ];
	dist = 1000000;
	ent = undefined;
	for ( i = 0;i < array.size;i++ )
	{
		newdist = distance( array[ i ] getorigin(), org );
		if ( newdist >= dist )
			continue;
		dist = newdist;
		ent = array[ i ];
	}
	return ent;
}