#using scripts\shared\ai_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\fx_shared;
#using scripts\shared\math_shared;
#using scripts\shared\scene_shared;
#using scripts\shared\spawner_shared;
#using scripts\shared\util_shared;
#using scripts\shared\array_shared;

#using scripts\shared\ai\systems\animation_state_machine_utility;
#using scripts\shared\ai\systems\animation_state_machine_notetracks;
#using scripts\shared\ai\systems\animation_state_machine_mocomp;
#using scripts\shared\ai\archetype_utility;
#using scripts\shared\ai\systems\behavior_tree_utility;
#using scripts\shared\ai\systems\blackboard;
#using scripts\shared\ai\systems\debug;
#using scripts\shared\ai\systems\gib;
#using scripts\shared\ai\margwa;
#using scripts\shared\ai\zombie_utility;
#using scripts\codescripts\struct;
#using scripts\shared\ai\archetype_mocomps_utility;

                                                                                                            	  	  	              	   	                                                                                                                                       	                                                                                                                                                            	                                                                                                                                                                
   	     	                                                                                                                                                                                                                                                                                                                                                                                                                                                             	                                                                                                                	         	    	                                                                                                    
        	                                                                                                                                                	                                                                                                                      	                                                                                     	                                                                                     	                                                            	                                                                                   	                                                                                     	                                                                                               	                                                                                                 	                                                                   	                                                                   	                                                                                                                 	                                                                                                                              	                                                                                                                       	                                                   	                                                                           	                                                                                 	                                       	                             	                                             	                                  	                                                                                 	                                                                                                                                                	      
                                                                                                                                               	
           	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              	  	                                 	                  	    	                                                      	   	        	                                                                         	                      	             	                                                                                                                                       	  	                                                                                                          	     	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                      	                                                                                                     	                                                                                                     	                                                                                                	     	                                                                                                                                                                                                                                                                                                                                                                                                                                	     	    	                                                                                                                                    	                      	              	  	             	  
                                                                                                                                                                                                          	     	                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                   
                                                                  	                             	  	                                      
    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   

#namespace MargwaBehavior;

function autoexec init()
{
	// INIT BEHAVIORS
	InitMargwaBehaviorsAndASM();
	
	// INIT BLACKBOARD	
	spawner::add_archetype_spawn_function( "margwa", &ArchetypeMargwaBlackboardInit );

	// INIT MARGWA ON SPAWN
	spawner::add_archetype_spawn_function( "margwa", &MargwaServerUtils::margwaSpawnSetup );

	clientfield::register( "actor", "margwa_head_left", 1, 2, "int" );
	clientfield::register( "actor", "margwa_head_mid", 1, 2, "int" );
	clientfield::register( "actor", "margwa_head_right", 1, 2, "int" );
	clientfield::register( "actor", "margwa_fx_in", 1, 1, "counter" );
	clientfield::register( "actor", "margwa_fx_out", 1, 1, "counter" );
	clientfield::register( "actor", "margwa_fx_spawn", 1, 1, "counter" );
	clientfield::register( "actor", "margwa_smash", 1, 1, "counter" );
	clientfield::register( "actor", "margwa_head_left_hit", 1, 1, "counter" );
	clientfield::register( "actor", "margwa_head_mid_hit", 1, 1, "counter" );
	clientfield::register( "actor", "margwa_head_right_hit", 1, 1, "counter" );

	clientfield::register( "actor", "margwa_head_killed", 1, 2, "int" );
	clientfield::register( "actor", "margwa_jaw", 1, 6, "int" );

	clientfield::register( "toplayer", "margwa_head_explosion", 1, 1, "counter" );
	clientfield::register( "scriptmover", "margwa_fx_travel", 1, 1, "int" );
	clientfield::register( "scriptmover", "margwa_fx_travel_tell", 1, 1, "int" );

	clientfield::register( "actor", "supermargwa", 1, 1, "int" ); // set this bit when spawning supermargwa for ee quest

	InitDirectHitWeapons();
}

function private InitDirectHitWeapons()
{
	if ( !IsDefined( level.dhWeapons ) )
	{
		level.dhWeapons = [];
	}

	level.dhWeapons[ level.dhWeapons.size ] = "ray_gun";
	level.dhWeapons[ level.dhWeapons.size ] = "ray_gun_upgraded";
	level.dhWeapons[ level.dhWeapons.size ] = "pistol_standard_upgraded";
	level.dhWeapons[ level.dhWeapons.size ] = "pistol_revolver38_upgraded";
	level.dhWeapons[ level.dhWeapons.size ] = "pistol_revolver38lh_upgraded";
	level.dhWeapons[ level.dhWeapons.size ] = "launcher_standard";
	level.dhWeapons[ level.dhWeapons.size ] = "launcher_standard_upgraded";
}

function AddDirectHitWeapon( weaponName )
{
	foreach( weapon in level.dhWeapons )
	{
		if ( weapon == weaponName )
		{
			return;
		}
	}

	level.dhWeapons[ level.dhWeapons.size ] = weaponName;
}

