//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Mode_Object.cpp
//
// Copyright (c) 2006 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header.
#include "Objects/ToolsAVP_Mode_Object.h"

// Asura
#include "AI/Asura_AI_Navigation.h"
#include "Core/Asura_UserInput.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/AVP_ServerNode_GS2Node.h"
#include "Entity/Triggers/Asura_ServerEntity_ProxyTrigger.h"
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Table_Dialog.h"
#include "Rendering/Asura_Font_System.h"

// project
#include "AnimTemplates/AVP_GS2_AnimPackage.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/AVP_Messages.h"
#include "Entity/Controller/AVP_Controller_Messages.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_Alien.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_FaceHugger.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_Marine.h"
#include "Entity/Controller/AVP_ServerEntity_Team_Alien.h"
#include "Entity/Controller/AVP_ServerEntity_Team_Marine.h"
#include "Entity/ObjectiveSystem/RoomNode/ToolsAVP_Entity_RoomNode.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Inventory/AVP_Inventory_ItemTypes.h"

// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/AVP_Waypoint_Manager.h"
#include "Core/BrainTypes/AVP_Brain_Actor.h"

// Tools
#include "AnimTemplates/Tools_Mode_AnimTemplates.h"
#include "Entity/Tools_Entity_AdvancedVolumeTrigger.h"
#include "Entity/Tools_Entity_Data.h"
#include "Entity/Tools_Message_Editing.h"
#include "Entity/Tools_SecondaryEntityFile_System.h"
#include "Hierarchy/Tools_Animation_Files.h"
#include "Load&Save/Tools_ModeDataFile.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/Axon/Tools_Object_Axon_Interface.h"

// Project tools.
#include "Entity/Tools_Project_Entity_CheckPointNode.h"
#include "Entity/Controller/ToolsAVP_Entity_AlienTeam.h"
#include "Entity/Controller/ToolsAVP_Entity_MarineSquad.h"
#include "Entity/Controller/ToolsAVP_Entity_MarineTeam.h"
#include "Entity/Controller/ToolsAVP_Entity_Squad_Alien.h"
#include "Entity/Controller/ToolsAVP_Entity_Squad_FaceHugger.h"
#include "Entity/GameMode/ToolsAVP_Entity_GameMode.h"
#include "Entity/GamePlayVolume/ToolsAVP_Entity_GamePlayVolume.h"
#include "Entity/Locations/Tools_Entity_Node.h"
#include "Entity/Locations/FleePoint/ToolsAVP_Node_FleePoint.h"
#include "Entity/Locations/FormationPoint/ToolsAVP_Node_FormationPoint.h"
#include "Entity/Locations/GuardZone/ToolsAVP_Node_GuardZone.h"
#include "Entity/Locations/LookAt/ToolsAVP_Entity_LookAt.h"
#include "Entity/Locations/Objective/ToolsAVP_Node_Objective.h"
#include "Entity/Locations/Objective/Marine/ToolsAVP_Node_Objective_Marine.h"
#include "Entity/Locations/OrientedNode/ToolsAVP_Node_OrientedNode.h"
#include "Entity/Locations/OrientedNode/CoverpointNode/ToolsAVP_Entity_CoverpointNode.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/ToolsAVP_Node_GS2Node.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/AttractorNode/ToolsAVP_Node_GS2Attractor.h"
#include "Entity/Locations/ShootAt/ToolsAVP_Entity_ShootAt.h"
#include "Entity/Locations/Spline/GamesceneSpline/ToolsAVP_Node_GS2Spline.h"
#include "Entity/Locations/VantagePoint/ToolsAVP_Node_VantagePoint_Predator.h"
#include "Entity/MotionTrackerBlip/ToolsAVP_Entity_MotionTrackerBlip.h"
#include "Entity/ObjectiveSystem/PlayerObjective/ToolsAVP_Entity_PlayerObjective.h"
#include "Entity/Pheromone/ToolsAVP_Entity_Pheromone.h"
#include "Entity/PhysicalObject/Actor/Vehicles/Dropship/ToolsAVP_Entity_Dropship.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Alien/ToolsAVP_Entity_Alien.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Alien/ToolsAVP_Entity_AlienQueen.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Alien/ToolsAVP_Entity_FaceHugger.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/ToolsAVP_Entity_Android.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/ToolsAVP_Entity_Civilian.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/ToolsAVP_Entity_Marine.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/ToolsAVP_Entity_Predalien.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/ToolsAVP_Entity_Predator.h"
#include "Entity/PhysicalObject/Actor/Weapons/Sentrygun/ToolsAVP_Entity_Sentrygun.h"
#include "Entity/PhysicalObject/CommandPost/ToolsAVP_Entity_CommandPost.h"
#include "Entity/PhysicalObject/PhysicsObject/DamageableObject/ToolsAVP_Entity_DamageableObject.h"
#include "Entity/PhysicalObject/PhysicsObject/ToolsAVP_Entity_PhysicsObject.h"
#include "Entity/PhysicalObject/Pickup/ToolsAVP_Entity_Pickup.h"
#include "Entity/PhysicalObject/Interact/ToolsAVP_Entity_InteractObject.h"
#include "Entity/PhysicalObject/Interact/InvisiSwitch/ToolsAVP_Entity_InteractInvisiSwitch.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/ToolsAVP_Entity_InteractToolReceptacle.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/BatteryReceptacle/ToolsAVP_Entity_InteractBatteryReceptacle.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/HackingPoint/ToolsAVP_Entity_InteractHackingPoint.h"
#include "Entity/PhysicalObject/Interact/ToolReceptacle/RetinalScanner/ToolsAVP_Entity_InteractRetinalScanner.h"
#include "Entity/PhysicalObject/Interact/PredatorLock/ToolsAVP_Entity_InteractPredatorLock.h"
#include "Entity/PlayerProxy/ToolsAVP_Entity_PlayerProxy.h"
#include "Entity/Spawners/ToolsAVP_Entity_SpawnController.h"
#include "Entity/Spawners/ToolsAVP_Entity_SpawnPoint2.h"
#include "Entity/Triggers/ToolsAVP_Entity_InteractionTrigger.h"
#include "Entity/Triggers/ToolsAVP_Entity_VolumeTrigger.h"
#include "Entity/Triggers/ToolsAVP_Entity_WaypointBlockerVolume.h"
#include "Entity/Vent/ToolsAVP_Entity_Vent.h"
#include "Misc/Tools_LOS.h"
#include "Objects/ToolsAVP_Object_Type.h"

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

//
// ToolsAVP_Mode_Object
//

int  ToolsAVP_Mode_Object::s_iWPUnderCursor = -1;
bool ToolsAVP_Mode_Object::s_bShowWPLighting  = false;
bool ToolsAVP_Mode_Object::s_bPaintWPLighting = false;
float ToolsAVP_Mode_Object::s_fHideWPLightValue = 0.0f;
float ToolsAVP_Mode_Object::s_fMaxWPLightValue = 0.1f;

ToolsAVP_Mode_Object::ToolsAVP_Mode_Object( void )
{
	m_fCategoryChangedTimer = 0.0f;
}

