#using scripts\shared\clientfield_shared;
#using scripts\shared\flagsys_shared;
#using scripts\shared\gameobjects_shared;
#using scripts\shared\hud_util_shared;
#using scripts\shared\lui_shared;
#using scripts\shared\math_shared;
#using scripts\shared\_oob;
#using scripts\shared\popups_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   
       	   

#using scripts\mp\gametypes\_globallogic;
#using scripts\mp\gametypes\_globallogic_audio;
#using scripts\mp\gametypes\_globallogic_score;
#using scripts\mp\gametypes\_spawning;
#using scripts\mp\gametypes\_spawnlogic;

#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\teams\_teams;
#using scripts\mp\_util;

/*
	Stockpile: Kill enemies and pick up objects.
				Deposit objects at the objective
	
	PLEASE NOTE:
		TACO stands for Totally Arbitrary Collectible Object
	
	Level requirementss
	------------------
		Spawnpoints:

		Spectator Spawnpoints:
			classname		mp_global_intermission
			
		Deposit Points:
			classname				trigger_multiple
		--- Not Used ---	
			targetname				clean_objective_scatter_trig
			targetname				clean_objective_center_trig
			targetname				clean_objective_base_trig

*/

#precache( "string", "OBJECTIVES_CLEAN" );
#precache( "string", "OBJECTIVES_CLEAN_SCORE" );
#precache( "string", "OBJECTIVES_CLEAN_HINT" );

#precache( "string", "MP_CLEAN_DEPOSIT" );

#precache( "objective", "clean_deposit" );
#precache( "objective", "clean_carry" );


#precache( "fx", "ui/fx_stockpile_deposit_point" );
	

#precache( "fx", "ui/fx_stockpile_deposit_point_end" );


#precache( "fx", "ui/fx_stockpile_player_marker" );	


	







	




	
// 0 horizontal, negative angles go up



	

#precache( "material", "t7_hud_waypoints_stockpile_dropped" );




	
// Sound Aliases


	





	






	





	












	
function autoexec __init__sytem__() {     system::register("clean",&__init__,undefined,undefined);    }

function __init__()
{
	clientfield::register( "clientuimodel", "hudItems.cleanCarryCount", 12000, 4, "int" );
	clientfield::register( "clientuimodel", "hudItems.cleanCarryFull", 12000, 1, "int" );
	clientfield::register( "scriptmover", "taco_flag", 12000, 2, "int" );
	clientfield::register( "allplayers", "taco_carry", 12000, 1, "int" );
}

function main()
{
	globallogic::init();
	
	util::registerTimeLimit( 0, 1440 );
	util::registerScoreLimit( 0, 50000 );
	util::registerRoundLimit( 0, 10 );
	util::registerRoundSwitch( 0, 9 );
	util::registerRoundWinLimit( 0, 10 );
	util::registerNumLives( 0, 100 );
	
	globallogic::registerFriendlyFireDelay( level.gameType, 15, 0, 1440 );
	
	level.tacos = [];
	
	level.teamScorePerKill = GetGametypeSetting( "teamScorePerKill" );
	level.teamScorePerCleanDeposit = GetGametypeSetting( "teamScorePerCleanDeposit" );
	level.cleanDepositOfflineTime = 0;
	level.cleanDepositOnlineTime = GetGametypeSetting( "cleanDepositOnlineTime" );
	level.cleanDepositRotation = GetGametypeSetting( "cleanDepositRotation" );
	
	level.scoreRoundWinBased = true;
	level.teamBased = true;
	level.overrideTeamScore = true;
	
	level.onPrecacheGameType =&onPrecacheGameType;
	level.onStartGameType =&onStartGameType;
	
	level.onSpawnPlayer =&onSpawnPlayer;
	
	level.onPlayerKilled =&onPlayerKilled;
	
	level.onRoundSwitch =&onRoundSwitch;
	level.onRoundEndGame =&onRoundEndGame;
	
	level.cleanDropWeapon = GetWeapon( "clean_drop" );
	
	// Sets the scoreboard columns and determines with data is sent across the network
	
	if ( !SessionModeIsSystemlink() && !SessionModeIsOnlineGame() && IsSplitScreen() )
		// local matches only show the first three columns
		globallogic::setvisiblescoreboardcolumns( "score", "kills", "cleandeposits", "cleandenies", "deaths" );
	else
		globallogic::setvisiblescoreboardcolumns( "score", "kills", "deaths",  "cleandeposits", "cleandenies" );
	
	globallogic_audio::set_leader_gametype_dialog ( "startStockpile", "hcStartStockpile", "stockpileOrders", "stockpileOrders" );
	
	gameobjects::register_allowed_gameobject( level.gameType );
}

