//
// Scripted agent common functions.
//

// called from code when animation state changes.
OnEnterState( prevState, nextState )
{
	if ( IsDefined( self.OnEnterAnimState ) )
		self [[ self.OnEnterAnimState ]]( prevState, nextState );
}

// called from code when the agent is freed.
OnDeactivate()
{
	self notify( "killanimscript" );
}


// util function
PlayAnimUntilNotetrack( animState, animLabel, notetrack, customFunction )
{
	PlayAnimNUntilNotetrack( animState, 0, animLabel, notetrack, customFunction );
}

PlayAnimNUntilNotetrack( animState, animIndex, animLabel, notetrack, customFunction )
{
	self SetAnimState( animState, animIndex );

	if ( !IsDefined( notetrack ) )
		notetrack = "end";

	WaitUntilNotetrack( animLabel, notetrack, animState, animIndex, customFunction );
}

PlayAnimNAtRateUntilNotetrack( animState, animIndex, animRate, animLabel, notetrack, customFunction )
{
	self SetAnimState( animState, animIndex, animRate );

	if ( !IsDefined( notetrack ) )
		notetrack = "end";

	WaitUntilNotetrack( animLabel, notetrack, animState, animIndex, customFunction );
}

WaitUntilNotetrack( animLabel, notetrack, animState, animIndex, customFunction )
{
	startTime = getTime();
	animTime = undefined;
	animLength = undefined;
	
	if ( isDefined ( animState ) && isDefined ( animIndex ) )
		animLength = getAnimLength( self GetAnimEntry( animState, animIndex ));
		
	while ( true )
	{
		self waittill( animLabel, note );
		
		if ( isDefined ( animLength ) )
			animTime = ( getTime() - startTime ) * 0.001 / animLength;
		
		if ( !isDefined( animLength ) || animTime > 0 )
		{
			if ( note == notetrack || note == "end" || note == "anim_will_finish" || note == "finish" )
			{
				break;
			}
		}
				
		if ( IsDefined( customFunction ) )
			[[ customFunction ]]( note, animState, animIndex, animTime );
	}
}

PlayAnimForTime( animState, time )
{
	PlayAnimNForTime( animState, 0, time );
}

PlayAnimNForTime( animState, animIndex, time )
{
	self SetAnimState( animState, animIndex );
	wait( time );
}

PlayAnimNAtRateForTime( animState, animIndex, animRate, time )
{
	self SetAnimState( animState, animIndex, animRate );
	wait( time );
}

GetAnimScaleFactors( delta, animDelta, bAnimInWorldSpace )
{
	distXY = Length2D( delta );
	distZ = delta[2];
	animXY = Length2D( animDelta );
	animZ = animDelta[2];
	
	scaleXY = 1;
	scaleZ = 1;
	if ( IsDefined( bAnimInWorldSpace ) && bAnimInWorldSpace )
	{
		animDelta2D = ( animDelta[0], animDelta[1], 0 );
		animDeltaDir = VectorNormalize( animDelta2D );
		if ( VectorDot( animDeltaDir, delta ) < 0 )
			scaleXY = 0;
		else if ( animXY > 0 )
			scaleXY = distXY / animXY;
	}
	else if ( animXY > 0 )
		scaleXY = distXY / animXY;

	assert( scaleXY >= 0 );

	if ( abs(animZ) > 0.001 && animZ * distZ >= 0 )	// animZ & distZ have to be same sign.
		scaleZ = distZ / animZ;

	assert( scaleZ >= 0 );

	scaleFactors = SpawnStruct();
	scaleFactors.xy = scaleXY;
	scaleFactors.z = scaleZ;
	
	return scaleFactors;
}

// -180, -135, -90, -45, 0, 45, 90, 135, 180
// favor underturning, unless you're within <threshold> degrees of the next one up.
GetAngleIndex( angle, threshold )
{
	if ( !IsDefined( threshold ) )
		threshold = 10;

	if ( angle < 0 )
		return int( ceil( ( 180 + angle - threshold ) / 45 ) );
	else
		return int( floor( ( 180 + angle + threshold ) / 45 ) );
}