void ToolsAVP_Mode_Object::BuildObjectCreationList( void )
{
    PARENT::BuildObjectCreationList();

	// Remove redundant objects to be replaced by project specific
	Tools_Mode_Object::RemoveObjectCreationFunction(TOT_Entity_GuardZone);
	Tools_Mode_Object::RemoveObjectCreationFunction(TOT_Entity_AdvancedVolumeTrigger);	// Removed so we can give it a new name - should maybe be done in Asura itself soon
	Tools_Mode_Object::RemoveObjectCreationFunction(TOT_Entity_CoverpointNode);			// Removed so we can override it with a new version
	Tools_Mode_Object::RemoveObjectCreationFunction(TOT_Entity_GS2Node);
	Tools_Mode_Object::RemoveObjectCreationFunction(TOT_Entity_GS2Attractor);

	// This one doesn't even have a project replacement, it's just not needed.
	Tools_Mode_Object::RemoveObjectCreationFunction(TOT_Entity_CountedVolumeTrigger);

	//	Add AVP objects
	//	NOTE : GBT : Try to minimise the number of categories please!!!

	//	Actors
	AddObjectCreationFunction("Predator",				"Actor",			"Add Predator",					&ToolsAVP_Entity_Predator::Project_Create,			TOT_Entity_Predator);
	AddObjectCreationFunction("Alien",					"Actor",			"Add Alien",					&ToolsAVP_Entity_Alien::Project_Create,				TOT_Entity_Alien);
	AddObjectCreationFunction("AlienQueen",				"Actor",			"Add AlienQueen",				&ToolsAVP_Entity_AlienQueen::Project_Create,		TOT_Entity_AlienQueen);
	AddObjectCreationFunction("Face-Hugger",			"Actor",			"Add Face-Hugger",				&ToolsAVP_Entity_FaceHugger::Project_Create,		TOT_Entity_FaceHugger);
	AddObjectCreationFunction("Android",				"Actor",			"Add Android",					&ToolsAVP_Entity_Android::Project_Create,			TOT_Entity_Android);
	AddObjectCreationFunction("Civilian",				"Actor",			"Add Civilian",					&ToolsAVP_Entity_Civilian::Project_Create,			TOT_Entity_Civilian);
	AddObjectCreationFunction("Marine",					"Actor",			"Add Marine",					&ToolsAVP_Entity_Marine::Project_Create,			TOT_Entity_Marine);
	AddObjectCreationFunction("Sentrygun",				"Actor",			"Add Sentrygun",				&ToolsAVP_Entity_Sentrygun::Project_Create,			TOT_Entity_Sentrygun);
	AddObjectCreationFunction("DropShip",				"Actor",			"Add DropShip",					&ToolsAVP_Entity_Dropship::Project_Create,			TOT_Entity_Dropship);
	AddObjectCreationFunction("Predalien",				"Actor",			"Add Predalien",				&ToolsAVP_Entity_Predalien::Project_Create,			TOT_Entity_Predalien);



	//	Triggers
	AddObjectCreationFunction("Interaction Trigger",	"Trigger",			"Add Trigger",					ToolsAVP_Entity_InteractionTrigger::Project_Create,	TOT_Entity_AdvancedVolumeTrigger);

	//	AI Objects
    AddObjectCreationFunction("Humanoid Controller",		"Axon",			"Add Humanoid Controller",		ToolsAVP_Entity_MarineTeam::Create,                 TOT_Entity_AlienTeam);
	AddObjectCreationFunction("Guard Zone",					"Axon",			"Add GuardZone",				ToolsAVP_Node_GuardZone::Project_Create,			TOT_Entity_GuardZone);
	AddObjectCreationFunction("Game Play Volume",			"Axon",			"Add GamePlay Volume",			ToolsAVP_Entity_GamePlayVolume::Project_Create,		TOT_Entity_GamePlayVolume);
	AddObjectCreationFunction("GS2 Attractor (AVP)",		"Axon",			"Add AVP GS2 Attractor",		ToolsAVP_Node_GS2Attractor::Create,					TOT_Entity_AVPGS2Attractor);
	AddObjectCreationFunction("GS2 Node (AVP)",				"Axon",			"Add AVP GS2 Node",				ToolsAVP_Node_GS2Node::Create,						TOT_Entity_AVPGS2Node);
	AddObjectCreationFunction("Humanoid Squad",				"Axon",			"Add Humanoid Squad",			ToolsAVP_Entity_MarineSquad::Project_Create,		TOT_Entity_MarineSquad);
	AddObjectCreationFunction("Humanoid AI Goal",			"Axon",			"Add Humanoid Goal Point",		ToolsAVP_Node_Objective_Marine::Project_Create,		TOT_Entity_AI_Marine_Objective);
//	AddObjectCreationFunction("Humanoid Formation Point",	"Axon",			"Add Humanoid Formation Point",	ToolsAVP_Node_FormationPoint::Project_Create,		TOT_Entity_FormationPoint);
	AddObjectCreationFunction("Humanoid LookAt Point",		"Axon",			"Add Humanoid LookAt Point",	ToolsAVP_Entity_LookAt::Project_Create,				TOT_Entity_LookAt);
	AddObjectCreationFunction("Predator Vantage Point",		"Axon",			"Add Predator Vantage Point",   ToolsAVP_Node_VantagePoint_Predator::Create,		TOT_Entity_VantagePoint_Predator);
	AddObjectCreationFunction("Cover Point",				"Axon",			"Add Cover Point",				ToolsAVP_Entity_CoverpointNode::Create,				TOT_Entity_AVPCoverpointNode);
	AddObjectCreationFunction("Flee Point",					"Axon",			"Add Flee Point",				ToolsAVP_Node_FleePoint::Create,					TOT_Entity_FleePoint);
	AddObjectCreationFunction("Spawn Controller",			"Axon",			"Add Spawn Controller",			ToolsAVP_Entity_SpawnController::Create,			TOT_Entity_SpawnController);
	AddObjectCreationFunction("Spawn Point",				"Axon",			"Add Spawn Point",				ToolsAVP_Entity_SpawnPoint2::Create,				TOT_Entity_SpawnPoint2);
	AddObjectCreationFunction("Alien Squad",				"Axon",			"Add Alien Squad",				ToolsAVP_Entity_Squad_Alien::Create,				TOT_Entity_AlienSquad);
	AddObjectCreationFunction("Face-Hugger Squad",			"Axon",			"Add Face-Hugger Squad",		ToolsAVP_Entity_Squad_FaceHugger::Create,			TOT_Entity_FaceHuggerSquad);
	AddObjectCreationFunction("Shoot At Target",			"Axon",			"Add Shoot At Target",			ToolsAVP_Entity_ShootAt::Project_Create,			TOT_Entity_ShootAt);
	AddObjectCreationFunction("Motion Tracker Blip",		"Axon",			"Add Motion Tracker Blip",		ToolsAVP_Entity_MotionTrackerBlip::Project_Create,	TOT_Entity_MotionTrackerBlip);


	//	Physics Objects
	AddObjectCreationFunction("Damageable Object",		"Physical Object",	"Add Damageable Object",		ToolsAVP_Entity_DamageableObject::Create,			TOT_Entity_DamageableObject);
	AddObjectCreationFunction("Vent",					"Vent",				"Add Vent",						ToolsAVP_Entity_Vent::Create,						TOT_Entity_Vent);

	//	Physical Objects
	AddObjectCreationFunction("Interaction Object",		"Interaction Object",	"Add Interaction Object",		ToolsAVP_Entity_InteractObject::Create,				TOT_Entity_InteractiveObject);

	//	Predator Puzzle
	AddObjectCreationFunction("Predator Puzzle",		"Interaction Object",	"Add Predator Puzzle",			ToolsAVP_Entity_InteractPredatorLock::Create,		TOT_Entity_InteractPredatorLock);

	//	Nodes
	AddObjectCreationFunction("Checkpoint Node",		"Misc",				"Add Checkpoint",				Tools_Project_Entity_CheckPointNode::Create,		TOT_Entity_CheckPointNode);

	// Volume triggers
	AddObjectCreationFunction("Volume Trigger", "Trigger", "New volume trigger, with more options on types of volume", ToolsAVP_Entity_VolumeTrigger::Create, TOT_Entity_VolumeTrigger);

	// Multiplayer
	AddObjectCreationFunction("Game Mode", "Multiplayer", "Add Game Mode", ToolsAVP_Entity_GameMode::Project_Create, TOT_Entity_GameMode );  
	AddObjectCreationFunction("Command Post", "Multiplayer", "Add Commnd Post", ToolsAVP_Entity_CommandPost::Project_Create, TOT_Entity_CommandPost ); 

    // Pickups
	AddObjectCreationFunction("Pickup", "Misc", "Pickup", ToolsAVP_Entity_Pickup::Create, TOT_Entity_Pickup);

	// Player objectives
	AddObjectCreationFunction("Player Objective", "Player Objective", "New player objective",	ToolsAVP_Entity_PlayerObjective::Project_Create,	TOT_Entity_Player_Objective);

	// Battery receptacle
	AddObjectCreationFunction("Battery Receptacle",	"Interaction Object",	"Add Battery Receptacle", ToolsAVP_Entity_InteractBatteryReceptacle::Create, TOT_Entity_InteractBatteryReceptacle);

	// Hacking Point
	AddObjectCreationFunction("Hacking Point",	"Interaction Object",	"Add Hacking Point", ToolsAVP_Entity_InteractHackingPoint::Create, TOT_Entity_InteractHackingPoint);

	// Invisible Switch
	AddObjectCreationFunction("Invisible Switch",	"Interaction Object",	"Add Invisible Switch", ToolsAVP_Entity_InteractInvisiSwitch::Create, TOT_Entity_InteractInvisiSwitch);

	// Retinal Scanner
	AddObjectCreationFunction("Retinal Scanner", "Interaction Object",	"Add Retinal Scanner", ToolsAVP_Entity_InteractRetinalScanner::Create, TOT_Entity_InteractRetinalScanner);

	// Room node
	AddObjectCreationFunction("Room Node", "Room Node",	"Add Room node", ToolsAVP_Entity_RoomNode::Create, TOT_Entity_RoomNode);

	// Player Proxy
	AddObjectCreationFunction("Player Proxy", "Player Proxy", "Add Player Proxy", ToolsAVP_Entity_PlayerProxy::Create, TOT_Entity_PlayerProxy);

	// AVP Waypoint Blocker Volume
	AddObjectCreationFunction("Waypoint Blocker Volume (AVP)", "Per specie Waypoint Blocker Volume", "Add AVP Waypoint Blocker Volume", ToolsAVP_Entity_WaypointBlockerVolume::Create, TOT_Entity_WaypointBlockerVolume);


	// SpecialFX
//	AddObjectCreationFunction("Pheromone", "Special FX", "Add Pheromone", ToolsAVP_Entity_Pheromone::Create, TOT_Entity_Pheromone);
}