function onPrecacheGameType()
{

}


function onStartGameType()
{
	if ( !isdefined( game["switchedsides"] ) )
	{
		game["switchedsides"] = false;
	}
	
	globallogic_score::resetTeamScores();
	
	level.spawnMins = ( 0, 0, 0 );
	level.spawnMaxs = ( 0, 0, 0 );
	
	foreach( team in level.teams )
	{
		util::setObjectiveText( team, &"OBJECTIVES_CLEAN" );
		util::setObjectiveHintText( team, &"OBJECTIVES_CLEAN_HINT" );
		
		if ( level.splitscreen )
		{
			util::setObjectiveScoreText( team, &"OBJECTIVES_CLEAN" );
		}
		else
		{
			util::setObjectiveScoreText( team, &"OBJECTIVES_CLEAN_SCORE" );
		}
		
		spawnlogic::add_spawn_points( team, "mp_tdm_spawn" );
		spawnlogic::place_spawn_points( spawning::getTDMStartSpawnName(team) );
	}
	
	spawning::updateAllSpawnPoints();
	
	level.spawn_start = [];
		
	foreach( team in level.teams )
	{
		level.spawn_start[ team ] =  spawnlogic::get_spawnpoint_array( spawning::getTDMStartSpawnName(team) );
	}
	
	level.mapCenter = math::find_box_center( level.spawnMins, level.spawnMaxs );
	setMapCenter( level.mapCenter );

	spawnpoint = spawnlogic::get_random_intermission_point();
	setDemoIntermissionPoint( spawnpoint.origin, spawnpoint.angles );
	
	// Create all the drops at once
	for( i = 0; i < 60; i++ )
	{
		level.tacos[i] = create_taco();
	}
	
	level setup_deposit_hubs();
	
	level thread rotate_deposit_hubs();
	level thread game_ended_cleanup();
	
/#
	level.activeDrops = 0;
	level.mostActiveDrops = 0;
	level.expiredDrops = 0;
	level.precycledDrops = 0;
	level.failedDrops = 0;
		
	//level thread debug_print();
#/
}

function game_ended_cleanup()
{
	level waittill( "game_ended" );
	
	foreach( taco in level.tacos )
	{
		if ( taco clientfield::get( "taco_flag" ) > 0 )
		{
			taco clientfield::set( "taco_flag", 0 );
		}
	}
	
	foreach( depositHub in level.cleanDepositHubs )
	{
		depositHub StopLoopSound( );
		
		if ( isdefined( depositHub.baseEffect ) )
		{
			depositHub.baseEffect delete();
		}
	}
	
	foreach( player in level.players )
	{
		player clientfield::set( "taco_carry", 0 );
	}
}

/#
function debug_print()
{
	while( 1 )
	{		
		IPrintLn( "Active: " + level.activeDrops );
		IPrintLn( "Most Active: " + level.mostActiveDrops );
		IPrintLn( "Timed Out: " + level.expiredDrops );
		IPrintLn( "Precycled: " + level.precycledDrops );
		IPrintLn( "Failed: " + level.failedDrops );
		
		wait 5;
	}
}
#/

function onSpawnPlayer( predictedSpawn )
{
	if ( level.useStartSpawns && !level.inGracePeriod )
	{
		level.useStartSpawns = false;
	}
	
	self.lastDepositTime = 0;
	self.depositStreak = 0;
	self.lastCarryFullTime = 0;
	self.carriedTacos = 0;
	
	self clientfield::set_player_uimodel( "hudItems.cleanCarryCount", 0 );

	spawning::onSpawnPlayer(predictedSpawn);
	
	self thread watch_camo_on();
	self thread watch_camo_off();
	
	self thread watch_clone_on();
	self thread watch_clone_off();
	
	//self thread watch_vehicle_interaction();
	
	self.same_hub_deposit_count = 0;
}

function onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
{
	player = self;

	if ( isPlayer( attacker ) && attacker.team != self.team  )
	{
		if( !isdefined( killstreaks::get_killstreak_for_weapon( weapon ) ) || ( isdefined( level.killstreaksGiveGameScore ) && level.killstreaksGiveGameScore ) )				
		{
			attacker globallogic_score::giveTeamScoreForObjective( attacker.team, level.teamScorePerKill );
		}
	}
	
	if ( isdefined( attacker ) && IsPlayer( attacker ) && attacker.team != self.team )
	{
		if ( isdefined( player ) && isdefined( player.carriedTacos ) )
		{
			if ( player.carriedTacos >= 5 )
			{
				scoreevents::processScoreEvent( "clean_kill_enemy_carrying_tacos", attacker );
			}
		}
		
		taco = get_droppable_taco( );
		
		if ( isdefined( taco ) )
		{
			yawAngle = RandomInt( 360 );
			
			taco drop_taco( self, attacker, undefined, yawAngle );
		}
		
		self thread drop_carried_tacos( attacker, yawAngle );
	}
}

function watch_camo_on()
{
	self endon( "death" );
	level endon( "game_ended" );

	while ( 1 )
	{
		self flagsys::wait_till( "camo_suit_on" );
		
		self clientfield::set( "taco_carry", 0 );
		
		self flagsys::wait_till_clear( "camo_suit_on" );
	}
}

function watch_camo_off()
{
	self endon( "death" );
	level endon( "game_ended" );
	
	while ( 1 )
	{	
		self flagsys::wait_till( "camo_suit_on" );
		self flagsys::wait_till_clear( "camo_suit_on" );
		
		self update_taco_carry();
	}
}

function watch_clone_on()
{
	self endon( "death" );
	level endon( "game_ended" );

	while ( 1 )
	{
		self flagsys::wait_till( "clone_activated" );
		
		self clientfield::set( "taco_carry", 0 );
		
		self flagsys::wait_till_clear( "clone_activated" );
	}
}

function watch_clone_off()
{
	self endon( "death" );
	level endon( "game_ended" );
	
	while ( 1 )
	{	
		self flagsys::wait_till( "clone_activated" );
		self flagsys::wait_till_clear( "clone_activated" );
		
		self update_taco_carry();
	}
}

function watch_vehicle_interaction()
{
	self endon( "death" );
	level endon( "game_ended" );
	
	while( 1 )
	{	
		self util::waittill_any( "enter_vehicle", "exit_vehicle" );
		self update_taco_carry();
	}
}

function update_taco_carry()
{
	if ( self.carriedTacos > 0 && 
		!self IsInVehicle() &&
		!self flagsys::get( "camo_suit_on" ) &&
		!self flagsys::get( "clone_activated" ) )
	{
		self clientfield::set( "taco_carry", 1 );
	}
	else
	{
		self clientfield::set( "taco_carry", 0 );
	}
}

function get_droppable_taco()
{	
	oldestTaco = undefined;
	
	foreach( taco in level.tacos )
	{
		// Look for a dormant one
		if ( taco.interactTeam == "none" )
		{
			return taco;
		}
		
		// Don't use ones still flying through the air
		if ( isdefined( taco.physicsAnchor ) )
		{
			continue;
		}
		
		// Track the oldest
		if ( !isdefined( oldestTaco ) || taco.dropTime < oldestTaco.dropTime )
		{
			oldestTaco = taco;
		}
	}
	
	// Return the oldest taco if it wasn't dropped this frame
	if ( isdefined( oldestTaco ) && oldestTaco.dropTime != GetTime() )
	{
/#		
		level.precycledDrops++;
#/	
		oldestTaco reset_taco();
		return oldestTaco;	
	}
	
/#		
		level.failedDrops++;
#/		
	
	return undefined;
}

