/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//=====================================================================================================================
/// @brief		This class represents the map and all the rooms. The map is tile based and square in dimensions.
//=====================================================================================================================

#include "Precompiled.h"
#include "GameObjects/GameMap.h"
#include "GameObjects/GameAmmo.h"
#include "GameObjects/GameHealth.h"
#include "GameObjects/GameEnemy.h"
#include "Game/GameCore.h"
#include "Game/GameSession.h"
#include "Resources/TextureManager.h"
#include "Resources/VertexShaderManager.h"
#include "Resources/PixelShaderManager.h"
#include "Graphics/Display.h"
#include "Graphics/Camera3D.h"
#include "Graphics/BufferedLineRenderer.h"
#include "Doom/DoomLevel.h"
#include "AI/PathNetwork.h"

using namespace Game;

//=====================================================================================================================
// Statics
//=====================================================================================================================

/// This is to allow easy access to the level

GameMap * GameMap::s_this = 0;

// Debug only variables:

#ifdef USE_DEBUG_CONSOLE

	/// If true then the current subsector of the doom map will be drawn
	
	bool GameMap::s_show_subsector = false;
	
	/// If true then we draw all the subsectors
	
	bool GameMap::s_render_all_subsectors = false;
	
	/// If true then we show the current raycast. Raycast is redone by left clicking.
	
	bool GameMap::s_show_testcast = false;
	
	/// The start point of the current test raycast 
	
	Vec3f GameMap::s_testcast_start;

	/// The start point of the current test raycast 
	
	Vec3f GameMap::s_testcast_end;
	
	/// Switches on and off wireframe
	
	bool GameMap::s_wireframe_level = false;

	/// Turns on/off drawing of the reject map

	bool GameMap::s_draw_reject_map = false;
	
	/// Turns on/off drawing of path nodes
	
	bool GameMap::s_draw_path_nodes = false;
	
	/// Start point for the test path-find

	Vec3f GameMap::s_test_pathfind_start = Vec3f::Zero();

	/// If true then we draw a test path-find

	bool GameMap::s_draw_test_pathfind = false;

#endif

//=====================================================================================================================
/// @brief		Default constructor. Creates the map. This is for the server only where we don't have to give
///				a net id and owner id.
//=====================================================================================================================

GameMap::GameMap(){ Create(); }

//=====================================================================================================================
/// @brief		Constructor. Creates the map and assigns it the given net id
/// @param		net_id - net id of this object
//=====================================================================================================================
				
GameMap::GameMap( unsigned net_id ) : GameObjectBase(0,net_id){ Create(); }

//=====================================================================================================================
/// @brief		Destructor. Destroys the map.
//=====================================================================================================================

GameMap::~GameMap()
{
	// Clear this reference
	
	s_this = 0;
	
	// Done with the path network
	
	if ( m_path_network ) delete m_path_network;

	// Get rid of the doom level
	
	delete m_doom_level;
	
	// Get rid of console commands
	
	#ifdef USE_DEBUG_CONSOLE
	
		DebugConsole::RemoveCommand("R_ShowSubsector");
		DebugConsole::RemoveCommand("R_RenderAllSubsectors");
		DebugConsole::RemoveCommand("R_ShowTestCast");
		DebugConsole::RemoveCommand("R_WireframeLevel");
		DebugConsole::RemoveCommand("R_DrawReject");
		
		// Server only
		
		if ( IsServer() )
		{		
			DebugConsole::RemoveCommand("A_DrawPathNodes");
			DebugConsole::RemoveCommand("A_SetTestPathStart");
			DebugConsole::RemoveCommand("A_DrawTestPath");
		}
		
	#endif
}

//=====================================================================================================================
/// @brief		Creates the map. This is called from both constructors.
//=====================================================================================================================

