#include "MW4Headers.hpp"

#include "MWObject.hpp"
#include "Subsystem.hpp"
#include "Torso.hpp"
#include "MWDamageObject.hpp"
#include "HeatManager.hpp"
#include "gameinfo.hpp"
#include "MWApplication.hpp"

#include <MissionLang\Resource.h>

#include <Adept\Tool.hpp>
#include <Adept\EntityManager.hpp>


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

int MWObject__GameModel::ConvertStringToMoveType (const char *str)
{
	if (!str)
		return NONE_MOVETYPE;
	if (!stricmp (str,"LEGMOVETYPE"))
		return LEG_MOVETYPE;
	if (!stricmp (str,"LEGJUMPMOVETYPE"))
		return LEGJUMP_MOVETYPE;
	if (!stricmp (str,"TRACKMOVETYPE"))
		return TRACK_MOVETYPE;
	if (!stricmp (str,"WHEELMOVETYPE"))
		return WHEEL_MOVETYPE;
	if (!stricmp (str,"FLYERMOVETYPE"))
		return FLYER_MOVETYPE;
	if (!stricmp (str,"HOVERMOVETYPE"))
		return HOVER_MOVETYPE;
	if (!stricmp (str,"HELIMOVETYPE"))
		return HELI_MOVETYPE;
	if (!stricmp (str,"DROPSHIPMOVETYPE"))
		return DROPSHIP_MOVETYPE;
	if (!stricmp (str,"WATERMOVETYPE"))
		return WATER_MOVETYPE;
	gosREPORT (false,"Unknown movement type in MWObject gamemodel");
	return NONE_MOVETYPE;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject__CreateMessage::ConstructCreateMessage(Script *script)
{
	Check_Object(script);
	#if defined(_ARMOR)
		int stack_level = Tool::Instance->GetStackLevel();
	#endif
#ifdef LAB_ONLY
	strcpy(MWGameInfo::g_ResourceFile, (char *)(script->instancePage->GetNotationFile()->GetFileName()));
	strcpy(MWGameInfo::g_ResourceEntry, (char *)(script->instancePage->GetName()));
#endif

	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *message_stream = script->messageStream;
	Check_Object(message_stream);
	message_stream->AllocateBytes(sizeof(MWObject__CreateMessage));
	BaseClass::ConstructCreateMessage(script);
	MWObject__CreateMessage *message =
		Cast_Pointer(
			MWObject__CreateMessage*,
			message_stream->GetPointer()
		);
	message->messageLength = sizeof(*message);

	//
	//---------------------------------------------------------------
	// Point at the notation file and make other files relative to it
	//---------------------------------------------------------------
	//
	Page *instance_page = script->instancePage;
	Check_Object(instance_page);
	NotationFile *instance_file = instance_page->GetNotationFile();
	Check_Object(instance_file);
	Check_Object(Tool::Instance);
	Tool::Instance->PushFilePath(instance_file);
	Check_Object(Resource::ParentFileDependencies);

	//
	//--------------------------------------
	// Make sure that no armature exists yet
	//--------------------------------------
	//
	{
		Verify(!message->armatureStreamResourceID);
		NotationFile armatures_file;
		if (instance_page->GetEntry("Armature", &armatures_file))
		{
			const char* armatures_filename = armatures_file.GetFileName();

			//
			//------------------------------------------------------------------
			// Look for the armature stream resource to see if it is up to date
			//------------------------------------------------------------------
			//
			Resource armature_resource(armatures_filename);
			if (
				armature_resource.DoesResourceExist() &&
				armature_resource.IsResourceUpToDate()
			)
			{
				WORD span;
				armature_resource.LoadData();
				armature_resource >> span;
				Verify(span > 0);
				*script->baseID += span;
				message->armatureStreamResourceID = armature_resource.GetResourceID();
				message->replicatorID += span;
				if (!armature_resource.IsRegistered())
					armature_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}

			//
			//------------------------------------------------
			// For each instance_page, an entity will be built
			//------------------------------------------------
			//
			else
			{
				FileDependencies arm_deps(*armatures_file.GetFileDependencies());
				FileDependencies *parent = Resource::ParentFileDependencies;
				Resource::ParentFileDependencies = &arm_deps;
				Tool::Instance->PushFilePath(&armatures_file);
				DynamicMemoryStream armature_stream;
				armature_stream << static_cast<WORD>(0);
				ReplicatorID starting_id = *script->baseID;
				NotationFile::PageIterator *instance_names = armatures_file.MakePageIterator();
				Check_Object(instance_names);
				Page *instance;
				while ((instance = instance_names->ReadAndNext()) != NULL)
				{
					Check_Object(instance);

					//
					//-----------------------------------------
					// Create the entity for this instance_page
					//-----------------------------------------
					//
					bool on_root = false;
					instance->GetEntry("AttachedToRoot", &on_root);
					if (on_root)
					{
						Entity::CreateMessage *message =
							Tool::Instance->ConstructCreateMessage(
								&armature_stream,
								instance,
								script->baseID
							);
						Check_Object(message);
						armature_stream.AdvancePointer(message->messageLength);
					}
				}

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (armature_stream.GetBytesUsed() > sizeof(WORD))
				{
					armature_stream.Rewind();
					Verify(*script->baseID != starting_id);
					WORD span =
						static_cast<WORD>(script->baseID->localID - starting_id.localID);
					armature_stream << span;
					armature_resource.Save(&armature_stream, &arm_deps);
					Check_Object(&armature_resource);
					message->armatureStreamResourceID = armature_resource.GetResourceID();
					message->replicatorID += span;
				}
				else
					message->armatureStreamResourceID = ResourceID::Null;
				if (!armature_resource.IsRegistered())
					parent->AddDependencies(&arm_deps);
				Resource::ParentFileDependencies = parent;

				//
				//------------------------
				// Clean up the tool stack
				//------------------------
				//
				Check_Object(instance_names);
				delete instance_names;
				Tool::Instance->PopFilePath();
			}
		}
	}

	//
	//------------------------------------------------------------
	// Create messages for the subsystem stream only if it's there
	//------------------------------------------------------------
	//
	{
		NotationFile subsystems_file;
		message->subsystemStreamResourceID = ResourceID::Null;
		if (instance_page->GetEntry("Subsystems", &subsystems_file))
		{
			const char *subsystems_filename = subsystems_file.GetFileName();
			Check_Pointer(subsystems_filename);

			//
			//------------------------------------------------------------------
			// Look for the subsystem stream resource to see if it is up to date
			//------------------------------------------------------------------
			//
			Resource subsystem_resource(subsystems_filename);
			if (
				subsystem_resource.DoesResourceExist() &&
				subsystem_resource.IsResourceUpToDate()
			)
			{
				subsystem_resource.LoadData();
				WORD span;
				subsystem_resource >> span;
				Verify(span > 0);
				*script->baseID += span;
				message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
				message->replicatorID += span;
				if (!subsystem_resource.IsRegistered())
					subsystem_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}

			else
			{
				//
				//---------------------------------------
				// For each instance_page, an entity will be built
				//---------------------------------------
				//
				FileDependencies sub_deps(*subsystems_file.GetFileDependencies());
				FileDependencies *parent = Resource::ParentFileDependencies;
				Resource::ParentFileDependencies = &sub_deps;
				Tool::Instance->PushFilePath(&subsystems_file);
				DynamicMemoryStream subsystem_stream(sizeof(WORD));
				subsystem_stream << static_cast<WORD>(0);
				ReplicatorID starting_id = *script->baseID;
				NotationFile::PageIterator *instance_names = subsystems_file.MakePageIterator();
				Check_Object(instance_names);
				Page *instance;
				while ((instance = instance_names->ReadAndNext()) != NULL)
				{
					Check_Object(instance);

					//
					//--------------------------------
					// Create the entity for this instance_page
					//--------------------------------
					//
					Entity::CreateMessage *message =
						Tool::Instance->ConstructCreateMessage(
							&subsystem_stream,
							instance,
							script->baseID
						);
					Check_Object(message);
					subsystem_stream.AdvancePointer(message->messageLength);
				}

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (subsystem_stream.GetBytesUsed() > sizeof(WORD))
				{
					subsystem_stream.Rewind();
					Verify(*script->baseID != starting_id);
					WORD span =
						static_cast<WORD>(script->baseID->localID - starting_id.localID);
					subsystem_stream << span;
					subsystem_resource.Save(&subsystem_stream, &sub_deps);
					Check_Object(&subsystem_resource);
					message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
					message->replicatorID += span;
				}
				else
					message->subsystemStreamResourceID = ResourceID::Null;
				if (!subsystem_resource.IsRegistered())
					parent->AddDependencies(&sub_deps);
				Resource::ParentFileDependencies = parent;
				
				//
				//------------------------
				// Clean up the tool stack
				//------------------------
				//
				Check_Object(instance_names);
				delete instance_names;
				Tool::Instance->PopFilePath();
			}
		}
	}
	
	//
	//----------------------------------------------------------
	// Create messages a damage object stream only if it's there
	//----------------------------------------------------------
	//
	{
		NotationFile damage_file;
		message->damageStreamResourceID = ResourceID::Null;
		if (instance_page->GetEntry("DamageObjects", &damage_file))
		{
			Check_Object(Tool::Instance);
			const char* damage_filename = damage_file.GetFileName();
			Check_Pointer(damage_filename);

			//
			//---------------------------------------------------------------
			// Look for the damage stream resource to see if it is up to date
			//---------------------------------------------------------------
			//
			Resource damage_resource(damage_filename);
			if (
				damage_resource.DoesResourceExist() &&
				damage_resource.IsResourceUpToDate()
			)
			{
				message->damageStreamResourceID = damage_resource.GetResourceID();
				if (!damage_resource.IsRegistered())
					damage_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}
				
			else
			{

				//
				//---------------------------------------
				// For each instance_page, an entity will be built
				//---------------------------------------
				//
				FileDependencies damage_deps(*damage_file.GetFileDependencies());
				FileDependencies *parent = Resource::ParentFileDependencies;
				Resource::ParentFileDependencies = &damage_deps;
				Tool::Instance->PushFilePath(&damage_file);
				DynamicMemoryStream damage_stream;
				NotationFile::PageIterator *damage_names = damage_file.MakePageIterator();
				Check_Object(damage_names);
				Page *damage_instance;

				//
				//---------------------------------------
				// Create the damage Object for this instance_page
				//---------------------------------------
				//
				while ((damage_instance = damage_names->ReadAndNext()) != NULL)
				{
					
					//
					//-------------------------------------------------------
					//Check to see if we are internal or just a damage object
					//-------------------------------------------------------
					//
					int damage_zone;
					if (!damage_instance->GetEntry("DamageZone", &damage_zone))
					{
						DamageObject::ConstructDamageObjectStream(
							&damage_stream,
							damage_instance
						);
					}
					else
					{
						MWInternalDamageObject::ConstructMWInternalDamageObjectStream(
							&damage_stream,
							damage_instance
						);
					}
				}

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (damage_stream.GetBytesUsed())
				{
					damage_resource.Save(
						&damage_stream,
						&damage_deps
					);
					if (!damage_resource.IsRegistered())
						parent->AddDependencies(&damage_deps);
					Check_Object(&damage_resource);
					message->damageStreamResourceID = damage_resource.GetResourceID();
				}
				else
					message->damageStreamResourceID = ResourceID::Null;
				Resource::ParentFileDependencies = parent;
			
				//------------------------
				// Clean up the tool stack
				//------------------------
				//
				Check_Object(damage_names);
				delete damage_names;
				Tool::Instance->PopFilePath();
			}
		}
	}

	const char *skin_name;
	message->skinPrefix = DefaultSkinPrefix;
	if(instance_page->GetEntry("Skin", &skin_name))
		message->skinPrefix = *skin_name;

	message->teamDecal = 0;
	instance_page->GetEntry("TeamDecal", &message->teamDecal);
	
	message->pilotDecal = 0;
	instance_page->GetEntry("PilotDecal", &message->pilotDecal);

	message->nameIndex = -1;
	instance_page->GetEntry("NameIndex", &message->nameIndex);

	message->doesHaveInstanceName = false;
	instance_page->GetEntry("DoesHaveInstanceName", &message->doesHaveInstanceName);
	
	Tool::Instance->PopFilePath();
	Verify(stack_level == Tool::Instance->GetStackLevel());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject__GameModel::ConstructGameModel(Script *script)
{
	Check_Object(script);
	#if defined(_ARMOR)
		int stack_level = Tool::Instance->GetStackLevel();
	#endif

	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *model_stream = script->modelStream;
	Check_Object(model_stream);
	model_stream->AllocateBytes(sizeof(MWObject__GameModel));
	BaseClass::ConstructGameModel(script);

	MWObject__GameModel *model =
		Cast_Pointer(MWObject__GameModel*, model_stream->GetPointer());


	NotationFile *model_file = script->modelFile;
	Check_Object(model_file);

	const char *temp_name = NULL;
	Page *game_page = model_file->GetPage("GameData");
	Check_Object(game_page);
	game_page->GetEntry("AnimationScript", &temp_name);
	
	model->animScriptName[0] = NULL;

	if (temp_name != NULL)
	{
		Str_Copy(model->animScriptName, temp_name, sizeof(model->animScriptName));
	}

	const char *str = NULL;
	game_page->GetEntry("MoveTypeFlag",&str);
	model->moveTypeFlag = ConvertStringToMoveType (str);

	//
	//---------------------------------------------
	//Create the array of Damage Effect ResourceIDs
	//---------------------------------------------
	//
	model->idleEffectResourceID = ResourceID::Null;
	NotationFile effects_file;
	if(game_page->GetEntry("IdleEffectsFile", &effects_file))
	{
		const char *effects_file_name = effects_file.GetFileName();
		Check_Pointer(effects_file_name);

		//
		//------------------------------------------------------------------
		// Look for the subsystem stream resource to see if it is up to date
		//------------------------------------------------------------------
		//
		Resource effects_resource(effects_file_name);
		if (
			effects_resource.DoesResourceExist() &&
			effects_resource.IsResourceUpToDate()
		)
		{
			model->idleEffectResourceID = effects_resource.GetResourceID();
			if (!effects_resource.IsRegistered())
				effects_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
		}

		else
		{
			//
			//---------------------------------------
			// For each page, an entity will be built
			//---------------------------------------
			//
			FileDependencies effect_deps(*effects_file.GetFileDependencies());
			FileDependencies *parent = Resource::ParentFileDependencies;
			Resource::ParentFileDependencies = &effect_deps;
			Tool::Instance->PushFilePath(&effects_file);
			DynamicMemoryStream effects_stream;
			NotationFile::PageIterator *instance_names = effects_file.MakePageIterator();
			Check_Object(instance_names);
			Page *instance;
			while ((instance = instance_names->ReadAndNext()) != NULL)
			{
				Check_Object(instance);

				//
				//--------------------------------
				// Create the entity for this page
				//--------------------------------
				//

				//First get and create the effect resource and store the ID
				const char* effect_file;
				instance->GetEntry("EffectFile", &effect_file, true);
				Resource effect_entry_resource;
				Tool::Instance->ConstructDataList(&effect_entry_resource, effect_file);
				Check_Object(&effect_entry_resource);
				Verify(effect_entry_resource.DoesResourceExist());
				effects_stream << effect_entry_resource.GetResourceID();

				//Next read in the site name and store it
				const char *site_name;
				MString site_string;
				instance->GetEntry("SiteName", &site_name);
				Check_Pointer(site_name);
				site_string = site_name;
				effects_stream << site_string;
			}

			//
			//-----------------------------------------
			// Only save out the stream if there is one
			//-----------------------------------------
			//
			if (effects_stream.GetBytesUsed() > 0)
			{
				effects_resource.Save(&effects_stream, &effect_deps);
				if (!effects_resource.IsRegistered())
					parent->AddDependencies(&effect_deps);
				Check_Object(&effects_resource);
				model->idleEffectResourceID = effects_resource.GetResourceID();
			}
			else
				model->idleEffectResourceID = ResourceID::Null;
			Resource::ParentFileDependencies = parent;
			
			//
			//------------------------
			// Clean up the tool stack
			//------------------------
			//
			Check_Object(instance_names);
			delete instance_names;
			Tool::Instance->PopFilePath();
		}
	}

	Verify(stack_level == Tool::Instance->GetStackLevel());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject__GameModel::ConstructOBBStream(Script *script)
{
	Check_Object(script);
	Check_Object(Resource::ParentFileDependencies);

	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *model_stream = script->modelStream;
	Check_Object(model_stream);
	MWObject__GameModel *model =
		Cast_Pointer(MWObject__GameModel*, model_stream->GetPointer());

	//
	//------------------------------
	// See if there is an OBB stream
	//------------------------------
	//
	NotationFile *model_file = script->modelFile;
	Check_Object(model_file);
	Page *game_page = model_file->GetPage("GameData");
	Check_Object(game_page);
	const char* obb_stream_name;

	//
	//---------------------------------------------------
	// If there is a solid OBB, store it in the resources
	//---------------------------------------------------
	//
	model->obbStreamResourceID = ResourceID::Null;
	if (game_page->GetEntry("SolidOBB", &obb_stream_name))
	{
		Check_Pointer(obb_stream_name);
		FileStream solid_stream(obb_stream_name);
		MString file_name = model_file->GetFileName();
		file_name += "{SolidOBB}";
		Resource obb_res(file_name);
		if (!obb_res.DoesResourceExist() || !obb_res.IsResourceUpToDate())
		{
			FileDependencies obb_dependencies;
			obb_dependencies.AddDependency(&solid_stream);
			obb_res.Save(&solid_stream, &obb_dependencies);
			if (!obb_res.IsRegistered())
				obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
		}
		else if (!obb_res.IsRegistered())
			obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);

		model->obbStreamResourceID = obb_res.GetResourceID();
	}

	//
	//----------------------------------------------------------
	// If there is a hierarchical OBB, store it in the resources
	//----------------------------------------------------------
	//
	model->hierarchicalOBBStreamResourceID = ResourceID::Null;
	if (game_page->GetEntry("HierarchicalOBB", &obb_stream_name))
	{
		Check_Pointer(obb_stream_name);
		FileStream solid_stream(obb_stream_name);
		MString file_name = model_file->GetFileName();
		file_name += "{HierarchicalOBB}";
		Resource obb_res(file_name);
		if (!obb_res.DoesResourceExist() || !obb_res.IsResourceUpToDate())
		{
			FileDependencies obb_dependencies;
			obb_dependencies.AddDependency(&solid_stream);
			obb_res.Save(&solid_stream, &obb_dependencies);
			if (!obb_res.IsRegistered())
				obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
		}
		else if (!obb_res.IsRegistered())
			obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);

		model->hierarchicalOBBStreamResourceID = obb_res.GetResourceID();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MWObject__GameModel::ReadAndVerify(
		MWObject__GameModel *model,
		ModelAttributeEntry *attribute_entry,
		const char *data,
		char **error,
		int error_buffer
	)
{
	Check_Object(attribute_entry);

	bool result = false;
	bool valid_data = (*data != '\0');

	//
	//----------------------------------------
	//Read in the values from the data entered
	//----------------------------------------
	//
	result =
		BaseClass::ReadAndVerify(
			model,
			attribute_entry,
			data,
			error,
			error_buffer
		);
	//
	//---------------------------
	//Verify all the model values
	//---------------------------
	//
	switch(attribute_entry->attributeID)
	{
	
	case DestroyedEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case DeathEntityResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case SecondaryDestroyedEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case SecondaryDeathEntityResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case VehicleTonnageAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->vehicleTonnage < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]VehicleTonnage=%f}: value must be >= 0!",
					model->vehicleTonnage
				);
				result = false;
			}
			break;
		}
	case MaxVehicleTonnageAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 500.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->maxVehicleTonnage < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MaxVehicleTonnage=%f}: value must be >= 0!",
					model->maxVehicleTonnage
				);
				result = false;
			}
			break;
		}
	case EyeSiteNameAttributeID:
		{
			if(!valid_data)
			{
				char *value;
				value = new char[MaxStringLength];
				Register_Pointer(value);
				Str_Copy(value, "site_eyepoint", MaxStringLength);
				attribute_entry->SetValue(model, value);
				result = true;
				Unregister_Pointer(value);
				delete value;
				break;
			}
			break;
		}
	case PartDestructionEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}

	case SplashDamageRadiusAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->splashDamageRadius < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]SplashDamageRadius=%f}: value must be > 0!",
					model->splashDamageRadius
				);
				result = false;
			}
			break;
		}

	case SplashDamageAmountAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->splashDamageAmount < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]SplashDamageAmount=%f}: value must be > 0!",
					model->splashDamageAmount
				);
				result = false;
			}
			break;
		}
	case VehicleBattleValueAttributeID:
		{
			if(!valid_data)
			{
				int value = 0;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->vehicleBattleValue < 0)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]VehicleBattleValue=%f}: value must be >= 0!",
					model->vehicleBattleValue
				);
				result = false;
			}
			break;
		}
	
	case CoolantEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case OverHeatEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case EjectEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	case SplashHeatAmountAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->splashHeatAmount < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]SplashHeatAmount=%f}: value must be >= 0!",
					model->splashHeatAmount
				);
				result = false;
			}
			break;
		}
	case NameIndexAttributeID:
		{
			if(!valid_data)
			{
				int value = IDS_NONAME;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_nameIndex < 0)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]NameIndex=%f}: value must be >= 0!",
					model->m_nameIndex
				);
				result = false;
			}
			break;
		}
	}

	return result;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	
