/**
 *	@param vRayStart	Start point of an infinite ray.
 *	@param vRayOffset	Direction of the ray, parametric t multiplier.
 *	@param fT0			Filled in with time of first intersection (if present).
 *	@param fT1			Filled in with time of second intersection (if present).
 *	@return				The number of intersections found.
 */
UINT32 CCircle::GetLineIntersectionTimes(CFVec2Arg vRayStart, CFVec2Arg vRayOffset, GDE::FLOAT32 &fT0, GDE::FLOAT32 &fT1) const
{
	const CFVec2 vToRay = vRayStart - m_vCentre;
	// TODO: reformulate without the square root?
	const FLOAT32 fExtentsRecip = 1.0f/vRayOffset.Magnitude();
	const FLOAT32 fRayDotToRay = vToRay.DotProduct( vRayOffset ) * fExtentsRecip;
	const FLOAT32 fDiscr = fRayDotToRay*fRayDotToRay - (vToRay.SquareMagnitude()-m_fRadius*m_fRadius);
	if ( fDiscr < 0.0f )
	{
		return 0;	// no intersections.
	}
	if ( fDiscr == 0.0f )
	{
		fT0 = -fRayDotToRay * fExtentsRecip;
		return 1;	// one intersection, just touching
	} else
	{
		const FLOAT32 fRoot = sqrtf( fDiscr );
		fT0 = (-fRayDotToRay - fRoot) * fExtentsRecip;
		fT1 = (-fRayDotToRay + fRoot) * fExtentsRecip;
		return 2;	// two intersections.
	}
}
void	CSquirrel::Update( FLOAT32 fTimeDelta )
{
	if ( 0 == m_uNumLives )
	{
		return;
	}

	const static CFVec2 s_vMoveOffsets[] = 
	{
		SFVec2( -1.0f,  0.0f ), //"Left",
		SFVec2(  1.0f,  0.0f ), //"Right",
		SFVec2(  0.0f, -1.0f ), //"Up",
		SFVec2(  0.0f,  1.0f ), //"Down"
	};

	_COMPILE_ASSERT( _ARRAY_SIZE( s_vMoveOffsets ) == EMove_COUNT );

	CFVec2 vMove = SFVec2( 0.0f, 0.0f );
	for ( UINT32 i=0; i< EMove_COUNT; i++ )
	{
		if ( m_Movements[i].m_bValue )
		{
			vMove += s_vMoveOffsets[i];
		}
	}

	// great, now we have the movement direction.
	if ( vMove.SquareMagnitude() != 0.0f )
	{
		m_fDistTimeMoving += fTimeDelta;
		vMove.Normalise();
		FLOAT32 fStep = 1.0f;
		CFVec2 vTestedMove = vMove * fTimeDelta * m_fSpeed * fStep;
		// now check the target position -  is it embedded in any walls?
		CCircle TargetBounds;
		while ( fStep > 0.0f )
		{
			TargetBounds.Initialise( m_vPosition + vTestedMove, m_fRadius );
			if ( false == CMMMContext::GetInstance().CircleIntersectsGeometry( TargetBounds ) )
			{
				break;	// found a valid, allowable movement.
			}
			fStep -= 0.2f;
			vTestedMove = vMove * fTimeDelta * m_fSpeed * fStep;
		}
		// now update to the new position
		m_vPosition += vTestedMove;

		// finally what happens at the new position
		// is an acorn collected?
		if ( m_uNumAcorns != m_uMaxAcorns )
		{
			CAcorn* pLevelAcorns;
			UINT32 uNumLevelAcorns;
			CMMMContext::GetInstance().GetAcorns( pLevelAcorns, uNumLevelAcorns );
			for ( UINT32 i=0; i<uNumLevelAcorns; i++ )
			{
				if ( pLevelAcorns[i].GetState() == CAcorn::ES_Available )
				{
					if ( pLevelAcorns[i].Intersects( TargetBounds ) )
					{
						pLevelAcorns[i].SetState( CAcorn::ES_Carried );
						m_ppAcorns[m_uNumAcorns++] = pLevelAcorns+i;
						if ( m_uNumAcorns == m_uMaxAcorns )
						{
							break;	// cannont collect any more!
						}
					}
				}
			}
		}
		// is a tunnel reached?
		if ( m_uNumAcorns > 0 )
		{
			CTunnel*	pTunnels;
			UINT32		uNumTunnels;
			CMMMContext::GetInstance().GetTunnels( pTunnels, uNumTunnels );
			for ( UINT32 i=0; i<uNumTunnels; i++ )
			{
				if ( pTunnels[i].Intersects( TargetBounds ) )
				{
					// reached the tunnel.
					for ( UINT32 i=0; i<m_uNumAcorns; i++ )
					{
						m_ppAcorns[i]->SetState( CAcorn::ES_Collected );
						m_uScore++;
					}
					m_uNumAcorns = 0;
				}
			}
		}
	}

	m_fTimeToDisturbance -= fTimeDelta;
	if ( m_fTimeToDisturbance <= 0.0f )
	{
		// schedule the next disturbance.
		m_fTimeToDisturbance = FLOAT32(rand())/FLOAT32(RAND_MAX);
		m_fTimeToDisturbance *= m_fMaxDistSep-m_fMinDistSep;
		m_fTimeToDisturbance += m_fMinDistSep;

		// create this disturbance:
		FLOAT32 fRad = m_fLastDistDelay=0.0f?0.0f:m_fDistTimeMoving/m_fLastDistDelay;
//		DbgPrint( "Creating Disturbance strength %0.2f, next delay %0.2f\n", fRad,m_fTimeToDisturbance );
		fRad *= m_fMaxDistRad-m_fMinDistRad;
		fRad += m_fMinDistRad;

		if ( fRad >= 0.0f )
		{
			CCircle Dist;
			Dist.Initialise( m_vPosition, fRad );
			CMMMContext::GetInstance().CreateDisturbance( Dist );
		}
		m_fDistTimeMoving = 0.0f;
		m_fLastDistDelay = m_fTimeToDisturbance;
	}



}