function create_taco( )
{
	visuals = [];
	
	trigger = spawn( "trigger_radius", (0,0,0), 0, 32, 32 );
	
	taco = gameobjects::create_use_object( "any", trigger, visuals, undefined, &"" );
	taco NotSolid();
	taco Ghost();
	
	taco gameobjects::set_use_time( 0 );
	taco.onUse = &on_use_taco;
	
	Objective_Add( taco.objectiveId, "invisible", (0,0,0) );
	Objective_Icon( taco.objectiveId, "t7_hud_waypoints_stockpile_dropped" );

	return taco;
}

function drop_taco( victim, attacker, pos, yawAngle )
{
/#
	level.activeDrops++;
	level.mostActiveDrops = Max( level.mostActiveDrops, level.activeDrops );
	
#/
	if(!isdefined(yawAngle))yawAngle=RandomInt( 360 );
	if(!isdefined(pos))pos=victim.origin + (0,0,40);

	self.dropTime = GetTime();
	
	self.team = victim.team;
	
	self.victim = victim;
	self.victimTeam = victim.team;
	self.attacker = attacker;
	self.attackerTeam = attacker.team;
	
	self.trigger.origin = pos;
	
	self Show();
	self clientfield::set( "taco_flag", 1 );
	
	self PlayLoopSound( "mpl_fracture_core_loop" );
	
	self DontInterpolate();
	
	// Show dropped objectives to the attacking player
	Objective_SetInvisibleToAll( self.objectiveId );
	Objective_Team( self.objectiveId, attacker.team );
	Objective_State( self.objectiveId, "active" );
	Objective_SetColor( self.objectiveId, &"EnemyOrange" );
	Objective_SetVisibleToPlayer( self.objectiveId, attacker );
		
	self gameobjects::allow_use( "any" );
	
	if ( isdefined( self.physicsAnchor ) )
	{
		self.physicsAnchor Delete();
	}
	
	dropAngles = ( -70, yawAngle, 0 );
	
	force = AnglesToForward( dropAngles ) * RandomFloatRange( GetDvarFloat( "dropMin", 220 ),  GetDvarFloat( "dropMax", 300 ) );
	
	self.physicsAnchor = victim MagicMissile( level.cleanDropWeapon, pos, force );
	self.physicsAnchor Hide();
	self.physicsAnchor NotSolid();
	
	self thread update_taco_position();
	self thread bounce_when_stationary();
	self thread timeout_wait();
}

function update_taco_position()
{
	level endon( "game_ended" );
	self endon( "reset" );
	self.physicsAnchor endon( "stationary" );
	
	while(1)
	{
		if ( !isdefined( self ) )
			return;
		
		if ( !isdefined( self.physicsAnchor ) )
			return;

		if ( self.physicsAnchor oob::IsTouchingAnyOOBTrigger() ||
		     self.physicsAnchor gameobjects::is_touching_any_trigger_key_value( "trigger_hurt", "classname", self.trigger.origin[2], self.trigger.origin[2] + 32 ) )
		{
			self thread reset_taco();
			return;
		}
		
		self.trigger.origin = self.physicsAnchor.origin;
		
		Objective_Position( self.objectiveId, self.trigger.origin );
		
		{wait(.05);};
	}
}

function bounce_when_stationary()
{
	level endon( "game_ended" );
	self endon( "reset" );
	self endon( "death" );
	
	if ( !isdefined( self ) )
		return;
	
	if ( !isdefined( self.physicsAnchor ) )
		return;
	
	self.physicsAnchor waittill( "stationary" );
	
	self.trigger.origin = self.physicsAnchor.origin;
	Objective_Position( self.objectiveId, self.trigger.origin );
	
	self PlaySound( "mpl_fracture_core_drop" );
	
	self clientfield::set( "taco_flag", 2 );
	
	self.physicsAnchor Delete();
	self.physicsAnchor = undefined;
}

function timeout_wait()
{
	level endon( "game_ended" );
	self endon( "reset" );	
	
	wait 60;
	
/#
	level.expiredDrops++;	
#/
	
	self thread reset_taco();
}

function reset_taco()
{
/#
	level.activeDrops--;
#/
	self notify( "reset" );
	
	self clientfield::set( "taco_flag", 0 );
	
	self StopLoopSound();
	
	self.trigger.origin = (0,0,1000);
	self gameobjects::allow_use( "none" );	
	
	if ( isdefined( self.physicsAnchor ) )
	{
		self.physicsAnchor Delete();
		self.physicsAnchor = undefined;
	}
	
	Objective_State( self.objectiveId, "invisible" );	
	
	self Ghost();
}