void GameMap::Create()
{
	// Save the static reference to this
	
	s_this = this;

	// Console commands:

	#ifdef USE_DEBUG_CONSOLE

		DebugConsole::AddCommand(	"R_ShowSubsector"		,	ConCmd_R_ShowSubsector			);
		DebugConsole::AddCommand(	"R_RenderAllSubsectors"	,	ConCmd_R_RenderAllSubsectors	);
		DebugConsole::AddCommand(	"R_ShowTestCast"		,	ConCmd_R_ShowTestCast			);
		DebugConsole::AddCommand(	"R_WireframeLevel"		,	ConCmd_R_WireframeLevel			);
		DebugConsole::AddCommand(	"R_DrawReject"			,	ConCmd_R_DrawReject				);
		
		// Server only:
		
		if ( IsServer() )
		{		
			DebugConsole::AddCommand(	"A_DrawPathNodes"		,	ConCmd_A_DrawPathNodes			);
			DebugConsole::AddCommand(	"A_SetTestPathStart"	,	ConCmd_A_SetTestPathStart		);
			DebugConsole::AddCommand(	"A_DrawTestPath"		,	ConCmd_A_DrawTestPath			);
		}

	#endif
	
	// Load the doom level
	
	m_doom_level = new DoomLevel("Levels\\Level1.wad");
	
	// Server only stuff:

	if ( IsServer() )
	{	
		// Make the pathfinding network

		m_path_network = new PathNetwork(*m_doom_level);

		// Generate starting positions etc.
		
		GenerateStartPositions();		
		GeneratePatrolPoints();
		GenerateAmbushPoints();
	}
	else
	{
		// No paths:

		m_path_network = 0;
	}
}

//=====================================================================================================================
/// @brief		Update function. called once for every frame. 
/// @param		time_delta - amount of time that has passed between this frame and the last one
/// @pre		Time delta must be > 0
//=====================================================================================================================

#pragma warning(disable:4100)

void GameMap::OnUpdate( float time_delta )
{
	// Make sure ok
	
	ENSURE( time_delta > 0 , "Time delta must be > 0" )
	
	// Debug only:
	
	#ifdef USE_DEBUG_CONSOLE
	
		if ( s_show_testcast )
		{
			// Get the camera:
			
			Camera3D * m_camera = GameCore::GetSingleton()->GetCamera();
		
			// Redo the raycast if the left mouse button or shift is down:
			
			if ( Mouse::IsButtonPressed( Mouse::BTN_LEFT ) || Keyboard::IsKeyPressed(Keyboard::KB_SHIFT) )
			{
				DoomCollision::RaycastResult r = m_doom_level->GetCollision().Raycast
				( 
					m_camera->GetPosition()	+ Vec3f::UnitY() * 25,
					m_camera->GetPosition() - ( m_camera->GetForward() * 3000.0f ) + Vec3f::UnitY() * 25
				);
				
				// Save the two points:				
				
				if ( r.m_hit ) 
				{
					s_testcast_start	= m_camera->GetPosition() + Vec3f::UnitY() * 25;
					s_testcast_end		= r.m_hit_point;
				}
				else
				{
					s_testcast_start	= m_camera->GetPosition() + Vec3f::UnitY() * 25  ;
					s_testcast_end		= m_camera->GetPosition() - ( m_camera->GetForward() * 3000.0f ) + Vec3f::UnitY() * 25;
				}
			}
		}
	
	#endif
}

#pragma warning(default:4100)

//=====================================================================================================================
/// @brief		Draw function. Makes the object render itself.
/// @param		c - camera to draw with
/// @pre		Given camera cannot be null
/// @pre		The game must exist
/// @pre		The game must have a valid display
//=====================================================================================================================