void ToolsAVP_Mode_Object::InitialiseMode()
{
    PARENT::InitialiseMode();

	if ( Tools_SaveAsura::GetFileType() != AsuraFile_Template )
	{
		// If there is no Alien team in the level then create one in front of the camera.
		if ( !AVP_ServerEntity_Team_Alien::GetInstance() )
		{
			ToolsAVP_Entity_AlienTeam::Create();
			Tools_MessageLog::AddMessage( "", "", "An Alien Team has been created for this level automatically (each level should have one only)." );
			Tools_MessageLog::ShowOverlay();
		}

		// If there is no Marine team in the level then create one in front of the camera.
		if ( !AVP_ServerEntity_Team_Marine::GetInstance() )
		{
			ToolsAVP_Entity_MarineTeam::Create();
			Tools_MessageLog::AddMessage( "", "", "A Marine Team has been created for this level automatically (each level should have one only)." );
			Tools_MessageLog::ShowOverlay();
		}

		// If there is no default Alien squad in the level then create one in front of the camera.
		if ( !AVP_ServerEntity_Squad_Alien::GetDefaultSquad() )
		{
			ToolsAVP_Entity_Squad_Alien::CreateDefault();
			Tools_MessageLog::AddMessage( "", "", "A default Alien squad has been created for this level automatically (each level should have one only)." );
			Tools_MessageLog::ShowOverlay();
		}

		// If there is no default Pet squad in the level then create one in front of the camera.
		if ( !AVP_ServerEntity_Squad_FaceHugger::GetDefaultSquad() )
		{
			ToolsAVP_Entity_Squad_FaceHugger::CreateDefault();
			Tools_MessageLog::AddMessage( "", "", "A default FaceHugger squad has been created for this level automatically (each level should have one only)." );
			Tools_MessageLog::ShowOverlay();
		}
		if ( !AVP_ServerEntity_Squad_FaceHugger::GetDefaultPetSquad() )
		{
			ToolsAVP_Entity_Squad_FaceHugger::CreateDefaultPet();
			Tools_MessageLog::AddMessage( "", "", "A default FaceHugger Pet squad has been created for this level automatically (each level should have one only)." );
			Tools_MessageLog::ShowOverlay();
		}
	}
}

void ToolsAVP_Mode_Object::Update(void)
{
	PARENT::Update();

	if (Asura_Overlay_System::GetTopOverlayID() == TOOLS_OVERLAY_MODE)
	{
		m_fCategoryChangedTimer += Asura_Timers::GetFrameTime();

		if (m_fCategoryChangedTimer > 0.1f)
		{
			if (Asura_UserInput::DebouncedKeyPressed('o'))      // 'o' to change to previous category
			{
				m_fCategoryChangedTimer = 0.0f;
				s_iSelectedObjectCategory -= 1;
				s_bSelectedCategoryChanged = true;

				if (s_iSelectedObjectCategory < 0)
				{
					s_iSelectedObjectCategory = s_iNumObjectCategories - 1;
				}
			}
			else if (Asura_UserInput::DebouncedKeyPressed('p'))	// 'p' to change next category
			{
				m_fCategoryChangedTimer = 0.0f;
				s_iSelectedObjectCategory += 1;
				s_bSelectedCategoryChanged = true;

				if (s_iSelectedObjectCategory > s_iNumObjectCategories - 1)
				{
					s_iSelectedObjectCategory = 0;
				}
			}
		}
	}

	if ( s_bShowWPLighting )
	{
		int            iPolyIndex;
		int            iModuleIndex;
		Asura_Vector_3 xPosition;
		if ( Tools_LOS::FindPolyAndPositionUnderCursor( iPolyIndex, iModuleIndex, xPosition ) )
		{
			const short sTemp = Asura_AI_Navigation_System::FindWaypointNearestTo( xPosition, ASURA_NAVVERTEX_MAX_ZONE_ID, false, true, false );
			s_iWPUnderCursor = sTemp;
		}
	}
	else
	{
		s_bPaintWPLighting = false;
		s_iWPUnderCursor = -1;
	}
// 	if ( s_bPaintWPLighting )
// 	{
// 		if ( s_iWPUnderCursor != -1 )
// 		{
// 			if ( Asura_UserInput::KeyPressed( ASURA_KEYID_MOUSEBUTTON1 ) )
// 			{
// 				if ( Asura_UserInput::KeyPressed( ASURA_KEYID_CTRL ) )
// 				{
// 					AVP_Waypoint_Manager::DecrementLuminanceFactor( s_iWPUnderCursor, Asura_Timers::GetGameTimeSlice() );
// 					Tools_SaveAsura::SetWaypointingModified();
// 				}
// 				else if ( Asura_UserInput::KeyPressed( ASURA_KEYID_SHIFT ) )
// 				{
// 					AVP_Waypoint_Manager::IncrementLuminanceFactor( s_iWPUnderCursor, Asura_Timers::GetGameTimeSlice() );
// 					Tools_SaveAsura::SetWaypointingModified();
// 				}
// 			}
// 		}
// 	}
}

void ToolsAVP_Mode_Object::RenderWorld_PostToneMap()
{
	extern void Render_Sphere( const Asura_Vector_3& xCentre, float fRadius, int iColour );

	PARENT::RenderWorld_PostToneMap();

	if ( s_bShowWPLighting )
	{
		if ( s_iWPUnderCursor != -1 )
		{
			const Asura_AI_NavVertex* pxWP = Asura_AI_Navigation_System::GetWaypoint( s_iWPUnderCursor );
			Asura_Vector_3 xOutputPos = pxWP->m_xPosition;
			if ( Asura_Camera::ProjectWorldCoordsToScreenSpace( xOutputPos, true ) && xOutputPos.z >= 0.0f )
			{
				float fLuminanceFactor = AVP_Waypoint_Manager::GetWPLuminance( s_iWPUnderCursor );

				Asura_Font_System::Print( xOutputPos.x, xOutputPos.y, 1.0f, 0xffff0000,
					ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING,
					"%0.2f", fLuminanceFactor );
			}
		}

		for ( u_int u = 0; u < Asura_AI_Navigation_System::GetNumberOfWaypoints(); ++u )
		{
			const Asura_AI_NavVertex* pxWP = Asura_AI_Navigation_System::GetWaypoint( u );

			if ( ( *Asura_Camera::GetPosition() - pxWP->m_xPosition ).MagnitudeSquared() > 10000.0f )
			{
				continue;
			}

			const float fLuminanceFactor = AVP_Waypoint_Manager::GetWPLuminance( u );

			if (fLuminanceFactor >= s_fHideWPLightValue && fLuminanceFactor <= s_fMaxWPLightValue )
			{
				u_char ucColour = static_cast< u_char >( 0.1f + Asura_Maths::ClampToRange( (fLuminanceFactor - s_fHideWPLightValue) / (s_fMaxWPLightValue - s_fHideWPLightValue), 0.0f, 1.0f ) * 255.0f );

				int iColour = ( ucColour * 0x00010101 ) + 0x40000000;
				Render_Sphere( pxWP->m_xPosition, pxWP->GetRadius(), iColour );

			}

		}
	}
}