function onRoundSwitch()
{
	game["switchedsides"] = !game["switchedsides"];
}

function onRoundEndGame( roundWinner )
{	
	return globallogic::determineTeamWinnerByGameStat( "roundswon" );
}

// Objectives
//========================================

function setup_deposit_hubs()
{	
	globallogic::waitForPlayers();
	
	remove_targetnames( "clean_objective_base_trig" );
	remove_targetnames( "clean_objective_center_trig" );
	remove_targetnames( "clean_objective_scatter_trig" );
	remove_flag_bases();
		
	if ( !isdefined( level.cleanDepositPoints ) )
	{
		/#util::error("level.cleanDepositPoints needs to be defined in level script");#/
		return;
	}

	level.cleanDepositHubs = [];
	
	foreach( point in level.cleanDepositPoints )
	{
		depositHub = create_deposit_hub( point );
			
		level.cleanDepositHubs[level.cleanDepositHubs.size] = depositHub;
	}
}

function remove_targetnames( targetname )
{
	ents = getEntArray( targetname, "targetname" );
	
	foreach( ent in ents )
	{
		ent Delete();
	}
}

function remove_flag_bases()
{
	scriptModels = getEntArray( "script_model", "className" );
	
	foreach( scriptModel in scriptModels )
	{
		if ( scriptModel.model === "p7_mp_flag_base" )
			scriptModel Delete();
	}
}

function create_deposit_hub( origin )
{
	trigger = spawn( "trigger_radius", origin, 0, 80, 108 );
	
	visuals[0] = spawn( "script_model", trigger.origin );

	depositHub = gameobjects::create_use_object( "neutral", trigger, visuals, undefined, &"clean_deposit" );
	
	depositHub gameobjects::set_use_time( 0 );
	depositHub gameobjects::allow_use( "none" );
	depositHub gameobjects::set_visible_team( "none" );
	
	depositHub.onUse = &on_use_deposit_hub;
	depositHub.canUseObject = &can_use_deposit_point;

	depositHub.effectOrigin = trigger.origin + ( 0, 0, 0 );
	
	depositHub spawning::create_influencer( "clean_deposit_hub", depositHub.origin, 0 );
	depositHub spawning::enable_influencers(false);
	
	return depositHub;
}

function trigger_base_effect()
{
	level endon( "game_ended" );
	self.baseEffectRotator = spawn( "script_model", self.effectOrigin );
	self.baseEffectRotator setModel( "tag_origin" );
	self.baseEffectRotator.angles = ( -90, 0, 0 );

	self.baseEffect = spawnFx( "ui/fx_stockpile_deposit_point", self.effectOrigin );
	self.baseEffect.team = "none";
	
	triggerFx( self.baseEffect, 0.001 );
	
	time_left = 5;
	wait_time = level.cleanDepositOnlineTime - time_left;
	if ( wait_time < 0 )
	{
		wait_time = level.cleanDepositOnlineTime * 0.05;
	}
	
	wait (wait_time);
	
	if ( !isdefined(self.baseEffect) )
		return;
		
	self PlaySound( "mpl_fracture_deposit_leave" );
	self.baseEffect delete();
	self.baseEffect = PlayFxOnTag( "ui/fx_stockpile_deposit_point_end", self.baseEffectRotator, "tag_origin" );
	self.baseEffect.team = "none";

	// dont want it to stop before being deleted
	time_left += 0.25; 
	
	num_rotations = 3;
	angles = (self.baseEffectRotator.angles[0], self.baseEffectRotator.angles[1] - num_rotations * 360, self.baseEffectRotator.angles[2]);
	
	self.baseEffectRotator RotateTo( angles, time_left, time_left, 0, false );
}

