#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\flagsys_shared;
#using scripts\shared\hud_util_shared;
#using scripts\shared\lui_shared;
#using scripts\shared\scene_shared;
#using scripts\shared\string_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   

#using scripts\cp\gametypes\_loadout;
#using scripts\cp\gametypes\_globallogic;
#using scripts\cp\gametypes\_globallogic_player;
#using scripts\cp\gametypes\_save;
#using scripts\cp\gametypes\_spectating;

#using scripts\cp\_util;
#using scripts\cp\teams\_teams;

#precache( "string", "MP_HALFTIME" );
#precache( "string", "MP_OVERTIME" );
#precache( "string", "MP_ROUNDEND" );
#precache( "string", "MP_INTERMISSION" );
#precache( "string", "MP_SWITCHING_SIDES_CAPS" );
#precache( "string", "MP_FRIENDLY_FIRE_WILL_NOT" );
#precache( "string", "MP_RAMPAGE" );
#precache( "string", "MP_ENDED_GAME" );
#precache( "string", "MP_HOST_ENDED_GAME" );

#precache( "eventstring", "medal_received" ); 
#precache( "eventstring", "killstreak_received" );
#precache( "eventstring", "player_callout" );
#precache( "eventstring", "score_event" );
#precache( "eventstring", "rank_up" ); 
#precache( "eventstring", "client_rank_up" ); 
#precache( "eventstring", "weapon_unlocked" );
#precache( "eventstring", "token_unlocked" );
#precache( "eventstring", "gun_level_complete" ); 
#precache( "eventstring", "challenge_complete" ); 

#precache( "menu", "InitialBlack" );


	
#namespace globallogic_ui;

//REGISTER_SYSTEM( "globallogic_ui", &__init__, undefined )

