//////////////////////////////////////////////////////////////////////////////
//
// Axon_Project_System.cpp
//
// Created by NJD - 17 August 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Core/Axon_Project_System.h"

// asura
#include "Core/Asura_List.h"
#include "Core/Asura_Multithread.h"
#include "Core/Asura_Scheduler.h"
#include "Core/Asura_Timers.h"
#include "Debugging/Asura_Profiling_System.h"
#include "Entity/Controller/AVP_ServerEntity_Team_Alien.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_Alien.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_FaceHugger.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/Asura_ServerNode_GS2Node.h"
#include "Entity/Locations/Spline/GamesceneSpline/Asura_ServerNode_GS2Spline.h"

#ifndef ASURA_NO_DEBUG_OUTPUT
#include "AI/Asura_AI_Navigation.h"
#include "Debugging/Asura_DebugLineRender.h"
#include "Interface/Asura_CommandConsole.h"
#include "Rendering/Asura_Font_System.h"
#endif

// avp
#include "Entity/PhysicalObject/Actor/Weapons/Sentrygun/AVP_ServerWeapon_Sentrygun.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"

// axon
#include "Behaviour/AVP_BehaviourParams.h"
#include "Behaviour/Axon_BehaviourParams.h"
#include "Behaviour/BehaviourTypes/AVP_Behaviour_GS2Node_AnimMessages.h"
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_GS2Node_Marine_Combat.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_GS2Node_Marine_LookAt.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_GS2Spline_Marine_Combat.h"
#include "Behaviour/BehaviourParamsTypes/Axon_BehaviourParams_GS2Spline.h"
#include "Core/AVP_Navigation.h"
#include "Core/AVP_Waypoint_Manager.h"
#include "Core/AxonAVP_Messages.h"
#include "Core/BrainTypes/AVP_Brain_Team_Alien.h"
#include "Core/BrainTypes/Axon_Project_Brain.h"
#include "Knowledge/AVP_Knowledge_System.h"
#include "Knowledge/AVP_Knowledge_System_Actor.h"
#include "Knowledge/AVP_Knowledge_System_AlienTeam.h"
#include "Knowledge/Axon_Knowledge.h"


//////////////////////////////////////////////////////////////////////////////
//
// Axon_Project_System
//
//////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_TOOLS
// Bunged this in here as there seemed nowhere better to put it.
const char* AVP_Message_SetPreferredTargetType::s_aszTargetTypeStrings[ PTT_END_ENUM ] =
{
	"No Preferred Type",
	"Humanoid",
	"Alien",
	"Predator"
};

const char* Axon_Project_System::s_aszSoundTypeNames[ AVP_SOUND_MAX_TYPES ] = 
{
		
	"Scream",				
	"Pred_Roar",			
	"Alien Roar",			
	"Human Vocal",			
	"Jump Landing Sound",	
};

const Asura_Hash_ID Axon_Project_System::s_auSoundTypeHashIDs[ AVP_SOUND_MAX_TYPES ] =
{
	
};

#endif

float Axon_Project_System::s_fFootstepSoundRangeLow	 = 5.0f;
float Axon_Project_System::s_fFootstepSoundRangeMed  = 10.0f;
float Axon_Project_System::s_fFootstepSoundRangeHigh = 25.0f;
float Axon_Project_System::s_fHurtSoundRange		 = 20.0f;

float Axon_Project_System::s_fLightCutOffValue = 1.75f;
float Axon_Project_System::s_fAndroidLightCutOffValue = 1.75f;
float Axon_Project_System::s_fLightCutOffTimeOut = 2.0f;

#ifndef ASURA_NO_DEBUG_OUTPUT
bool		Axon_Project_System::s_bRenderDebugInfo  = false;
bool		Axon_Project_System::s_bRenderSentryDebugInfo  = false;
bool		Axon_Project_System::s_bRenderGS2DebugInfo = false;
bool		Axon_Project_System::s_bDisableAIUpdates = false;
bool		Axon_Project_System::s_bRenderNavData	  = false;
Asura_Guid	Axon_Project_System::s_uKnowledgeRenderGuid = ASURA_GUID_UNREGISTERED;
//static bool s_bDoTest = false;
#endif