void ToolsAVP_Mode_Object::AddItemsToObjectModeOverlay( Asura_Overlay* pxNewOverlay, Asura_Vector_2& xOffset )
{
	PARENT::AddItemsToObjectModeOverlay( pxNewOverlay, xOffset );
	xOffset.y += Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();

	Asura_Dialog* pxNewDialog = new Asura_Function_Dialog( "Recalc wp light vals", xOffset, UpdateWaypointLightingValues );
	pxNewDialog->SetHelpText( "Recalculates the waypoint lighting values." );
	pxNewOverlay->AddDialog( pxNewDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

// 	pxNewDialog = new Asura_Function_Dialog( "Reset user light tweaks", xOffset, ResetUserWaypointLightingValues );
// 	pxNewDialog->SetHelpText( "Resets any user lighting tweaks that have been added to the waypoints." );
// 	pxNewOverlay->AddDialog( pxNewDialog );
// 	xOffset.y += Asura_Dialog::DefaultSpacing();
// 
	pxNewDialog = new Asura_Tickbox_Dialog( "Show WP Lighting", xOffset, &s_bShowWPLighting );
	pxNewOverlay->AddDialog( pxNewDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();
// 
// 	Asura_Tickbox_Dialog* pxNewTBDialog = new Asura_Tickbox_Dialog( "Paint WP Lighting", xOffset, &s_bPaintWPLighting );
// 	pxNewTBDialog->SetIsEnabledFunction( PaintWPEnabled );
// 	pxNewTBDialog->SetHelpText( "Hold SHIFT+LMB to increment/CTRL+LMB to decrement the value of the waypoint under the cursor." );
// 	pxNewOverlay->AddDialog( pxNewTBDialog );
// 	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxNewDialog = new Asura_Numerical_Dialog( "Light Range Min", xOffset, &s_fHideWPLightValue, 0.0f, 10.0f, 0.05f, "%0.2f" );
	pxNewDialog->SetIsEnabledFunction( PaintWPEnabled );
	pxNewDialog->SetHelpText( "Changes the min value that waypoint lighting values are rendered with" );
	pxNewOverlay->AddDialog( pxNewDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxNewDialog = new Asura_Numerical_Dialog( "Light Range Max", xOffset, &s_fMaxWPLightValue, 0.0f, 10.0f, 0.05f, "%0.2f" );
	pxNewDialog->SetIsEnabledFunction( PaintWPEnabled );
	pxNewDialog->SetHelpText( "Changes the max value that waypoint lighting values are rendered with" );
	pxNewOverlay->AddDialog( pxNewDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxNewDialog = new Asura_Function_Dialog("E3 Dodgy Message Check", xOffset, E3DodgyMessageCheck);
	pxNewDialog->SetHelpText("Searches for messages that refer to other objects within their message data , and so might be broken as a result of the secondary entity file issues");
	pxNewOverlay->AddDialog( pxNewDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();
} 

void ToolsAVP_Mode_Object::UpdateWaypointLightingValues()
{
	if ( !AVP_Waypoint_Manager::CalculateWaypointLuminanceFactors() )
	{
		Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "Calculation failed - try generating all extra data in waypointing mode." );
	}
	else
	{
		Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_SUCCESS, "Recalculated WP lighting values." );
		Tools_SaveAsura::SetWaypointingModified();
	}
}

void ToolsAVP_Mode_Object::ResetUserWaypointLightingValues()
{
	AVP_Waypoint_Manager::ResetUserLuminanceFactors();
	Tools_SaveAsura::SetWaypointingModified();
}

bool ToolsAVP_Mode_Object::PaintWPEnabled()
{
	return s_bShowWPLighting;
}

bool ToolsAVP_Mode_Object::DoVerificationTests( const bool bAutomatic )
{
	bool bOk = PARENT::DoVerificationTests( bAutomatic );
	bOk &= VerifyStaticMessages();
	return bOk;
}

bool ToolsAVP_Mode_Object::VerifyStaticMessages()
{
	bool bOk = true;

	// Make sure that all static messages have message IDs within the static message range.
	for ( Tools_StaticMessageIterator xSMIt; !xSMIt.Done(); xSMIt.Next() )
	{
		Asura_StaticMessage* pxMsg = xSMIt.GetCurrent();
		if ( pxMsg->m_usMsgID > AVP_MSGID_END_OF_STATIC_MESSAGES )
		{
			Tools_Object* pxFromObject = Tools_Object_System::GetOwnerOfMessageBlock( xSMIt.GetCurrentMessageBlockID() );
			if ( !pxFromObject )
			{
				continue;
			}

			Asura_String xErrorText( "Object '" );
			xErrorText += pxFromObject->GetName();
			xErrorText += "'";
			xErrorText += " is sending out-of-range static message ";
			xErrorText += Asura_Network::GetMsgIDDesc( pxMsg->m_usMsgID );
			xErrorText += " to object ";
			Tools_Object* pxToObject = Tools_Object_System::GetObjectFromGuid( pxMsg->m_uSendTo );
			if ( pxToObject )
			{
				xErrorText += "'";
				xErrorText += pxToObject->GetName();
				xErrorText += "'";
			}
			else
			{
				xErrorText += "with guid ";
				char acNum[ 12 ];
				Asura_PrintfToBfr( acNum, "%u", 12, true, pxMsg->m_uSendTo );
				xErrorText += acNum;
			}

			xErrorText += ".";

			Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Messages",
				new Tools_MessageLogAction_GotoEntity( pxFromObject->GetGuid() ),
				xErrorText.GetString() );

			bOk = false;
		}
	}

	// Test for deprecated messages.
	for ( Tools_StaticMessageIterator xSMIt; !xSMIt.Done(); xSMIt.Next() )
	{
		Asura_StaticMessage* pxMsg = xSMIt.GetCurrent();

		bool bDeprecated = false;
		switch ( pxMsg->m_usMsgID )
		{
			case AVP_MSGID_CHANGE_ALIEN_SPAWN_SETTINGS:
			case AVP_MSGID_ADD_ALIENS_TO_SPAWN_QUEUE:
			case AVP_MSGID_ALIEN_TEAM_SET_BEHAVIOUR:
			case AVP_MSGID_ALIEN_TEAM_ADD_SPAWNTOKEN:
			case AVP_MSGID_ALIEN_TEAM_REMOVE_SPAWNTOKEN:
			case AVP_MSGID_ALIEN_TEAM_PREPARE_ROOM:
			{
				bDeprecated = true;
				break;
			}
			
			case AVP_MSGID_ADD_AI_OBJECTIVE:
			{
				const AVP_Message_AddObjective* pxMsgData = static_cast< const AVP_Message_AddObjective* >( pxMsg->m_pData );

				if ( pxMsgData )
				{
					if ( pxMsgData->GetObjectiveGuid() == ASURA_GUID_UNREGISTERED )
					{
						Tools_Object* pxFromObject = Tools_Object_System::GetOwnerOfMessageBlock( xSMIt.GetCurrentMessageBlockID() );

						if ( pxFromObject )
						{
							Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Messages", new Tools_MessageLogAction_GotoEntity( pxFromObject->GetGuid() ), "Add AI Goal Message has no AI Goal Set, please fix." );
							bOk = false;
						}
					}
					else
					{
						ToolsAVP_Node_Objective_Marine* pxToolsObject = static_cast<ToolsAVP_Node_Objective_Marine*>( ToolsAVP_Node_Objective_Marine::FindEntity( pxMsgData->GetObjectiveGuid() ) );

						if ( !pxToolsObject )
						{
							Tools_Object* pxFromObject = Tools_Object_System::GetOwnerOfMessageBlock( xSMIt.GetCurrentMessageBlockID() );

							if ( pxFromObject )
							{
								Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Messages", new Tools_MessageLogAction_GotoEntity( pxFromObject->GetGuid() ), "Add AI Goal Message has an AI Goal Set, But that AI Goal does not exist!." );
								bOk = false;
							}
						}
					}
				}

 			}break;

			default:
				break;
		}

		if ( bDeprecated )
		{
			Tools_Object* pxFromObject = Tools_Object_System::GetOwnerOfMessageBlock( xSMIt.GetCurrentMessageBlockID() );
			if ( !pxFromObject )
			{
				continue;
			}

			Asura_String xErrorText( "Object '" );
			xErrorText += pxFromObject->GetName();
			xErrorText += "'";
			xErrorText += " is sending deprecated static message ";
			xErrorText += Asura_Network::GetMsgIDDesc( pxMsg->m_usMsgID );
			xErrorText += " to object ";
			Tools_Object* pxToObject = Tools_Object_System::GetObjectFromGuid( pxMsg->m_uSendTo );
			if ( pxToObject )
			{
				xErrorText += "'";
				xErrorText += pxToObject->GetName();
				xErrorText += "'";
			}
			else
			{
				xErrorText += "with guid ";
				char acNum[ 12 ];
				Asura_PrintfToBfr( acNum, "%u", 12, true, pxMsg->m_uSendTo );
				xErrorText += acNum;
			}

			xErrorText += ".";

			Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Messages",
				new Tools_MessageLogAction_GotoEntity( pxFromObject->GetGuid() ),
				xErrorText.GetString() );

			bOk = false;
		}
	}

	return bOk;
}

bool ToolsAVP_Mode_Object::EntityReceivesActivateMessage( Asura_Guid uGuid ) const
{
	// Marines and Androids can be activated via squads so we need to see if this happens before calling the parent.
	// (Changed to check the squad guid for all actors. RAR 01/04/2009)

	AVP_ServerEntity_Actor* pxEntity = AVP_ServerEntity_Actor::FindEntity(uGuid);

	if(pxEntity)
	{
		Asura_Guid uSquadGuid = pxEntity->GetInitialSquadGuid();
		if(uSquadGuid != ASURA_GUID_UNREGISTERED)
		{
			//check for the squad recieving an activate message
			if(PARENT::EntityReceivesActivateMessage(uSquadGuid))
			{
				return true;
			}
		}
	}

	return PARENT::EntityReceivesActivateMessage( uGuid );
}

void ToolsAVP_Mode_Object::E3DodgyMessageCheck()
{
	const char* szSubCat = "E3 Dodgy Message Check";
	Tools_MessageLog::DeleteMessages(Tools_MessageLog::ENTITIES, szSubCat);
	u_int uNextID = Tools_MessageLog::GetNextID();

	u_int uCount = 0;
	for(Tools_StaticMessageIterator xIt(true); !xIt.Done(); xIt.Next())
	{
		Asura_StaticMessage* pxMessage = xIt.GetCurrent();
		switch(pxMessage->m_usMsgID)
		{
			case ASURA_MSG_AXON_GS2_DONT_STOP_AT_NODE:
			case ASURA_MSG_AXON_GS2_TAKE_LINK:
			case ASURA_MSG_AXON_GS2_SET_LINK_WEIGHT:
			case ASURA_MSG_AXON_GS2_TELEPORT_TO_NODE:
			case ASURA_MSG_AXON_GS2_PATHFIND_TO_NODE:
			case AVP_MSGID_ADD_AI_OBJECTIVE:
			case AVP_MSGID_SPAWN_HUMANOIDS:
			case AVP_MSGID_MERGE_HUMANOID_SQUADS:
			case AVP_MSGID_SPLIT_HUMANOID_SQUAD:
			case AVP_MSGID_ADD_SQUAD_MEMBER :
			case AVP_MSGID_REMOVE_SQUAD_MEMBER :
			case AVP_MSGID_REQUEST_HUMANOID_PATROL :
			case AVP_MSGID_PERFORM_AI_OBJECTIVE_ACTION:
			case AVP_MSGID_SPAWN:
			case AVP_MSGID_SET_AI_TARGET_PRIORITIES:
			case AVP_MSGID_CHANGE_MARINE_SQUAD_SETTINGS :
			case AVP_MSGID_ATTACK_SCRIPTED_TARGET:
			case AVP_MSGID_ADD_PLAYER_OBJECTIVE:
			case AVP_MSGID_SET_PLAYER_OBJECTIVE_COMPLETE:
			case AVP_MSGID_PLAYER_OBJECTIVE_SET_MARKER_LOCATION :
			case AVP_MSGID_PLAYER_OBJECTIVE_SET_TARGET_ENTITY:
			case AVP_MSGID_ADD_PLAYER_PICKUP:
			case AVP_MSGID_LOOK_AT_ENTITY :
			case AVP_MSGID_SET_HEALTH:
			case AVP_MSGID_ALIENQUEEN_ADD_TO_TARGET_LIST:
			case AVP_MSGID_ALIENQUEEN_REMOVE_FROM_TARGET_LIST:
			case AVP_MSGID_ALIENQUEEN_FORCE_ROAR:
			case AVP_MSGID_START_CAMERA_SHAKE:
			case AVP_MSGID_STOP_CAMERA_SHAKE:
			case AVP_MSGID_FACEHUGGER_HUG_ENTITY:
			case AVP_MSGID_DISMEMBER:
			{
				Tools_StaticMessageID xMessageID;
				xIt.GetCurrentMessageID(xMessageID);
				//Search for messages that are being sent from a secondary entity file.
				bool bNeedCheck = false;
				if(xMessageID.GetLocation() == TOOLS_STATICMESSAGELOCATION_STATICMESSAGE)
				{
					Tools_Object* pxSender = Tools_Object_System::GetOwnerOfMessageBlock(xMessageID.GetStaticMessageBlockID());
					if(pxSender && pxSender->IsEntityObject())
					{
						Tools_Entity_Object* pxToolsEntity = (Tools_Entity_Object*) pxSender;
						if(!pxToolsEntity->Entity->ToolsData->m_xSecondaryEntityFilename.IsBlank())
						{
							bNeedCheck = true;
						}

					}
					else
					{
						bNeedCheck = true;
					}
				}
				else
				{
					bNeedCheck = true;
				}
				if(bNeedCheck)
				{
					Asura_String xMessageDesc;
					Tools_Message_Editing::GetMessageDescription(pxMessage->m_usMsgID, NULL, xMessageDesc);

					Asura_String xSender;
					xMessageID.GetSenderInfo(NULL, &xSender, NULL);
		
					Tools_MessageLog::AddMessage(Tools_MessageLog::ENTITIES, szSubCat, 
												new Tools_MessageLogAction_StaticMessage(xMessageID), 
												"'%s' sends '%s'", xSender.GetString(), xMessageDesc);
					uCount++;
				}

				break;
			}
			
		}
	}
	if(uCount)
	{
		Tools_Timed_Message_System::AddMessage( 0xffffff, "Found %d message(s) that might be broken", uCount );
		Tools_MessageLog::ShowOverlay(Tools_MessageLog::ENTITIES, szSubCat, uNextID);
	}
	else
	{
		Tools_Timed_Message_System::AddMessage( 0xffffff, "No potentially broken messages were found" );
	}

}

//////////////////////////////////////////////////////////////////////////////
//
// Anim Template Mapping Factor strings
//
//////////////////////////////////////////////////////////////////////////////

static const char* s_pszMappingNames[ NUM_AVP_GS2_MAPPING_FACTORS ] =
{
	"Skin",
	"Weapon"
};

static const char* s_pszWeaponMappingFactorStrings[ AVP_WMF_NUM_WEAPONMAPPINGFACTORS ] =
{
	"X",
	"Flamethrower",
	"Shotgun",
	"Smartgun"
};

//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Object_Axon_Interface
//
//////////////////////////////////////////////////////////////////////////////

class ToolsAVP_Object_Axon_Interface : public Tools_Object_Axon_Interface
{
	typedef Tools_Object_Axon_Interface PARENT;

public:
	virtual void TransferModeData( Tools_ModeDataFile& xFile );

	virtual void* GetPreviewScoringData() { return &s_xScoringData; }

	virtual Asura_String GetSkinNameFromGuid( const Asura_Guid uGuid ) const;

	virtual void BuildGS2StructureList( ListSelection_Overlay& xList, const Tools_EntityNode_GS2Node* pxGS2Node = NULL );
	virtual void BuildGS2NodeBehaviourSetList( ListSelection_Overlay& xList, const Tools_EntityNode_GS2Node* pxGS2Node = NULL );
	virtual void BuildGS2SplineBehaviourSetList( ListSelection_Overlay& xList, const Tools_EntityNode_GS2Spline* pxGS2Spline = NULL );
	virtual void ForEachGS2StartNode( TOGV_NodeOwnerGuidFn* pfnNodeOwnerGuidCallback );

	virtual Tools_EntityNode_GS2Node*   CreateGS2Node();
	virtual Tools_EntityNode_GS2Spline* CreateGS2Link();

private:
	virtual void AddPreviewSettingsControls( Asura_Overlay* pxNewOverlay, Asura_Vector_2& xOffset );

	static void PickPreviewSkin();

	static AVP_GS2_AnimMappingData s_xScoringData;

	enum { CURRENT_TRANSFER_VERSION = 0 };
};

AVP_GS2_AnimMappingData ToolsAVP_Object_Axon_Interface::s_xScoringData;

Tools_Object_Axon_Interface* Tools_Object_Axon_Interface::Project_CreateAxonInterface()
{
	return new ToolsAVP_Object_Axon_Interface;
}

void ToolsAVP_Object_Axon_Interface::TransferModeData( Tools_ModeDataFile& xFile )
{
	int iVersion = CURRENT_TRANSFER_VERSION;
	xFile.Transfer( iVersion );

	PARENT::TransferModeData( xFile );

	if ( iVersion == CURRENT_TRANSFER_VERSION )
	{
		xFile.Transfer( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] );
		xFile.Transfer( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ] );
	}
	else
	{
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] = ASURA_HASH_ID_UNSET;
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ] = AVP_WMF_X;
	}
}

