mirror of
				https://github.com/JezuzLizard/t4sp_bot_warfare.git
				synced 2025-11-03 19:37:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1386 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1386 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
#include common_scripts\utility;
 | 
						|
#include maps\_utility;
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if player is the host
 | 
						|
*/
 | 
						|
is_host()
 | 
						|
{
 | 
						|
	return ( isDefined( self.pers["bot_host"] ) && self.pers["bot_host"] );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Setups the host variable on the player
 | 
						|
*/
 | 
						|
doHostCheck()
 | 
						|
{
 | 
						|
	self.pers["bot_host"] = false;
 | 
						|
 | 
						|
	if ( self is_bot() )
 | 
						|
		return;
 | 
						|
 | 
						|
	result = false;
 | 
						|
 | 
						|
	if ( getDvar( "bots_main_firstIsHost" ) != "0" )
 | 
						|
	{
 | 
						|
		PrintConsole( "WARNING: bots_main_firstIsHost is enabled\n" );
 | 
						|
 | 
						|
		if ( getDvar( "bots_main_firstIsHost" ) == "1" )
 | 
						|
		{
 | 
						|
			setDvar( "bots_main_firstIsHost", self getguid() );
 | 
						|
		}
 | 
						|
 | 
						|
		if ( getDvar( "bots_main_firstIsHost" ) == self getguid() + "" )
 | 
						|
			result = true;
 | 
						|
	}
 | 
						|
 | 
						|
	DvarGUID = getDvar( "bots_main_GUIDs" );
 | 
						|
 | 
						|
	if ( DvarGUID != "" )
 | 
						|
	{
 | 
						|
		guids = strtok( DvarGUID, "," );
 | 
						|
 | 
						|
		for ( i = 0; i < guids.size; i++ )
 | 
						|
		{
 | 
						|
			if ( self getguid() + "" == guids[i] )
 | 
						|
				result = true;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ( !result )
 | 
						|
		return;
 | 
						|
 | 
						|
	self.pers["bot_host"] = true;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the player is a bot.
 | 
						|
*/
 | 
						|
is_bot()
 | 
						|
{
 | 
						|
	return self isBot();
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Set the bot's stance
 | 
						|
*/
 | 
						|
BotSetStance( stance )
 | 
						|
{
 | 
						|
	switch ( stance )
 | 
						|
	{
 | 
						|
		case "stand":
 | 
						|
			//self scripts\sp\bots\_bot_internal::stand();
 | 
						|
			break;
 | 
						|
 | 
						|
		case "crouch":
 | 
						|
			//self scripts\sp\bots\_bot_internal::crouch();
 | 
						|
			break;
 | 
						|
 | 
						|
		case "prone":
 | 
						|
			//self scripts\sp\bots\_bot_internal::prone();
 | 
						|
			break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot changes to the weap
 | 
						|
*/
 | 
						|
BotChangeToWeapon( weap )
 | 
						|
{
 | 
						|
	self botWeapon( weap );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot presses the button for time.
 | 
						|
*/
 | 
						|
BotPressAttack( time )
 | 
						|
{
 | 
						|
	self scripts\sp\bots\_bot_internal::pressFire( time );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot presses the ads button for time.
 | 
						|
*/
 | 
						|
BotPressADS( time )
 | 
						|
{
 | 
						|
	self scripts\sp\bots\_bot_internal::pressADS( time );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot presses the use button for time.
 | 
						|
*/
 | 
						|
BotPressUse( time )
 | 
						|
{
 | 
						|
	self scripts\sp\bots\_bot_internal::use( time );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot presses the frag button for time.
 | 
						|
*/
 | 
						|
BotPressFrag( time )
 | 
						|
{
 | 
						|
	self scripts\sp\bots\_bot_internal::frag( time );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot presses the smoke button for time.
 | 
						|
*/
 | 
						|
BotPressSmoke( time )
 | 
						|
{
 | 
						|
	self scripts\sp\bots\_bot_internal::smoke( time );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the bot's random assigned number.
 | 
						|
*/
 | 
						|
BotGetRandom()
 | 
						|
{
 | 
						|
	return self.bot.rand;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns a random number thats different everytime it changes target
 | 
						|
*/
 | 
						|
BotGetTargetRandom()
 | 
						|
{
 | 
						|
	if ( !isDefined( self.bot.target ) )
 | 
						|
		return undefined;
 | 
						|
 | 
						|
	return self.bot.target.rand;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot is fragging.
 | 
						|
*/
 | 
						|
IsBotFragging()
 | 
						|
{
 | 
						|
	return self.bot.isfraggingafter;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot is pressing smoke button.
 | 
						|
*/
 | 
						|
IsBotSmoking()
 | 
						|
{
 | 
						|
	return self.bot.issmokingafter;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot is sprinting.
 | 
						|
*/
 | 
						|
IsBotSprinting()
 | 
						|
{
 | 
						|
	return self.bot.issprinting;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot is reloading.
 | 
						|
*/
 | 
						|
IsBotReloading()
 | 
						|
{
 | 
						|
	return self.bot.isreloading;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Is bot knifing
 | 
						|
*/
 | 
						|
IsBotKnifing()
 | 
						|
{
 | 
						|
	return self.bot.isknifingafter;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Freezes the bot's controls.
 | 
						|
*/
 | 
						|
BotFreezeControls( what )
 | 
						|
{
 | 
						|
	self.bot.isfrozen = what;
 | 
						|
 | 
						|
	if ( what )
 | 
						|
		self notify( "kill_goal" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot is script frozen.
 | 
						|
*/
 | 
						|
BotIsFrozen()
 | 
						|
{
 | 
						|
	return self.bot.isfrozen;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Bot will stop moving
 | 
						|
*/
 | 
						|
BotStopMoving( what )
 | 
						|
{
 | 
						|
	self.bot.stop_move = what;
 | 
						|
 | 
						|
	if ( what )
 | 
						|
		self notify( "kill_goal" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Notify the bot chat message
 | 
						|
*/
 | 
						|
BotNotifyBotEvent( msg, a, b, c, d, e, f, g )
 | 
						|
{
 | 
						|
	self notify( "bot_event", msg, a, b, c, d, e, f, g );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot has a script goal.
 | 
						|
	(like t5 gsc bot)
 | 
						|
*/
 | 
						|
HasScriptGoal()
 | 
						|
{
 | 
						|
	return ( isDefined( self GetScriptGoal() ) );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the pos of the bot's goal
 | 
						|
*/
 | 
						|
GetScriptGoal()
 | 
						|
{
 | 
						|
	return self.bot.script_goal;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Sets the bot's goal, will acheive it when dist away from it.
 | 
						|
*/
 | 
						|
SetScriptGoal( goal, dist )
 | 
						|
{
 | 
						|
	if ( !isDefined( dist ) )
 | 
						|
		dist = 16;
 | 
						|
 | 
						|
	self.bot.script_goal = goal;
 | 
						|
	self.bot.script_goal_dist = dist;
 | 
						|
	waittillframeend;
 | 
						|
	self notify( "new_goal_internal" );
 | 
						|
	self notify( "new_goal" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Clears the bot's goal.
 | 
						|
*/
 | 
						|
ClearScriptGoal()
 | 
						|
{
 | 
						|
	self SetScriptGoal( undefined, 0 );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Sets the aim position of the bot
 | 
						|
*/
 | 
						|
SetScriptAimPos( pos )
 | 
						|
{
 | 
						|
	self.bot.script_aimpos = pos;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Clears the aim position of the bot
 | 
						|
*/
 | 
						|
ClearScriptAimPos()
 | 
						|
{
 | 
						|
	self SetScriptAimPos( undefined );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the aim position of the bot
 | 
						|
*/
 | 
						|
GetScriptAimPos()
 | 
						|
{
 | 
						|
	return self.bot.script_aimpos;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot has a aim pos
 | 
						|
*/
 | 
						|
HasScriptAimPos()
 | 
						|
{
 | 
						|
	return isDefined( self GetScriptAimPos() );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Sets the bot's target to be this ent.
 | 
						|
*/
 | 
						|
SetAttacker( att )
 | 
						|
{
 | 
						|
	self.bot.target_this_frame = att;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Sets the script enemy for a bot.
 | 
						|
*/
 | 
						|
SetScriptEnemy( enemy, offset )
 | 
						|
{
 | 
						|
	self.bot.script_target = enemy;
 | 
						|
	self.bot.script_target_offset = offset;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Removes the script enemy of the bot.
 | 
						|
*/
 | 
						|
ClearScriptEnemy()
 | 
						|
{
 | 
						|
	self SetScriptEnemy( undefined, undefined );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the entity of the bot's target.
 | 
						|
*/
 | 
						|
GetThreat()
 | 
						|
{
 | 
						|
	if ( !isdefined( self.bot.target ) )
 | 
						|
		return undefined;
 | 
						|
 | 
						|
	return self.bot.target.entity;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot has a script enemy.
 | 
						|
*/
 | 
						|
HasScriptEnemy()
 | 
						|
{
 | 
						|
	return ( isDefined( self.bot.script_target ) );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the bot has a threat.
 | 
						|
*/
 | 
						|
HasThreat()
 | 
						|
{
 | 
						|
	return ( isDefined( self GetThreat() ) );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns a valid grenade launcher weapon
 | 
						|
*/
 | 
						|
getValidTube()
 | 
						|
{
 | 
						|
	weaps = self getweaponslist();
 | 
						|
 | 
						|
	for ( i = 0; i < weaps.size; i++ )
 | 
						|
	{
 | 
						|
		weap = weaps[i];
 | 
						|
 | 
						|
		if ( !self getAmmoCount( weap ) )
 | 
						|
			continue;
 | 
						|
 | 
						|
		if ( isSubStr( weap, "gl_" ) && !isSubStr( weap, "_gl_" ) )
 | 
						|
			return weap;
 | 
						|
	}
 | 
						|
 | 
						|
	return undefined;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns a random grenade in the bot's inventory.
 | 
						|
*/
 | 
						|
getValidGrenade()
 | 
						|
{
 | 
						|
	grenadeTypes = [];
 | 
						|
	grenadeTypes[grenadeTypes.size] = "frag_grenade_mp";
 | 
						|
	grenadeTypes[grenadeTypes.size] = "molotov_mp";
 | 
						|
	grenadeTypes[grenadeTypes.size] = "m8_white_smoke_mp";
 | 
						|
	grenadeTypes[grenadeTypes.size] = "tabun_gas_mp";
 | 
						|
	grenadeTypes[grenadeTypes.size] = "sticky_grenade_mp";
 | 
						|
	grenadeTypes[grenadeTypes.size] = "signal_flare_mp";
 | 
						|
 | 
						|
	possibles = [];
 | 
						|
 | 
						|
	for ( i = 0; i < grenadeTypes.size; i++ )
 | 
						|
	{
 | 
						|
		if ( !self hasWeapon( grenadeTypes[i] ) )
 | 
						|
			continue;
 | 
						|
 | 
						|
		if ( !self getAmmoCount( grenadeTypes[i] ) )
 | 
						|
			continue;
 | 
						|
 | 
						|
		possibles[possibles.size] = grenadeTypes[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return PickRandom( possibles );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Picks a random thing
 | 
						|
*/
 | 
						|
PickRandom( arr )
 | 
						|
{
 | 
						|
	if ( !arr.size )
 | 
						|
		return undefined;
 | 
						|
 | 
						|
	return arr[randomInt( arr.size )];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	If weap is a secondary gnade
 | 
						|
*/
 | 
						|
isSecondaryGrenade( gnade )
 | 
						|
{
 | 
						|
	return ( gnade == "tabun_gas_mp" || gnade == "m8_white_smoke_mp" || gnade == "signal_flare_mp" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	CoD4
 | 
						|
*/
 | 
						|
getBaseWeaponName( weap )
 | 
						|
{
 | 
						|
	return strtok( weap, "_" )[0];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns if the given weapon is full auto.
 | 
						|
*/
 | 
						|
WeaponIsFullAuto( weap )
 | 
						|
{
 | 
						|
	weaptoks = strtok( weap, "_" );
 | 
						|
 | 
						|
	return isDefined( weaptoks[0] ) && isString( weaptoks[0] ) && isdefined( level.bots_fullautoguns[weaptoks[0]] );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns what our eye height is.
 | 
						|
*/
 | 
						|
GetEyeHeight()
 | 
						|
{
 | 
						|
	myEye = self GetEyePos();
 | 
						|
 | 
						|
	return myEye[2] - self.origin[2];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns (iw4) eye pos.
 | 
						|
*/
 | 
						|
GetEyePos()
 | 
						|
{
 | 
						|
	return self getTagOrigin( "tag_eye" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	helper
 | 
						|
*/
 | 
						|
waittill_either_return_( str1, str2 )
 | 
						|
{
 | 
						|
	self endon( str1 );
 | 
						|
	self waittill( str2 );
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns which string gets notified first
 | 
						|
*/
 | 
						|
waittill_either_return( str1, str2 )
 | 
						|
{
 | 
						|
	if ( !isDefined( self waittill_either_return_( str1, str2 ) ) )
 | 
						|
		return str1;
 | 
						|
 | 
						|
	return str2;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Taken from iw4 script
 | 
						|
*/
 | 
						|
waittill_any_timeout( timeOut, string1, string2, string3, string4, string5 )
 | 
						|
{
 | 
						|
	if ( ( !isdefined( string1 ) || string1 != "death" ) &&
 | 
						|
	    ( !isdefined( string2 ) || string2 != "death" ) &&
 | 
						|
	    ( !isdefined( string3 ) || string3 != "death" ) &&
 | 
						|
	    ( !isdefined( string4 ) || string4 != "death" ) &&
 | 
						|
	    ( !isdefined( string5 ) || string5 != "death" ) )
 | 
						|
		self endon( "death" );
 | 
						|
 | 
						|
	ent = spawnstruct();
 | 
						|
 | 
						|
	if ( isdefined( string1 ) )
 | 
						|
		self thread waittill_string( string1, ent );
 | 
						|
 | 
						|
	if ( isdefined( string2 ) )
 | 
						|
		self thread waittill_string( string2, ent );
 | 
						|
 | 
						|
	if ( isdefined( string3 ) )
 | 
						|
		self thread waittill_string( string3, ent );
 | 
						|
 | 
						|
	if ( isdefined( string4 ) )
 | 
						|
		self thread waittill_string( string4, ent );
 | 
						|
 | 
						|
	if ( isdefined( string5 ) )
 | 
						|
		self thread waittill_string( string5, ent );
 | 
						|
 | 
						|
	ent thread _timeout( timeOut );
 | 
						|
 | 
						|
	ent waittill( "returned", msg );
 | 
						|
	ent notify( "die" );
 | 
						|
	return msg;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Used for waittill_any_timeout
 | 
						|
*/
 | 
						|
_timeout( delay )
 | 
						|
{
 | 
						|
	self endon( "die" );
 | 
						|
 | 
						|
	wait( delay );
 | 
						|
	self notify( "returned", "timeout" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Gets a player who is host
 | 
						|
*/
 | 
						|
GetHostPlayer()
 | 
						|
{
 | 
						|
	for ( i = 0; i < level.players.size; i++ )
 | 
						|
	{
 | 
						|
		player = level.players[i];
 | 
						|
 | 
						|
		if ( !player is_host() )
 | 
						|
			continue;
 | 
						|
 | 
						|
		return player;
 | 
						|
	}
 | 
						|
 | 
						|
	return undefined;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
    Waits for a host player
 | 
						|
*/
 | 
						|
bot_wait_for_host()
 | 
						|
{
 | 
						|
	host = undefined;
 | 
						|
 | 
						|
	while ( !isDefined( level ) || !isDefined( level.players ) )
 | 
						|
		wait 0.05;
 | 
						|
 | 
						|
	for ( i = getDvarFloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 )
 | 
						|
	{
 | 
						|
		host = GetHostPlayer();
 | 
						|
 | 
						|
		if ( isDefined( host ) )
 | 
						|
			break;
 | 
						|
 | 
						|
		wait 0.05;
 | 
						|
	}
 | 
						|
 | 
						|
	if ( !isDefined( host ) )
 | 
						|
		return;
 | 
						|
 | 
						|
	for ( i = getDvarFloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 )
 | 
						|
	{
 | 
						|
		if ( IsDefined( host.pers[ "team" ] ) )
 | 
						|
			break;
 | 
						|
 | 
						|
		wait 0.05;
 | 
						|
	}
 | 
						|
 | 
						|
	if ( !IsDefined( host.pers[ "team" ] ) )
 | 
						|
		return;
 | 
						|
 | 
						|
	for ( i = getDvarFloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 )
 | 
						|
	{
 | 
						|
		if ( host.pers[ "team" ] == "allies" || host.pers[ "team" ] == "axis" )
 | 
						|
			break;
 | 
						|
 | 
						|
		wait 0.05;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the cone dot (like fov, or distance from the center of our screen). 1.0 = directly looking at, 0.0 = completely right angle, -1.0, completely 180
 | 
						|
*/
 | 
						|
getConeDot( to, from, dir )
 | 
						|
{
 | 
						|
	dirToTarget = VectorNormalize( to - from );
 | 
						|
	forward = AnglesToForward( dir );
 | 
						|
	return vectordot( dirToTarget, forward );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the distance squared in a 2d space
 | 
						|
*/
 | 
						|
DistanceSquared2D( to, from )
 | 
						|
{
 | 
						|
	to = ( to[0], to[1], 0 );
 | 
						|
	from = ( from[0], from[1], 0 );
 | 
						|
 | 
						|
	return DistanceSquared( to, from );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Rounds to the nearest whole number.
 | 
						|
*/
 | 
						|
Round( x )
 | 
						|
{
 | 
						|
	y = int( x );
 | 
						|
 | 
						|
	if ( abs( x ) - abs( y ) > 0.5 )
 | 
						|
	{
 | 
						|
		if ( x < 0 )
 | 
						|
			return y - 1;
 | 
						|
		else
 | 
						|
			return y + 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		return y;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Rounds up the given value.
 | 
						|
*/
 | 
						|
RoundUp( floatVal )
 | 
						|
{
 | 
						|
	i = int( floatVal );
 | 
						|
 | 
						|
	if ( i != floatVal )
 | 
						|
		return i + 1;
 | 
						|
	else
 | 
						|
		return i;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Clamps between value
 | 
						|
*/
 | 
						|
Clamp( a, minv, maxv )
 | 
						|
{
 | 
						|
	return max( min( a, maxv ), minv );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	converts a string into a float
 | 
						|
*/
 | 
						|
float( num )
 | 
						|
{
 | 
						|
	setdvar( "temp_dvar_bot_util", num );
 | 
						|
 | 
						|
	return GetDvarFloat( "temp_dvar_bot_util" );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Tokenizes a string (strtok has limits...) (only one char tok)
 | 
						|
*/
 | 
						|
tokenizeLine( line, tok )
 | 
						|
{
 | 
						|
	tokens = [];
 | 
						|
 | 
						|
	token = "";
 | 
						|
 | 
						|
	for ( i = 0; i < line.size; i++ )
 | 
						|
	{
 | 
						|
		c = line[i];
 | 
						|
 | 
						|
		if ( c == tok )
 | 
						|
		{
 | 
						|
			tokens[tokens.size] = token;
 | 
						|
			token = "";
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		token += c;
 | 
						|
	}
 | 
						|
 | 
						|
	tokens[tokens.size] = token;
 | 
						|
 | 
						|
	return tokens;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Parses tokens into a waypoint obj
 | 
						|
*/
 | 
						|
parseTokensIntoWaypoint( tokens )
 | 
						|
{
 | 
						|
	waypoint = spawnStruct();
 | 
						|
 | 
						|
	orgStr = tokens[0];
 | 
						|
	orgToks = strtok( orgStr, " " );
 | 
						|
	waypoint.origin = ( float( orgToks[0] ), float( orgToks[1] ), float( orgToks[2] ) );
 | 
						|
 | 
						|
	childStr = tokens[1];
 | 
						|
	childToks = strtok( childStr, " " );
 | 
						|
	waypoint.children = [];
 | 
						|
 | 
						|
	for ( j = 0; j < childToks.size; j++ )
 | 
						|
		waypoint.children[j] = int( childToks[j] );
 | 
						|
 | 
						|
	type = tokens[2];
 | 
						|
	waypoint.type = type;
 | 
						|
 | 
						|
	anglesStr = tokens[3];
 | 
						|
 | 
						|
	if ( isDefined( anglesStr ) && anglesStr != "" )
 | 
						|
	{
 | 
						|
		anglesToks = strtok( anglesStr, " " );
 | 
						|
		waypoint.angles = ( float( anglesToks[0] ), float( anglesToks[1] ), float( anglesToks[2] ) );
 | 
						|
	}
 | 
						|
 | 
						|
	return waypoint;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns an array of each line
 | 
						|
*/
 | 
						|
getWaypointLinesFromFile( filename )
 | 
						|
{
 | 
						|
	result = spawnStruct();
 | 
						|
	result.lines = [];
 | 
						|
 | 
						|
	waypointStr = fileRead( filename );
 | 
						|
 | 
						|
	if ( !isDefined( waypointStr ) )
 | 
						|
		return result;
 | 
						|
 | 
						|
	line = "";
 | 
						|
 | 
						|
	for ( i = 0; i < waypointStr.size; i++ )
 | 
						|
	{
 | 
						|
		c = waypointStr[i];
 | 
						|
 | 
						|
		if ( c == "\n" )
 | 
						|
		{
 | 
						|
			result.lines[result.lines.size] = line;
 | 
						|
 | 
						|
			line = "";
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		line += c;
 | 
						|
	}
 | 
						|
 | 
						|
	result.lines[result.lines.size] = line;
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Read from file a csv, and returns an array of waypoints
 | 
						|
*/
 | 
						|
readWpsFromFile( mapname )
 | 
						|
{
 | 
						|
	waypoints = [];
 | 
						|
	filename = "waypoints/" + mapname + "_wp.csv";
 | 
						|
 | 
						|
	res = getWaypointLinesFromFile( filename );
 | 
						|
 | 
						|
	if ( !res.lines.size )
 | 
						|
		return waypoints;
 | 
						|
 | 
						|
	PrintConsole( "Attempting to read waypoints from " + filename + "\n" );
 | 
						|
 | 
						|
	waypointCount = int( res.lines[0] );
 | 
						|
 | 
						|
	for ( i = 1; i <= waypointCount; i++ )
 | 
						|
	{
 | 
						|
		tokens = tokenizeLine( res.lines[i], "," );
 | 
						|
 | 
						|
		waypoint = parseTokensIntoWaypoint( tokens );
 | 
						|
 | 
						|
		waypoints[i - 1] = waypoint;
 | 
						|
	}
 | 
						|
 | 
						|
	return waypoints;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Loads the waypoints. Populating everything needed for the waypoints.
 | 
						|
*/
 | 
						|
load_waypoints()
 | 
						|
{
 | 
						|
	mapname = getDvar( "mapname" );
 | 
						|
 | 
						|
	level.waypointCount = 0;
 | 
						|
	level.waypoints = [];
 | 
						|
 | 
						|
	wps = readWpsFromFile( mapname );
 | 
						|
 | 
						|
	if ( wps.size )
 | 
						|
	{
 | 
						|
		level.waypoints = wps;
 | 
						|
		PrintConsole( "Loaded " + wps.size + " waypoints from file.\n" );
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if ( level.waypoints.size )
 | 
						|
			PrintConsole( "Loaded " + level.waypoints.size + " waypoints from script.\n" );
 | 
						|
	}
 | 
						|
 | 
						|
	level.waypointCount = level.waypoints.size;
 | 
						|
 | 
						|
	for ( i = 0; i < level.waypointCount; i++ )
 | 
						|
	{
 | 
						|
		if ( !isDefined( level.waypoints[i].children ) || !isDefined( level.waypoints[i].children.size ) )
 | 
						|
			level.waypoints[i].children = [];
 | 
						|
 | 
						|
		if ( !isDefined( level.waypoints[i].origin ) )
 | 
						|
			level.waypoints[i].origin = ( 0, 0, 0 );
 | 
						|
 | 
						|
		if ( !isDefined( level.waypoints[i].type ) )
 | 
						|
			level.waypoints[i].type = "crouch";
 | 
						|
 | 
						|
		level.waypoints[i].childCount = undefined;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Is bot near any of the given waypoints
 | 
						|
*/
 | 
						|
nearAnyOfWaypoints( dist, waypoints )
 | 
						|
{
 | 
						|
	dist *= dist;
 | 
						|
 | 
						|
	for ( i = 0; i < waypoints.size; i++ )
 | 
						|
	{
 | 
						|
		waypoint = level.waypoints[waypoints[i]];
 | 
						|
 | 
						|
		if ( DistanceSquared( waypoint.origin, self.origin ) > dist )
 | 
						|
			continue;
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the waypoints that are near
 | 
						|
*/
 | 
						|
waypointsNear( waypoints, dist )
 | 
						|
{
 | 
						|
	dist *= dist;
 | 
						|
 | 
						|
	answer = [];
 | 
						|
 | 
						|
	for ( i = 0; i < waypoints.size; i++ )
 | 
						|
	{
 | 
						|
		wp = level.waypoints[waypoints[i]];
 | 
						|
 | 
						|
		if ( DistanceSquared( wp.origin, self.origin ) > dist )
 | 
						|
			continue;
 | 
						|
 | 
						|
		answer[answer.size] = waypoints[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return answer;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns nearest waypoint of waypoints
 | 
						|
*/
 | 
						|
getNearestWaypointOfWaypoints( waypoints )
 | 
						|
{
 | 
						|
	answer = undefined;
 | 
						|
	closestDist = 2147483647;
 | 
						|
 | 
						|
	for ( i = 0; i < waypoints.size; i++ )
 | 
						|
	{
 | 
						|
		waypoint = level.waypoints[waypoints[i]];
 | 
						|
		thisDist = DistanceSquared( self.origin, waypoint.origin );
 | 
						|
 | 
						|
		if ( isDefined( answer ) && thisDist > closestDist )
 | 
						|
			continue;
 | 
						|
 | 
						|
		answer = waypoints[i];
 | 
						|
		closestDist = thisDist;
 | 
						|
	}
 | 
						|
 | 
						|
	return answer;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns all waypoints of type
 | 
						|
*/
 | 
						|
getWaypointsOfType( type )
 | 
						|
{
 | 
						|
	answer = [];
 | 
						|
 | 
						|
	for ( i = 0; i < level.waypointCount; i++ )
 | 
						|
	{
 | 
						|
		wp = level.waypoints[i];
 | 
						|
 | 
						|
		if ( type == "camp" )
 | 
						|
		{
 | 
						|
			if ( wp.type != "crouch" )
 | 
						|
				continue;
 | 
						|
 | 
						|
			if ( wp.children.size != 1 )
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
		else if ( type != wp.type )
 | 
						|
			continue;
 | 
						|
 | 
						|
		answer[answer.size] = i;
 | 
						|
	}
 | 
						|
 | 
						|
	return answer;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the waypoint for index
 | 
						|
*/
 | 
						|
getWaypointForIndex( i )
 | 
						|
{
 | 
						|
	if ( !isDefined( i ) )
 | 
						|
		return undefined;
 | 
						|
 | 
						|
	return level.waypoints[i];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns a good amount of players.
 | 
						|
*/
 | 
						|
getGoodMapAmount()
 | 
						|
{
 | 
						|
	return 2;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the friendly user name for a given map's codename
 | 
						|
*/
 | 
						|
getMapName( map )
 | 
						|
{
 | 
						|
	return map;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns an array of all the bots in the game.
 | 
						|
*/
 | 
						|
getBotArray()
 | 
						|
{
 | 
						|
	result = [];
 | 
						|
	playercount = level.players.size;
 | 
						|
 | 
						|
	for ( i = 0; i < playercount; i++ )
 | 
						|
	{
 | 
						|
		player = level.players[i];
 | 
						|
 | 
						|
		if ( !player is_bot() )
 | 
						|
			continue;
 | 
						|
 | 
						|
		result[result.size] = player;
 | 
						|
	}
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	A heap invarient comparitor, used for numbers, numbers with the highest number will be first in the heap.
 | 
						|
*/
 | 
						|
Heap( item, item2 )
 | 
						|
{
 | 
						|
	return item > item2;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	A heap invarient comparitor, used for numbers, numbers with the lowest number will be first in the heap.
 | 
						|
*/
 | 
						|
ReverseHeap( item, item2 )
 | 
						|
{
 | 
						|
	return item < item2;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	A heap invarient comparitor, used for traces. Wanting the trace with the largest length first in the heap.
 | 
						|
*/
 | 
						|
HeapTraceFraction( item, item2 )
 | 
						|
{
 | 
						|
	return item["fraction"] > item2["fraction"];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns a new heap.
 | 
						|
*/
 | 
						|
NewHeap( compare )
 | 
						|
{
 | 
						|
	heap_node = spawnStruct();
 | 
						|
	heap_node.data = [];
 | 
						|
	heap_node.compare = compare;
 | 
						|
 | 
						|
	return heap_node;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Inserts the item into the heap. Called on a heap.
 | 
						|
*/
 | 
						|
HeapInsert( item )
 | 
						|
{
 | 
						|
	insert = self.data.size;
 | 
						|
	self.data[insert] = item;
 | 
						|
 | 
						|
	current = insert + 1;
 | 
						|
 | 
						|
	while ( current > 1 )
 | 
						|
	{
 | 
						|
		last = current;
 | 
						|
		current = int( current / 2 );
 | 
						|
 | 
						|
		if ( ![[self.compare]]( item, self.data[current - 1] ) )
 | 
						|
			break;
 | 
						|
 | 
						|
		self.data[last - 1] = self.data[current - 1];
 | 
						|
		self.data[current - 1] = item;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Helper function to determine what is the next child of the bst.
 | 
						|
*/
 | 
						|
_HeapNextChild( node, hsize )
 | 
						|
{
 | 
						|
	left = node * 2;
 | 
						|
	right = left + 1;
 | 
						|
 | 
						|
	if ( left > hsize )
 | 
						|
		return -1;
 | 
						|
 | 
						|
	if ( right > hsize )
 | 
						|
		return left;
 | 
						|
 | 
						|
	if ( [[self.compare]]( self.data[left - 1], self.data[right - 1] ) )
 | 
						|
		return left;
 | 
						|
	else
 | 
						|
		return right;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Removes an item from the heap. Called on a heap.
 | 
						|
*/
 | 
						|
HeapRemove()
 | 
						|
{
 | 
						|
	remove = self.data.size;
 | 
						|
 | 
						|
	if ( !remove )
 | 
						|
		return remove;
 | 
						|
 | 
						|
	move = self.data[remove - 1];
 | 
						|
	self.data[0] = move;
 | 
						|
	self.data[remove - 1] = undefined;
 | 
						|
	remove--;
 | 
						|
 | 
						|
	if ( !remove )
 | 
						|
		return remove;
 | 
						|
 | 
						|
	last = 1;
 | 
						|
	next = self _HeapNextChild( 1, remove );
 | 
						|
 | 
						|
	while ( next != -1 )
 | 
						|
	{
 | 
						|
		if ( [[self.compare]]( move, self.data[next - 1] ) )
 | 
						|
			break;
 | 
						|
 | 
						|
		self.data[last - 1] = self.data[next - 1];
 | 
						|
		self.data[next - 1] = move;
 | 
						|
 | 
						|
		last = next;
 | 
						|
		next = self _HeapNextChild( next, remove );
 | 
						|
	}
 | 
						|
 | 
						|
	return remove;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	A heap invarient comparitor, used for the astar's nodes, wanting the node with the lowest f to be first in the heap.
 | 
						|
*/
 | 
						|
ReverseHeapAStar( item, item2 )
 | 
						|
{
 | 
						|
	return item.f < item2.f;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Will linearly search for the nearest waypoint to pos that has a direct line of sight.
 | 
						|
*/
 | 
						|
GetNearestWaypointWithSight( pos )
 | 
						|
{
 | 
						|
	candidate = undefined;
 | 
						|
	dist = 2147483647;
 | 
						|
 | 
						|
	for ( i = 0; i < level.waypointCount; i++ )
 | 
						|
	{
 | 
						|
		if ( !bulletTracePassed( pos + ( 0, 0, 15 ), level.waypoints[i].origin + ( 0, 0, 15 ), false, undefined ) )
 | 
						|
			continue;
 | 
						|
 | 
						|
		curdis = DistanceSquared( level.waypoints[i].origin, pos );
 | 
						|
 | 
						|
		if ( curdis > dist )
 | 
						|
			continue;
 | 
						|
 | 
						|
		dist = curdis;
 | 
						|
		candidate = i;
 | 
						|
	}
 | 
						|
 | 
						|
	return candidate;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Will linearly search for the nearest waypoint
 | 
						|
*/
 | 
						|
GetNearestWaypoint( pos )
 | 
						|
{
 | 
						|
	candidate = undefined;
 | 
						|
	dist = 2147483647;
 | 
						|
 | 
						|
	for ( i = 0; i < level.waypointCount; i++ )
 | 
						|
	{
 | 
						|
		curdis = DistanceSquared( level.waypoints[i].origin, pos );
 | 
						|
 | 
						|
		if ( curdis > dist )
 | 
						|
			continue;
 | 
						|
 | 
						|
		dist = curdis;
 | 
						|
		candidate = i;
 | 
						|
	}
 | 
						|
 | 
						|
	return candidate;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Modified Pezbot astar search.
 | 
						|
	This makes use of sets for quick look up and a heap for a priority queue instead of simple lists which require to linearly search for elements everytime.
 | 
						|
	It is also modified to make paths with bots already on more expensive and will try a less congested path first. Thus spliting up the bots onto more paths instead of just one (the smallest).
 | 
						|
*/
 | 
						|
AStarSearch( start, goal, team, greedy_path )
 | 
						|
{
 | 
						|
	open = NewHeap( ::ReverseHeapAStar ); //heap
 | 
						|
	openset = [];//set for quick lookup
 | 
						|
	closed = [];//set for quick lookup
 | 
						|
 | 
						|
 | 
						|
	startWp = getNearestWaypoint( start );
 | 
						|
 | 
						|
	if ( !isDefined( startWp ) )
 | 
						|
		return [];
 | 
						|
 | 
						|
	_startwp = undefined;
 | 
						|
 | 
						|
	if ( !bulletTracePassed( start + ( 0, 0, 15 ), level.waypoints[startWp].origin + ( 0, 0, 15 ), false, undefined ) )
 | 
						|
		_startwp = GetNearestWaypointWithSight( start );
 | 
						|
 | 
						|
	if ( isDefined( _startwp ) )
 | 
						|
		startWp = _startwp;
 | 
						|
 | 
						|
 | 
						|
	goalWp = getNearestWaypoint( goal );
 | 
						|
 | 
						|
	if ( !isDefined( goalWp ) )
 | 
						|
		return [];
 | 
						|
 | 
						|
	_goalWp = undefined;
 | 
						|
 | 
						|
	if ( !bulletTracePassed( goal + ( 0, 0, 15 ), level.waypoints[goalWp].origin + ( 0, 0, 15 ), false, undefined ) )
 | 
						|
		_goalwp = GetNearestWaypointWithSight( goal );
 | 
						|
 | 
						|
	if ( isDefined( _goalwp ) )
 | 
						|
		goalWp = _goalwp;
 | 
						|
 | 
						|
 | 
						|
	node = spawnStruct();
 | 
						|
	node.g = 0; //path dist so far
 | 
						|
	node.h = DistanceSquared( level.waypoints[startWp].origin, level.waypoints[goalWp].origin ); //herustic, distance to goal for path finding
 | 
						|
	node.f = node.h + node.g; // combine path dist and heru, use reverse heap to sort the priority queue by this attru
 | 
						|
	node.index = startWp;
 | 
						|
	node.parent = undefined; //we are start, so we have no parent
 | 
						|
 | 
						|
	//push node onto queue
 | 
						|
	openset[node.index + ""] = node;
 | 
						|
	open HeapInsert( node );
 | 
						|
 | 
						|
	//while the queue is not empty
 | 
						|
	while ( open.data.size )
 | 
						|
	{
 | 
						|
		//pop bestnode from queue
 | 
						|
		bestNode = open.data[0];
 | 
						|
		open HeapRemove();
 | 
						|
		openset[bestNode.index + ""] = undefined;
 | 
						|
		wp = level.waypoints[bestNode.index];
 | 
						|
 | 
						|
		//check if we made it to the goal
 | 
						|
		if ( bestNode.index == goalWp )
 | 
						|
		{
 | 
						|
			path = [];
 | 
						|
 | 
						|
			while ( isDefined( bestNode ) )
 | 
						|
			{
 | 
						|
				//construct path
 | 
						|
				path[path.size] = bestNode.index;
 | 
						|
 | 
						|
				bestNode = bestNode.parent;
 | 
						|
			}
 | 
						|
 | 
						|
			return path;
 | 
						|
		}
 | 
						|
 | 
						|
		//for each child of bestnode
 | 
						|
		for ( i = wp.children.size - 1; i >= 0; i-- )
 | 
						|
		{
 | 
						|
			child = wp.children[i];
 | 
						|
			childWp = level.waypoints[child];
 | 
						|
 | 
						|
			penalty = 1;
 | 
						|
 | 
						|
			// have certain types of nodes more expensive
 | 
						|
			if ( childWp.type == "climb" || childWp.type == "prone" )
 | 
						|
				penalty += 4;
 | 
						|
 | 
						|
			//calc the total path we have took
 | 
						|
			newg = bestNode.g + DistanceSquared( wp.origin, childWp.origin ) * penalty; //bots on same team's path are more expensive
 | 
						|
 | 
						|
			//check if this child is in open or close with a g value less than newg
 | 
						|
			inopen = isDefined( openset[child + ""] );
 | 
						|
 | 
						|
			if ( inopen && openset[child + ""].g <= newg )
 | 
						|
				continue;
 | 
						|
 | 
						|
			inclosed = isDefined( closed[child + ""] );
 | 
						|
 | 
						|
			if ( inclosed && closed[child + ""].g <= newg )
 | 
						|
				continue;
 | 
						|
 | 
						|
			node = undefined;
 | 
						|
 | 
						|
			if ( inopen )
 | 
						|
				node = openset[child + ""];
 | 
						|
			else if ( inclosed )
 | 
						|
				node = closed[child + ""];
 | 
						|
			else
 | 
						|
				node = spawnStruct();
 | 
						|
 | 
						|
			node.parent = bestNode;
 | 
						|
			node.g = newg;
 | 
						|
			node.h = DistanceSquared( childWp.origin, level.waypoints[goalWp].origin );
 | 
						|
			node.f = node.g + node.h;
 | 
						|
			node.index = child;
 | 
						|
 | 
						|
			//check if in closed, remove it
 | 
						|
			if ( inclosed )
 | 
						|
				closed[child + ""] = undefined;
 | 
						|
 | 
						|
			//check if not in open, add it
 | 
						|
			if ( !inopen )
 | 
						|
			{
 | 
						|
				open HeapInsert( node );
 | 
						|
				openset[child + ""] = node;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		//done with children, push onto closed
 | 
						|
		closed[bestNode.index + ""] = bestNode;
 | 
						|
	}
 | 
						|
 | 
						|
	return [];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Returns the natural log of x using harmonic series.
 | 
						|
*/
 | 
						|
Log( x )
 | 
						|
{
 | 
						|
	/*  if (!isDefined(level.log_cache))
 | 
						|
		level.log_cache = [];
 | 
						|
 | 
						|
	    key = x + "";
 | 
						|
 | 
						|
	    if (isDefined(level.log_cache[key]))
 | 
						|
		return level.log_cache[key];*/
 | 
						|
 | 
						|
	//thanks Bob__ at stackoverflow
 | 
						|
	old_sum = 0.0;
 | 
						|
	xmlxpl = ( x - 1 ) / ( x + 1 );
 | 
						|
	xmlxpl_2 = xmlxpl * xmlxpl;
 | 
						|
	denom = 1.0;
 | 
						|
	frac = xmlxpl;
 | 
						|
	sum = frac;
 | 
						|
 | 
						|
	while ( sum != old_sum )
 | 
						|
	{
 | 
						|
		old_sum = sum;
 | 
						|
		denom += 2.0;
 | 
						|
		frac *= xmlxpl_2;
 | 
						|
		sum += frac / denom;
 | 
						|
	}
 | 
						|
 | 
						|
	answer = 2.0 * sum;
 | 
						|
 | 
						|
	//level.log_cache[key] = answer;
 | 
						|
	return answer;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Taken from t5 gsc.
 | 
						|
	Returns an array of number's average.
 | 
						|
*/
 | 
						|
array_average( array )
 | 
						|
{
 | 
						|
	assert( array.size > 0 );
 | 
						|
	total = 0;
 | 
						|
 | 
						|
	for ( i = 0; i < array.size; i++ )
 | 
						|
	{
 | 
						|
		total += array[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return ( total / array.size );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Taken from t5 gsc.
 | 
						|
	Returns an array of number's standard deviation.
 | 
						|
*/
 | 
						|
array_std_deviation( array, mean )
 | 
						|
{
 | 
						|
	assert( array.size > 0 );
 | 
						|
	tmp = [];
 | 
						|
 | 
						|
	for ( i = 0; i < array.size; i++ )
 | 
						|
	{
 | 
						|
		tmp[i] = ( array[i] - mean ) * ( array[i] - mean );
 | 
						|
	}
 | 
						|
 | 
						|
	total = 0;
 | 
						|
 | 
						|
	for ( i = 0; i < tmp.size; i++ )
 | 
						|
	{
 | 
						|
		total = total + tmp[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return Sqrt( total / array.size );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	Taken from t5 gsc.
 | 
						|
	Will produce a random number between lower_bound and upper_bound but with a bell curve distribution (more likely to be close to the mean).
 | 
						|
*/
 | 
						|
random_normal_distribution( mean, std_deviation, lower_bound, upper_bound )
 | 
						|
{
 | 
						|
	x1 = 0;
 | 
						|
	x2 = 0;
 | 
						|
	w = 1;
 | 
						|
	y1 = 0;
 | 
						|
 | 
						|
	while ( w >= 1 )
 | 
						|
	{
 | 
						|
		x1 = 2 * RandomFloatRange( 0, 1 ) - 1;
 | 
						|
		x2 = 2 * RandomFloatRange( 0, 1 ) - 1;
 | 
						|
		w = x1 * x1 + x2 * x2;
 | 
						|
	}
 | 
						|
 | 
						|
	w = Sqrt( ( -2.0 * Log( w ) ) / w );
 | 
						|
	y1 = x1 * w;
 | 
						|
	number = mean + y1 * std_deviation;
 | 
						|
 | 
						|
	if ( IsDefined( lower_bound ) && number < lower_bound )
 | 
						|
	{
 | 
						|
		number = lower_bound;
 | 
						|
	}
 | 
						|
 | 
						|
	if ( IsDefined( upper_bound ) && number > upper_bound )
 | 
						|
	{
 | 
						|
		number = upper_bound;
 | 
						|
	}
 | 
						|
 | 
						|
	return ( number );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	If the player is in laststand
 | 
						|
*/
 | 
						|
inLastStand()
 | 
						|
{
 | 
						|
	return ( isDefined( self.lastStand ) && self.lastStand );
 | 
						|
} |