#if !_DEBUG
DEBUGVAR float dbg_fAxonBehaviourSchedulerMaxPerFrameTime = 0.002f; // 2ms = 6.0% of the frame at 30 FPS
DEBUGVAR float dbg_fAxonKnowledgeSchedulerMaxPerFrameTime = 0.00133f; // 1.33ms = 4.0% of the frame at 30 FPS
#else
// Expect lower framerates in debug so scale appropriately.
DEBUGVAR float dbg_fAxonBehaviourSchedulerMaxPerFrameTime = 0.002f * 2.0f;
DEBUGVAR float dbg_fAxonKnowledgeSchedulerMaxPerFrameTime = 0.00133f * 2.0f;
#endif

Axon_System* Axon_System::Project_CreateAxonSystem()
{
	return new Axon_Project_System();
}

#ifndef ASURA_NO_DEBUG_OUTPUT

#include "Knowledge/SenseTypes/AVP_Sense_Vision_Actor.h"
#include "Knowledge/SenseTypes/AVP_Sense_MotionTracker.h"

void Axon_Project_System::RenderDebugInfo()
{
	AVP_Sense_Vision::RenderKnowledgeDebugInfo(s_uKnowledgeRenderGuid);
	AVP_Sense_MotionTracker::RenderKnowledgeDebugInfo();

	// Can we use the new Core Debug Info instead. AI.NAV.RENDER.->
    //Asura_AI_Navigation_System::RenderWaypoints();
	//Asura_AI_Navigation_System::RenderLinks();
	//Asura_AI_Navigation_System::RenderBlockedLinks();

    if ( s_bRenderDebugInfo )
	{
		// Render any static debug info.
		Asura_Vector_2 xDebugOutputPos;
		xDebugOutputPos.x = xDebugOutputPos.y = 20.0f;
		Asura_Font_System::Print( xDebugOutputPos.x, xDebugOutputPos.y, 0.5f, 0xffffffff,
			ASURA_TEXTFORMAT_LEFTJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, "Num routes allocated: %d", AVP_Navigation::GetDebugNumRoutesAllocated() );
		xDebugOutputPos.y += 20.0f;

		Asura_Font_System::Print( xDebugOutputPos.x, xDebugOutputPos.y, 0.5f, 0xffffffff,
			ASURA_TEXTFORMAT_LEFTJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, "Behaviour scheduler data:" );
		xDebugOutputPos.y += 10.0f;
		s_xBehaviourUpdateScheduler.RenderDebugInfo( xDebugOutputPos );
		xDebugOutputPos.y += 20.0f;

		Asura_Font_System::Print( xDebugOutputPos.x, xDebugOutputPos.y, 0.5f, 0xffffffff,
			ASURA_TEXTFORMAT_LEFTJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, "Knowledge scheduler data:" );
		xDebugOutputPos.y += 10.0f;
		s_xKnowledgeUpdateScheduler.RenderDebugInfo( xDebugOutputPos );
		xDebugOutputPos.y += 20.0f;

		// Set debug output position for alien team
		if( AVP_ServerEntity_Team_Alien::GetInstance() && AVP_ServerEntity_Team_Alien::GetInstance()->GetAlienTeamBrain() )
		{
			AVP_ServerEntity_Team_Alien::GetInstance()->GetAlienTeamBrain()->GetDebugOutputPos() = xDebugOutputPos;
		}

		for ( Asura_List_It< Axon_Brain > xBrainIt( &s_xBrainList ); !xBrainIt.Done(); xBrainIt.Next() )
		{
			Axon_Brain* pxBrain = xBrainIt.GetCurrent();
			if ( pxBrain && pxBrain->IsActive() )
			{
				if( ! AVP_ServerWeapon_Sentrygun::FindEntity( pxBrain->GetOwnerGuid() ) )
				{
					// render debug info if the owner of this brain is not a sentry gun. (it has its own command variable)
					pxBrain->DoRenderDebugInfo();
				}
			}
		}
	}

	if( s_bRenderSentryDebugInfo )
	{
		for ( Asura_Hashed_List_It< AVP_ServerWeapon_Sentrygun > xSentryGunIter( AVP_ServerWeapon_Sentrygun::GetList() ); !xSentryGunIter.Done(); xSentryGunIter.Next() )
		{
			xSentryGunIter.GetCurrent()->GetBrain()->DoRenderDebugInfo();
		}
	}

	if ( s_bRenderGS2DebugInfo )
	{
		for ( Asura_Hashed_List_It< Asura_ServerNode_GS2Node > xGS2NodeIter( Asura_ServerNode_GS2Node::GetList() ); !xGS2NodeIter.Done(); xGS2NodeIter.Next() )
		{
			xGS2NodeIter.GetCurrent()->RenderDebugInfo();
		}
		for ( Asura_Hashed_List_It< Asura_ServerNode_GS2Spline > xGS2SplineIter( Asura_ServerNode_GS2Spline::GetList() ); !xGS2SplineIter.Done(); xGS2SplineIter.Next() )
		{
			xGS2SplineIter.GetCurrent()->RenderDebugInfo();
		}
	}

	//// Players' position.
	//u_int uPlayerCount = 0;
	//Asura_Vector_3 xPosition = Asura_Maths::ZeroVector3;
	//for ( Asura_Hashed_List_ConstIt< AVP_ServerEntity_PlayerInfo > xPlayerIter( AVP_ServerEntity_PlayerInfo::GetList() );
	//	!xPlayerIter.Done();
	//	xPlayerIter.Next() )
	//{
	//	const AVP_ServerEntity_PlayerInfo* pxPlayerInfo = xPlayerIter.GetCurrent();
	//	const AVP_ServerEntity_Actor*	   pxActor = AVP_ServerEntity_Actor::FindEntity( pxPlayerInfo->GetPuppetGuid() );
	//	if ( !pxActor || pxActor->IsDead() || !pxActor->IsEntityActive() )
	//	{
	//		continue;
	//	}

	//	++uPlayerCount;
	//	const Asura_Vector_3 xCurrentGravity( pxActor->GetCurrentGravityDirection() );
	//	xPosition += pxActor->GetPosition() - ( xCurrentGravity * 1.2f );
	//}
	//if ( uPlayerCount > 1 )
	//{
	//	xPosition /= static_cast< float >( uPlayerCount );
	//}

	//// Get the nearest waypoint to the player.
	//u_short usPlayersWPID = ASURA_INVALID_WAYPOINT_ID;
	//if ( AVP_Navigation::GetNearestWaypointID( xPosition, usPlayersWPID ) )
	//{
	//	extern void Render_Sphere( const Asura_Vector_3& xCentre, float fRadius, int iColour );

	//	// Render waypoints if they are not in the line of fire of the players' position.
	//	for ( u_int uWP = 0; uWP < Asura_AI_Navigation_System::GetNumberOfWaypoints(); ++uWP )
	//	{
	//		if ( AVP_Waypoint_Manager::HasCoverFrom( uWP, usPlayersWPID ) )
	//		{
	//			const Asura_AI_NavVertex* pxWP = Asura_AI_Navigation_System::GetWaypoint( uWP );
	//			if ( pxWP )
	//			{
	//				Render_Sphere( pxWP->GetPosition(), pxWP->GetRadius(), 0xff00ff00 );
	//			}
	//		}
	//	}
	//}
}
#endif