Asura_String ToolsAVP_Object_Axon_Interface::GetSkinNameFromGuid( const Asura_Guid uGuid ) const
{
	AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( uGuid );
	if ( !pxActor ) { return Asura_String( "" ); }

	Asura_Blueprint* pxActorBP = pxActor->GetBlueprint();
	if ( pxActorBP )
	{
		Asura_Value xValue;
		if ( pxActorBP->GetParameterValueByHashID( 0xbe7b9f98, xValue ) ) // Asura_GetHashID( "ThirdPerson.Skin.Main" )
		{
			Asura_String xSkinFileName = xValue.GetHashStringValue();

			// Need to do some fixing up of the skin name because of the torso, hands, feet skin thing.
			if ( Asura_StringUtil::Contains( xSkinFileName.GetString(), "marine" ) )
			{
				xSkinFileName = "marinetestfullrig.asr";
			}

			if (!xSkinFileName.IsBlank())
			{
				Asura_String xSkinName;
				xSkinFileName.SplitFilename(NULL, &xSkinName, NULL);

				if ( Tools_Animation_Files::GetSkinFromID( xSkinName.GetHash() ) )
				{
					return xSkinName.GetString();
				}
			}
		}
	}

	return Asura_String( "" );
}

void ToolsAVP_Object_Axon_Interface::BuildGS2NodeBehaviourSetList( ListSelection_Overlay& xList, const Tools_EntityNode_GS2Node* pxGS2Node /*= NULL*/ )
{
	PARENT::BuildGS2NodeBehaviourSetList( xList, pxGS2Node );

	static struct StringAndValue
	{
		const char* m_pszString;
		int			m_iValue;
	} s_axNodeBehaviours[] =
	{
		{ "AVP Route Traversal",                 AVP_BS_ID_NODE_ROUTE_TRAVERSE },
		{ "AVP Humanoid Node Combat",            AVP_BS_ID_NODE_MARINE_COMBAT },
		{ "AVP Humanoid Node LookAt",            AVP_BS_ID_NODE_MARINE_LOOK_AT },
		{ "AVP Anim & Messages",	             AVP_BS_ID_NODE_ANIMMESSAGES },
		{ "AVP Human Core Node With Gunfire",    AVP_BS_ID_NODE_HUMAN_GS2_ACTOR_WITH_GUNFIRE },
		{ "",                          -1 } // terminator
	};

	StringAndValue* pxEntry = s_axNodeBehaviours;
	while ( pxEntry->m_iValue != -1 )
	{
		xList.AddItem( pxEntry->m_pszString, pxEntry->m_iValue );
		++pxEntry;
	}
}