DropPosToGround( position, drop_distance )
{
	//droppedPos = GetGroundPosition( position, radius, 64, 64 );

	assert( IsDefined( self.radius ) && IsDefined( self.height ) );
	if ( !IsDefined( drop_distance ) )
		drop_distance = 18;
	
	startPos = position + (0, 0, drop_distance);
	endPos = position + (0, 0, drop_distance * -1 );

	droppedPos = self AIPhysicsTrace( startPos, endPos, self.radius, self.height, true );
	
	if ( abs( droppedPos[2] - startPos[2] ) < 0.1 )
		return undefined;

	if ( abs( droppedPos[2] - endPos[2] ) < 0.1 )
		return undefined;

	return droppedPos;
}


TRACE_RADIUS_BUFFER = 4;
CanMovePointToPoint( startPos, endPos, stepSize )
{
	if ( !isDefined( stepSize ) )
	{
		stepSize = 6;		
	}
	
	step_offset = (0, 0, 1) * stepSize;
	startPosRaised = startPos + step_offset;
	endPosRaised = endPos + step_offset;

	assert( IsDefined( self.radius ) && IsDefined( self.height ) );	
	assert( stepSize < self.height );
	
	return self AIPhysicsTracePassed( startPosRaised, endPosRaised, self.radius, self.height - stepSize, true );
}

GetValidPointToPointMoveLocation( startPos, endPos, stepSize )
{
	if ( !isDefined( stepSize ) )
	{
		stepSize = 6;		
	}
	
	step_offset = (0, 0, 1) * stepSize;
	startPosRaised = startPos + step_offset;
	endPosRaised = endPos + step_offset;

	assert( IsDefined( self.radius ) && IsDefined( self.height ) );	
	assert( stepSize < self.height );
	
	return self AIPhysicsTrace( startPosRaised, endPosRaised, self.radius + TRACE_RADIUS_BUFFER, self.height - stepSize, true );
}

GetSafeAnimMoveDeltaPercentage( moveAnim )
{
	animTranslation = GetMoveDelta( moveAnim );
	endPos = self LocalToWorldCoords( animTranslation );
	validMovePosition = GetValidPointToPointMoveLocation( self.origin, endPos );
	validMoveDistance = Distance( self.origin, validMovePosition );
	desiredMoveDistance = Distance( self.origin, endPos );
	
	return Min( 1.0, validMoveDistance / desiredMoveDistance );
}

SafelyPlayAnimUntilNotetrack( animState, animLabel, notetrack, customFunction )
{
	animIndex = GetRandomAnimEntry( animState );
	SafelyPlayAnimNUntilNotetrack( animState, animIndex, animLabel, notetrack, customFunction );
}

SafelyPlayAnimAtRateUntilNotetrack( animState, animRate, animLabel, notetrack, customFunction )
{
	animIndex = GetRandomAnimEntry( animState );
	SafelyPlayAnimNAtRateUntilNotetrack( animState, animIndex, animRate, animLabel, notetrack, customFunction );
}

SafelyPlayAnimNAtRateUntilNotetrack( animState, animIndex, animRate, animLabel, notetrack, customFunction )
{
	self SetAnimState( animState, animIndex, animRate );
	SafelyPlayAnimNUntilNotetrack( animState, animIndex, animLabel, notetrack, customFunction );
}

SafelyPlayAnimNUntilNotetrack( animState, animIndex, animLabel, notetrack, customFunction )
{
	animToPlay = self GetAnimEntry( animState, animIndex );
	moveScale = GetSafeAnimMoveDeltaPercentage( animToPlay );
	self ScrAgentSetAnimScale( moveScale, 1.0 );
	self PlayAnimNUntilNotetrack( animState, animIndex, animLabel, notetrack, customFunction );
	self ScrAgentSetAnimScale( 1.0, 1.0 );
}

GetRandomAnimEntry( state )
{
	count = self GetAnimEntryCount( state );
	return RandomInt( count );
}

GetAngleIndexFromSelfYaw( targetVector )
{
	targetAngles = VectorToAngles( targetVector );
	angleDiff = AngleClamp180( targetAngles[1] - self.angles[1] );
	return GetAngleIndex( angleDiff );
}