//static void ProfileMutex()
//{
//	Asura_Handle iTimer = Asura_Profiling_System::CreateTimer();
//
//	Asura_Profiling_System::StartTiming( iTimer );
//	Asura_Mutex xMutex;
//	u_int u;
//	for ( u = 0; u < 100000000; ++u )
//	{
//		xMutex.Lock();
//		xMutex.Unlock();
//	}
//	Asura_Profiling_System::StopTiming( iTimer );
//
//	const float fTotalDuration = Asura_Profiling_System::GetTotalDuration( iTimer );
//	const float fPerCycle = fTotalDuration / u;
//
//	Asura_OutputToDebugger_Retail( ( "%u lock/unlock cycles = %f seconds (%f seconds/cycle)\n", u, fTotalDuration, fPerCycle ) );
//}

void Axon_Project_System::InitialiseThis()
{
	PARENT::InitialiseThis();

	GetBehaviourUpdateScheduler().SetMaxPerFrameTime( dbg_fAxonBehaviourSchedulerMaxPerFrameTime );
	GetKnowledgeUpdateScheduler().SetMaxPerFrameTime( dbg_fAxonKnowledgeSchedulerMaxPerFrameTime );

	Axon_Project_Brain::InitialiseBehaviourMempool();
    AVP_Navigation::InitialiseRouteMempools();
	AVP_Knowledge_System_Actor::CreateStorage();
	AVP_Knowledge_System_AlienTeam::CreateStorage();
	AVP_ServerEntity_Squad_Alien::InitialiseMempools();
	AVP_ServerEntity_Squad_FaceHugger::InitialiseMempools();

	Asura_Sound_Event_System::SetSoundRegistryFunction( RegisterSound );

#if defined(ASURA_SUPPORT_COMMAND_CONSOLE) && !defined(ASURA_NO_DEBUG_OUTPUT)
    //extern float s_fCollisionAvoidOverallScalar;
    //extern int   s_iCollisionAvoidRangePower;
    //extern float s_fCollisionAvoidLocalScalar;
    //extern float s_fCollisionAvoidRangeBias;
    //extern float s_fCollisionAvoidMinimumAngleDeg;
    //extern bool  s_bCollisionAvoidDoLocalAngleHack;
    //extern bool  s_bCollisionAvoidDoGlobalAngleHack;
    //extern float s_fToFollowPointScaling;
    //extern Asura_Guid s_uFocusGuid;

    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidOverallScalar",     &s_fCollisionAvoidOverallScalar,     0.0f,	FLT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidRangePower",        &s_iCollisionAvoidRangePower,        0,		INT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidLocalScalar",       &s_fCollisionAvoidLocalScalar,       0.0f,	FLT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidRangeBias",         &s_fCollisionAvoidRangeBias,			-10.0f, 10.0f,		Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidMinimumAngleDeg",   &s_fCollisionAvoidMinimumAngleDeg,   0.0f,	FLT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidDoLocalAngleHack",  &s_bCollisionAvoidDoLocalAngleHack,						Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.CollisionAvoidDoGlobalAngleHack", &s_bCollisionAvoidDoGlobalAngleHack,						Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.ToFollowPointScaling",            &s_fToFollowPointScaling,            0.0f,	FLT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
    //Asura_CommandConsole::AddVar( L"AVP.AI.FocusGuid",                       &s_uFocusGuid,                       0,		INT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	Asura_CommandConsole::AddVar( L"AVP.AI.RenderDebugInfo",			&s_bRenderDebugInfo,		Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"AVP.AI.RenderSentryGunDebugInfo",	&s_bRenderSentryDebugInfo,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"AVP.AI.RenderGS2DebugInfo",			&s_bRenderGS2DebugInfo,		Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"AVP.AI.DisableAIUpdates",			&s_bDisableAIUpdates,		Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"AVP.AI.RenderNavData",				&s_bRenderNavData,			Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	Asura_CommandConsole::AddVar( L"AVP.AI.KnowledgeRenderGuid",	&s_uKnowledgeRenderGuid,	0,	INT_MAX,	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	Asura_CommandConsole::AddVar( L"AVP.AI.AlienPlayerLightCutOffValue",		&s_fLightCutOffValue,			0.0f, 10.0f, 	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"AVP.AI.AlienPlayerLightCutOffTimeOut",		&s_fLightCutOffTimeOut,			0.0f, 5.0f, 	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"AVP.AI.AlienPlayerAndroidLightCutOffValue",	&s_fAndroidLightCutOffValue,	0.0f, 10.0f, 	Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	//Asura_CommandConsole::AddVar( L"AVP.DoTest", &s_bDoTest, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	AVP_Navigation::AddCommandConsoleVars();
#endif
}