void GameMap::OnDraw( Camera3D * c )
{
	// Make sure ok:
	
	ENSURE( c != 0									, "Given camera cannot be null"			)
	ENSURE( GameCore::GetSingleton()				, "The game must exist"					)
	ENSURE( GameCore::GetSingleton()->GetDisplay()	, "The game must have a valid display"	)
	
	// Debug only:
	
	#ifdef USE_DEBUG_CONSOLE
	
		if ( s_wireframe_level )
		{
			GameCore::GetSingleton()->GetDisplay()->GetDevice()->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
		}
	
	#endif

	// Draw the doom level:
	
	m_doom_level->Draw(c);

	// Debug only:
	
	#ifdef USE_DEBUG_CONSOLE

		if ( s_wireframe_level )
		{
			GameCore::GetSingleton()->GetDisplay()->GetDevice()->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
		}			
	
	#endif

	// Debug only drawing:

	#ifdef USE_DEBUG_CONSOLE

		//=============================================================================================================
		// SHOW OUR CURRENT SUBSECTOR ?
		//=============================================================================================================

		if ( s_show_subsector )
		{
			// Get the buffered line renderer from the game:

			BufferedLineRenderer * r = GameCore::GetSingleton()->GetBufferedLineRenderer();

			// Get the stack from the game

			Stack & s = GameCore::GetSingleton()->GetStack();

			// Get the subsector for the current camera position:

			const DoomGLSubsectorV2 * subsector = m_doom_level->GetSubsector(c->GetPosition());

			// See if found:

			if ( subsector && subsector->m_count > 0 )
			{
				// Get the height of the floor and ceiling of the subsector:

				float fh = m_doom_level->GetSector(*subsector).m_floor_y;
				float ch = m_doom_level->GetSector(*subsector).m_ceiling_y;

				// Run through all the subsectors segs and put them into the stack for rendering:

				for ( int i = 0 ; i < subsector->m_count ; ++i )
				{
					Vec2f two_d = m_doom_level->GetSeg(subsector->m_first_seg+i).m_start;

					s.Push( Vec3f(two_d.x,fh,two_d.y) );
					s.Push(0xffffffff);

					two_d = m_doom_level->GetSeg(subsector->m_first_seg+i).m_end;

					s.Push( Vec3f(two_d.x,fh,two_d.y) );
					s.Push(0xffffffff);

					two_d = m_doom_level->GetSeg(subsector->m_first_seg+i).m_start;

					s.Push( Vec3f(two_d.x,ch,two_d.y) );
					s.Push(0xffffffff);

					two_d = m_doom_level->GetSeg(subsector->m_first_seg+i).m_end;

					s.Push( Vec3f(two_d.x,ch,two_d.y) );
					s.Push(0xffffffff);
				}

				// Draw the subsector outline

				r->Draw( c->GetViewProjectionMatrix() , subsector->m_count * 2 , s );
			}
		}

		//=============================================================================================================
		// RENDER ALL SUBSECTORS ?
		//=============================================================================================================
		
		if ( s_render_all_subsectors )
		{
			// Get the buffered line renderer from the game:

			BufferedLineRenderer * r = GameCore::GetSingleton()->GetBufferedLineRenderer();

			// Get the stack from the game

			Stack & s = GameCore::GetSingleton()->GetStack();

			// Run through all the subsectors
			
			for ( unsigned i = 0 ; i < m_doom_level->GetSubsectorCount() ; ++i )
			{
				// Get this subsector
				
				const DoomGLSubsectorV2 & subsector = m_doom_level->GetSubsector(i);
			
				// Get the height of the floor and ceiling of the subsector:

				float fh = m_doom_level->GetSector(subsector).m_floor_y;
				float ch = m_doom_level->GetSector(subsector).m_ceiling_y;

				// Run through all the subsectors segs and put them into the stack for rendering:

				for ( int i = 0 ; i < subsector.m_count ; ++i )
				{
					Vec2f two_d = m_doom_level->GetSeg(subsector.m_first_seg+i).m_start;

					s.Push( Vec3f(two_d.x,fh,two_d.y) );
					s.Push(0xffffffff);

					two_d = m_doom_level->GetSeg(subsector.m_first_seg+i).m_end;

					s.Push( Vec3f(two_d.x,fh,two_d.y) );
					s.Push(0xffffffff);

					two_d = m_doom_level->GetSeg(subsector.m_first_seg+i).m_start;

					s.Push( Vec3f(two_d.x,ch,two_d.y) );
					s.Push(0xffffffff);

					two_d = m_doom_level->GetSeg(subsector.m_first_seg+i).m_end;

					s.Push( Vec3f(two_d.x,ch,two_d.y) );
					s.Push(0xffffffff);
				}

				// Draw the subsector outline

				r->Draw( c->GetViewProjectionMatrix() , subsector.m_count * 2 , s );
			}		
		}

		//=============================================================================================================
		// SHOW THE TEST RAYCAST ?
		//=============================================================================================================
		
		if ( s_show_testcast )
		{
			// Get the buffered line renderer from the game:

			BufferedLineRenderer * r = GameCore::GetSingleton()->GetBufferedLineRenderer();

			// Get the stack from the game

			Stack & s = GameCore::GetSingleton()->GetStack();
			
			// Put the test cast line onto the stack
			
			s.Push( s_testcast_start	);
			s.Push( 0xffff00ff			);
			s.Push( s_testcast_end		);
			s.Push( 0xffff00ff			);
						
			// Draw the subsector outline

			r->Draw( c->GetViewProjectionMatrix() , 1 , s );				
		}

		//=============================================================================================================
		// DRAW THE REJECT MAP ?
		//=============================================================================================================

		if ( s_draw_reject_map )
		{
			// Get the subsector we are in:

			const DoomGLSubsectorV2 * cam_subsector = m_doom_level->GetSubsector(c->GetPosition());

			// Only if we are in a subsector:

			if ( cam_subsector )
			{
				// Get what sector that is in:

				const DoomSector & cam_sector = m_doom_level->GetSector(*cam_subsector);

				// Get the buffered line renderer from the game:

				BufferedLineRenderer * r = GameCore::GetSingleton()->GetBufferedLineRenderer();

				// Get the stack from the game

				Stack & s = GameCore::GetSingleton()->GetStack();

				// Run through all the subsectors
				
				for ( unsigned i = 0 ; i < m_doom_level->GetSubsectorCount() ; ++i )
				{
					// Get this subsector
					
					const DoomGLSubsectorV2 & subsector = m_doom_level->GetSubsector(i);

					// See if it is visible from where we are:

					bool visible = m_doom_level->GetCollision().IsPotentiallyVisible
					( 
						cam_sector ,  
						m_doom_level->GetSector(subsector)
					);
				
					// Get the height of the floor of the subsector:

					float fh = m_doom_level->GetSector(subsector).m_floor_y;

					// Run through all the subsectors segs and put them into the stack for rendering:
					// Draw visible subsectors in white and non-visible subsectors in red.

					for ( int i = 0 ; i < subsector.m_count ; ++i )
					{
						Vec2f two_d = m_doom_level->GetSeg(subsector.m_first_seg+i).m_start;

						s.Push( Vec3f(two_d.x,fh,two_d.y) );

						if ( visible ) s.Push(0xffffffff); else s.Push(0xffff0000);

						two_d = m_doom_level->GetSeg(subsector.m_first_seg+i).m_end;

						s.Push( Vec3f(two_d.x,fh,two_d.y) );

						if ( visible ) s.Push(0xffffffff); else s.Push(0xffff0000);
					}

					// Make sure to disable depth testing:

					IDirect3DDevice9 * device = GameCore::GetSingleton()->GetDisplay()->GetDevice();
					
					device->SetRenderState( D3DRS_ZENABLE , 0 );

					// Draw the subsector outline

					r->Draw( c->GetViewProjectionMatrix() , subsector.m_count , s );

					// Re-enable depth testing

					device->SetRenderState( D3DRS_ZENABLE , 1 );
				}
			}
		}

		//=============================================================================================================
		// DRAW PATH NODES ?
		//=============================================================================================================
		
		if ( s_draw_path_nodes )
		{
			m_path_network->DrawPathNodes(c);
		}

		//=============================================================================================================
		// DRAW THE TEST PATHFIND ?
		//=============================================================================================================
		
		if ( s_draw_test_pathfind )
		{
			m_path_network->DrawPath
			(
				c , 
				Vec2f( s_test_pathfind_start.x , s_test_pathfind_start.z ) , 
				Vec2f( c->GetPosition().x , c->GetPosition().z ) 
			);
		}

	#endif
}