function private InitMargwaBehaviorsAndASM()
{
	// SERVICES
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaTargetService",&MargwaBehavior::margwaTargetService);;

	// CONDITIONS
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldSmashAttack",&MargwaBehavior::margwaShouldSmashAttack);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldSwipeAttack",&MargwaBehavior::margwaShouldSwipeAttack);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldShowPain",&MargwaBehavior::margwaShouldShowPain);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldReactStun",&MargwaBehavior::margwaShouldReactStun);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldReactIDGun",&MargwaBehavior::margwaShouldReactIDGun);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldReactSword",&MargwaBehavior::margwaShouldReactSword);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldSpawn",&MargwaBehavior::margwaShouldSpawn);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldFreeze",&MargwaBehavior::margwaShouldFreeze);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldTeleportIn",&MargwaBehavior::margwaShouldTeleportIn);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldTeleportOut",&MargwaBehavior::margwaShouldTeleportOut);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldWait",&MargwaBehavior::margwaShouldWait);;

	// Consolidated condition checking to limit VM calls
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaShouldReset",&MargwaBehavior::margwaShouldReset);;

	// ACTIONS
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeAction("margwaReactStunAction",&MargwaBehavior::margwaReactStunAction,undefined,undefined);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeAction("margwaSwipeAttackAction",&MargwaBehavior::margwaSwipeAttackAction,&MargwaBehavior::margwaSwipeAttackActionUpdate,undefined);;

	// FUNCTIONS
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaIdleStart",&MargwaBehavior::margwaIdleStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaMoveStart",&MargwaBehavior::margwaMoveStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaTraverseActionStart",&MargwaBehavior::margwaTraverseActionStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaTeleportInStart",&MargwaBehavior::margwaTeleportInStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaTeleportInTerminate",&MargwaBehavior::margwaTeleportInTerminate);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaTeleportOutStart",&MargwaBehavior::margwaTeleportOutStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaTeleportOutTerminate",&MargwaBehavior::margwaTeleportOutTerminate);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaPainStart",&MargwaBehavior::margwaPainStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaPainTerminate",&MargwaBehavior::margwaPainTerminate);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaReactStunStart",&MargwaBehavior::margwaReactStunStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaReactStunTerminate",&MargwaBehavior::margwaReactStunTerminate);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaReactIDGunStart",&MargwaBehavior::margwaReactIDGunStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaReactIDGunTerminate",&MargwaBehavior::margwaReactIDGunTerminate);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaReactSwordStart",&MargwaBehavior::margwaReactSwordStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaReactSwordTerminate",&MargwaBehavior::margwaReactSwordTerminate);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaSpawnStart",&MargwaBehavior::margwaSpawnStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaSmashAttackStart",&MargwaBehavior::margwaSmashAttackStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaSmashAttackTerminate",&MargwaBehavior::margwaSmashAttackTerminate);;

	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaSwipeAttackStart",&MargwaBehavior::margwaSwipeAttackStart);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("margwaSwipeAttackTerminate",&MargwaBehavior::margwaSwipeAttackTerminate);;

	// MOCOMPS
	AnimationStateNetwork::RegisterAnimationMocomp("mocomp_teleport_traversal@margwa",&mocompMargwaTeleportTraversalInit,&mocompMargwaTeleportTraversalUpdate,&mocompMargwaTeleportTraversalTerminate);;

	// NOTETRACKS
	AnimationStateNetwork::RegisterNotetrackHandlerFunction("margwa_smash_attack",&MargwaBehavior::margwaNotetrackSmashAttack);;
	AnimationStateNetwork::RegisterNotetrackHandlerFunction("margwa_bodyfall large",&MargwaBehavior::margwaNotetrackBodyfall);;	
	AnimationStateNetwork::RegisterNotetrackHandlerFunction("margwa_melee_fire",&MargwaBehavior::margwaNotetrackPainMelee);;	
}

function private ArchetypeMargwaBlackboardInit()
{
	// CREATE BLACKBOARD
	Blackboard::CreateBlackBoardForEntity( self );
	
	// USE UTILITY BLACKBOARD
	self AiUtility::RegisterUtilityBlackboardAttributes();
	
	// CREATE MARGWA BLACKBOARD
	Blackboard::RegisterBlackBoardAttribute(self,"_locomotion_speed","locomotion_speed_walk",undefined);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_locomotion_speed");#/    };
	Blackboard::RegisterBlackBoardAttribute(self,"_board_attack_spot",undefined,undefined);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_board_attack_spot");#/    };	
	Blackboard::RegisterBlackBoardAttribute(self,"_locomotion_should_turn","should_not_turn",&BB_GetShouldTurn);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_locomotion_should_turn");#/    };
	Blackboard::RegisterBlackBoardAttribute(self,"_zombie_damageweapon_type","regular",undefined);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_zombie_damageweapon_type");#/    };
	
	// REGISTER ANIMSCRIPTED CALLBACK
	self.___ArchetypeOnAnimscriptedCallback = &ArchetypeMargwaOnAnimscriptedCallback;
	
	// ENABLE DEBUGGING IN ODYSSEY
	/#self FinalizeTrackedBlackboardAttributes();#/;
}

function private ArchetypeMargwaOnAnimscriptedCallback( entity )
{
	// UNREGISTER THE BLACKBOARD
	entity.__blackboard = undefined;
	
	// REREGISTER BLACKBOARD
	entity ArchetypeMargwaBlackboardInit();
}

function private BB_GetShouldTurn()
{
	if( IsDefined( self.should_turn ) && self.should_turn )
	{
		return "should_turn";
	}
	return "should_not_turn";
}