//static void TestMultiThreadedWaypointing()
//{
//	if ( Asura_AI_Navigation_System::GetNumberOfWaypoints() == 0 )
//	{
//		return;
//	}
//
//	static AVP_Navigation::NavData	s_axNavData[ 32 ];
//	static Asura_Handle				s_aiRouteFindHandle[ 32 ];
//	static bool						s_bInit = false;
//
//	if ( s_bInit == false )
//	{
//		s_bInit = true;
//
//		for ( int i = 0; i < 32; ++i )
//		{
//			s_aiRouteFindHandle[ i ] = ASURA_INVALID_HANDLE;
//		}
//	}
//
//	const int iNumToCreate = Asura_Random::GetInt( 1, 5 );
//	for ( int i = 0; i < iNumToCreate; ++i )
//	{
//		for ( int j = 0; j < 32; ++j )
//		{
//			if ( s_aiRouteFindHandle[ j ] == ASURA_INVALID_HANDLE )
//			{
//				// Get a route to test out the route finding.
//				// Pick a random waypoint, then another, and find a route between them.
//				// Pretend we're an Alien so we can cover most ground.
//				s_axNavData[ j ].m_uPathfinderFlags = AVP_Navigation::AVP_AI_PATHFINDER_FLAG_ALIEN_HIGH_MOBILITY | ASURA_AI_PATHFINDER_FLAGS_IGNOREZONES;
//				s_axNavData[ j ].m_ucCurrentZone	  = ASURA_NAVVERTEX_MAX_ZONE_ID;
//
//				const u_short usNumWaypoints = Asura_AI_Navigation_System::GetNumberOfWaypoints();
//				s_axNavData[ j ].m_usCurrentWPID  = static_cast< u_short >( Asura_Random::GetIntU( 0, usNumWaypoints - 1 ) );
//				s_axNavData[ j ].m_xStartPosition = Asura_AI_Navigation_System::GetWaypoint( s_axNavData[ j ].m_usCurrentWPID )->m_xPosition;
//				do 
//				{
//					s_axNavData[ j ].m_usDestinationWPID = static_cast< u_short >( Asura_Random::GetIntU( 0, usNumWaypoints - 1 ) );
//				} while ( s_axNavData[ j ].m_usDestinationWPID == s_axNavData[ j ].m_usCurrentWPID );
//				s_axNavData[ j ].m_xDestinationPosition = Asura_AI_Navigation_System::GetWaypoint( s_axNavData[ j ].m_usDestinationWPID )->m_xPosition;
//				s_aiRouteFindHandle[ j ] = AVP_RouteFind::RequestRouteFind( s_axNavData[ j ] );
//				Asura_OutputToDebugger( ( "%u: %d requested route %u->%u\n",
//					Asura_Timers::GetFrameNumber(), j, s_axNavData[ j ].m_usCurrentWPID, s_axNavData[ j ].m_usDestinationWPID ) );
//			}
//		}
//	}
//
//	for ( int j = 0; j < 32; ++j )
//	{
//		if ( s_aiRouteFindHandle[ j ] != ASURA_INVALID_HANDLE )
//		{
//			if ( AVP_RouteFind::GetRouteFindResults( s_aiRouteFindHandle[ j ], s_axNavData[ j ] ) )
//			{
//				if ( s_axNavData[ j ].m_usRouteLength > 0 )
//				{
//					Asura_OutputToDebugger( ( "%u: %d route succeeded %u->%u\n",
//						Asura_Timers::GetFrameNumber(), j, s_axNavData[ j ].m_usCurrentWPID, s_axNavData[ j ].m_usDestinationWPID ) );
//				}
//				else
//				{
//					Asura_OutputToDebugger( ( "%u: %d route failed %u->%u\n",
//						Asura_Timers::GetFrameNumber(), j, s_axNavData[ j ].m_usCurrentWPID, s_axNavData[ j ].m_usDestinationWPID ) );
//				}
//			}
//		}
//	}
//}