function rotate_deposit_hubs()
{
	level endon( "game_ended" );
	
	while ( level.inPrematchPeriod )
	{
		{wait(.05);};
	}	
	
	SetBombTimer( "A", 0 );
	setMatchFlag( "bomb_timer_a", 0 );

	hubIndex = -1;
	
	while ( 1 )
	{
		if ( level.cleanDepositOfflineTime > 0 )
		{
			foreach( team in level.teams )
			{
				setMatchFlag( "bomb_timer_a", 1 );
				SetBombTimer( "A", int( gettime() + 1000 + level.cleanDepositOfflineTime * 1000 ) );

				if ( hubIndex >= 0 )
				{
					globallogic_audio::leader_dialog( "hubOffline", team );
					globallogic_audio::play_2d_on_team( "mpl_fracture_sting_powerdown", team );
				}
			}
			
			wait level.cleanDepositOfflineTime;
		}
		
		nextHubIndex = get_next_hub_index( hubIndex );
		depositHub = level.cleanDepositHubs[nextHubIndex];
		
		// Enable the point
		depositHub gameobjects::allow_use( "any" );
		depositHub gameobjects::set_visible_team( "any" );
		depositHub thread trigger_base_effect();
		depositHub spawning::enable_influencers( true );
		depositHub PlayLoopSound( "mpl_fracture_location_lp" );
		
		foreach( team in level.teams )
		{
			setMatchFlag( "bomb_timer_a", 1 );
			SetBombTimer( "A", int( gettime() + 1000 + level.cleanDepositOnlineTime * 1000 ) );
			
			if ( level.cleanDepositOfflineTime > 0 )
			{
				globallogic_audio::leader_dialog( "hubOnline", team );
			}
			else if ( hubIndex >= 0 )
			{
				globallogic_audio::leader_dialog( "hubMoved", team );
			}
			
			if ( hubIndex >= 0 )
			{
				globallogic_audio::play_2d_on_team( "mpl_fracture_sting_moved", team );
			}
		}
		
		hubIndex = nextHubIndex;
		//depositHub thread shutdown_warning();
		wait level.cleanDepositOnlineTime;
		
		// Disable the point
		depositHub gameobjects::allow_use( "none" );
		depositHub gameobjects::set_visible_team( "none" );
		depositHub spawning::enable_influencers(false);
		depositHub StopLoopSound( );
		
		depositHub.baseEffect delete();
		
		level notify( "clean_deposit_hub_moved" );
	}
}
	
function get_next_hub_index( hubIndex )
{	
	if(!isdefined(hubIndex))hubIndex=-1;
	
	switch( level.cleanDepositRotation )
	{
		case 0:	// Linear
			return ( hubIndex + 1 ) % level.cleanDepositHubs.size;
		case 1:	// Fixed start random
			return get_fixed_start_hub_index( hubIndex, &get_random_cycle_hub_index );
	}
	
	//case 2: // Random Cycle
	return get_random_cycle_hub_index( hubIndex );
}

// Start with hub index 0
function get_fixed_start_hub_index( hubIndex, randomFunc )
{
	if ( hubIndex < 0 )
	{
		return 0;
	}
	
	return [[randomFunc]]( hubIndex );
}


// Get a new index without repeating any until all hubs have come online
function get_random_cycle_hub_index( hubIndex )
{
	if(!isdefined(level.unusedDepositHubIndexes))level.unusedDepositHubIndexes=[];
	
	if ( level.unusedDepositHubIndexes.size == 0 )
	{
		for( i = 0; i < level.cleanDepositHubs.size; i++ )
		{
			if ( i != hubIndex )
			{
				level.unusedDepositHubIndexes[level.unusedDepositHubIndexes.size] = i;
			}
		}
	}
	
	unusedIndex = RandomInt( level.unusedDepositHubIndexes.size );
	nextIndex = level.unusedDepositHubIndexes[unusedIndex];
	ArrayRemoveIndex( level.unusedDepositHubIndexes, unusedIndex );
	
	return nextIndex;
}

// Random index without repeating the last
function get_random_hub_index( hubIndex )
{
	if ( hubIndex < 0 )
	{
		return RandomInt( level.cleanDepositHubs.size );
	}
	
	nextIndex = RandomInt( level.cleanDepositHubs.size - 1 );
	
	if ( nextIndex >= hubIndex )
	{
		nextIndex++;
	}
	
	return nextIndex;
}

function hideTimerDisplayOnGameEnd()
{
	level waittill("game_ended");
	setMatchFlag( "bomb_timer_a", 0 );
}