//=====================================================================================================================
/// @brief		Picks a starting position for a player
/// @returns	The starting position chosen
/// @pre		This may only be called on the server
//=====================================================================================================================

Vec3f GameMap::PickStartPosition() 
{ 
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()->GetSession()->IsServer() , "This may only be called on the server" )

	// Pick the point:

	return m_start_points[ m_random.NextUnsigned() % m_start_points.size() ];
}

//=====================================================================================================================
/// @brief		Picks a starting position for an enemy
/// @returns	The starting position chosen
/// @pre		This may only be called on the server
//=====================================================================================================================

Vec3f GameMap::PickEnemyStartPosition()
{
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()->GetSession()->IsServer() , "This may only be called on the server" )
	
	// See if we have start points:
	
	if ( m_enemy_start_points.size() > 0 )
	{
		// Pick the point:

		return m_enemy_start_points[ m_random.NextUnsigned() % m_enemy_start_points.size() ];
	}
	else
	{
		// Return a player start point
		
		return PickStartPosition();
	}	
}

//=====================================================================================================================
/// @brief		Generates a list of start positions in the level
/// @pre		This should only be called on the server
//=====================================================================================================================

void GameMap::GenerateStartPositions()
{
	// Make sure ok

	ENSURE( IsServer() , "This should only be called on the server" )

	// Run through the map:
	
	for ( unsigned i = 0 ; i < m_doom_level->GetThingCount() ; i++ )
	{
		// Get this thing
		
		const DoomThing & thing = m_doom_level->GetThing(i);
		
		// See if it is a player start:
		
		if 
		( 
			(DoomThing::ThingType) thing.m_type == DoomThing::TT_PLAYER1_START ||
			(DoomThing::ThingType) thing.m_type == DoomThing::TT_PLAYER2_START ||
			(DoomThing::ThingType) thing.m_type == DoomThing::TT_PLAYER3_START ||
			(DoomThing::ThingType) thing.m_type == DoomThing::TT_PLAYER4_START
		)
		{
			// Good: get the things position:
			
			Vec3f pos = Vec3f( thing.m_x , 0 , thing.m_z );
			
			// Get the subsector the thing is in:
			
			const DoomGLSubsectorV2 * subsector = m_doom_level->GetSubsector(pos);
			
			// Get the sector if there:
			
			if ( subsector )
			{
				// Do it:
				
				const DoomSector & sector = m_doom_level->GetSector(*subsector);
				
				// Set the height of the thing based on the sector height:
				
				pos.y = sector.m_floor_y + float(64);
				
				// Save:
				
				m_start_points.push_back(pos);
			}
		}
	}
	
	// If there are no start points then make one:
	
	if ( m_start_points.size() == 0 ) m_start_points.push_back(Vec3f::Zero());
}