void Axon_Project_System::UpdateThis()
{
#ifndef ASURA_NO_DEBUG_OUTPUT
	if ( s_bDisableAIUpdates )
	{
		return;
	}

	if ( s_bRenderNavData )
	{
		static const float fRENDER_RANGE_SQ = 50.0f * 50.0f;

		const Asura_Vector_3& xCamPos = *Asura_Camera::GetPosition();

		for ( u_short us = 0; us < Asura_AI_Navigation_System::GetNumberOfWaypoints(); ++us )
		{
			const Asura_AI_NavVertex* pxWP = Asura_AI_Navigation_System::GetWaypoint( us );
			if ( ( pxWP->m_xPosition - xCamPos ).MagnitudeSquared() > fRENDER_RANGE_SQ )
			{
				continue;
			}

			if (!Asura_Camera::IsSphereInFrustum(pxWP->m_xPosition, pxWP->GetRadius()))
			{
				continue;
			}

			Asura_Matrix_3x3 xMOri; Asura_Maths::OrientationFromNormal(xMOri, -pxWP->GetNormal());
			Asura_Quat xQOri; xQOri.FromMatrix(xMOri);
			Asura_DebugLineRender::AddCylinder(pxWP->m_xPosition - (pxWP->GetNormal()), xQOri, pxWP->GetRadius(), pxWP->GetRadius() + 1.0f, 0xff888888, 6);

			for ( u_char uc = 0; uc	< pxWP->m_ucNumConnections; ++uc )
			{
				if ( pxWP->m_pxConnections[ uc ].m_usIndex > us )
				{
					const Asura_AI_NavVertex* pxNextWP = Asura_AI_Navigation_System::GetWaypoint( pxWP->m_pxConnections[ uc ].m_usIndex );
					Asura_DebugLineRender::AddLine( pxWP->m_xPosition, pxNextWP->m_xPosition, 0xffffffff );
				}
			}
		}
	}
#endif

	PARENT::UpdateThis();
}