void ToolsAVP_Object_Axon_Interface::BuildGS2SplineBehaviourSetList( ListSelection_Overlay& xList, const Tools_EntityNode_GS2Spline* pxGS2Spline /*= NULL*/ )
{
	PARENT::BuildGS2SplineBehaviourSetList( xList, pxGS2Spline );

	static struct StringAndValue
	{
		const char* m_pszString;
		int			m_iValue;
	} s_axSplineBehaviours[] =
	{
		{ "Marine Combat Spline Behaviour",	     AVP_BS_ID_SPLINE_MARINE_COMBAT },
		{ "AVP Human Core Spline With Gunfire",  AVP_BS_ID_SPLINE_HUMAN_GS2_ACTOR_WITH_GUNFIRE },
		{ "",								-1 } // terminator
	};

	StringAndValue* pxEntry = s_axSplineBehaviours;
	while ( pxEntry->m_iValue != -1 )
	{
		xList.AddItem( pxEntry->m_pszString, pxEntry->m_iValue );
		++pxEntry;
	}
}

void ToolsAVP_Object_Axon_Interface::BuildGS2StructureList( ListSelection_Overlay& xList, const Tools_EntityNode_GS2Node* pxGS2Node /*= NULL*/ )
{
	PARENT::BuildGS2StructureList( xList, pxGS2Node );

	static struct StringAndValue
	{
		const char* m_pszString;
		int			m_iValue;
	} s_axStructures[] =
	{
		{ "Alien Vent",				AVP_GS_ST_ALIEN_VENT },
		{ "Predator Jump",			AVP_GS_ST_PREDATOR_JUMP },
		{ "Marine Required Action", AVP_GS_ST_REQUIRED_MARINE_ACTION },
		{ "Marine Optional Action", AVP_GS_ST_OPTIONAL_MARINE_ACTION },
		{ "Civilian Action",		AVP_GS_ST_CIVILIAN_ACTION },
		{ "Humanoid Flee Action",	AVP_GS_ST_HUMANOID_FLEE_ACTION },
		{ "Motion Tracker Blip",	AVP_GS_ST_MOTION_TRACKER_BLIP },
		{ "",						-1 } // terminator
	};

	StringAndValue* pxEntry = s_axStructures;
	while ( pxEntry->m_iValue != -1 )
	{
		xList.AddItem( pxEntry->m_pszString, pxEntry->m_iValue );
		++pxEntry;
	}
}

void ToolsAVP_Object_Axon_Interface::ForEachGS2StartNode( TOGV_NodeOwnerGuidFn* pfnNodeOwnerGuidCallback )
{
	for ( Asura_Hashed_List_It< AVP_ServerEntity_Actor > xActorIter( AVP_ServerEntity_Actor::GetList() ); !xActorIter.Done(); xActorIter.Next() )
	{
		// If the actor has a start node set, then pass this to the callback.
		AVP_ServerEntity_Actor* pxActor = xActorIter.GetCurrent();
		if ( pxActor && pxActor->GetActorBrain() && pxActor->GetInitialGamesceneGuid() != ASURA_GUID_UNREGISTERED )
		{
			Asura_ServerNode_GS2Node* pxNode = Asura_ServerNode_GS2Node::FindEntity( pxActor->GetInitialGamesceneGuid() );
			if ( pxNode )
			{
				pfnNodeOwnerGuidCallback( pxNode, pxActor->GetGuid() );
			}
		}
	}
}

Tools_EntityNode_GS2Node* ToolsAVP_Object_Axon_Interface::CreateGS2Node()
{
	Tools_SecondaryEntityFile_System::PreCreateObject();
	Tools_EntityNode_GS2Node* pxNode = ToolsAVP_Node_GS2Node::CreateAndReturn();
	Tools_SecondaryEntityFile_System::PostCreateObject();
	return pxNode;
}

Tools_EntityNode_GS2Spline* ToolsAVP_Object_Axon_Interface::CreateGS2Link()
{
	Tools_SecondaryEntityFile_System::PreCreateObject();
	Tools_EntityNode_GS2Spline* pxSpline = ToolsAVP_Node_GS2Spline::Create();
	Tools_SecondaryEntityFile_System::PostCreateObject();
	return pxSpline;
}