//----------------------------------------------------------------------------------------------------------------------------
// NOTETRACK HANDLERS
//----------------------------------------------------------------------------------------------------------------------------
function private margwaNotetrackSmashAttack( entity )
{
	players = GetPlayers();
	foreach( player in players )
	{
		smashPos = entity.origin + VectorScale( AnglesToForward( self.angles ), 60 );
		distSq = DistanceSquared( smashPos, player.origin );
		if ( distSq < 144 * 144 )
		{
			if ( !IsGodMode( player ) )
			{
				// riot shield can block damage from front or back
				if ( ( isdefined( player.hasRiotShield ) && player.hasRiotShield ) )
				{
					damageShield = false;
					attackDir = player.origin - self.origin;

					if ( ( isdefined( player.hasRiotShieldEquipped ) && player.hasRiotShieldEquipped ) )
					{
						if ( player margwaServerUtils::shieldFacing( attackDir, 0.2 ) )
						{
							damageShield = true;
						}
					}
					else
					{
						if ( player margwaServerUtils::shieldFacing( attackDir, 0.2, false ) )
						{
							damageShield = true;
						}
					}

					if ( damageShield )
					{
						self clientfield::increment( "margwa_smash" );
						shield_damage = level.weaponRiotshield.weaponstarthitpoints;
						if ( IsDefined( player.weaponRiotshield ) )
							shield_damage = player.weaponRiotshield.weaponstarthitpoints;
						player [[ player.player_shield_apply_damage ]]( shield_damage, false );
						continue;
					}
				}
				
				if ( isdefined( level.margwa_smash_damage_callback ) && IsFunctionPtr( level.margwa_smash_damage_callback ) )
				{
					if ( player [[ level.margwa_smash_damage_callback ]]( self ) )
					{
						continue;
					}
				}
				
				self clientfield::increment( "margwa_smash" );
				player DoDamage( 166, self.origin, self );
			}
		}
	}

	if ( IsDefined( self.smashAttackCB ) )
	{
		self [[ self.smashAttackCB ]]();
	}
}

// Fx takes over after margwa hits the ground
function private margwaNotetrackBodyfall( entity )
{
	if( self.archetype == "margwa" )
	{
		entity Ghost();

		if ( IsDefined( self.bodyfallCB ) )
		{
			self [[ self.bodyfallCB ]]();
		}
	}
}

function private margwaNotetrackPainMelee( entity )
{
	entity Melee();
}

//----------------------------------------------------------------------------------------------------------------------------
// BEHAVIOR TREE
//----------------------------------------------------------------------------------------------------------------------------
function private margwaTargetService( entity )
{
	if ( ( isdefined( entity.ignoreall ) && entity.ignoreall ) )
	{
		return false;
	}

	player = zombie_utility::get_closest_valid_player( self.origin, self.ignore_player );

	if( !IsDefined( player ) )
	{
		if( IsDefined( self.ignore_player ) )
		{
			if(isDefined(level._should_skip_ignore_player_logic) && [[level._should_skip_ignore_player_logic]]() )
			{
				return;
			}
			self.ignore_player = [];
		}

		self SetGoal( self.origin );		
		return false;
	}
	else
	{
		targetPos = GetClosestPointOnNavMesh( player.origin, 64, 30 );
		if ( IsDefined( targetPos ) )
		{
			entity SetGoal( targetPos );		
			return true;
		}
		else
		{
			entity SetGoal( entity.origin );
			return false;
		}
	}
}

function margwaShouldSmashAttack( entity )
{
	if( !IsDefined( entity.enemy ) )
    {
		return false;
	}

	if ( !entity MargwaServerUtils::inSmashAttackRange( entity.enemy ) )
	{
		return false;
	}

	yaw = abs( zombie_utility::getYawToEnemy() );
	if( ( yaw > 45 ) )
	{
		return false;
	}

	return true;
}

function margwaShouldSwipeAttack( entity )
{
	if( !IsDefined( entity.enemy ) )
    {
		return false;
	}

	if( DistanceSquared( entity.origin, entity.enemy.origin ) > 128 * 128 )
	{
		return false;
	}

	yaw = abs( zombie_utility::getYawToEnemy() );
	if( ( yaw > 45 ) )
	{
		return false;
	}
	
	return true;
}

function private margwaShouldShowPain( entity )
{
	if ( IsDefined( entity.headDestroyed ) )
	{
		headInfo = entity.head[ entity.headDestroyed ];
		switch( headInfo.cf )
		{
			case "margwa_head_left":
				Blackboard::SetBlackBoardAttribute( self, "_margwa_head", "left" );
				break;
				
			case "margwa_head_mid":
				Blackboard::SetBlackBoardAttribute( self, "_margwa_head", "middle" );
				break;
					
			case "margwa_head_right":
				Blackboard::SetBlackBoardAttribute( self, "_margwa_head", "right" );
				break;
		}

		return true;
	}

	return false;
}