void Axon_Project_System::ShutdownThis()
{
	//AVP_RouteFind::Shutdown();
// 	AVP_Brain_Actor_Marine::ShutdownPosEvalMempool();
	AVP_ServerEntity_Squad_FaceHugger::ShutdownMempools();
	AVP_ServerEntity_Squad_Alien::ShutdownMempools();
	AVP_Knowledge_System_Actor::DestroyStorage();
	AVP_Knowledge_System_AlienTeam::DestroyStorage();
	AVP_Navigation::ShutdownRouteMempools();
	Axon_Project_Brain::ShutdownBehaviourMempool();

#if defined(_DEBUG) && !defined(ASURA_NO_DEBUG_OUTPUT)
	AVP_Navigation::PosEvalFunctor::DestoryList();
#endif

	PARENT::ShutdownThis();
}

void Axon_Project_System::ResetThis()
{
	AVP_Knowledge_System_AlienTeam::ResetStorage();
	AVP_Knowledge_System_Actor::ResetStorage();

	//AVP_RouteFind::Reset();

	PARENT::ResetThis();
}

void Axon_Project_System::RegisterSound( const Asura_Guid uSourceGuid, const Asura_Vector_3* pxPosition, const u_int uSoundType, const float fSoundRange )
{
	AVP_ServerEntity_PhysicalObject* pxPhysicalObject = AVP_ServerEntity_PhysicalObject::FindEntity( uSourceGuid );
	u_short usClassification = ( pxPhysicalObject != NULL ) ? pxPhysicalObject->GetClassification() : 0;

	if ( uSoundType != AXON_SOUND_TYPE_NO_TYPE )
	{
		Asura_Vector_3 xSoundPosition(pxPosition->x, pxPosition->y, pxPosition->z);

		Axon_System::GetSoundRegistry()->RegisterSound(uSourceGuid, usClassification, xSoundPosition, fSoundRange, uSoundType );
	}
}

void Axon_Project_System::PostLoadInitialiseThis()
{
    PARENT::PostLoadInitialiseThis();

	UpdateFromSettingsBlueprint();

    //Axon_Project_Brain::GetMarineAISettingsFromBlueprint();

    //Asura_Thread_System::CreateThread( "AI Thread", UpdateWaypointLightingValues_ThreadFn, NULL );
}