void ToolsAVP_Object_Axon_Interface::AddPreviewSettingsControls( Asura_Overlay* pxNewOverlay, Asura_Vector_2& xOffset )
{
	PARENT::AddPreviewSettingsControls( pxNewOverlay, xOffset );

	Asura_String xSkinString( "Skin: " );
	if ( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] == ASURA_HASH_ID_UNSET )
	{
		xSkinString += "don't care";
	}
	else
	{
		Asura_Hierarchy_Skin* pxSkin = Asura_Animation_System::GetSkinByHash( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] );
		xSkinString += pxSkin ? pxSkin->GetName() : "NOT FOUND";
	}

	Asura_Function_Dialog* pxFDialogue = new Asura_Function_Dialog( xSkinString.GetString(), xOffset, PickPreviewSkin );
	pxNewOverlay->AddDialog( pxFDialogue );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	Asura_DropDown_List_Dialog* pxDDLDialog = NULL;
	pxDDLDialog = new Asura_DropDown_List_Dialog( xOffset, s_pszWeaponMappingFactorStrings, &s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ],
		6, AVP_WMF_NUM_WEAPONMAPPINGFACTORS, NULL );
	pxDDLDialog->SetSortStrings( true );
	pxNewOverlay->AddDialog( pxDDLDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();
}

void ToolsAVP_Object_Axon_Interface::PickPreviewSkin()
{
	Asura_String xSkinName;
	Asura_String xSkinFileName;
	Asura_Hierarchy_Skin* pxSkin = Tools_Animation_Files::ChooseSkin( &xSkinName, &xSkinFileName );
	if ( pxSkin )
	{
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] = pxSkin->GetHashID();
	}
	RequestRefreshPreviewSettingsOverlay();
}

//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_TableCell_MappingFactor
//
//////////////////////////////////////////////////////////////////////////////

class ToolsAVP_TableCell_WeaponMappingFactor : public Asura_TableCell_Dialog
{
	typedef Asura_TableCell_Dialog PARENT;

public:
	ToolsAVP_TableCell_WeaponMappingFactor( AVP_GS2_AnimPackage* pxAnimPackage,
											Asura_Table_Dialog& xTableDialog,
											const Asura_Vector_2& xOffset, const Asura_Vector_2& xMinCellSize, const u_int uRow, const u_int uColumn )
	: PARENT( xTableDialog, xOffset, xMinCellSize, uRow, uColumn )
	, m_pxAnimPackage( pxAnimPackage )
	, m_puFactor( NULL )
	, m_iFactor( 0 )
	{
		// The row will correspond to the mapping we are, and the column to the mapping factor.
		AVP_GS2_AnimMapping* pxMapping = static_cast< AVP_GS2_AnimMapping* >( m_pxAnimPackage->GetMapping( uRow ) );
		m_puFactor = &pxMapping->GetFactor( AVP_GS2_MF_WEAPON );
		m_iFactor = static_cast< int >( *m_puFactor );

		Asura_Vector_2 xLocalOffset( 0.0f, 0.0f );
		Asura_DropDown_List_Dialog* pxDDLDialog = NULL;
		pxDDLDialog = new Asura_DropDown_List_Dialog( xLocalOffset, s_pszWeaponMappingFactorStrings, &m_iFactor,
			6, AVP_WMF_NUM_WEAPONMAPPINGFACTORS, NULL );
		pxDDLDialog->SetEnabled( uRow > 0 );
		pxDDLDialog->SetOnSelectCallback( FactorChanged, reinterpret_cast< int >( this ) );
		pxDDLDialog->SetSortStrings( true );
		AddDialogToPanel( pxDDLDialog );
		xLocalOffset.y += Asura_Dialog::DefaultSpacing();
	}

	virtual int Compare( const Asura_TableCell_Dialog& xOther ) const
	{
		// We're only ever going to be sorting by column, so we can guarantee that the other cell is of the same type as us.
		const ToolsAVP_TableCell_WeaponMappingFactor* pxOther = static_cast< const ToolsAVP_TableCell_WeaponMappingFactor* >( &xOther );
		return stricmp( s_pszWeaponMappingFactorStrings[ *m_puFactor ], s_pszWeaponMappingFactorStrings[ *pxOther->m_puFactor ] );
	}

private:
	static void FactorChanged( int iThis )
	{
		ToolsAVP_TableCell_WeaponMappingFactor* pxThis = reinterpret_cast< ToolsAVP_TableCell_WeaponMappingFactor* >( iThis );
		*pxThis->m_puFactor = static_cast< u_int >( pxThis->m_iFactor );
		Tools_AnimTemplates::SetAnimPackageModified( pxThis->m_pxAnimPackage->GetUniqueID() );
	}

private:
	AVP_GS2_AnimPackage* m_pxAnimPackage;
	u_int* m_puFactor;
	int m_iFactor;
};

class ToolsAVP_TableCell_SkinMappingFactor : public Asura_TableCell_Dialog
{
	typedef Asura_TableCell_Dialog PARENT;

public:
	ToolsAVP_TableCell_SkinMappingFactor( AVP_GS2_AnimPackage* pxAnimPackage,
										  Asura_Table_Dialog& xTableDialog,
										  const Asura_Vector_2& xOffset, const Asura_Vector_2& xMinCellSize, const u_int uRow, const u_int uColumn )
	: PARENT( xTableDialog, xOffset, xMinCellSize, uRow, uColumn )
	, m_pxAnimPackage( pxAnimPackage )
	, m_puFactor( NULL )
	{
		// The row will correspond to the mapping we are, and the column to the mapping factor.
		AVP_GS2_AnimMapping* pxMapping = static_cast< AVP_GS2_AnimMapping* >( m_pxAnimPackage->GetMapping( uRow ) );
		m_puFactor = &pxMapping->GetFactor( AVP_GS2_MF_SKIN );

		Asura_String xSkinString( "Skin: " );
		if ( *m_puFactor == ASURA_HASH_ID_UNSET )
		{
			xSkinString += "don't care";
		}
		else
		{
			const char* pszFileName = Asura_HashedFilename_System::GetFilename( *m_puFactor );
			if ( pszFileName )
			{
				xSkinString += pszFileName;
			}
			else
			{
				xSkinString += "NOT FOUND";
			}
		}

		Asura_Vector_2 xLocalOffset( 0.0f, 0.0f );
		Asura_Function_Dialog* pxFDialogue = new Asura_Function_Dialog( xSkinString.GetString(), xLocalOffset, PickSkin, reinterpret_cast< int >( this ) );
		pxFDialogue->SetEnabled( uRow > 0 );
		AddDialogToPanel( pxFDialogue );
		xLocalOffset.y += Asura_Dialog::DefaultSpacing();
	}

	virtual int Compare( const Asura_TableCell_Dialog& xOther ) const
	{
		// We're only ever going to be sorting by column, so we can guarantee that the other cell is of the same type as us.
		const ToolsAVP_TableCell_SkinMappingFactor* pxOther = static_cast< const ToolsAVP_TableCell_SkinMappingFactor* >( &xOther );

		Asura_String xOne( "not set" );
		if ( *m_puFactor != ASURA_HASH_ID_UNSET )
		{
			Asura_Hierarchy_Skin* pxSkin = Asura_Animation_System::GetSkinByHash( *m_puFactor );
			xOne = pxSkin ? pxSkin->GetName() : "don't care";
		}
		Asura_String xTwo( "not set" );
		if ( *pxOther->m_puFactor != ASURA_HASH_ID_UNSET )
		{
			Asura_Hierarchy_Skin* pxSkin = Asura_Animation_System::GetSkinByHash( *pxOther->m_puFactor );
			xTwo = pxSkin ? pxSkin->GetName() : "don't care";
		}

		return xOne.Compare( xTwo );
	}

private:
	static void PickSkin( int iThis )
	{
		ToolsAVP_TableCell_SkinMappingFactor* pxThis = reinterpret_cast< ToolsAVP_TableCell_SkinMappingFactor* >( iThis );

		Asura_String xSkinName;
		Asura_String xSkinFileName;
		Asura_Hierarchy_Skin* pxSkin = Tools_Animation_Files::ChooseSkin( &xSkinName, &xSkinFileName );
		if ( pxSkin )
		{
			*pxThis->m_puFactor = pxSkin->GetHashID();

			Tools_AnimTemplates::SetAnimPackageModified( pxThis->m_pxAnimPackage->GetUniqueID() );
			Tools_AnimTemplates::RequestRefreshAnimPackageOverlay();
		}
	}

private:
	AVP_GS2_AnimPackage* m_pxAnimPackage;
	u_int* m_puFactor;
};

//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_AnimTemplates
//
//////////////////////////////////////////////////////////////////////////////