function private margwaShouldReactStun( entity )
{
	if ( ( isdefined( entity.reactStun ) && entity.reactStun ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldReactIDGun( entity )
{
	if ( ( isdefined( entity.reactIDGun ) && entity.reactIDGun ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldReactSword( entity )
{
	if ( ( isdefined( entity.reactSword ) && entity.reactSword ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldSpawn( entity )
{
	if ( ( isdefined( entity.needSpawn ) && entity.needSpawn ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldFreeze( entity )
{
	if ( ( isdefined( entity.isFrozen ) && entity.isFrozen ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldTeleportIn( entity )
{
	if ( ( isdefined( entity.needTeleportIn ) && entity.needTeleportIn ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldTeleportOut( entity )
{
	if ( ( isdefined( entity.needTeleportOut ) && entity.needTeleportOut ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldWait( entity )
{
	if ( ( isdefined( entity.waiting ) && entity.waiting ) )
	{
		return true;
	}

	return false;
}

function private margwaShouldReset( entity )
{
	if ( IsDefined( entity.headDestroyed ) )
	{
		return true;
	}

	if ( ( isdefined( entity.reactIDGun ) && entity.reactIDGun ) )
	{
		return true;
	}

	if ( ( isdefined( entity.reactSword ) && entity.reactSword ) )
	{
		return true;
	}

	if ( ( isdefined( entity.reactStun ) && entity.reactStun ) )
	{
		return true;
	}

	return false;
}

//----------------------------------------------------------------------------------------------------------------------------------
// ACTIONS
//----------------------------------------------------------------------------------------------------------------------------------
function private margwaReactStunAction( entity, asmStateName )
{
	AnimationStateNetworkUtility::RequestState( entity, asmStateName );

	stunActionAST = entity ASTSearch( IString( asmStateName ) );
	stunActionAnimation = AnimationStateNetworkUtility::SearchAnimationMap( entity, stunActionAST[ "animation" ] );

	closeTime = GetAnimLength( stunActionAnimation ) * 1000;

	entity MargwaServerUtils::margwaCloseAllHeads( closeTime );

	MargwaBehavior::margwaReactStunStart( entity );

	return 5;
}


function private margwaSwipeAttackAction( entity, asmStateName )
{
	AnimationStateNetworkUtility::RequestState( entity, asmStateName );

	if ( !isdefined( entity.swipe_end_time ) )
	{
		swipeActionAST = entity ASTSearch( IString( asmStateName ) );
		swipeActionAnimation = AnimationStateNetworkUtility::SearchAnimationMap( entity, swipeActionAST[ "animation" ] );
		swipeActionTime = GetAnimLength( swipeActionAnimation ) * 1000;

		entity.swipe_end_time = GetTime() + swipeActionTime;
	}

	return 5;
}

function private margwaSwipeAttackActionUpdate( entity, asmStateName )
{
	if ( isdefined( entity.swipe_end_time ) && GetTime() > entity.swipe_end_time )
	{
		return 4;
	}

	return 5;
}

function private margwaIdleStart( entity )
{
	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		entity clientfield::set( "margwa_jaw", 1 );
	}
}

function private margwaMoveStart( entity )
{
	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		if ( entity.zombie_move_speed == "run" )
		{
			entity clientfield::set( "margwa_jaw", 13 );
		}
		else
		{
			entity clientfield::set( "margwa_jaw", 7 );
		}
	}
}

function private margwaDeathAction( entity )
{
	//insert anything that needs to be done right before zombie death
}

function private margwaTraverseActionStart( entity )
{
	Blackboard::SetBlackBoardAttribute( entity, "_traversal_type", entity.traverseStartNode.animscript );

	if( isdefined( entity.traverseStartNode.animscript ) )
	{
		if ( entity MargwaServerUtils::shouldUpdateJaw() )
		{
			switch ( entity.traverseStartNode.animscript )
			{
			case "jump_down_36":
				entity clientfield::set( "margwa_jaw", 21 );
				break;
	
			case "jump_down_96":
				entity clientfield::set( "margwa_jaw", 22 );
				break;
	
			case "jump_up_36":
				entity clientfield::set( "margwa_jaw", 24 );
				break;
	
			case "jump_up_96":
				entity clientfield::set( "margwa_jaw", 25 );
				break;
			}
		}
	}
}

function private margwaTeleportInStart( entity )
{
	entity Unlink();
	if ( IsDefined( entity.teleportPos ) )
	{
		entity ForceTeleport( entity.teleportPos );
	}
	entity Show();
	entity PathMode( "move allowed" );
	entity.needTeleportIn = false;
	Blackboard::SetBlackBoardAttribute( self, "_margwa_teleport", "in" );

	if ( isdefined( self.traveler ) )
	{
		self.traveler clientfield::set( "margwa_fx_travel", 0 );
	}
	self clientfield::increment( "margwa_fx_in", 1 );

	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		entity clientfield::set( "margwa_jaw", 17 );
	}
}

function margwaTeleportInTerminate( entity )
{
	if ( isdefined( self.traveler ) )
	{
		self.traveler clientfield::set( "margwa_fx_travel", 0 );
	}
	entity.isTeleporting = false;
}

function private margwaTeleportOutStart( entity )
{
	entity.needTeleportOut = false;
	entity.isTeleporting = true;
	entity.teleportStart = entity.origin;

	Blackboard::SetBlackBoardAttribute( self, "_margwa_teleport", "out" );
	self clientfield::increment( "margwa_fx_out", 1 );

	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		entity clientfield::set( "margwa_jaw", 18 );
	}
}

function private margwaTeleportOutTerminate( entity )
{
	if ( isdefined( entity.traveler ) )
	{
		entity.traveler.origin = entity GetTagOrigin( "j_spine_1" );
		entity.traveler clientfield::set( "margwa_fx_travel", 1 );
	}

	entity Ghost();
	entity PathMode( "dont move" );

	if ( isdefined( entity.traveler ) )
	{
		entity LinkTo( entity.traveler );
	}

	if ( isdefined( entity.margwaWait ) )
	{
		entity thread [[ entity.margwaWait ]]();
	}
	else
	{
		entity thread MargwaServerUtils::margwaWait();
	}
}

function private margwaPainStart( entity )
{
	entity notify( "stop_head_update" );

	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		head = Blackboard::GetBlackBoardAttribute( self, "_margwa_head" );
		switch ( head )
		{
		case "left":
			entity clientfield::set( "margwa_jaw", 3 );
			break;

		case "middle":
			entity clientfield::set( "margwa_jaw", 4 );
			break;

		case "right":
			entity clientfield::set( "margwa_jaw", 5 );
			break;

		}
	}

	entity.headDestroyed = undefined;
	entity.canStun = false;
	entity.canDamage = false;
}

function private margwaPainTerminate( entity )
{
	entity.headDestroyed = undefined;
	entity.canStun = true;
	entity.canDamage = true;

	entity MargwaServerUtils::margwaCloseAllHeads( 5000 );

	entity ClearPath();

	if ( IsDefined( entity.margwaPainTerminateCB ) )
	{
		entity [[ entity.margwaPainTerminateCB ]]();
	}
}

function private margwaReactStunStart( entity )
{
	entity.reactStun = undefined;
	entity.canStun = false;

	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		entity clientfield::set( "margwa_jaw", 6 );
	}
}

function margwaReactStunTerminate( entity )
{
	entity.canStun = true;
}

function private margwaReactIDGunStart( entity )
{
	entity.reactIDGun = undefined;
	entity.canStun = false;

	isPacked = false;
	
	if( BlackBoard::GetBlackBoardAttribute( entity, "_zombie_damageweapon_type" ) == "regular" )
	{
		if ( entity MargwaServerUtils::shouldUpdateJaw() )
		{
			entity clientfield::set( "margwa_jaw", 8 );
		}
		entity MargwaServerUtils::margwaCloseAllHeads( 5000 );
	}
	else
	{
		if ( entity MargwaServerUtils::shouldUpdateJaw() )
		{
			entity clientfield::set( "margwa_jaw", 9 );
		}
		entity MargwaServerUtils::margwaCloseAllHeads( 2 * 5000 );

		isPacked = true;
	}

	if ( IsDefined( entity.idgun_damage ) )
	{
		entity [[ entity.idgun_damage ]]( isPacked );
	}
}

function margwaReactIDGunTerminate( entity )
{
	entity.canStun = true;
	Blackboard::SetBlackBoardAttribute( entity, "_zombie_damageweapon_type", "regular" );
}

function private margwaReactSwordStart( entity )
{
	entity.reactSword = undefined;
	entity.canStun = false;

	if ( IsDefined( entity.head_chopper ) )
	{
		entity.head_chopper notify( "react_sword" );
	}
}

function private margwaReactSwordTerminate( entity )
{
	entity.canStun = true;
}

function private margwaSpawnStart( entity )
{
	entity.needSpawn = false;
}

function private margwaSmashAttackStart( entity )
{
	entity MargwaServerUtils::margwaHeadSmash();

	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		entity clientfield::set( "margwa_jaw", 14 );
	}
}

function margwaSmashAttackTerminate( entity )
{
	entity MargwaServerUtils::margwaCloseAllHeads();
}

function margwaSwipeAttackStart( entity )
{
	if ( entity MargwaServerUtils::shouldUpdateJaw() )
	{
		entity clientfield::set( "margwa_jaw", 16 );
	}
}

function private margwaSwipeattackTerminate( entity )
{
	entity MargwaServerUtils::margwaCloseAllHeads();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MOCOMPS
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function private mocompMargwaTeleportTraversalInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
{
	entity OrientMode( "face angle", entity.angles[1] );
	entity AnimMode( "normal" );

	if ( isdefined( entity.traverseEndNode ) )
	{
		entity.teleportStart = entity.origin;
		entity.teleportPos = entity.traverseEndNode.origin;
		self clientfield::increment( "margwa_fx_out", 1 );

		if ( isdefined( entity.traverseStartNode ) )
		{
			if ( isdefined( entity.traverseStartNode.speed ) )
			{
				self.margwa_teleport_speed = entity.traverseStartNode.speed;
			}
		}
	}
}

function private mocompMargwaTeleportTraversalUpdate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
{
}

function private mocompMargwaTeleportTraversalTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
{
	margwaTeleportOutTerminate( entity );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#namespace MargwaServerUtils;

function private margwaSpawnSetup()
{
	self DisableAimAssist();

	self.disableAmmoDrop = true;
	self.no_gib = true;
	self.ignore_nuke = true;
	self.ignore_enemy_count = true;
	self.ignore_round_robbin_death = true; 

	self.zombie_move_speed = "walk";

	self.overrideActorDamage = &margwaDamage;
	self.canDamage = true;

	self.headAttached = 3;
	self.headOpen = 0;

	self margwaInitHead( "c_zom_margwa_chunks_le", "j_chunk_head_bone_le" );
	self margwaInitHead( "c_zom_margwa_chunks_mid", "j_chunk_head_bone" );
	self margwaInitHead( "c_zom_margwa_chunks_ri", "j_chunk_head_bone_ri" );

	self.headHealthMax = 600;

	self margwaDisableStun();

	self.traveler = Spawn( "script_model", self.origin );
	self.traveler SetModel( "tag_origin" );
	self.traveler NotSolid();

	self.travelerTell = Spawn( "script_model", self.origin );
	self.travelerTell SetModel( "tag_origin" );
	self.travelerTell NotSolid();

	self thread margwaDeath();

	self.updateSight = false;
	self.ignoreRunAndGunDist = true;
}

function private margwaDeath()
{
	self waittill( "death" );

	if( isdefined(self.e_head_attacker) )
	{
		self.e_head_attacker notify( "margwa_kill" );
	}

	if ( IsDefined( self.traveler ) )
	{
		self.traveler Delete();
	}

	if ( IsDefined( self.travelerTell ) )
	{
		self.travelerTell Delete();
	}
}

function margwaEnableStun()
{
	self.canStun = true;
}

function private margwaDisableStun()
{
	self.canStun = false;
}

function private margwaInitHead( headModel, headTag )
{	
	model = headModel;
	model_gore = undefined;
	
	switch ( headModel )
	{
	case "c_zom_margwa_chunks_le":
		if( isdefined( level.margwa_head_left_model_override ))
		{
			model = level.margwa_head_left_model_override;
			model_gore = level.margwa_gore_left_model_override;
		}
		break;

	case "c_zom_margwa_chunks_mid":
		if( isdefined( level.margwa_head_mid_model_override ))
		{
			model = level.margwa_head_mid_model_override;
			model_gore = level.margwa_gore_mid_model_override;
		}
		break;

	case "c_zom_margwa_chunks_ri":
		if( isdefined( level.margwa_head_right_model_override ))
		{
			model = level.margwa_head_right_model_override;
			model_gore = level.margwa_gore_right_model_override;
		}
		break;
	}
	
	self Attach( model );

	if ( !IsDefined( self.head ) )
	{
		self.head = [];
	}

	self.head[ model ] = SpawnStruct();
	self.head[ model ].model = model;
	self.head[ model ].tag = headTag;
	self.head[ model ].health = 600;
	self.head[ model ].canDamage = false;

	self.head[ model ].open = 1;
	self.head[ model ].closed = 2;
	self.head[ model ].smash = 3;

	switch ( headModel )
	{
	case "c_zom_margwa_chunks_le":
		self.head[ model ].cf = "margwa_head_left";
		self.head[ model ].impactCF = "margwa_head_left_hit";
		self.head[ model ].gore = "c_zom_margwa_gore_le";
		if( isdefined( model_gore ))
		{
			self.head[ model ].gore = model_gore;
		}
		self.head[ model ].killIndex = 1;
		self.head_left_model = model;
		break;

	case "c_zom_margwa_chunks_mid":
		self.head[ model ].cf = "margwa_head_mid";
		self.head[ model ].impactCF = "margwa_head_mid_hit";
		self.head[ model ].gore = "c_zom_margwa_gore_mid";
		if( isdefined( model_gore ))
		{
			self.head[ model ].gore = model_gore;
		}
		self.head[ model ].killIndex = 2;
		self.head_mid_model = model;
		break;

	case "c_zom_margwa_chunks_ri":
		self.head[ model ].cf = "margwa_head_right";
		self.head[ model ].impactCF = "margwa_head_right_hit";
		self.head[ model ].gore = "c_zom_margwa_gore_ri";
		if( isdefined( model_gore ))
		{
			self.head[ model ].gore = model_gore;
		}
		self.head[ model ].killIndex = 3;
		self.head_right_model = model;
		break;
	}

	self thread margwaHeadUpdate( self.head[ model ] );
}

function margwaSetHeadHealth( health )
{
	self.headHealthMax = health;

	foreach( head in self.head )
	{
		head.health = health;
	}
}

function private margwaResetHeadTime( min, max )
{
	time = GetTime() + RandomIntRange( min, max );
	return time;
}

function private margwaHeadCanOpen()
{
	if ( self.headAttached > 1 )
	{
		if ( self.headOpen < (self.headAttached - 1) )
		{
			return true;
		}
	}
	else
	{
		return true;
	}

	return false;
}

function private margwaHeadUpdate( headInfo )
{
	self endon( "death" );
	self endon( "stop_head_update" );

	headInfo notify( "stop_head_update" );
	headInfo endon( "stop_head_update" );

	while ( 1 )
	{
		if ( self IsPaused() )
		{
			util::wait_network_frame();
			continue;
		}
	
		if ( !IsDefined( headInfo.closeTime ) )
		{
			if ( self.headAttached == 1 )
			{
				headInfo.closeTime = margwaResetHeadTime( 500, 1000 );
			}
			else
			{
				headInfo.closeTime = margwaResetHeadTime( 1500, 3500 );
			}
		}

		if ( GetTime() > headInfo.closeTime && self margwaHeadCanOpen() )
		{
			self.headOpen++;
			headInfo.closeTime = undefined;
		}
		else
		{
			util::wait_network_frame();
			continue;
		}

		self margwaHeadDamageDelay( headInfo, true );
		self clientfield::set( headInfo.cf, headInfo.open );
		self playsoundontag( "zmb_vocals_margwa_ambient", headInfo.tag );

		while ( 1 )
		{
			if ( !IsDefined( headInfo.openTime ) )
			{
				headInfo.openTime = margwaResetHeadTime( 3000, 5000 );
			}

			if ( GetTime() > headInfo.openTime )
			{
				self.headOpen--;
				headInfo.openTime = undefined;
				break;
			}
			else
			{
				util::wait_network_frame();
				continue;
			}
		}

		self margwaHeadDamageDelay( headInfo, false );
		self clientfield::set( headInfo.cf, headInfo.closed );
	}
}

function private margwaHeadDamageDelay( headInfo, canDamage )
{
	self endon( "death" );

	wait( 0.1 );

	headInfo.canDamage = canDamage;
}

function private margwaHeadSmash()
{
	self notify( "stop_head_update" );

	headAlive = [];
	foreach( head in self.head )
	{
		if ( head.health > 0 )
		{
			headAlive[ headAlive.size ] = head;
		}
	}

	headAlive = array::randomize( headAlive );
	open = false;

	foreach( head in headAlive )
	{
		if ( !open )
		{
			head.canDamage = true;
			self clientfield::set( head.cf, head.smash );
			open = true;
		}
		else
		{
			self margwaCloseHead( head );
		}
	}
}

function private margwaCloseHead( headInfo )
{
	headInfo.canDamage = false;
	self clientfield::set( headInfo.cf, headInfo.closed );
}

function private margwaCloseAllHeads( closeTime )
{
	if ( self IsPaused() )
	{
		return;
	}

	foreach ( head in self.head )
	{
		if ( head.health > 0 )
		{
			head.closeTime = undefined;
			head.openTime = undefined;

			if ( IsDefined( closeTime ) )
			{
				head.closeTime = GetTime() + closeTime;
			}

			self.headOpen = 0;

			self margwaCloseHead( head );
			self thread margwaHeadUpdate( head );
		}
	}
}

function margwaKillHead( modelHit, attacker )
{
	headInfo = self.head[ modelHit ];

	headInfo.health = 0;
	headInfo notify( "stop_head_update" );

	if ( ( isdefined( headInfo.canDamage ) && headInfo.canDamage ) )
	{
		self margwaCloseHead( headInfo );
		self.headOpen--;
	}

	self margwaUpdateMoveSpeed();

	if ( IsDefined( self.destroyHeadCB ) )
	{
		self thread [[ self.destroyHeadCB ]]( modelHit, attacker );
	}

	self clientfield::set( "margwa_head_killed", headInfo.killIndex );

	self Detach( headInfo.model );
	self Attach( headInfo.gore );
	self.headAttached--;

	if ( self.headAttached <= 0 )
	{
		self.e_head_attacker = attacker;
		return true;
	}
	else
	{
		self.headDestroyed = modelHit;
	}

	return false;
}

function margwaCanDamageAnyHead()
{
	foreach( head in self.head )
	{
		if ( IsDefined( head ) && head.health > 0 && ( isdefined( head.canDamage ) && head.canDamage ) )
		{
			return true;
		}
	}
	
	return false;
}

function margwaCanDamageHead()
{
	if ( IsDefined( self ) && self.health > 0 && ( isdefined( self.canDamage ) && self.canDamage ) )
	{
		return true;
	}

	return false;
}


function show_hit_marker()  // self = player
{
	if ( IsDefined( self ) && IsDefined( self.hud_damagefeedback ) )
	{
		self.hud_damagefeedback SetShader( "damage_feedback", 24, 48 );
		self.hud_damagefeedback.alpha = 1;
		self.hud_damagefeedback FadeOverTime(1);
		self.hud_damagefeedback.alpha = 0;
	}	
}

function private isDirectHitWeapon( weapon )
{
	foreach( dhWeapon in level.dhWeapons )
	{
		if ( weapon.name == dhWeapon )
		{
			return true;
		}

		if ( isdefined( weapon.rootweapon ) && isdefined( weapon.rootweapon.name ) && weapon.rootweapon.name == dhWeapon )
		{
			return true;
		}
	}

	return false;
}


// uses the bone name to figure out which head was hit
function margwaDamage( inflictor, attacker, damage, dFlags, mod, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
{
	if ( ( isdefined( self.is_kill ) && self.is_kill ) )
	{
		return damage;
	}

	if( isdefined(attacker) && isdefined(attacker.n_margwa_head_damage_scale) )
	{
	   	damage = damage * attacker.n_margwa_head_damage_scale;
	}
	
	if( isdefined( level._margwa_damage_cb ) )
	{
		n_result = [[ level._margwa_damage_cb ]]( inflictor, attacker, damage, dFlags, mod, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex );
		
		if( isdefined( n_result ) )
		{
			return n_result;
		}
	}
	
	damageOpen = false;		// mouth was open during damage
	
	if ( !( isdefined( self.canDamage ) && self.canDamage ) )
	{
		self.health += 1;	// impact fx only work when damage is applied
		return 1;
	}

	if ( isDirectHitWeapon( weapon ) )
	{
		headAlive = [];
		foreach ( head in self.head )
		{
			if ( head margwaCanDamageHead() )
			{
				headAlive[ headAlive.size ] = head;
			}
		}

		if ( headAlive.size > 0 )
		{
			max = 100000;
			headClosest = undefined;
			foreach ( head in headAlive )
			{
				distSq = DistanceSquared( point, self GetTagOrigin( head.tag ) );
				if ( distSq < max )
				{
					max = distSq;
					headClosest = head;
				}
			}
			if ( IsDefined( headClosest ) )
			{
				if ( max < 24 * 24 )
				{
					if ( isdefined( level.margwa_damage_override_callback ) && IsFunctionPtr( level.margwa_damage_override_callback ) )
					{
						damage = attacker [[ level.margwa_damage_override_callback ]]( damage );
					}
					
					headClosest.health -= damage;
					damageOpen = true;
					self clientfield::increment( headClosest.impactCF );
					attacker show_hit_marker();

					if ( headClosest.health <= 0 )
					{
						if( isdefined(level.margwa_head_kill_weapon_check) )
						{
							[[level.margwa_head_kill_weapon_check]]( self, weapon );
						}
						
						if ( self margwaKillHead( headClosest.model, attacker ) )
						{
							return self.health;
						}
					}
				}
			}
		}
	}
	
	partName = GetPartName( self.model, boneIndex );
	if ( IsDefined( partName ) )
	{
		/#
			if ( ( isdefined( self.debugHitLoc ) && self.debugHitLoc ) )
			{
				PrintTopRightLn( partName + " damage: " + damage );
			}
		#/
		modelHit = self margwaHeadHit( self, partName );
		if ( IsDefined( modelHit ) )
		{
			headInfo = self.head[ modelHit ];
			if ( headInfo margwaCanDamageHead() )
			{
				if ( isdefined( level.margwa_damage_override_callback ) && IsFunctionPtr( level.margwa_damage_override_callback ) )
				{
					damage = attacker [[ level.margwa_damage_override_callback ]]( damage );
				}
				
				if( isdefined( attacker ) )
				{
					attacker notify( "margwa_headshot", self );
				}
				
				headInfo.health -= damage;
				damageOpen = true;
				self clientfield::increment( headInfo.impactCF );
				attacker show_hit_marker();

				if ( headInfo.health <= 0 )
				{
					if( isdefined(level.margwa_head_kill_weapon_check) )
					{
						[[level.margwa_head_kill_weapon_check]]( self, weapon );
					}

					if ( self margwaKillHead( modelHit, attacker ) )
					{
						return self.health;
					}
				}
			}
		}
	}

	if ( damageOpen )
	{
		return 0;		// custom fx when damaging head
	}

	self.health += 1;	// impact fx only work when damage is applied to ent
	return 1;
}

function private margwaHeadHit( entity, partName )
{
	switch ( partName )
	{
	case "j_chunk_head_bone_le":
	case "j_jaw_lower_1_le":
		return self.head_left_model;

	case "j_chunk_head_bone":
	case "j_jaw_lower_1":
		return self.head_mid_model;

	case "j_chunk_head_bone_ri":
	case "j_jaw_lower_1_ri":
		return self.head_right_model;
	}

	return undefined;
}

function private margwaUpdateMoveSpeed()
{
	if ( self.zombie_move_speed == "walk" )
	{
		self.zombie_move_speed = "run";
		//self ASMSetAnimationRate( 0.8 );
		Blackboard::SetBlackBoardAttribute( self, "_locomotion_speed", "locomotion_speed_run" );
	}
	else if ( self.zombie_move_speed == "run" )
	{
		self.zombie_move_speed = "sprint";
		//self ASMSetAnimationRate( 1.0 );
		Blackboard::SetBlackBoardAttribute( self, "_locomotion_speed", "locomotion_speed_sprint" );
	}
}

function margwaForceSprint()
{
	self.zombie_move_speed = "sprint";
	Blackboard::SetBlackBoardAttribute( self, "_locomotion_speed", "locomotion_speed_sprint" );
}

function private margwaDestroyHead( modelHit )
{
}

function shouldUpdateJaw()
{
	if ( !( isdefined( self.jawAnimEnabled ) && self.jawAnimEnabled ) )
	{
		return false;
	}

	if ( self.headAttached < 3 )
	{
		return true;
	}

	return false;
}

function margwaSetGoal( origin, radius, boundaryDist )
{
	pos = GetClosestPointOnNavMesh( origin, 64, 30 );
	if ( IsDefined( pos ) )
	{
		self SetGoal( pos );
		return true;
	}

	self SetGoal( self.origin );
	return false;
}

function private margwaWait()
{
	self endon( "death" );

	self.waiting = true;
	self.needTeleportIn = true;

	destPos = self.teleportPos + ( 0, 0, 60 );
	dist = Distance( self.teleportStart, destPos );
	time = dist / 600;

	if ( isdefined( self.margwa_teleport_speed ) )
	{
		if ( self.margwa_teleport_speed > 0 )
		{
			time = dist / self.margwa_teleport_speed;
		}
	}

	if ( isdefined( self.traveler ) )
	{
		self thread margwaTell();

		self.traveler MoveTo( destPos, time );
		self.traveler util::waittill_any_ex( ( time + 0.1 ), "movedone", self, "death" );

		self.travelerTell clientfield::set( "margwa_fx_travel_tell", 0 );
	}

	self.waiting = false;
	self.needTeleportOut = false;

	if ( isdefined( self.margwa_teleport_speed ) )
	{
		self.margwa_teleport_speed = undefined;
	}
}

function margwaTell()
{
	self endon( "death" );

	self.travelerTell.origin = self.teleportPos;

	util::wait_network_frame();

	self.travelerTell clientfield::set( "margwa_fx_travel_tell", 1 );
}

function private shieldFacing( vDir, limit, front = true )
{
	orientation = self getPlayerAngles();
	forwardVec = anglesToForward( orientation );
	if ( !front )
	{
		forwardVec = -forwardVec;
	}
	forwardVec2D = ( forwardVec[0], forwardVec[1], 0 );
	unitForwardVec2D = VectorNormalize( forwardVec2D );

	toFaceeVec = -vDir;
	toFaceeVec2D = ( toFaceeVec[0], toFaceeVec[1], 0 );
	unitToFaceeVec2D = VectorNormalize( toFaceeVec2D );
	
	dotProduct = VectorDot( unitForwardVec2D, unitToFaceeVec2D );
	return ( dotProduct > limit ); // more or less in front
}

function private inSmashAttackRange( enemy )
{
	smashPos = self.origin;
	
	heightOffset = abs( self.origin[2] - enemy.origin[2] );
	if ( heightOffset > 48 )
	{
		return false;
	}
	
	distSq = DistanceSquared( smashPos, enemy.origin );
	range = 160 * 160;

	if ( distSq < range )
	{
		return true;
	}

	return false;
}