void
	MWObject::SaveInstanceText(Page *instance_page)
{
	Check_Object(this);
	Check_Object(instance_page);

	BaseClass::SaveInstanceText(instance_page);

	//
	//----------------------------
	//Save all of the stream names
	//----------------------------
	//
	if(armatureStreamResourceID != ResourceID::Null)
	{
		Resource armature_resource(armatureStreamResourceID);
		Verify(armature_resource.DoesResourceExist());
		instance_page->SetEntry("Armature", armature_resource.GetName());
	}
	if(subsystemStreamResourceID != ResourceID::Null)
	{
		Resource subsystem_resource(subsystemStreamResourceID);
		Verify(subsystem_resource.DoesResourceExist());
		instance_page->SetEntry("Subsystems", subsystem_resource.GetName());
	}
	if(!invulnerable && damageStreamResourceID != ResourceID::Null)
	{
		Resource damage_resource(damageStreamResourceID);
		Verify(damage_resource.DoesResourceExist());
		instance_page->SetEntry("DamageObjects", damage_resource.GetName());
	}

	if(m_heatManager)
		instance_page->SetEntry("CurrentHeat", m_heatManager->GetHeat());	

	char szTemp[2];
	szTemp[0] = m_skinPrefix;
	szTemp[1] = 0;
	instance_page->SetEntry("Skin", szTemp);


	instance_page->SetEntry("TeamDecal", m_teamDecal);
	instance_page->SetEntry("PilotDecal", m_teamDecal);

	instance_page->SetEntry("DoesHaveInstanceName", m_doesHaveInstanceName);
	
	if(m_doesHaveInstanceName)
		instance_page->SetEntry("@LocalizedInstanceName", instanceName);


	if(m_localizeIndex > -1)
//		instance_page->SetEntry("NameIndex", m_localizeIndex);
// Wipe this value out so that NameTable doesn't replace a define with a hard number.
		instance_page->SetEntry("NameIndex", -1);
	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceID
	MWObject__GameModel::CreateEffectTableResource(Stuff::NotationFile *effect_file, BYTE length)
{
	Check_Object(Resource::ParentFileDependencies);

	Resource table_resource(effect_file->GetFileName());
	if (
		table_resource.DoesResourceExist() &&
		table_resource.IsResourceUpToDate()
	)
	{
		if (!table_resource.IsRegistered())
			table_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
		return table_resource.GetResourceID();
	}

	DynamicMemoryStream effects_stream(sizeof(int) + length * sizeof(ResourceID));

	//
	//----------------------
	//Create the stream here
	//----------------------
	//
	effects_stream << length;
	ResourceID *stream_array = Cast_Pointer(ResourceID *, effects_stream.GetPointer());
	for(int i=0;i<length;i++)
	{
		stream_array[i] = ResourceID::Null;
	}

	Check_Object(effect_file);
	Page *effect_page = effect_file->FindPage("EffectList");
	if (effect_page)
	{
		ChainOf<Note*> *effects = effect_page->MakeNoteChain("Effect");
		Check_Object(effects);
		Page::NoteIterator effects_list(effects);
		Note *effects_entry;
		while ((effects_entry = effects_list.ReadAndNext()) != NULL)
		{
			Check_Object(effects_entry);
			const char *effect_data;
			effects_entry->GetEntry(&effect_data);
			Check_Pointer(effect_data);

			MString entry_string;
			MString effect_file_name;

			entry_string = effect_data;
			effect_file_name = entry_string.GetNthToken(0, ",");

			Check_Object(Tool::Instance);
			Check_Object(ResourceManager::Instance);
			Resource effect_resource;
			Tool::Instance->ConstructDataList(&effect_resource, effect_file_name);
			Check_Object(&effect_resource);
			Verify(effect_resource.DoesResourceExist());
			MString material_name;
			material_name = entry_string.GetNthToken(1, ",");
			int material_num = MaterialTypeTextToAscii(material_name);
			Verify(material_num < length);
			stream_array[material_num] = effect_resource.GetResourceID();
		}

		if (effects_stream.GetBytesUsed() > 0)
		{
			table_resource.Save(
				&effects_stream,
				Resource::ParentFileDependencies
			);
			Check_Object(&table_resource);

			delete effects;
			return table_resource.GetResourceID();
		}

		delete effects;
	}
	return ResourceID::Null;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::CreateArmatureStream(MemoryStream *stream, NotationFile *notation_file)
{
	Check_Pointer(stream);
	Check_Pointer(notation_file);

	Tool::Instance->PushFilePath(notation_file);
	FileDependencies arm_deps(*notation_file->GetFileDependencies());
	FileDependencies *parent = Resource::ParentFileDependencies;
	Resource::ParentFileDependencies = &arm_deps;
	*stream << static_cast<WORD>(0);
	ReplicatorID starting_id = ReplicatorID::Null;
	NotationFile::PageIterator *instance_names = notation_file->MakePageIterator();
	Check_Object(instance_names);
	Page *instance;
	while ((instance = instance_names->ReadAndNext()) != NULL)
	{
		Check_Object(instance);

		//
		//-----------------------------------------
		// Create the entity for this instance_page
		//-----------------------------------------
		//
		bool on_root = false;
		instance->GetEntry("AttachedToRoot", &on_root);
		if (on_root)
		{
			Entity::CreateMessage *message =
				Tool::Instance->ConstructCreateMessage(
					stream,
					instance,
					&starting_id
				);
			Check_Object(message);
			stream->AdvancePointer(message->messageLength);
		}
	}

	if (stream->GetBytesUsed() > sizeof(WORD))
	{
		stream->Rewind();
		WORD span =
			static_cast<WORD>(starting_id.localID - 0);
		*stream << span;
	}
	//
	//------------------------
	// Clean up the tool stack
	//------------------------
	//
	Resource::ParentFileDependencies = parent;

	Check_Object(instance_names);
	delete instance_names;
	Tool::Instance->PopFilePath();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::CreateDamageStream(MemoryStream *stream, NotationFile *notation_file)
{
	Check_Pointer(stream);
	Check_Pointer(notation_file);

	FileDependencies damage_deps(*notation_file->GetFileDependencies());
	FileDependencies *parent = Resource::ParentFileDependencies;
	Resource::ParentFileDependencies = &damage_deps;
	Tool::Instance->PushFilePath(notation_file);
	NotationFile::PageIterator *damage_names = notation_file->MakePageIterator();
	Check_Object(damage_names);
	Page *damage_instance;

	//
	//---------------------------------------
	// Create the damage Object for this instance_page
	//---------------------------------------
	//
	while ((damage_instance = damage_names->ReadAndNext()) != NULL)
	{
		//
		//-------------------------------------------------------
		//Check to see if we are internal or just a damage object
		//-------------------------------------------------------
		//
		int damage_zone;
		if (!damage_instance->GetEntry("DamageZone", &damage_zone))
		{
			DamageObject::ConstructDamageObjectStream(stream, damage_instance);
		}
		else
		{
			MWInternalDamageObject::ConstructMWInternalDamageObjectStream(stream, damage_instance);
		}
	}

	Resource::ParentFileDependencies = parent;

	Check_Object(damage_names);
	delete damage_names;
	Tool::Instance->PopFilePath();
			
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::CreateSubsystemStream(MemoryStream *stream, NotationFile *notation_file)
{
	Check_Pointer(stream);
	Check_Pointer(notation_file);

	FileDependencies sub_deps(*notation_file->GetFileDependencies());
	FileDependencies *parent = Resource::ParentFileDependencies;
	Resource::ParentFileDependencies = &sub_deps;
	Tool::Instance->PushFilePath(notation_file);
	*stream << static_cast<WORD>(0);
	ReplicatorID starting_id = ReplicatorID::Null;
	NotationFile::PageIterator *instance_names = notation_file->MakePageIterator();
	Check_Object(instance_names);
	Page *instance;
	while ((instance = instance_names->ReadAndNext()) != NULL)
	{
		Check_Object(instance);

		//
		//-----------------------------------------
		// Create the entity for this instance_page
		//-----------------------------------------
		//
		Entity::CreateMessage *message =
			Tool::Instance->ConstructCreateMessage(
				stream,
				instance,
				&starting_id
			);
		Check_Object(message);
		stream->AdvancePointer(message->messageLength);
	}

	//
	//-----------------------------------------
	// Only save out the stream if there is one
	//-----------------------------------------
	//
	if (stream->GetBytesUsed() > sizeof(WORD))
	{
		stream->Rewind();
		WORD span =
			static_cast<WORD>(starting_id.localID - 0);
		*stream << span;
	}
	Resource::ParentFileDependencies = parent;

	Check_Object(instance_names);
	delete instance_names;
	Tool::Instance->PopFilePath();
}