//=====================================================================================================================
/// @brief		Generates a list of patrol points in the level
/// @pre		This should only be called on the server
//=====================================================================================================================

void GameMap::GeneratePatrolPoints()
{
	// Make sure ok

	ENSURE( IsServer() , "This should only be called on the server" )

	// Run through the map:
	
	for ( unsigned i = 0 ; i < m_doom_level->GetThingCount() ; i++ )
	{
		// Get this thing
		
		const DoomThing & thing = m_doom_level->GetThing(i);
		
		// See if it is a small techno floor lamp: these represent patrol points
		
		if ( (DoomThing::ThingType) thing.m_type == DoomThing::TT_TECHNO_SMALL_FLOOR_LAMP )
		{
			// Good: get the things position:
			
			Vec3f pos = Vec3f( thing.m_x , 0 , thing.m_z );
			
			// Get the subsector the thing is in:
			
			const DoomGLSubsectorV2 * subsector = m_doom_level->GetSubsector(pos);
			
			// Get the sector if there:
			
			if ( subsector )
			{
				// Do it:
				
				const DoomSector & sector = m_doom_level->GetSector(*subsector);
				
				// Set the height of the thing based on the sector height:
				
				pos.y = sector.m_floor_y + float(32);
				
				// Save:
				
				m_patrol_points.push_back(pos);
			}
		}
	}
}