class ToolsAVP_AnimTemplates : public Tools_AnimTemplates
{
	typedef Tools_AnimTemplates PARENT;

protected:
	virtual void TransferModeData( Tools_ModeDataFile& xFile );

	virtual void AddPreviewScoringDataControls( Asura_Overlay& xNewOverlay, Asura_Vector_2& xOffset );

	virtual void AddAnimPackageOverlayItems( Axon_GS2_AnimPackage& xPackage, Asura_Tabs_Dialog& xTabsDialogue, Asura_Vector_2& xOffset );

	void* GetPreviewScoringData() { return &s_xScoringData; }

	virtual u_int GetNumAnimPackageMappingFactors() { return NUM_AVP_GS2_MAPPING_FACTORS; }
	virtual const char* const* GetAnimPackageMappingNames();
	virtual Asura_TableCell_Dialog* CreateAnimPackageTableCell( Asura_Table_Dialog& xTableDialog,
																const Asura_Vector_2& xOffset, const Asura_Vector_2& xMinCellSize,
																const u_int uRow, const u_int uColumn, void* const pxUserData );

private:
	static void PickPreviewSkin();
	static void SetFinalPosture( int iPackage );
	static void SetFinalPose( int iPackage );

private:
	static AVP_GS2_AnimMappingData s_xScoringData;

	static const u_int uCURRENT_MODE_FILE_VERSION = 1001;
};

AVP_GS2_AnimMappingData ToolsAVP_AnimTemplates::s_xScoringData;

Tools_AnimTemplates* Tools_AnimTemplates::Project_CreateAnimTemplateTools()
{
	return new ToolsAVP_AnimTemplates;
}

void ToolsAVP_AnimTemplates::TransferModeData( Tools_ModeDataFile& xFile )
{
	u_int uVersion = uCURRENT_MODE_FILE_VERSION;

	xFile.Transfer( uVersion );

	PARENT::TransferModeData( xFile );

	if ( uVersion == uCURRENT_MODE_FILE_VERSION )
	{
		xFile.Transfer( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] );
		xFile.Transfer( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ] );
	}
	else if ( uVersion == 1000 )
	{
		xFile.Transfer( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] );
		xFile.Transfer( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ] );

		// Jigged these values about, so reset this to "don't care".
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ] = AVP_WMF_X;
	}
	else
	{
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] = ASURA_HASH_ID_UNSET;
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ] = NUM_AVP_INVENTORYITEMTYPES;
	}
}

void ToolsAVP_AnimTemplates::AddPreviewScoringDataControls( Asura_Overlay& xNewOverlay, Asura_Vector_2& xOffset )
{
	Asura_String xSkinString( "Skin: " );
	if ( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] == ASURA_HASH_ID_UNSET )
	{
		xSkinString += "don't care";
	}
	else
	{
		Asura_Hierarchy_Skin* pxSkin = Asura_Animation_System::GetSkinByHash( s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] );
		xSkinString += pxSkin ? pxSkin->GetName() : "NOT FOUND";
	}

	Asura_Function_Dialog* pxFDialogue = new Asura_Function_Dialog( xSkinString.GetString(), xOffset, PickPreviewSkin );
	xNewOverlay.AddDialog( pxFDialogue );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	Asura_DropDown_List_Dialog* pxDDLDialog = NULL;
	pxDDLDialog = new Asura_DropDown_List_Dialog( xOffset, s_pszWeaponMappingFactorStrings, &s_xScoringData.m_auFactorValues[ AVP_GS2_MF_WEAPON ],
		6, AVP_WMF_NUM_WEAPONMAPPINGFACTORS, NULL );
	pxDDLDialog->SetSortStrings( true );
	xNewOverlay.AddDialog( pxDDLDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();
}

void ToolsAVP_AnimTemplates::AddAnimPackageOverlayItems( Axon_GS2_AnimPackage& xPackage, Asura_Tabs_Dialog& xTabsDialogue, Asura_Vector_2& xOffset )
{
	PARENT::AddAnimPackageOverlayItems( xPackage, xTabsDialogue, xOffset );

	AVP_GS2_AnimPackage* pxAVPPackage = static_cast< AVP_GS2_AnimPackage* >( &xPackage );

	Asura_String xTitle;

	xTitle = "Final Posture: ";
	xTitle += s_aszAVPPostureStrings[ pxAVPPackage->GetFinalPosture() ];
	Asura_Dialog* pxDialogue = new Asura_Function_Dialog( xTitle.GetString(), xOffset, SetFinalPosture, reinterpret_cast< int >( &xPackage ) );
	xTabsDialogue.AddDialog( pxDialogue );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	xTitle = "Final Pose: ";
	xTitle += s_aszAVPPoseStrings[ pxAVPPackage->GetFinalPose() ];
	pxDialogue = new Asura_Function_Dialog( xTitle.GetString(), xOffset, SetFinalPose, reinterpret_cast< int >( &xPackage ) );
	xTabsDialogue.AddDialog( pxDialogue );
	xOffset.y += Asura_Dialog::DefaultSpacing();
}

const char* const* ToolsAVP_AnimTemplates::GetAnimPackageMappingNames()
{
	return s_pszMappingNames;
}

Asura_TableCell_Dialog* ToolsAVP_AnimTemplates::CreateAnimPackageTableCell( Asura_Table_Dialog& xTableDialog,
																		    const Asura_Vector_2& xOffset, const Asura_Vector_2& xMinCellSize,
																			const u_int uRow, const u_int uColumn, void* const pxUserData )
{
	AVP_GS2_AnimPackage* pxAnimPackage = static_cast< AVP_GS2_AnimPackage* >( pxUserData );

	if ( uColumn == 0 )
	{
		return new ToolsAVP_TableCell_SkinMappingFactor( pxAnimPackage, xTableDialog, xOffset, xMinCellSize, uRow, uColumn );
	}
	else if ( uColumn == 1 )
	{
		return new ToolsAVP_TableCell_WeaponMappingFactor( pxAnimPackage, xTableDialog, xOffset, xMinCellSize, uRow, uColumn );
	}
	else
	{
		// Let the parent handle anything that isn't to do with our mapping factors.
		return PARENT::CreateAnimPackageTableCell( xTableDialog, xOffset, xMinCellSize, uRow, uColumn, pxUserData );
	}
}

void ToolsAVP_AnimTemplates::PickPreviewSkin()
{
	Asura_String xSkinName;
	Asura_String xSkinFileName;
	Asura_Hierarchy_Skin* pxSkin = Tools_Animation_Files::ChooseSkin( &xSkinName, &xSkinFileName );
	if ( pxSkin )
	{
		s_xScoringData.m_auFactorValues[ AVP_GS2_MF_SKIN ] = pxSkin->GetHashID();
	}
	Tools_AnimTemplates::RequestRefreshMainOverlay();
}

void ToolsAVP_AnimTemplates::SetFinalPosture( int iPackage )
{
	AVP_GS2_AnimPackage* pxAnimPackage = reinterpret_cast< AVP_GS2_AnimPackage* >( iPackage );

	ListSelection_Overlay xOverlay( "Pick Final Posture" );
	for ( int i = 0; i < NUM_AVP_ANIM_POSTURE; ++i )
	{
		xOverlay.AddItem( s_aszAVPPostureStrings[ i ], i );
	}
	if ( xOverlay.DoModal() )
	{
		pxAnimPackage->SetFinalPosture( xOverlay.GetSelectionData() );

		Tools_AnimTemplates::SetAnimPackageModified( pxAnimPackage->GetUniqueID() );
		Tools_AnimTemplates::RequestRefreshAnimPackageOverlay();
	}
}

void ToolsAVP_AnimTemplates::SetFinalPose( int iPackage )
{
	AVP_GS2_AnimPackage* pxAnimPackage = reinterpret_cast< AVP_GS2_AnimPackage* >( iPackage );

	ListSelection_Overlay xOverlay( "Pick Final Pose" );
	for ( int i = 0; i < NUM_AVP_ANIM_POSE; ++i )
	{
		xOverlay.AddItem( s_aszAVPPoseStrings[ i ], i );
	}
	if ( xOverlay.DoModal() )
	{
		pxAnimPackage->SetFinalPose( xOverlay.GetSelectionData() );

		Tools_AnimTemplates::SetAnimPackageModified( pxAnimPackage->GetUniqueID() );
		Tools_AnimTemplates::RequestRefreshAnimPackageOverlay();
	}
}

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