void Axon_Project_System::UpdateWaypointLightingValues_ThreadFn( const void* pUserData )
{
    const u_short usNumWaypoints = Asura_AI_Navigation_System::GetNumberOfWaypoints();
    if ( usNumWaypoints == 0 )
    {
        return;
    }

    u_int uUpdateCount = 0;
    do
    {
        Asura_Thread_System::DelayCurrentThread( 0.02f, false );

        // Splitting the waypoints into 128 batches. This should mean that the waypoints get updated every 2.5 seconds or so.
        //const u_int uUpdateMask = uUpdateCount & 0x000007f;


        // Getting the static value.
        // Iterating over the projectors (using their frustum) and the omni-photons (?) and adding their contribution.

        ++uUpdateCount;
    } while ( 1 );
}

void Axon_Project_System::UpdateFromSettingsBlueprint()
{
	// Get the central settings (footstep range, etc).
}

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////

Axon_BehaviourParams* Axon_BehaviourParams::Project_Create( const u_int uParamType, const u_int uBehaviourType )
{
	Axon_BehaviourParams* pxBehaviourParams = NULL;

	switch ( uParamType )
	{
		case AVP_BP_TYPE_MARINE_COMBAT:
		{
			pxBehaviourParams = new AVP_BehaviourParams_Marine_Combat( uBehaviourType );
			break;
		}

		case AVP_BP_TYPE_MARINE_LOOKAT:
		{
			pxBehaviourParams = new AVP_BehaviourParams_Marine_LookAt( uBehaviourType );
			break;
		}

		case AVP_BP_TYPE_MARINE_SPLINE_COMBAT:
		{
			pxBehaviourParams = new AVP_BehaviourParams_GS2Spline_Marine_Combat( uBehaviourType );
			break;
		}

		case AVP_BP_TYPE_GS2_NODE_ANIMMESSAGES:
		{
			pxBehaviourParams = new AVP_BehaviourParams_GS2Node_AnimMessages( uBehaviourType );
			break;
		}

		case AVP_BS_ID_NODE_HUMAN_GS2_ACTOR_WITH_GUNFIRE:
		{
			pxBehaviourParams = new Axon_BehaviourParams_GS2Node( AXON_BEHAVIOUR_TYPE_HUMAN_GS2NODE_ACTOR_WITH_GUNFIRE );
			break;
		}

		case AVP_BS_ID_SPLINE_HUMAN_GS2_ACTOR_WITH_GUNFIRE:
		{
			pxBehaviourParams = new Axon_BehaviourParams_GS2Spline( AXON_BEHAVIOUR_TYPE_HUMAN_GS2SPLINE_ACTOR_WITH_GUNFIRE );
			break;
		}

		default:
			break;
	}

	return pxBehaviourParams;
}

bool Axon_BehaviourParams::Project_CreateTree( const int iBehaviourSet, Axon_BehaviourParams*& pxBehaviourParams )
{
	switch ( iBehaviourSet )
	{
		case AVP_BS_ID_NODE_ROUTE_TRAVERSE:
		{
			pxBehaviourParams = new Axon_BehaviourParams( AVP_BEHAVIOUR_TYPE_GS2_NODE_ROUTETRAVERSE );
			return true;

		}break;

		case AVP_BS_ID_NODE_MARINE_COMBAT:
		{
			pxBehaviourParams = new AVP_BehaviourParams_Marine_Combat( AVP_BEHAVIOUR_TYPE_GS2_MARINE_NODE_COMBAT );
			return true;

		}break;

		case AVP_BS_ID_NODE_MARINE_LOOK_AT:
		{
			pxBehaviourParams = new AVP_BehaviourParams_Marine_LookAt( AVP_BEHAVIOUR_TYPE_GS2_MARINE_NODE_LOOKAT );
			return true;

		}break;

		case AVP_BS_ID_SPLINE_MARINE_COMBAT:
		{
			pxBehaviourParams = new AVP_BehaviourParams_GS2Spline_Marine_Combat( AVP_BEHAVIOUR_TYPE_GS2_MARINE_SPLINE_COMBAT );
			return true;

		}break;

		case AVP_BS_ID_NODE_ANIMMESSAGES:
		{
			pxBehaviourParams = new AVP_BehaviourParams_GS2Node_AnimMessages( AVP_BEHAVIOUR_TYPE_GS2_NODE_ANIMMESSAGES );
			return true;

		}break;

		case AVP_BS_ID_NODE_HUMAN_GS2_ACTOR_WITH_GUNFIRE:
		{
			pxBehaviourParams = new Axon_BehaviourParams_GS2Node( AXON_BEHAVIOUR_TYPE_HUMAN_GS2NODE_ACTOR_WITH_GUNFIRE );
			return true;

		}break;

		case AVP_BS_ID_SPLINE_HUMAN_GS2_ACTOR_WITH_GUNFIRE:
		{
			pxBehaviourParams = new Axon_BehaviourParams_GS2Spline( AXON_BEHAVIOUR_TYPE_HUMAN_GS2SPLINE_ACTOR_WITH_GUNFIRE );
			return true;

		}break;

		default:
		{
			return false;

		}break;
	}
}