//=====================================================================================================================
/// @brief		Generates a list of ambush points in the level
/// @pre		This should only be called on the server
//=====================================================================================================================

void GameMap::GenerateAmbushPoints()
{
	// Make sure ok

	ENSURE( IsServer() , "This should only be called on the server" )

	// Run through the map:
	
	for ( unsigned i = 0 ; i < m_doom_level->GetThingCount() ; i++ )
	{
		// Get this thing
		
		const DoomThing & thing = m_doom_level->GetThing(i);
		
		// See if it is a blue keycard: these represent ambush points
		
		if ( (DoomThing::ThingType) thing.m_type == DoomThing::TT_BLUE_KEYCARD )
		{
			// Good: get the things position:
			
			Vec3f pos = Vec3f( thing.m_x , 0 , thing.m_z );
			
			// Get the subsector the thing is in:
			
			const DoomGLSubsectorV2 * subsector = m_doom_level->GetSubsector(pos);
			
			// Get the sector if there:
			
			if ( subsector )
			{
				// Do it:
				
				const DoomSector & sector = m_doom_level->GetSector(*subsector);
				
				// Set the height of the thing based on the sector height:
				
				pos.y = sector.m_floor_y + float(32);
				
				// Save the position of the ambush point:
				
				m_ambush_point_positions.push_back(pos);
				
				// Save the direction of the ambush point:
				
				m_ambush_point_directions.push_back( - Angle::ToRadians( float(thing.m_angle) - 90 ) + Float::PI() );
			}
		}
	}
}

//=====================================================================================================================
/// @brief		Called when the object is added into the game world
//=====================================================================================================================

void GameMap::OnGameAdded()
{
	// Call the base class function
	
	GameObjectBase::OnGameAdded();
	
	// If on the server then make ammo boxes:
	
	if ( IsServer() )
	{
		// Make the ammo and health boxes, and.. Monsters!!!
		
		CreateAmmoBoxes();
		CreateHealthBoxes();
		CreateMonsters();
	}
}

//=====================================================================================================================
/// @brief		Creates all the ammo boxes for the level
/// @pre		This must be called on the server
/// @pre		We must have a game object manager
//=====================================================================================================================

void GameMap::CreateAmmoBoxes()
{
	// Make sure ok:
	
	ENSURE( IsServer()		, "This must be called on the server"	)
	ENSURE( GetManager()	, "We must have a game object manager"	)
	
	// Run through the map:
	
	for ( unsigned i = 0 ; i < m_doom_level->GetThingCount() ; i++ )
	{
		// Get this thing
		
		const DoomThing & thing = m_doom_level->GetThing(i);
		
		// See if it is a rocket ammo box:
		
		if ( (DoomThing::ThingType) thing.m_type == DoomThing::TT_ROCKETS )
		{
			// Good: get the things position:
			
			Vec2f pos = Vec2f( thing.m_x , thing.m_z );
			
			// Create the ammo box:
			
			GameAmmo * ammo = new GameAmmo(pos);
			
			// Add to the level:
			
			GetManager()->AddObject(ammo);
			
			// Done with this:
			
			ammo->RemoveReference();
		}
	}
}

//=====================================================================================================================
/// @brief		Creates all the health boxes for the level
/// @pre		This must be called on the server
/// @pre		We must have a game object manager
//=====================================================================================================================

void GameMap::CreateHealthBoxes()
{
	// Make sure ok:
	
	ENSURE( IsServer()		, "This must be called on the server"	)
	ENSURE( GetManager()	, "We must have a game object manager"	)
	
	// Run through the map:
	
	for ( unsigned i = 0 ; i < m_doom_level->GetThingCount() ; i++ )
	{
		// Get this thing
		
		const DoomThing & thing = m_doom_level->GetThing(i);
		
		// See if it is a health box:
		
		if ( (DoomThing::ThingType) thing.m_type == DoomThing::TT_SOULSPHERE )
		{
			// Good: get the things position:
			
			Vec2f pos = Vec2f( thing.m_x , thing.m_z );
			
			// Create the health box:
			
			GameHealth * health = new GameHealth(pos);
			
			// Add to the level:
			
			GetManager()->AddObject(health);
			
			// Done with this:
			
			health->RemoveReference();
		}
	}
}