function init()
{
	callback::add_callback( #"on_player_spawned", &on_player_spawn);
	clientfield::register( "clientuimodel", "hudItems.cybercoreSelectMenuDisabled", 1, 1, "int" );
	clientfield::register( "clientuimodel", "hudItems.playerInCombat", 1, 1, "int" );
	clientfield::register( "clientuimodel", "playerAbilities.repulsorIndicatorDirection", 1, 2, "int" );
	clientfield::register( "clientuimodel", "playerAbilities.repulsorIndicatorIntensity", 1, 2, "int" );
	clientfield::register( "clientuimodel", "playerAbilities.proximityIndicatorDirection", 1, 2, "int" );
	clientfield::register( "clientuimodel", "playerAbilities.proximityIndicatorIntensity", 1, 2, "int" );
	clientfield::register( "clientuimodel", "serverDifficulty", 1, 3, "int" );
}

function on_player_spawn()
{
	self thread watch_player_in_combat();
	
	assert( isdefined( level.gameSkill ) );
	
	self clientfield::set_player_uimodel( "serverDifficulty", level.gameSkill );
}

function IsAnyAIAttackingThePlayer( playerEnt )
{
	ais = GetAITeamArray( "axis" ); 
	ais = ArrayCombine( ais, GetAITeamArray( "team3" ), false, false ); // sometimes enemy AI is on team 3 as well
    
    foreach( ai in ais )
    {
		if ( IsSentient( ai ) )
		{
			if ( ai AttackedRecently( playerEnt, 10 ) )
			{
				return true;
			}
			else if ( ai.enemy === playerEnt &&
				IsDefined( ai.weapon ) &&
				ai.weapon.name === "none" &&
				DistanceSquared( ai.origin, playerEnt.origin ) < ( (240) * (240) ) )
			{
				// Melee AI is close to the player.
				return true;
			}
		}
    }
    
    return false;
}
                                
function IsAnyAIAwareOfPlayer( playerEnt )
{
	ais = GetAITeamArray( "axis" ); 
	ais = ArrayCombine( ais, GetAITeamArray( "team3" ), false, false ); // sometimes enemy AI is on team 3 as well
    
    foreach( ai in ais )
    {
		if ( IsSentient( ai ) )
		{
			// Has known about player recently?
			if ( ( ai LastKnownTime( playerEnt ) + 4000 ) >= GetTime() )
				return true;
		}
    }
    
    return false;
}

function IsPlayerHurt( playerEnt )
{
	return playerEnt.health < playerEnt.maxhealth;
}

function watch_player_in_combat()
{
	self endon("kill_watch_player_in_combat");
	self endon( "disconnect" );
	
	while( true )
	{
		if ( IsPlayerHurt( self ) || IsAnyAIAttackingThePlayer( self ) )
		{
			self clientfield::set_player_uimodel( "hudItems.playerInCombat", 1 );
		}
		else
		{
			self clientfield::set_player_uimodel( "hudItems.playerInCombat", 0 );
		}

		wait( 0.5 );
	}
}

function SetupCallbacks()
{
	level.autoassign =&menuAutoAssign;
	level.spectator =&menuSpectator;
	level.curClass =&menuClass;
	level.teamMenu =&menuTeam;
}

function freeGameplayHudElems()
{
	// free up some hud elems so we have enough for other things.
	
	// perk icons
	if ( isdefined( self.perkicon ) )
	{
		for ( numSpecialties = 0; numSpecialties < level.maxSpecialties; numSpecialties++ )
		{
			if ( isdefined( self.perkicon[ numSpecialties ] ) )
			{
				self.perkicon[ numSpecialties ] hud::destroyElem();
				self.perkname[ numSpecialties ] hud::destroyElem();
			}
		}
	}

	if ( isdefined( self.perkHudelem ) )
	{
		self.perkHudelem hud::destroyElem();
	}
	
	// Killstreak icons
	if ( isdefined( self.killstreakicon ) )
	{
		if ( isdefined( self.killstreakicon[0] ) )
		{
			self.killstreakicon[0] hud::destroyElem();
		}
		if ( isdefined( self.killstreakicon[1] ) )
		{
			self.killstreakicon[1] hud::destroyElem();
		}
		if ( isdefined( self.killstreakicon[2] ) )
		{
			self.killstreakicon[2] hud::destroyElem();
		}
		if ( isdefined( self.killstreakicon[3] ) )
		{
			self.killstreakicon[3] hud::destroyElem();
		}
		if ( isdefined( self.killstreakicon[4] ) )
		{
			self.killstreakicon[4] hud::destroyElem();
		}
	}
	
	// lower message
	if ( isdefined( self.lowerMessage ) )
		self.lowerMessage hud::destroyElem();
	if ( isdefined( self.lowerTimer ) )
		self.lowerTimer hud::destroyElem();
	
	// progress bar
	if ( isdefined( self.proxBar ) )
		self.proxBar hud::destroyElem();
	if ( isdefined( self.proxBarText ) )
		self.proxBarText hud::destroyElem();
		
	// carry icon
	if ( isdefined( self.carryIcon ) )
		self.carryIcon hud::destroyElem();
}

function teamPlayerCountsEqual( playerCounts )
{
	count = undefined;
	
	foreach( team in level.teams )
	{
		if ( !isdefined( count ) )
		{
			count = playerCounts[team];
			continue;
		}
		if ( count != playerCounts[team] )
			return false;
	}
	
	return true;
}

function teamWithLowestPlayerCount( playerCounts, ignore_team )
{
	count = 9999;
	lowest_team = undefined;
	
	foreach( team in level.teams )
	{
		if ( count > playerCounts[team] )
		{
			count = playerCounts[team];
			lowest_team = team;
		}
	}
	
	return lowest_team;
}

function menuAutoAssign( comingFromMenu )
{
	teamKeys = GetArrayKeys( level.teams );
	assignment = teamKeys[randomInt(teamKeys.size)];
	
	self closeMenus();

	assignment = "allies";

	if ( level.teamBased )
	{	
		if ( assignment == self.pers["team"] && (self.sessionstate == "playing" || self.sessionstate == "dead") )
		{
			self beginClassChoice();
			return;
		}
	}
	else
	{
		if ( GetDvarint( "party_autoteams" ) == 1 )
		{
			// after they have spawned in once then we should let the random team assignment logic handle itself.
			if( level.allow_teamchange != "1" || ( !self.hasSpawned && !comingFromMenu ) )
			{
				team = getAssignedTeam( self );	
				if( isdefined( level.teams[team] )  )
				{
					assignment = team;
				}
				else if ( team == "spectator" && (!level.forceAutoAssign) )
				{   
					self SetClientScriptMainMenu( game[ "menu_start_menu" ] );
					return;
				}
			}
		}	
	}

	if ( assignment != self.pers["team"] && (self.sessionstate == "playing" || self.sessionstate == "dead") )
	{
		self.switching_teams = true;
		self.switchedTeamsResetGadgets = true;
		self.joining_team = assignment;
		self.leaving_team = self.pers["team"];
		self suicide();
	}

	self.pers["team"] = assignment;
	self.team = assignment;
	self.pers["class"] = undefined;
	self.curClass = undefined;
	self.pers["weapon"] = undefined;
	self.pers["savedmodel"] = undefined;

	self updateObjectiveText();

	self.sessionteam = assignment;
	
	if ( !isAlive( self ) )
		self.statusicon = "hud_status_dead";
	
	self notify("joined_team");
	level notify( "joined_team" );
	callback::callback( #"on_joined_team" );
	self notify("end_respawn");
	
	self beginClassChoice();	
	self SetClientScriptMainMenu( game[ "menu_start_menu" ] );

}

function teamScoresEqual( )
{
	score = undefined;
	
	foreach( team in level.teams )
	{
		if ( !isdefined( score ) )
		{
			score = getTeamScore(team);
			continue;
		}
		if ( score != getTeamScore(team) )
			return false;
	}
	
	return true;
}

function teamWithLowestScore()
{
	score = 99999999;
	lowest_team = undefined;
	
	foreach( team in level.teams )
	{
		if ( score > getTeamScore(team ) )
			lowest_team = team;
	}
	
	return lowest_team;
}

function pickTeamFromScores(teams)
{
	assignment = "allies";
	
	if ( teamScoresEqual() )
		assignment = teams[randomInt(teams.size)];
	else
		assignment = teamWithLowestScore();
		
	return assignment;
}

function get_splitscreen_team()
{
	for ( index = 0; index < level.players.size; index++ )
	{
		if ( !isdefined(level.players[index]) )
			continue;
			
		if ( level.players[index] == self )
			continue;
			
		if ( !(self IsPlayerOnSameMachine( level.players[index] )) )
			continue;
			
		team = level.players[index].sessionteam;

		// going to assume first non-spectator 
		if ( team != "spectator" )
			return team;
	}
	
	return "";
}

function updateObjectiveText()
{
	if ( SessionModeIsZombiesGame() || (self.pers["team"] == "spectator") )
	{
		self SetClientCGObjectiveText( "" );
		return;
	}

	if( level.scorelimit > 0 ) 
	{
		self SetClientCGObjectiveText( util::getObjectiveScoreText( self.pers["team"] ) );
	}
	else
	{
		self SetClientCGObjectiveText( util::getObjectiveText( self.pers["team"] ) );
	}
}


function closeMenus()
{
	self closeInGameMenu();
}

function beginClassChoice()
{
	assert( isdefined( level.teams[self.pers["team"]] ) );
	
	team = self.pers["team"];
	
	self CloseMenu( game["menu_start_menu"] );
	
	if ( !GetDvarInt( "art_review", 0 ) )
	{
		self thread fullscreen_black();
	}
	
	b_disable_cac = GetDvarInt( "force_no_cac", 0 );
	
	if ( !GetDvarInt( "force_cac", 0 ) || b_disable_cac )
	{
		prevclass = self savegame::get_player_data( "playerClass", undefined );
		prevHeroWeapons = self savegame::get_player_data( savegame::get_mission_name() + "hero_weapon", undefined );
	
		if ( isdefined( prevclass ) || b_disable_cac
		    || ( isdefined( level.disableClassSelection ) && level.disableClassSelection )
		    || ( isdefined( self.disableClassSelection ) && self.disableClassSelection )
		    || GetDvarint( "migration_soak" ) == 1 )
		{
			self.curClass = (isdefined(prevclass)?prevclass:level.defaultClass);
			self.pers[ "class" ] = self.curClass;
	
			{wait(.05);};
			
			if ( self.sessionstate != "playing" && game[ "state" ] == "playing" )
			{
				self thread [[ level.spawnClient ]]();
			}
			
			globallogic::updateTeamStatus();
			self thread spectating::set_permissions_for_machine();
			
			return;
		}
	}

	// menu_changeclass_team is the one where you choose one of the n classes to play as.
	// menu_class_team is where you can choose to change your team, class, controls, or leave game.
	self CloseMenu( game[ "menu_changeclass" ] );
	self openMenu( game[ "menu_changeclass_" + team ] );

	//if ( level.rankedMatch )
	//	self openMenu( game[ "menu_changeclass_" + team ] );
	//else
	//	self openMenu( game[ "menu_start_menu" ] );
}

function fullscreen_black()
{
	self endon( "disconnect" );
	
	util::show_hud( 0 );
	
	self CloseMenu( "InitialBlack" );
	self OpenMenu( "InitialBlack" );
	
	b_hot_joining = false;
	if ( level flag::get( "all_players_spawned" ) )
	{
		b_hot_joining = true;
	}
	
	self.fullscreen_black_active = true;
	self thread fullscreen_black_checkpoint_restore(); //this thread makes sure the fullscreen black is held up even if you restore from checkpoint and it needs to be held up
	
	self Hide();
	
	{wait(.05);};
	
	if ( isdefined( level.str_level_start_flag ) || isdefined( level.str_player_start_flag ) )
	{
		init_start_flags();
		
		self thread fullscreen_black_freeze_controls();
		
		if ( isdefined( level.str_level_start_flag ) )
		{
			level flag::wait_till( level.str_level_start_flag );
		}
		
		if ( isdefined( level.str_player_start_flag ) )
		{
			self flag::wait_till( level.str_player_start_flag );
		}
	}
	
	if ( b_hot_joining && !( isdefined( level.is_safehouse ) && level.is_safehouse ) )
	{
		while ( self.sessionstate !== "playing" )
		{
			{wait(.05);};
		}
		
		self thread fullscreen_black_freeze_controls();
		
		while ( self IsLoadingCinematicPlaying() )
		{
			{wait(.05);};
		}
		
		self flag::wait_till( "loadout_given" );
		waittillframeend; // if we are hot-joining an IGC wait until we can detect that
		
		wait 2;
		
		// hold black and wait for streamer
		self util::streamer_wait( undefined, 5, 5 );
		
		self thread lui::screen_fade_in( .3, "black", "hot_join" );
	}
	
	if ( !flagsys::get( "shared_igc" ) )
	{	
		self Show();
	}
	
	self flagsys::set( "kill_fullscreen_black" );
	
	self clientfield::set_to_player( "sndLevelStartSnapOff", 1 );
	self CloseMenu( "InitialBlack" );
	
	self.fullscreen_black_active = undefined;
	
	util::show_hud( 1 );

	/#
		PrintTopRightln( "["+GetTime()+"] KILL INITIAL BLACKSCREEN: PLAYER " + self GetEntityNumber(), ( 1, 1, 1 ) );
		streamerSkiptoDebug( GetSkiptos() );
	#/
}

function fullscreen_black_checkpoint_restore()
{
	self endon( "disconnect" );
	self endon( "kill_fullscreen_black" ); //this seems to be set when the initial fullscreen is done
	
	b_fullscreen_black = self.fullscreen_black_active;
	
	level waittill( "save_restore" );
	
	if( ( isdefined( b_fullscreen_black ) && b_fullscreen_black ) )
	{
		self CloseMenu( "InitialBlack" );
		self OpenMenu( "InitialBlack" );
	}
}

function init_start_flags()
{
	if ( isdefined( level.str_player_start_flag ) && !self flag::exists( level.str_player_start_flag ) )
	{
		self flag::init( level.str_player_start_flag );
	}
	
	if ( isdefined( level.str_level_start_flag ) && !level flag::exists( level.str_level_start_flag ) )
	{
		level flag::init( level.str_level_start_flag );
	}
}

function fullscreen_black_freeze_controls()
{
	self endon( "disconnect" );
	
	self.b_game_start_invulnerability = true;
	
	self flagsys::wait_till( "loadout_given" );
	
	self DisableWeapons();
	self FreezeControls( true );
	
	wait 0.1;	// Several other scripts unfreeze controls when spawning, need to wait
	waittillframeend;
	
	self FreezeControls( true );
	self DisableWeapons();
	
	self flagsys::wait_till( "kill_fullscreen_black" );
	
	self EnableWeapons();
	self FreezeControls( false );
	
	self.b_game_start_invulnerability = undefined;
}

function showMainMenuForTeam()
{
	assert( isdefined( level.teams[self.pers["team"]] ) );
	
	team = self.pers["team"];
	
	// menu_changeclass_team is the one where you choose one of the n classes to play as.
	// menu_class_team is where you can choose to change your team, class, controls, or leave game.
	
	self openMenu( game[ "menu_changeclass_" + team ] );
}

function menuTeam( team )
{
	self closeMenus();
	
	if ( !level.console && level.allow_teamchange == "0" && (isdefined(self.hasDoneCombat) && self.hasDoneCombat) )
	{
			return;
	}
	
	if(self.pers["team"] != team)
	{
		// allow respawn when switching teams during grace period.
		if ( level.inGracePeriod && (!isdefined(self.hasDoneCombat) || !self.hasDoneCombat) )
			self.hasSpawned = false;
			
		if(self.sessionstate == "playing")
		{
			self.switching_teams = true;
			self.switchedTeamsResetGadgets = true;
			self.joining_team = team;
			self.leaving_team = self.pers["team"];
			self suicide();
		}

		self.pers["team"] = team;
		self.team = team;
		self.pers["class"] = undefined;
		self.curClass = undefined;
		self.pers["weapon"] = undefined;
		self.pers["savedmodel"] = undefined;

		self updateObjectiveText();

		if ( !level.rankedMatch && !level.leagueMatch )
		{
			self.sessionstate = "spectator";
		}
		
		self.sessionteam = team;

		self SetClientScriptMainMenu( game[ "menu_start_menu" ] );

		self notify("joined_team");
		level notify( "joined_team" );
		callback::callback( #"on_joined_team" );
		self notify("end_respawn");
	}
	
	self beginClassChoice();
}

function menuSpectator()
{
	self closeMenus();
	
	if(self.pers["team"] != "spectator")
	{
		if(isAlive(self))
		{
			self.switching_teams = true;
			self.switchedTeamsResetGadgets = true;
			self.joining_team = "spectator";
			self.leaving_team = self.pers["team"];
			self suicide();
		}

		self.pers["team"] = "spectator";
		self.team = "spectator";
		self.pers["class"] = undefined;
		self.curClass = undefined;
		self.pers["weapon"] = undefined;
		self.pers["savedmodel"] = undefined;

		self updateObjectiveText();

		self.sessionteam = "spectator";

		[[level.spawnSpectator]]();
		
		self thread globallogic_player::spectate_player_watcher();

		self SetClientScriptMainMenu( game[ "menu_start_menu" ] );

		self notify("joined_spectators");
		callback::callback( #"on_joined_spectate" );
	}
}

function menuClass( response )
{
	self closeMenus();
	
	// this should probably be an assert
	if ( !isdefined( self.pers[ "team" ] ) || !( isdefined( level.teams[ self.pers[ "team" ]] ) ) )
	{
		return;
	}

	//-- mobile armory handles these changes within the system
	if ( flagsys::get( "mobile_armory_in_use" ) )
	{
		return;
	}
	
	playerclass = "";
	
	if ( response == "cancel" )
	{
		prevclass = self savegame::get_player_data( "playerClass", undefined );
		
		if ( isdefined( prevclass ) )
		{
			playerclass = prevclass;
		}
		else
		{
			playerclass = level.defaultClass;
		}
	}
	else
	{			
		responseArray = strtok( response, "," );
		if( responseArray.size > 1 )
		{
			str_class_chosen = responseArray[0];
			clientNum = Int( responseArray[1] );
			
			altPlayer = util::getPlayerFromClientNum( clientNum );
		}
		else
		{
			str_class_chosen = response;
		}
				
		playerclass = self loadout::getClassChoice( str_class_chosen );
		
		if( IsDefined( altPlayer ) )
		{
			xuid = altPlayer GetXUID();
			self savegame::set_player_data( "altPlayerID", xuid );
		}
		else
		{
			self savegame::set_player_data( "altPlayerID", undefined );
		}
		
		self savegame::set_player_data( "saved_weapon", undefined );
		self savegame::set_player_data( "saved_weapondata", undefined );
		self savegame::set_player_data( "lives", undefined );
		self savegame::set_player_data( "saved_rig1", undefined );
		self savegame::set_player_data( "saved_rig1_upgraded", undefined );
		self savegame::set_player_data( "saved_rig2", undefined );
		self savegame::set_player_data( "saved_rig2_upgraded", undefined );
	}

	if( (isdefined( self.pers["class"] ) && self.pers["class"] == playerclass) )
		return;

	self.pers["changed_class"] = true;
	self notify ( "changed_class" );
	waittillframeend;
	//The player selected the class they are currently using
	if( isdefined(self.curClass) && self.curClass == playerclass )
	{
		self.pers["changed_class"] = false;
	}

	if ( self.sessionstate == "playing" )
	{
		self savegame::set_player_data( "playerClass", playerClass );
		self.pers["class"] = playerClass;
		self.curClass = playerclass;
		self.pers["weapon"] = undefined;

		if ( game["state"] == "postgame" )
			return;

		supplyStationClassChange = isdefined( self.usingSupplyStation ) && self.usingSupplyStation;
		self.usingSupplyStation = false;

		if ( ( level.inGracePeriod && !self.hasDoneCombat ) || supplyStationClassChange ) // used weapons check?
		{
			self loadout::setClass( self.pers["class"] );
			self.tag_stowed_back = undefined;
			self.tag_stowed_hip = undefined;
			self loadout::giveLoadout( self.pers["team"], self.pers["class"] );
		}
		else if ( !( self IsSplitScreen() ) )
		{
			self IPrintLnBold( game["strings"]["change_class"] );
		}
	}
	else
	{
		self savegame::set_player_data( "playerClass",playerClass);
		self.pers["class"] = playerclass;
		self.curClass = playerclass;
		self.pers["weapon"] = undefined;

		if ( game["state"] == "postgame" )
			return;
			
		if ( self.sessionstate != "spectator" )
		{
			if ( self IsInVehicle() )
				return;

			if ( self IsRemoteControlling() )
				return;
	
			if ( self IsWeaponViewOnlyLinked() )
				return false;
		}

		if ( game["state"] == "playing" )
		{
			timePassed = undefined;
			
			if ( isdefined( self.respawnTimerStartTime ) )
			{
				timePassed = (gettime() - self.respawnTimerStartTime) / 1000;
			}
			
			self thread [[level.spawnClient]](timePassed);
			
			self.respawnTimerStartTime = undefined;
			
		}
	}

	globallogic::updateTeamStatus();

	self thread spectating::set_permissions_for_machine();
	self notify("class_changed");
}


/*
function showSafeSpawnMessage()
{
	if ( level.splitscreen )
		return;
	
	// don't show it if they've already asked for a safe spawn
	if ( self.wantSafeSpawn )
		return;
	
	if ( !isdefined( self.safeSpawnMsg ) )
	{
		self.safeSpawnMsg = hud::createFontString( "default", 1.4 );
		self.safeSpawnMsg hud::setPoint( "CENTER", level.lowerTextYAlign, 0, level.lowerTextY + 50 );
		self.safeSpawnMsg setText( &"PLATFORM_PRESS_TO_SAFESPAWN" );
		self.safeSpawnMsg.archived = false;
	}
	self.safeSpawnMsg.alpha = 1;
}
function hideSafeSpawnMessage()
{
	if ( !isdefined( self.safeSpawnMsg ) )
		return;
	
	self.safeSpawnMsg.alpha = 0;
}
*/


function removeSpawnMessageShortly( delay )
{
	self endon("disconnect");
	
	waittillframeend; // so we don't endon the end_respawn from spawning as a spectator
	
	self endon("end_respawn");
	
	wait delay;
	
	self util::clearLowerMessage( 2.0 );
}

// weakpoint helpers
#precache( "eventstring", "weakpoint_update" );

// self = entity
function weakpoint_anim_watch( precachedBoneName )
{
	self endon( "death" );
	self endon( "weakpoint_destroyed" );
	
	while(true)
	{
		self waittill( "weakpoint_update", boneName, event );
		
		if ( boneName == precachedBoneName )
		{
			if ( event == "damage" )
			{
				LUINotifyEvent( &"weakpoint_update", 3, 2, self getEntityNumber(), precachedBoneName );
			}
			else if ( event == "repulse" )
			{
				LUINotifyEvent( &"weakpoint_update", 3, 3, self getEntityNumber(), precachedBoneName );
			}
			
			wait 0.5;
		}
	}
}

// self = entity
function destroyWeakpointWidget( precachedBoneName )
{
	LUINotifyEvent( &"weakpoint_update", 3, 0, self getEntityNumber(), precachedBoneName );
	self notify( "weakpoint_destroyed" );
}

// self = entity
function createWeakpointWidget( precachedBoneName, closeStateMaxDistance = undefined, mediumStateMaxDistance = undefined )
{
	if ( !isdefined( closeStateMaxDistance ) )
	{
		closeStateMaxDistance = GetDVarInt( "ui_weakpointIndicatorNear", 1050 );
	}
	
	if ( !isdefined( mediumStateMaxDistance ) )
	{
		mediumStateMaxDistance = GetDVarInt( "ui_weakpointIndicatorMedium", 1900 );
	}
	
	LUINotifyEvent( &"weakpoint_update", 5, 1, self getEntityNumber(), precachedBoneName, closeStateMaxDistance, mediumStateMaxDistance );
	
	self thread weakpoint_anim_watch( precachedBoneName );
}

// self = entity
function triggerWeakpointDamage( precachedBoneName )
{
	self notify( "weakpoint_update", precachedBoneName, "damage" );
}

// self = entity
function triggerWeakpointRepulsed( precachedBoneName )
{
	self notify( "weakpoint_update", precachedBoneName, "repulse" );
}