function on_use_deposit_hub( player )
{	
	time = GetTime();
	
	if ( time - player.lastDepositTime > ( .05 + 0.25 ) * 1000 )
	{
		player.depositStreak = 0;
	}
	
	player.lastDepositTime = time;
	
	if( isdefined(player.pers["cleandeposits"]) )
	{
		player.pers["cleandeposits"] = player.pers["cleandeposits"] + 1;
		player.cleandeposits = player.pers["cleandeposits"];
		score_event_deposit( player, self );
	}

	player AddPlayerStatWithGameType( "CLEANDEPOSITS", 1 );
	
	if ( level.teamScorePerCleanDeposit > 0 )
	{
		depositTeamScore =  level.teamScorePerCleanDeposit;
		
		player globallogic_score::giveTeamScoreForObjective( player.team, depositTeamScore );
	}
	
	enemyTeam = util::getOtherTeam( player.team );
	level thread popups::DisplayTeamMessageToTeam( &"MP_CLEAN_DEPOSIT", player, player.team );
	level thread popups::DisplayTeamMessageToTeam( &"MP_CLEAN_DEPOSIT", player, enemyTeam );
	
	//globallogic_audio::play_2d_on_team( ENEMY_DEPOSIT_SOUND, enemyTeam );
	globallogic_audio::play_2d_on_team( "mpl_flagcapture_sting_friendly", player.team );
	
	switch( player.depositStreak )
	{
		case 0:
			player playLocalSound( "mpl_fracture_deposit_1" );
			break;
		case 1:
			player playLocalSound( "mpl_fracture_deposit_2" );
			break;
		case 2:	
			player playLocalSound( "mpl_fracture_deposit_3" );
			break;			
		case 3:
			player playLocalSound( "mpl_fracture_deposit_4" );
			break;
		default:
			player playLocalSound( "mpl_fracture_deposit_5" );
	}

	player.depositStreak++;
	
	scoreevents::processScoreEvent( "clean_enemy_deposit", player );
	
	player.carriedTacos--;
	player clientfield::set_player_uimodel( "hudItems.cleanCarryCount", player.carriedTacos );
	
	player update_taco_carry();
}

function score_event_deposit( player, deposit_hub )
{
	if ( !isdefined( player ) )
		return;
	
	time = GetTime(); // in MS
	
	player.same_hub_deposit_count++;
	
	if ( player.same_hub_deposit_count == 1 )
	{
		player thread watch_leave_hub( deposit_hub );
	}
	else if ( player.same_hub_deposit_count == 5 )
	{
		scoreevents::processScoreEvent( "clean_multi_deposit_normal", player );
	}
	else if ( player.same_hub_deposit_count == 10 )
	{
		scoreevents::processScoreEvent( "clean_multi_deposit_big", player );
		player.same_hub_deposit_count = 0;
	}
}

function watch_leave_hub( deposit_hub )
{
	self endon( "death" );
	self endon( "disconnect" );
	level endon( "clean_deposit_hub_moved" );

	self thread watch_leave_hub_on_move();

	wait 0.1;

	while( 1 )
	{
		// strange that this doesn't work. (will use an endon instead)
		//
		// if ( !deposit_hub.trigger IsTriggerEnabled() )
		// 	break;
		//
		
		if ( Distance2DSquared( self.origin, deposit_hub.origin ) > ( (80 + 10) * (80 + 10) ) )
			break;
		
		wait 0.1;
	}

	self.same_hub_deposit_count = 0;
}

function watch_leave_hub_on_move()
{
	self endon( "death" );
	self endon( "disconnect" );
	
	level waittill( "clean_deposit_hub_moved" );

	self.same_hub_deposit_count = 0;
}