//=====================================================================================================================
/// @brief		Creates all monsters
/// @pre		This must be called on the server
/// @pre		We must have a game object manager
//=====================================================================================================================

void GameMap::CreateMonsters()
{
	// Make sure ok:
	
	ENSURE( IsServer()		, "This must be called on the server"	)
	ENSURE( GetManager()	, "We must have a game object manager"	)
	
	// Run through the map:
	
	for ( unsigned i = 0 ; i < m_doom_level->GetThingCount() ; i++ )
	{
		// Get this thing
		
		const DoomThing & thing = m_doom_level->GetThing(i);
		
		// See if it is a baron of hell:
		
		if ( (DoomThing::ThingType) thing.m_type == DoomThing::TT_BARON_OF_HELL )
		{
			// Good: get the things position:
			
			Vec3f pos = Vec3f( thing.m_x , 0 , thing.m_z );

			// Get the subsector this enemy is in:

			const DoomGLSubsectorV2 * subsector = m_doom_level->GetSubsector(pos);

			// See if there:

			if ( subsector )
			{
				// Get the sector:

				const DoomSector & sector = m_doom_level->GetSector(*subsector);

				// Set height accordingly:

				pos.y = sector.m_floor_y + GameEnemy::COLLISION_HEIGHT;
			}
			
			// Create the enemy:
			
			GameEnemy * enemy = new GameEnemy(pos,0,NetObject::NET_ID_INVALID);
			
			// Add to the level:
			
			GetManager()->AddObject(enemy);
			
			// Done with this:
			
			enemy->RemoveReference();
			
			// Remember this start point:
			
			m_enemy_start_points.push_back(pos);
		}
	}
}

#ifdef USE_DEBUG_CONSOLE

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables showing of the current subsector
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================

bool GameMap::ConCmd_R_ShowSubsector( bool arg , bool arg_given )
{
	if ( arg_given ) s_show_subsector = arg; return s_show_subsector;
}

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables rendering of all subsectors
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================
				
bool GameMap::ConCmd_R_RenderAllSubsectors( bool arg , bool arg_given )
{
	if ( arg_given ) s_render_all_subsectors = arg; return s_render_all_subsectors;
}

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables rendering of the test raycast
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================

bool GameMap::ConCmd_R_ShowTestCast( bool arg , bool arg_given )
{
	if ( arg_given ) s_show_testcast = arg; return s_show_testcast;
}

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables wireframe rendering
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================

bool GameMap::ConCmd_R_WireframeLevel( bool arg , bool arg_given )
{
	if ( arg_given ) s_wireframe_level = arg; return s_wireframe_level;
}

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables drawing of the reject map
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================

bool GameMap::ConCmd_R_DrawReject( bool arg , bool arg_given )
{
	if ( arg_given ) s_draw_reject_map = arg; return s_draw_reject_map;
}

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables drawing of path nodes
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================

bool GameMap::ConCmd_A_DrawPathNodes( bool arg , bool arg_given )
{
	if ( arg_given ) s_draw_path_nodes = arg; return s_draw_path_nodes;
}

//=====================================================================================================================
/// @brief		Debug only console command: sets the start point of the test point to the camera position
//=====================================================================================================================

void GameMap::ConCmd_A_SetTestPathStart()
{
	// Set:
	
	s_test_pathfind_start = GameCore::GetSingleton()->GetCamera()->GetPosition(); 
}

//=====================================================================================================================
/// @brief		Debug only console command: enables / disables drawing of the test path find
/// @param		arg - argument from the console
/// @param		arg_given - if an argument was given
/// @returns	value of the parameter
//=====================================================================================================================

bool GameMap::ConCmd_A_DrawTestPath( bool arg , bool arg_given )
{
	if ( arg_given ) s_draw_test_pathfind = arg; return s_draw_test_pathfind;
}
					
#endif		// #ifdef USE_DEBUG_CONSOLE