bool Axon_BehaviourParams::Project_ConvertTree( const int iBehaviourSet, const Axon_BehaviourParams* pxOldBehaviourParams, Axon_BehaviourParams*& pxNewBehaviourParams )
{
	if ( iBehaviourSet == AVP_BS_ID_NODE_MARINE_COMBAT )
	{
		// Convert from the old blank params type to the new marine combat one.
		if ( !pxOldBehaviourParams || pxOldBehaviourParams->GetParamsType() == AXON_BP_TYPE_BLANK )
		{
			pxNewBehaviourParams = new AVP_BehaviourParams_Marine_Combat( AVP_BEHAVIOUR_TYPE_GS2_MARINE_NODE_COMBAT );
			return true;
		}
	}
	else if ( iBehaviourSet == AVP_BS_ID_NODE_MARINE_LOOK_AT )
	{
		// Convert from the old blank params type to the new marine look-at one.
		if ( !pxOldBehaviourParams || pxOldBehaviourParams->GetParamsType() == AXON_BP_TYPE_BLANK )
		{
			pxNewBehaviourParams = new AVP_BehaviourParams_Marine_LookAt( AVP_BEHAVIOUR_TYPE_GS2_MARINE_NODE_LOOKAT );
			return true;
		}
	}
	else if ( iBehaviourSet == AVP_BS_ID_SPLINE_MARINE_COMBAT )
	{
		// Convert from the old blank params type to the new marine look-at one.
		if ( !pxOldBehaviourParams || pxOldBehaviourParams->GetParamsType() == AXON_BP_TYPE_BLANK )
		{
			pxNewBehaviourParams = new AVP_BehaviourParams_GS2Spline_Marine_Combat( AVP_BEHAVIOUR_TYPE_GS2_MARINE_SPLINE_COMBAT );
			return true;
		}
	}
	else if ( iBehaviourSet == AVP_BS_ID_NODE_HUMAN_GS2_ACTOR_WITH_GUNFIRE )
	{
		// Convert from the old blank params type to the new marine look-at one.
		if ( !pxOldBehaviourParams || pxOldBehaviourParams->GetParamsType() == AXON_BP_TYPE_BLANK )
		{
			pxNewBehaviourParams = new Axon_BehaviourParams_GS2Node( AXON_BEHAVIOUR_TYPE_HUMAN_GS2NODE_ACTOR_WITH_GUNFIRE );
			return true;
		}
	}
	else if ( iBehaviourSet == AVP_BS_ID_SPLINE_HUMAN_GS2_ACTOR_WITH_GUNFIRE )
	{
		// Convert from the old blank params type to the new marine look-at one.
		if ( !pxOldBehaviourParams || pxOldBehaviourParams->GetParamsType() == AXON_BP_TYPE_BLANK )
		{
			pxNewBehaviourParams = new Axon_BehaviourParams_GS2Spline( AXON_BEHAVIOUR_TYPE_HUMAN_GS2SPLINE_ACTOR_WITH_GUNFIRE );
			return true;
		}
	}

	// You only need to add an entry here if you have changed which behaviour parameters go with which behaviour set
	// and you need to convert from the old to the new.

	return false;
}

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