function score_event_deny( player, victim )
{
	if ( !isdefined( player ) )
		return;
	
	if ( victim === player )
	{
		scoreevents::processScoreEvent( "clean_own_collect", player );
	}
	else
	{
		scoreevents::processScoreEvent( "clean_friendly_collect", player );
	}
	
	time = GetTime(); // in MS
	
	if(!isdefined(player.clean_deny_times))player.clean_deny_times=[];
	deny_time_threshold = time - ( 3000 + 250 );
	prune_time_ms_array( player.clean_deny_times, deny_time_threshold );

	if ( player.clean_deny_times.size >= ( 5 - 1 ) )
	{
		scoreevents::processScoreEvent( "clean_multi_deny_tacos", player );
		player.clean_deny_times = undefined;
	}
	else
	{
		if ( !isdefined( player.clean_deny_times ) ) player.clean_deny_times = []; else if ( !IsArray( player.clean_deny_times ) ) player.clean_deny_times = array( player.clean_deny_times ); player.clean_deny_times[player.clean_deny_times.size]=time;;
	}
}

function prune_time_ms_array( &times, time_threshold )
{
	for( i = 0; i < times.size; i++ )
	{
		if ( times[ i ] < time_threshold )
			times[ i ] = 0;
	}
	ArrayRemoveValue( times, 0 );	
}

function can_use_deposit_point( player )
{
	if ( player.carriedTacos <= 0 )
	{
		// Reset the centered/colored/pulsing objective
		Objective_ClearPlayerUsing( self.objectiveID, player );
		return false;
	}
	
	if ( !player.lastDepositTime )
		return true;
	
	return player.lastDepositTime + ( 0.25 * 1000 ) < GetTime();
}


// Tag Functions
//========================================

function on_use_taco( player )
{
	if ( self.victimTeam == player.team )
	{
		PlaySoundAtPosition( "mpl_fracture_enemy_pickup_m", self.origin );
		
		if( isdefined(player.pers["cleandenies"]) )
		{
			player.pers["cleandenies"] = player.pers["cleandenies"] + 1;
			player.cleandenies = player.pers["cleandenies"];
		}
		
		player AddPlayerStatWithGameType( "CLEANDENIES", 1 );
		
		score_event_deny( player, self.victim );
	}
	else if ( player.carriedTacos >= 10 )
	{
		// Done here instead of in can_use since touching multiple triggers in the same frame will let you pick them all up
		
		time = GetTime();
		if ( time - player.lastCarryFullTime > 500 )
		{
			player PlayLocalSound( "mpl_fracture_enemy_pickup_nope" );
			if(!isdefined(player.carryFull))player.carryFull=0;
			player clientfield::set_player_uimodel( "hudItems.cleanCarryFull", player.carryFull );
			player.carryFull = ( !player.carryFull ? 1 : 0 );
		}
		
		player.lastCarryFullTime = time;
		
		return;
	}
	else 
	{			
		player.carriedTacos++;	
		player clientfield::set_player_uimodel( "hudItems.cleanCarryCount", player.carriedTacos );
		player update_taco_carry();
		
		if ( player.carriedTacos < 4 )
		{
			PlaySoundAtPosition( "mpl_fracture_enemy_pickup_s", self.origin );
		}
		else if ( player.carriedTacos < 7 )
		{
			PlaySoundAtPosition( "mpl_fracture_enemy_pickup_m", self.origin );
		}
		else
		{
			PlaySoundAtPosition( "mpl_fracture_enemy_pickup_l", self.origin );
		}
		
		scoreevents::processScoreEvent( "clean_enemy_collect", player );	
		
		if ( self.attackerTeam == player.team &&
		     isdefined( self.attacker ) &&
			 self.attacker != player )
		{
			scoreevents::processScoreEvent( "clean_assist_collect", self.attacker );
		}
	}
	
	self reset_taco();
}

function drop_carried_tacos( attacker, yawAngle )
{	
	dropCount = self.carriedTacos;
	
	self.carriedTacos = 0;
	self clientfield::set_player_uimodel( "hudItems.cleanCarryCount", self.carriedTacos );
	self update_taco_carry();
	
/#
	dropCount += GetDvarInt( "extraTacos", 0 );
#/	
	
	yawInterval = 360 / ( dropCount + 1 );
	
	for ( i = 0; i < dropCount; i++ )
	{	
		taco = get_droppable_taco( );
		
		if ( !isdefined( taco ) )
		{
			return;
		}
		
		yawAngle += yawInterval;
		randomYaw = 0.8 * yawInterval;
		randomYaw = RandomFloatRange( -randomYaw, randomYaw );
		taco drop_taco( self, attacker, undefined, yawAngle + randomYaw );
	}
}