//===========================================================================//
// File:	Mission.cpp                                                         //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 02/19/95  JMA  Initial coding.                                            //
// 08/25/97  ECH  Infrastructure changes.                                    //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "Mission.hpp"
#include "Map.hpp"
#include "EntityManager.hpp"
#include "Player.hpp"
#include "VideoRenderer.hpp"
#include "NameTable.hpp"
#include "Interface.hpp"
#include "Tile.hpp"
#include "CameraComponent.hpp"
#include "Application.hpp"

#include "Tool.hpp"
#include <ElementRenderer\StateChange.hpp>
#include <MLR\MLRInfiniteLightWithFallOff.hpp>
#include <MLR\MLRCulturShape.hpp>
#include "LightManager.hpp"
#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLR_Water.hpp>


#define DEBUG_POLYS "jmalbert"

//#############################################################################
//###########################    Mission    ###################################
//#############################################################################

Mission::ClassData*
	Mission::DefaultData = NULL;

HGOSHEAP
	Mission::s_Heap = NULL;

extern DWORD	gEnableCulturals;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::InitializeClass()
{
	Verify(!s_Heap);
	s_Heap = gos_CreateMemoryHeap("Mission", 0, g_LibraryHeap);
	Check_Pointer(s_Heap);

	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MissionClassID,
			"Adept::Mission",
			Entity::DefaultData,
			0, NULL,
			(Entity::Factory)Make,
			(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
			ExecutionStateEngine::DefaultData,
			(Entity::GameModel::Factory)GameModel::ConstructGameModel,
			NULL,
			(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
			(Entity::GameModel::ModelWrite)GameModel::WriteToText,
			(Entity::GameModel::ModelSave)GameModel::SaveGameModel
		);
	Register_Object(DefaultData);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogStart,
		m_generalFogStart,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogEnd,
		m_generalFogEnd,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogDensity,
		m_generalFogDensity,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogStart,
		m_lightFogStart,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogEnd,
		m_lightFogEnd,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogDensity,
		m_lightFogDensity,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogStart,
		m_customFogStart,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogEnd,
		m_customFogEnd,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogDensity,
		m_customFogDensity,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		FogColor,
		m_fogColor,
		RGBAColor
	);


	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogStartUnderwater,
		m_generalFogStartUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogEndUnderwater,
		m_generalFogEndUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogDensityUnderwater,
		m_generalFogDensityUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogStartUnderwater,
		m_lightFogStartUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogEndUnderwater,
		m_lightFogEndUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogDensityUnderwater,
		m_lightFogDensityUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogStartUnderwater,
		m_customFogStartUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogEndUnderwater,
		m_customFogEndUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogDensityUnderwater,
		m_customFogDensityUnderwater,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		FogColorUnderwater,
		m_fogColorUnderwater,
		RGBAColor
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogStartSmoke,
		m_generalFogStartSmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogEndSmoke,
		m_generalFogEndSmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		GeneralFogDensitySmoke,
		m_generalFogDensitySmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogStartSmoke,
		m_lightFogStartSmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogEndSmoke,
		m_lightFogEndSmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		LightFogDensitySmoke,
		m_lightFogDensitySmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogStartSmoke,
		m_customFogStartSmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogEndSmoke,
		m_customFogEndSmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CustomFogDensitySmoke,
		m_customFogDensitySmoke,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		FogColorSmoke,
		m_fogColorSmoke,
		RGBAColor
	);


	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		AllowRespawn,
		m_allowRespawn,
		bool,
		BoolClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		WeatherEffectResource,
		m_weatherEffectResource,
		ResourceID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		AllowSearchLights,
		m_allowSearchLights,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		AllowRunningLights,
		m_allowRunningLights,
		bool,
		BoolClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		HeightFogStart,
		m_heightFogStart,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		HeightFogEnd,
		m_heightFogEnd,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		HeightFogOpacity,
		m_heightFogOpacity,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		NearClip,
		m_nearClip,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		FarClip,
		m_farClip,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		NightGroundColor,
		m_nightGroundColor,
		RGBAColor
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		CanSetTime,
		m_canSetTime,
		bool,
		BoolClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		NightFogColor,
		m_nightFogColor,
		RGBAColor
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		HeatSinkEfficiency,
		m_heatSinkEfficiency,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		NightWeatherEffectResource,
		m_nightWeatherEffectResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		WaterSpecularFactor,
		m_waterSpecularFactor,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		WaterAtNightSpecularFactor,
		m_waterAtNightSpecularFactor,
		Scalar
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		WaterSpecularPower,
		m_waterSpecularPower,
		int,
		IntClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		WaterAtNightSpecularPower,
		m_waterAtNightSpecularPower,
		int,
		IntClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mission__GameModel,
		IsNightMission,
		m_isNightMission,
		bool,
		BoolClassID
	);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Check_Pointer(s_Heap);
	gos_DestroyMemoryHeap(s_Heap);
	s_Heap = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mission*
	Mission::Make(
		const CreateMessage *message,
		ReplicatorID *base_id
	)
{
	gos_PushCurrentHeap(s_Heap);
	Mission *new_entity = new Mission(DefaultData, message, base_id, NULL);
	Check_Object(new_entity);
	gos_PopCurrentHeap();
	return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
	Mission::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
	Check_Object(this);
	Check_Object(stream);

	//
	//--------------------------
	// Let our parent save stuff
	//--------------------------
	//
	stream->AllocateBytes(sizeof(CreateMessage));
	Entity::SaveMakeMessage(stream, res_file);
	CreateMessage *message = Cast_Pointer(CreateMessage*, stream->GetPointer());
	message->messageLength = sizeof(*message);


	message->m_skyResourceID = skyResourceID;
	message->m_nightSkyResourceID = nightSkyResourceID;

	//
	//-------------------------------------
	// Create the memory stream for the map
	//-------------------------------------
	//
	Resource map_resource(NULL);
	DynamicMemoryStream map_stream;
	Check_Object(Map::GetInstance());
	Replicator::CreateMessage *create_message =
		Map::GetInstance()->SaveMakeMessage(&map_stream, NULL);
	Check_Object(create_message);
	ReplicatorID span = create_message->replicatorID;
	map_resource.Save(&map_stream, NULL);
	STOP(("Not updated"));
	Check_Object(&map_resource);
	message->m_mapResourceID = map_resource.GetResourceID();
	message->replicatorID += span;

	//
	//----------------------------------------
	// Create the memory stream for the props
	//----------------------------------------
	//
	DynamicMemoryStream prop_stream(sizeof(WORD));
	prop_stream << static_cast<WORD>(0);
	span = ReplicatorID::Null;

	//
	//--------------------------------------------------------------------
	// Tell each prop to save itself and bump the stream pointer afterword
	//--------------------------------------------------------------------
	//
	ChainIteratorOf<Entity *> iterator(&Map::GetInstance()->childEntityChain);
	Entity *entity;
	while ((entity = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(entity);
		if (entity->GetPropType() == MissionPropType)
		{
			Replicator::CreateMessage *create_message =
				entity->SaveMakeMessage(&prop_stream, NULL);
			if (create_message)
			{
				Check_Object(create_message);
				span += create_message->replicatorID;
				prop_stream.AdvancePointer(create_message->messageLength);
			}
		}
	}

	//
	//----------------------------------------------------------------------
	// If we actually wrote out some props, rewind the stream and save it to
	// the resource.  Otherwise, just set the resourceID to NULL
	//----------------------------------------------------------------------
	//
	if (prop_stream.GetBytesUsed() > sizeof(WORD))
	{
		Resource prop_resource(NULL);
		prop_stream.Rewind();
		Verify(span.localID > 0);
		prop_stream << span.localID;
		prop_resource.Save(&prop_stream, NULL);
		Check_Object(&prop_resource);
		message->m_propStreamResourceID = prop_resource.GetResourceID();
		message->replicatorID += span;
	}
	else
		message->m_propStreamResourceID = ResourceID::Null;

	//
	//--------------------
	// Save armory entries
	//--------------------
	//
	DynamicMemoryStream armory_stream(sizeof(WORD));
	armory_stream << static_cast<WORD>(0);
	span = ReplicatorID::Null;

#if 0
	//
	//---------------------------------------------------------------
	// Spin through the armory entities and have them save themselves
	//---------------------------------------------------------------
	//
	HashIteratorOf<Entity *, ResourceID> armory_iterator(&m_armory);
	while((entity = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(entity);
		Replicator::CreateMessage *create_message =
			entity->SaveMakeMessage(&armory_stream);
		if (create_message)
		{
			Check_Object(create_message);
			span += create_message->replicatorID;
			armory_stream.AdvancePointer(create_message->messageLength);
		}
	}
#endif

	//
	//-----------------------------------------------------------------------
	// If there were actually armory entries to write, rewind the stream and
	// write it to the resources.  Otherwise, just write NULL to the resource
	// ID
	//-----------------------------------------------------------------------
	//
	if (armory_stream.GetBytesUsed() > sizeof(WORD))
	{
		Resource armory_resource(NULL);
		armory_stream.Rewind();
		Verify(span.localID > 0);
		armory_stream << span.localID;
		armory_resource.Save(&armory_stream, NULL);
		Check_Object(&armory_resource);
		message->m_armoryStreamResourceID = armory_resource.GetResourceID();
		message->replicatorID += span;
	}
	else
		message->m_armoryStreamResourceID = ResourceID::Null;

	//
	//-----------------------------------------------
	// LAST!  Write out the Mission Name Table Stream
	//-----------------------------------------------
	//
	Resource name_table_resource(NULL);
	DynamicMemoryStream name_table_stream;

	Check_Object(NameTable::GetInstance());
	NameTable::GetInstance()->SaveTable(&name_table_stream);

	if (name_table_stream.GetBytesUsed())
	{
		name_table_resource.Save(&name_table_stream, NULL);
		Check_Object(&name_table_resource);
		message->m_nameTableStreamResourceID = name_table_resource.GetResourceID();
	}
	else
		message->m_nameTableStreamResourceID = ResourceID::Null;

	message->m_isNightMission = m_isNightMission;
	return message;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mission::Mission(
	ClassData *class_data,
	const CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	Entity(class_data, message, base_id, element),
	m_staticLights(NULL),
	m_scoringChain(NULL, true),
	m_sky(NULL),
	m_nightSky(NULL),
	m_respawnProps(NULL)
{
	Check_Pointer(this);
	Check_Object(message);


	GlobalPointers::AddGlobalPointer(this, MissionGlobalPointerIndex);
	//
	//----------------------
	// Set up the name table
	//----------------------
	//
	Verify(NameTable::GetInstance() == NULL);
	GlobalPointers::AddGlobalPointer(new NameTable(), NameTableGlobalPointerIndex); 
	Check_Object(NameTable::GetInstance());

	const GameModel *model = GetGameModel();
	Check_Object(model);
	m_isNightMission = model->m_isNightMission;
	if(model->m_canSetTime)
		m_isNightMission = message->m_isNightMission;
	MidLevelRenderer::MLRCulturShape::IsDayTime(!m_isNightMission);

	//
	//--------------------------
	// Set up the video renderer
	//--------------------------
	//
	Check_Object(VideoRenderer::Instance);
	VideoRenderer::Instance->SetSceneRoot(entityElement);

	MidLevelRenderer::MLRTexturePool::Instance->Add("scorch");

	//
	//---------------------------------------------------------
	//Set up the Name Table so all entities can get their names
	//---------------------------------------------------------
	//
	nameTableResourceID = ResourceID::Null;

	if(message->m_nameTableStreamResourceID != ResourceID::Null)
	{
		Resource name_table_stream(message->m_nameTableStreamResourceID);
		Verify(name_table_stream.DoesResourceExist());
		Check_Object(NameTable::GetInstance());
		NameTable::GetInstance()->LoadTable(&name_table_stream);
		nameTableResourceID = message->m_nameTableStreamResourceID;

		name_table_stream.UnloadData();
	}

	//
	//-----------------------------------------------------------------
	// Create the map.  It will never have any rendering/collision data
	//-----------------------------------------------------------------
	//
	Resource stream(message->m_mapResourceID);
	Verify(stream.DoesResourceExist());
	Verify(!Map::GetInstance());

	Map *map = Cast_Object(Map*, CreateEntity(&stream, base_id));
	GlobalPointers::AddGlobalPointer( map, MapGlobalPointerIndex);
	map->BecomeInteresting(false);
	
	AddChild(Map::GetInstance());
	mapResourceID = message->m_mapResourceID;
	map->ActivateZones();

	//
	//-----------------
	// Create the props
	//-----------------
	//
	gos_PushCurrentHeap(Entity::s_Heap);
	propListResourceID = ResourceID::Null;
	if (message->m_propStreamResourceID != ResourceID::Null)
	{
		Resource prop_stream(message->m_propStreamResourceID);
		prop_stream.AdvancePointer(sizeof(WORD));
		Verify(prop_stream.DoesResourceExist());
		while (prop_stream.GetBytesRemaining() > 0)
		{
			Entity::CreateMessage *message =
				Cast_Pointer(Entity::CreateMessage*, prop_stream.GetPointer());
			Check_Object(message);
			Entity *entity = CreateEntity(&prop_stream, base_id);
			Check_Object(entity);
			entity->SetPropType(MissionPropType);
			map->AddChild(entity);
			m_respawnProps.Add(entity);
			prop_stream.AdvancePointer(message->messageLength);
		}
		propListResourceID = message->m_propStreamResourceID;
		prop_stream.UnloadData();
	}
	gos_PopCurrentHeap();

	//
	//------------------------------------------------------------------------
	// Create the armory in the game, them kill it to get them into the armory
	//------------------------------------------------------------------------
	//
	armoryResourceID = ResourceID::Null;
	if (message->m_armoryStreamResourceID != ResourceID::Null)
	{
		Resource armory_stream(message->m_armoryStreamResourceID);
		armory_stream.AdvancePointer(sizeof(WORD));
		Verify(armory_stream.DoesResourceExist());
		while (armory_stream.GetBytesRemaining() > 0)
		{
			Entity::CreateMessage *message =
				Cast_Pointer(Entity::CreateMessage*, armory_stream.GetPointer());
			Check_Object(message);
			Entity *entity = CreateEntity(&armory_stream, base_id);
			Check_Object(entity);
			entity->SetPropType(ArmoryPropType);
			armory_stream.AdvancePointer(message->messageLength);
			entity->replicatorFlags |= ReusableFlag;
			entity->SentenceToDeathRow();
		}
		Check_Object(EntityManager::GetInstance());
		EntityManager::GetInstance()->FryDeathRow();
		armoryResourceID = message->m_armoryStreamResourceID;
	}

	//
	//-----------------------------------------------------------------------
	// If the bounds data is missing, set up an automatic warning and mission
	// boundary
	//-----------------------------------------------------------------------
	//
	if (!message->m_missionBoundsResourceID || !message->m_warningBoundsResourceID)
	{
Whoops:
		Scalar
			min_x=0.0625f,
			min_z=0.0625f,
			max_x=map->m_columnZoneCount - 0.0625f,
			max_z=map->m_rowZoneCount - 0.0625f;
		missionPolygon.SetLength(4);
		missionPolygon[0].x = min_x;
		missionPolygon[0].y = min_z;
		missionPolygon[1].x = min_x;
		missionPolygon[1].y = max_z;
		missionPolygon[2].x = max_x;
		missionPolygon[2].y = max_z;
		missionPolygon[3].x = max_x;
		missionPolygon[3].y = min_z;

		min_z += 0.0625f;
		max_z -= 0.0625f;
		min_x += 0.0625f;
		max_x -= 0.0625f;
		warningPolygon.SetLength(4);
		warningPolygon[0].x = min_x;
		warningPolygon[0].y = min_z;
		warningPolygon[1].x = min_x;
		warningPolygon[1].y = max_z;
		warningPolygon[2].x = max_x;
		warningPolygon[2].y = max_z;
		warningPolygon[3].x = max_x;
		warningPolygon[3].y = min_z;
	}

	//
	//----------------------------------------------------------
	// Otherwise, read in the data from resource into the arrays
	//----------------------------------------------------------
	//
	else
	{
		Resource warning(message->m_warningBoundsResourceID);
		MemoryStreamIO_Read(&warning, &warningPolygon);
		Resource mission(message->m_missionBoundsResourceID);
		MemoryStreamIO_Read(&mission, &missionPolygon);
		if (!warningPolygon.GetLength() || !missionPolygon.GetLength())
			goto Whoops;
	}

	//
	//----------------------
	// Set up the fog tables
	//----------------------
	//
	ElementRenderer::StateChange::SetFogColor(model->m_fogColor);
	

	// set up network overrides...

	if (Application::GetInstance()->networkingFlag)
	{

		NetMissionParameters::AdeptNetMissionParameters *params = Application::GetInstance()->m_localMissionParameters;

		switch (params->m_visibility)
		{
		case ClearVisibility:
			m_generalFogStart = 500.0f;
			m_generalFogEnd = 1200.0f;
			
			m_lightFogStart = 400.0f;
			m_lightFogEnd = 1100.0f;
			
			m_customFogStart = 500.0f;
			m_customFogEnd = 1200.0f;

			m_heightFogStart = model->m_heightFogStart;
			m_heightFogEnd = model->m_heightFogEnd;
			m_heightFogOpacity = model->m_heightFogOpacity;
// MSL 5.02 Shadow
//			TiledLightManager::s_ShadowMode = TiledLightManager::e_ArticulatedShadows;
			break;

		case LightVisibility:
			m_generalFogStart = 250.0f;
			m_generalFogEnd = 800.0f;
			
			m_lightFogStart = 150.0f;
			m_lightFogEnd = 700.0f;
			
			m_customFogStart = 250.0f;
			m_customFogEnd = 800.0f;

			m_heightFogStart = model->m_heightFogStart;
			m_heightFogEnd = model->m_heightFogEnd;
			m_heightFogOpacity = model->m_heightFogOpacity;
// MSL 5.02 Shadow
//			TiledLightManager::s_ShadowMode = TiledLightManager::e_ArticulatedShadows;
			break;

		case HeavyVisibility:
			m_generalFogStart = 50.0f;
			m_generalFogEnd = 250.0f;
			
			m_lightFogStart = 50.0f;
			m_lightFogEnd = 250.0f;
			
			m_customFogStart = 100.0f;
			m_customFogEnd = 300.0f;

			m_heightFogStart = model->m_heightFogStart;
			m_heightFogEnd = model->m_heightFogEnd;
			m_heightFogOpacity = model->m_heightFogOpacity;
// MSL 5.02 Shadow
//			gEnableCulturals = 0;
//			TiledLightManager::s_ShadowMode = TiledLightManager::e_ArticulatedShadows;
			break;

		case PeaSoupVisibility:
			m_generalFogStart = 50.0f;
			m_generalFogEnd = 100.0f;
			
			m_lightFogStart = 50.0f;
			m_lightFogEnd = 100.0f;
			
			m_customFogStart = 50.0f;
			m_customFogEnd = 100.0f;

			m_heightFogStart = model->m_heightFogStart;
			m_heightFogEnd = model->m_heightFogEnd;
			m_heightFogOpacity = model->m_heightFogOpacity;
// MSL 5.02 Shadow
//			gEnableCulturals = 0;
////		TiledLightManager::s_ShadowMode = TiledLightManager::e_ArticulatedShadows;
			break;

		default:
			m_generalFogStart = model->m_generalFogStart;
			m_generalFogEnd = model->m_generalFogEnd;
			
			m_lightFogStart = model->m_lightFogStart;
			m_lightFogEnd = model->m_lightFogEnd;
			
			m_customFogStart = model->m_customFogStart;
			m_customFogEnd = model->m_customFogEnd;

			m_heightFogStart = model->m_heightFogStart;
			m_heightFogEnd = model->m_heightFogEnd;
			m_heightFogOpacity = model->m_heightFogOpacity;
// MSL 5.02 Shadow
//			TiledLightManager::s_ShadowMode = TiledLightManager::e_ArticulatedShadows;
			break;

		}

	}
	else
	{
		m_generalFogStart = model->m_generalFogStart;
		m_generalFogEnd = model->m_generalFogEnd;
		
		m_lightFogStart = model->m_lightFogStart;
		m_lightFogEnd = model->m_lightFogEnd;
		
		m_customFogStart = model->m_customFogStart;
		m_customFogEnd = model->m_customFogEnd;

		m_heightFogStart = model->m_heightFogStart;
		m_heightFogEnd = model->m_heightFogEnd;
		m_heightFogOpacity = model->m_heightFogOpacity;
	}






	//
	// Moved these to a function so we can access from VehicleInterface
	//
	ResetNormalFogData();

	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		MidLevelRenderer::Limits::Max_Number_Of_FogStates,
		model->m_heightFogStart,
		model->m_heightFogEnd,
		model->m_heightFogOpacity
	);

	//
	//-------------------
	// Load the lights up
	//-------------------
	//
	m_mainLight = NULL;

	ResourceID lights_id;
	if(m_isNightMission)
	{
		lights_id = model->m_nightLightStreamResourceID;
	}
	else
	{
		lights_id = model->m_lightStreamResourceID;
	}

	if (lights_id != ResourceID::Null)
	{
		Resource light_stream(lights_id);
		Verify(light_stream.DoesResourceExist());
		int version = MidLevelRenderer::ReadMLRVersion(&light_stream);
		Check_Object(TiledLightManager::Instance);
		while (light_stream.GetBytesRemaining() > 0)
		{
			MidLevelRenderer::MLRLight *light =
				MidLevelRenderer::MLRLight::Make(&light_stream, version);
			Check_Object(light);
			light->SetStaticLight();
			gosFX::Light *gos_light = TiledLightManager::Instance->MakeLight(light);
			m_staticLights.Add(gos_light);
			if (!m_mainLight)
				m_mainLight = gos_light;
		}
	}

	if (m_mainLight)
	{
		Stuff::UnitVector3D sun;
		m_mainLight->m_light->GetInWorldDirection(sun);
		MidLevelRenderer::MLR_Water::SetSunLight(sun);
	}

	//
	//---------------------------------
	// Set up the water specular values
	//---------------------------------
	//
	if(m_isNightMission)
	{
		MidLevelRenderer::MLR_Water::SetSpecularValues(model->m_waterAtNightSpecularFactor, model->m_waterAtNightSpecularPower);
	}
	else
	{
		MidLevelRenderer::MLR_Water::SetSpecularValues(model->m_waterSpecularFactor, model->m_waterSpecularPower);
	}

	//
	//-----------------------------------------
	// Set up the sky elements if there are any
	//-----------------------------------------
	//
	skyResourceID = message->m_skyResourceID;
	nightSkyResourceID = message->m_nightSkyResourceID;

	
	if (skyResourceID != ResourceID::Null)
	{
		Resource sky_resource(skyResourceID);
		m_sky.Add(
			ElementRenderer::Element::Create(
				&sky_resource,
				ElementRenderer::ReadERFVersion(&sky_resource)
			)
		);
		Check_Object(m_sky.GetCurrent());
	}


	if (nightSkyResourceID != ResourceID::Null)
	{
		Resource sky_resource(nightSkyResourceID);
		m_nightSky.Add(
			ElementRenderer::Element::Create(
				&sky_resource,
				ElementRenderer::ReadERFVersion(&sky_resource)
			)
		);
		Check_Object(m_nightSky.GetCurrent());
	}

	if(m_isNightMission)
	{
		Tile::s_GroundColor = &model->m_nightGroundColor;
		ElementRenderer::StateChange::SetFogColor(model->m_nightFogColor);
	}
	else
	{
		Tile::s_GroundColor = NULL;
	}
	MidLevelRenderer::MLRCulturShape::SetColor(RGBAColor::White, model->m_nightGroundColor);

	m_FirstFrame = true;
	scoreDirty = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::RespawnMission()
{
	Check_Object(this);

	EntityManager::GetInstance()->FryDeathRow();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mission::~Mission()
{

	//temp code- //moved to the end of ~Mission by jcem - GlobalPointers::ClearPointer(MissionGlobalPointerIndex);
	GlobalPointers::ClearPointer(MissionGlobalPointerIndex);

	Check_Object(TiledLightManager::Instance);
	ChainIteratorOf<gosFX::Light*> lights(&m_staticLights);
	gosFX::Light *light;
	while ((light = lights.ReadAndNext()) != NULL)
	{
		Check_Object(light);
		TiledLightManager::Instance->DeleteLight(light);
	}

	// Clean up the lights

	ElementRenderer::StateChange *state = GetElement()->GetStateChange();

	if (state)
	{
		Check_Object(state);
		for (int i = 0; i < MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive; i++)
		{
			if (state->m_lights[i])
			{
				Check_Object(state->m_lights[i]);
				delete state->m_lights[i];
			}
			else
				break;
		}
	}

	if (m_nightSky.GetCurrent())
	{
		Check_Object(m_nightSky.GetCurrent());
		delete m_nightSky.GetCurrent();
	}

	if (m_sky.GetCurrent())
	{
		Check_Object(m_sky.GetCurrent());
		delete m_sky.GetCurrent();
	}

	//temp code- Entity::DeleteChildEntities(); // jcem - in this routine, Mission::GetInstance() will be called copied from Entity::~Entity()

	Check_Object(NameTable::GetInstance());
	delete NameTable::GetInstance();
	GlobalPointers::ClearPointer(NameTableGlobalPointerIndex);
	

	m_scoringChain.DeletePlugs();

	//temp code- GlobalPointers::ClearPointer(MissionGlobalPointerIndex); // moved from begin of ~Mission by jcem
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::ResetNormalFogData()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		1,
		m_generalFogStart,
		m_generalFogEnd,
		model->m_generalFogDensity
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		2,
		m_lightFogStart,
		m_lightFogEnd,
		model->m_lightFogDensity
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		3,
		m_customFogStart,
		m_customFogEnd,
		model->m_customFogDensity
	);


	CameraComponent* camera = VideoRenderer::Instance->GetSceneCamera();
	if (camera)
	{
		ElementRenderer::CameraElement* element = camera->GetElement();
		if (element)
		{
			ElementRenderer::StateChange * view_states = element->GetViewingStateChange();
			if (view_states)
			{
				if (m_isNightMission)
				{
					view_states->SetFogColor(model->m_nightFogColor);
				}
				else
				{
					view_states->SetFogColor(model->m_fogColor);
				}
			}
			Element* sky = element->GetSky();
			if (sky)
			{
				ElementRenderer::StateChange *state = sky->GetStateChange();
				if (sky)
				{
					state->SetFogMode(ElementRenderer::StateChange::DisableFogMode);
				}
			}
		}
		
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::BlendSmokeFogData(Stuff::Scalar percentageSmoke)
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	//
	// Need to calculate the blend for the smoke data vs. the normal date
	//
	Stuff::Scalar 
		diffGeneralFogStart,
		diffGeneralFogEnd,
		diffGeneralFogDensity,
		diffLightFogStart,
		diffLightFogEnd,
		diffLightFogDensity,
		diffCustomFogStart,
		diffCustomFogEnd,
		diffCustomFogDensity;
	
	Stuff::RGBAColor diffFogColor;

		diffGeneralFogStart = model->m_generalFogStartSmoke - m_generalFogStart;
		diffGeneralFogEnd = model->m_generalFogEndSmoke - m_generalFogEnd;
		diffGeneralFogDensity = model->m_generalFogDensitySmoke - model->m_generalFogDensity;

		diffLightFogStart = model->m_lightFogStartSmoke - m_lightFogStart;
		diffLightFogEnd = model->m_lightFogEndSmoke - m_lightFogEnd;
		diffLightFogDensity = model->m_lightFogDensitySmoke - model->m_lightFogDensity;

		diffCustomFogStart = model->m_customFogStartSmoke - m_customFogStart;
		diffCustomFogEnd = model->m_customFogEndSmoke - m_customFogEnd;
		diffCustomFogDensity = model->m_customFogDensitySmoke - model->m_customFogDensity;

		diffGeneralFogStart = m_generalFogStart + diffGeneralFogStart*percentageSmoke;
		diffLightFogStart = m_lightFogStart + diffLightFogStart*percentageSmoke;
		diffCustomFogStart = m_customFogStart + diffCustomFogStart*percentageSmoke;

		diffGeneralFogEnd = m_generalFogEnd + diffGeneralFogEnd*percentageSmoke;
		diffLightFogEnd = m_lightFogEnd + diffLightFogEnd*percentageSmoke;
		diffCustomFogEnd = m_customFogEnd + diffCustomFogEnd*percentageSmoke;

		diffGeneralFogDensity = model->m_generalFogDensity + diffGeneralFogDensity*percentageSmoke;
		diffLightFogDensity = model->m_lightFogDensity + diffLightFogDensity*percentageSmoke;
		diffCustomFogDensity = model->m_customFogDensity + diffCustomFogDensity*percentageSmoke;

		diffFogColor.red = model->m_fogColorSmoke.red - model->m_fogColor.red;
		diffFogColor.red = model->m_fogColor.red + diffFogColor.red*percentageSmoke;
		diffFogColor.green = model->m_fogColorSmoke.green - model->m_fogColor.green;
		diffFogColor.green = model->m_fogColor.green + diffFogColor.green*percentageSmoke;
		diffFogColor.blue = model->m_fogColorSmoke.blue - model->m_fogColor.blue;
		diffFogColor.blue = model->m_fogColor.blue + diffFogColor.blue*percentageSmoke;
		diffFogColor.alpha = model->m_fogColorSmoke.alpha - model->m_fogColor.alpha;
		diffFogColor.alpha = model->m_fogColor.alpha + diffFogColor.alpha*percentageSmoke;


	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		1,
		diffGeneralFogStart,
		diffGeneralFogEnd,
		diffGeneralFogDensity
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		2,
		diffLightFogStart,
		diffLightFogEnd,
		diffLightFogDensity
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		3,
		diffCustomFogStart,
		diffCustomFogEnd,
		diffCustomFogDensity
	);
	//
	// This is to protect from trying to access the camera too early.
	//
	CameraComponent* camera = VideoRenderer::Instance->GetSceneCamera();
	if (camera)
	{
		ElementRenderer::CameraElement* element = camera->GetElement();
		if (element)
		{
			ElementRenderer::StateChange * view_states = element->GetViewingStateChange();
			if (view_states)
			{
				view_states->SetFogColor(diffFogColor);
			}
		}
		Element* sky = element->GetSky();
		if (sky)
		{
			ElementRenderer::StateChange *state = sky->GetStateChange();
			if (sky)
			{
				state->SetFogMode(ElementRenderer::StateChange::GeneralFogMode);
			}
		}
		
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetSmokeFogData()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		1,
		model->m_generalFogStartSmoke,
		model->m_generalFogEndSmoke,
		model->m_generalFogDensitySmoke
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		2,
		model->m_lightFogStartSmoke,
		model->m_lightFogEndSmoke,
		model->m_lightFogDensitySmoke
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		3,
		model->m_customFogStartSmoke,
		model->m_customFogEndSmoke,
		model->m_customFogDensitySmoke
	);
	//
	// This is to protect from trying to access the camera too early.
	//
	CameraComponent* camera = VideoRenderer::Instance->GetSceneCamera();
	if (camera)
	{
		ElementRenderer::CameraElement* element = camera->GetElement();
		if (element)
		{
			ElementRenderer::StateChange * view_states = element->GetViewingStateChange();
			if (view_states)
			{
				view_states->SetFogColor(model->m_fogColorSmoke);
			}
			Element* sky = element->GetSky();
			if (sky)
			{
				ElementRenderer::StateChange *state = sky->GetStateChange();
				if (sky)
				{
				  state->SetFogMode(ElementRenderer::StateChange::GeneralFogMode);
				}
			}
		}
		
	}

}
	
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetUnderwaterFogData()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		1,
		model->m_generalFogStartUnderwater,
		model->m_generalFogEndUnderwater,
		model->m_generalFogDensityUnderwater
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		2,
		model->m_lightFogStartUnderwater,
		model->m_lightFogEndUnderwater,
		model->m_lightFogDensityUnderwater
	);
	MidLevelRenderer::MLRPrimitiveBase::SetFogTableEntry(
		3,
		model->m_customFogStartUnderwater,
		model->m_customFogEndUnderwater,
		model->m_customFogDensityUnderwater
	);
	//
	// This is to protect from trying to access the camera too early.
	//
	CameraComponent* camera = VideoRenderer::Instance->GetSceneCamera();
	if (camera)
	{
		ElementRenderer::CameraElement* element = camera->GetElement();
		if (element)
		{
			ElementRenderer::StateChange * view_states = element->GetViewingStateChange();
			if (view_states)
			{
				view_states->SetFogColor(model->m_fogColorUnderwater);
			}
			Element* sky = element->GetSky();
			if (sky)
			{
				ElementRenderer::StateChange *state = sky->GetStateChange();
				if (sky)
				{
				  state->SetFogMode(ElementRenderer::StateChange::GeneralFogMode);
				}
			}
		}
		
	}
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::PreCollisionExecute(Time till)
{
	Check_Object(this);
	PRECOLLISION_LOGIC("Mission");

	//
	//---------------------------------
	// Verify that this always executes
	//---------------------------------
	//
	Check_Object(executionState);
	Verify(
		executionState->GetState() !=
		ExecutionStateEngine::NeverExecuteState
	);
	Entity::PreCollisionExecute(till);

	//
	//--------------------------------------------------------------------------
	// If we are allowed to execute, first do ourself, then execute our children
	//--------------------------------------------------------------------------
	//
	Check_Object(executionState);
	if (executionState->GetState() != ExecutionStateEngine::NeverExecuteState)
	{
		if (!childEntityChain.IsEmpty())
		{
			ChainIteratorOf<Entity *> iterator(&childEntityChain);
			Entity *child;
			while ((child = iterator.ReadAndNext()) != NULL)
			{
				Check_Object(child);
				Verify(child->GetInterestLevel() != DormantInterestLevel);
				child->PreCollisionExecute(till);
				Verify(!child->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(child));
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mission::MissionArea
	Mission::GetMissionArea(const Stuff::Point3D &where)
{
	Check_Object(this);

	//
	//-------------------------------------------------
	// Figure out the coordinates in terms of the zones
	//-------------------------------------------------
	//
	Vector2DOf<Scalar> origin;
	origin.x = (where.x - Map::GetInstance()->m_columnZoneOrigin) * Map::GetInstance()->m_columnZoneScale;
	origin.y = (where.z - Map::GetInstance()->m_rowZoneOrigin) * Map::GetInstance()->m_rowZoneScale;

	//
	//------------------------------------------
	// See if we are within the warning polygons
	//------------------------------------------
	//
	if (IsInsidePolygon(origin, warningPolygon))
		return InMissionArea;
	return (IsInsidePolygon(origin, missionPolygon))?InWarningArea:OutOfMissionArea;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetWarningPolygon(DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list)
{
	int count = list.GetLength();
	warningPolygon.SetLength(count);
	for (int i = 0; i < count; i++)
	{
		warningPolygon[i] = list[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetMissionPolygon(DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list)
{
	int count = list.GetLength();
	missionPolygon.SetLength(count);
	for (int i = 0; i < count; i++)
	{
		missionPolygon[i] = list[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::GetWarningPolygon(DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list)
{
	int count = warningPolygon.GetLength();
	list.SetLength(count);
	for (int i = 0; i < count; i++)
	{
		list[i] = warningPolygon[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::GetMissionPolygon(DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list)
{
	int count = missionPolygon.GetLength();
	list.SetLength(count);
	for (int i = 0; i < count; i++)
	{
		list[i] = missionPolygon[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mission::IsInsidePolygon(
		const Stuff::Vector2DOf<Scalar> &origin,
		DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &polygon
	)
{
	Check_Object(&polygon);
	Check_Object(&origin);

	//
	//-------------------------------------
	// Make sure to handle an empty polygon
	//-------------------------------------
	//
	unsigned poly_count = polygon.GetLength();
	Verify(poly_count >= 3);

	//
	//-------------------------------------------------------------------
	// Loop through the polygon, making sure to wrap around the end point
	//-------------------------------------------------------------------
	//
	for (unsigned i=0; i<poly_count; ++i)
	{
		unsigned next = i+1;
		if (next == poly_count)
			next = 0;
		Vector2DOf<Scalar> leg1, leg2;
		leg1.Subtract(polygon[i], origin);
		leg2.Subtract(polygon[next], polygon[i]);

		//
		//-------------------------------------------------
		// Now cross the legs and add the total to the area
		//-------------------------------------------------
		//
		Scalar area = leg1.y*leg2.x - leg1.x*leg2.y;
		if (area < 0.0f)
			return false;
	}
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::AddChild(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);
	Verify(entity == Map::GetInstance() || entity->IsDerivedFrom(Player::DefaultData));
	Entity::AddChild(entity);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::ChildPreCollisionChanged(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);
	Verify(entity == Map::GetInstance() || entity->IsDerivedFrom(Player::DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

bool
	Mission::AllowRespawn()
{

	const GameModel *model = GetGameModel();
	Check_Object(model);

	return model->m_allowRespawn;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::ResetMissionLights()
{
	Check_Object(this);
	Check_Object(VideoRenderer::Instance);
	
	const GameModel *model = GetGameModel();
	Check_Object(model);

	//
	// [johnyo] 08/27/00 PreviousSearchLight code is experimental code that I have checked in to keep a backup
	//									 of only. It may be ripped out shortly if the effect that it was intended to have isn't
	//									 put into the game
	//
//	if (
//		!VideoRenderer::Instance ||
//		!VideoRenderer::Instance->GetSceneCamera() ||
//		!VideoRenderer::Instance->GetSceneCamera()->GetElement() ||
//		!VideoRenderer::Instance->GetSceneCamera()->GetElement()->GetViewingStateChange())
//		return;

	ElementRenderer::StateChange *view_states = 
		VideoRenderer::Instance->GetSceneCamera()->GetElement()->GetViewingStateChange();

	view_states->EnableChildLightingControl();

	if(m_isNightMission)
	{
		Tile::s_GroundColor = &model->m_nightGroundColor;
		view_states->SetFogColor(model->m_nightFogColor);
		if(m_nightSky.GetCurrent())
			VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_nightSky.GetCurrent());
	}
	else
	{
		Tile::s_GroundColor = NULL;
	}
	MidLevelRenderer::MLRCulturShape::SetColor(RGBAColor::White, model->m_nightGroundColor);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetLightAmpMissionLights()
{
	Check_Object(this);
	Check_Object(VideoRenderer::Instance);

	const GameModel *model = GetGameModel();
	Check_Object(model);

	ElementRenderer::StateChange *view_states = 
		VideoRenderer::Instance->GetSceneCamera()->GetElement()->GetViewingStateChange();

	view_states->DisableChildLightingControl();
	view_states->SetFogColor(model->m_fogColor);
//	VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_sky);
	Tile::s_GroundColor = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
	//
	// [johnyo] 08/27/00 PreviousSearchLight code is experimental code that I have checked in to keep a backup
	//									 of only. It may be ripped out shortly if the effect that it was intended to have isn't
	//									 put into the game
	//

//void
//	Mission::SetSearchLightMissionLights()
//{
//	Check_Object(this);
//	Check_Object(VideoRenderer::Instance);
///*	
//	const GameModel *model = GetGameModel();
//	Check_Object(model);
//
//	ElementRenderer::StateChange *view_states = 
//		VideoRenderer::Instance->GetSceneCamera()->GetElement()->GetViewingStateChange();
//
//	if(m_isNightMission)
//	{
//		Tile::s_GroundColor = NULL;
//		view_states->EnableChildLightingControl();
//		view_states->SetFogColor(model->m_nightFogColor);
//		if(m_nightSky.GetCurrent())
//			VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_nightSky.GetCurrent());
//		Tile::s_GroundColor = NULL;
//		MidLevelRenderer::MLRCulturShape::SetColor(RGBAColor::White, model->m_nightGroundColor);
//	}
//
////	VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_sky);
//*/
//}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetToNight()
{
	Check_Object(this);
	Check_Object(VideoRenderer::Instance);
	
	const GameModel *model = GetGameModel();
	Check_Object(model);

	ElementRenderer::StateChange *view_states = 
		VideoRenderer::Instance->GetSceneCamera()->GetElement()->GetViewingStateChange();

	view_states->EnableChildLightingControl();

	Tile::s_GroundColor = &model->m_nightGroundColor;
	view_states->SetFogColor(model->m_nightFogColor);
	if(m_nightSky.GetCurrent())
		VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_nightSky.GetCurrent());

	MidLevelRenderer::MLRCulturShape::SetColor(RGBAColor::White, model->m_nightGroundColor);

	m_isNightMission=true;
	MidLevelRenderer::MLRCulturShape::IsDayTime(!m_isNightMission);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetToDay()
{
	Check_Object(this);
	Check_Object(VideoRenderer::Instance);

	const GameModel *model = GetGameModel();
	Check_Object(model);

	ElementRenderer::StateChange *view_states = 
		VideoRenderer::Instance->GetSceneCamera()->GetElement()->GetViewingStateChange();

//	view_states->DisableChildLightingControl();
	view_states->EnableChildLightingControl();

	view_states->SetFogColor(model->m_fogColor);
	VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_sky.GetCurrent());
	Tile::s_GroundColor = NULL;

	m_isNightMission=false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	Mission::SetDaySky(ResourceID &res)
{
skyResourceID=res;

	if (nightSkyResourceID != ResourceID::Null)
	{
		Resource sky_resource(skyResourceID);
		if(m_sky.GetCurrent())	m_sky.Remove();
		m_sky.Add(
			ElementRenderer::Element::Create(
				&sky_resource,
				ElementRenderer::ReadERFVersion(&sky_resource)
			)
		);
		Check_Object(m_sky.GetCurrent());
	}

	if(!m_isNightMission)
	{
	Check_Object(VideoRenderer::Instance);
	VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_sky.GetCurrent());
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SetNightSky(ResourceID &res)
{
nightSkyResourceID=res;

	if (nightSkyResourceID != ResourceID::Null)
	{
		if(m_nightSky.GetCurrent())	m_nightSky.Remove();
		m_nightSky.Remove();
		Resource sky_resource(nightSkyResourceID);
		m_nightSky.Add(
			ElementRenderer::Element::Create(
				&sky_resource,
				ElementRenderer::ReadERFVersion(&sky_resource)
			)
		);
		Check_Object(m_nightSky.GetCurrent());
	}

	if(m_isNightMission)
	{
	Check_Object(VideoRenderer::Instance);
	VideoRenderer::Instance->GetSceneCamera()->GetElement()->AdoptSkyElement(m_nightSky.GetCurrent());
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
// MSL 5.02 headshot
//	Mission::ScoringReactToMechDeath(const ReplicatorID& inflicting_id, const ReplicatorID& victim_id)
	Mission::ScoringReactToMechDeath(const ReplicatorID& inflicting_id, const ReplicatorID& victim_id, int damageMode)
{
	Check_Object(this);

	if (!Application::GetInstance()->serverFlag)
		return;

	ScoreObject *inflicting = m_scoringChain.Find(inflicting_id);
	ScoreObject *victim = m_scoringChain.Find(victim_id);

	if((inflicting) && (inflicting_id != victim_id))
		inflicting->AddKill();
	if(victim)
		victim->AddDeath();

	scoreDirty = true;

}

void
Mission::ScoringReactToTurretDeath (const ReplicatorID& inflicting_id, const ReplicatorID& victim_id)
{
	Check_Object(this);

	if (!Application::GetInstance()->serverFlag)
		return;

}

void
Mission::ScoringReactToBuildingDeath (const ReplicatorID& inflicting_id, const ReplicatorID& victim_id)
{
	Check_Object(this);

	if (!Application::GetInstance()->serverFlag)
		return;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mission::AddScoreMember (const ReplicatorID& member, const Stuff::MString& name)
{
	gos_PushCurrentHeap(Adept::g_Heap);
	ScoreObject *score_object = new ScoreObject(member, name);
	gos_PopCurrentHeap();
	m_scoringChain.AddValue(score_object, member);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mission::RemoveScoreMember(const ReplicatorID& member)
{
	ScoreObject *score = m_scoringChain.Find(member);
	if (score)
		m_scoringChain.Remove(score);
}

ScoreObject *Mission::GetScoreMember (const ReplicatorID& member)
{
	return m_scoringChain.Find(member);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mission::DoesAllowRunningLights()
{
	Check_Object(this);

	const GameModel *model = GetGameModel();
	Check_Object(model);

	if(m_isNightMission)
		return true;

	return model->m_allowRunningLights;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mission::DoesAllowSearchLights()
{
	Check_Object(this);

	const GameModel *model = GetGameModel();
	Check_Object(model);

	if(m_isNightMission)
		return true;

	return model->m_allowSearchLights;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission::SaveInstanceText(Stuff::Page *page)
{
	//
	//--------------------
	// Save the Model Name
	//--------------------
	//
	Check_Object(&gameModelResource);
	page->SetEntry("Model", (const char *)GetModelName());

	Resource map_res(mapResourceID),
			 prop_res(propListResourceID),
			 sky_res(skyResourceID),
			 nametable_res(nameTableResourceID);
			 

	
	page->SetEntry("Map",map_res.GetName());
	page->SetEntry("Props",prop_res.GetName());
	page->SetEntry("Sky",sky_res.GetName());
	page->SetEntry("MissionBounds","Mission.Bounds");
	page->SetEntry("WarningBounds","Warning.Bounds");

	if(nightSkyResourceID!=ResourceID::Null)
	{
	Resource nsky_res(nightSkyResourceID);
	page->SetEntry("NightSky",nsky_res.GetName());
	}
	//
	//-------------------------
	// Save the Execution State
	//-------------------------
	//
	int execution_state = executionState->GetState();
	MString execution_state_text;
	switch(execution_state)
	{
	case ExecutionStateEngine::NeverExecuteState:
		{
			execution_state_text = "NeverExecuteState";
			break;
		}
	case ExecutionStateEngine::ExecuteOnceState:
		{
			execution_state_text = "ExecuteOnceState";
			break;
		}
	case ExecutionStateEngine::AlwaysExecuteState:
		{
			execution_state_text = "AlwaysExecuteState";
			break;
		}
	default:
		{
			execution_state_text = "AlwaysExecuteState";
			break;
		}
	}
	page->SetEntry("ExecutionState", execution_state_text);

	
	MString table_name,table_path;
	table_name=nametable_res.GetName();
	int bidx;
	for(bidx=0;table_name[bidx]!='\0' && table_name[bidx]!='{';bidx++);
	Verify(table_name[bidx]!='\0');
	table_name[bidx]='\0';
	table_path=table_name;
	table_path+=".table";

	page->SetEntry("NameTable",table_path);

}
