/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : LevelEdit                                                    *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Tools/LevelEdit/Preset.cpp                   $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 1/29/02 4:04p                                               $*
 *                                                                                             *
 *                    $Revision:: 49                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "stdafx.h"

#include "preset.h"
#include "presetgeneraltab.h"
#include "presetsettingstab.h"
#include "presetpropsheet.h"
#include "chunkio.h"
#include "persistfactory.h"
#include "editorchunkids.h"
#include "definition.h"
#include "definitionmgr.h"
#include "filemgr.h"
#include "parameter.h"
#include "terrainnode.h"
#include "terraindefinition.h"
#include "tilenode.h"
#include "objectnode.h"
#include "assetmgr.h"
#include "wwstring.h"
#include "combatchunkid.h"
#include "spawnernode.h"
#include "soundnode.h"
#include "vispointnode.h"
#include "presettransitiontab.h"
#include "vehicle.h"
#include "zonenode.h"
#include "damagezonenode.h"
#include "transitionnode.h"
#include "pathfindstartnode.h"
#include "dummyobjectnode.h"
#include "editoronlyobjectnode.h"
#include "presetmgr.h"
#include "lightnode.h"
#include "physobjedittab.h"
#include "definitionutils.h"
#include "waypathnode.h"
#include "utils.h"
#include "coverspotnode.h"
#include "presetdependencytab.h"
#include "presetzonetab.h"
#include "presetdialoguetab.h"
#include "buildingnode.h"
#include "nodescriptsproppage.h"
#include "nodemgr.h"
#include "sceneeditor.h"
#include "editorbuild.h"


///////////////////////////////////////////////////////////////////////
//
//	Global persist factory for presets
//
///////////////////////////////////////////////////////////////////////
SimplePersistFactoryClass<PresetClass, CHUNKID_PRESET> _PresetPersistFactory;


//////////////////////////////////////////////////////////////////////////////////
//	Constants
//////////////////////////////////////////////////////////////////////////////////
enum
{
	CHUNKID_VARIABLES			= 0x00000100,
	CHUNKID_COMMENTS,
	XXX_CHUNKID_NODES
};

enum
{
	VARID_DEFINITIONID	= 0x01,
	VARID_ISTEMPORARY,
	VARID_COMMENTS,
	VARID_PARENTPTR,
	VARID_THISPTR,
	XXX_VARID_FILEDEPENDENCY,
	VARID_PARENT_ID,
	VARID_MANUALDEPENDENCY
};


///////////////////////////////////////////////////////////////////////
//
//	PresetClass
//
///////////////////////////////////////////////////////////////////////
PresetClass::PresetClass (void)
	:	m_Definition (NULL),
		m_DefinitionID (0),
		m_Parent (NULL),
		m_ParentID (0),
		m_NextPreset (NULL),
		m_PrevPreset (NULL),
		m_IsTemporary (false),
		m_IsValid (true)
{
	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	~PresetClass
//
///////////////////////////////////////////////////////////////////////
PresetClass::~PresetClass (void)
{
	//
	//	Remove this preset from its parent (if possible or necessary)
	//
	PresetClass *parent = PresetMgrClass::Find_Preset (m_ParentID);
	if (parent != NULL) {
		parent->Remove_Child_Preset (m_DefinitionID);
	}

	//
	//	Unlink this definition from its preset (if possible or necessary)
	//
	DefinitionClass *definition = DefinitionMgrClass::Find_Definition (m_DefinitionID, false);
	if (definition != NULL && (definition->Get_User_Data () == (uint32)this)) {
		definition->Set_User_Data (NULL);
	}

	Free_Node_List ();
	return ;	
}


///////////////////////////////////////////////////////////////////////
//
//	Show_Properties
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Show_Properties (bool read_only)
{	
	PresetGeneralTabClass		general_tab (this);
	PhysObjEditTabClass			phys_model_tab;
	PresetSettingsTabClass		settings_tab (this);
	PresetDependencyTabClass	dependencies_tab (this);
	PresetTransitionTabClass	transition_tab (this);	
	PresetZoneTabClass			zone_tab (this);	
	PresetDialogueTabClass		dialogue_tab (this);
	NodeScriptsPropPage			scripts_tab;

	//
	//	Add the general page first
	//
	PresetPropSheetClass prop_sheet;
	prop_sheet.Set_Preset (this);
	prop_sheet.Add_Page (&general_tab);

	//
	// Should we add a physics-definition page?
	//
	ModelDefParameterClass *phys_def_param = Get_Phys_Def_Param ();
	if (phys_def_param != NULL) {
		phys_model_tab.Set_PhysDef_Param (phys_def_param);
		phys_model_tab.Set_Filter (phys_def_param->Get_Base_Class ());
		phys_model_tab.Set_Is_Temp (m_IsTemporary);
		phys_model_tab.Set_Definition_ID (phys_def_param->Get_Value ());		
		prop_sheet.Add_Page (&phys_model_tab);		
	}	

	//
	//	Add the settings and file dependencies page
	//
	prop_sheet.Add_Page (&settings_tab);
	prop_sheet.Add_Page (&dependencies_tab);

	//
	// Should we add a scripts page?
	//
	ScriptListParameterClass *script_list_param = Get_Script_List_Param ();
	if (script_list_param != NULL) {
		scripts_tab.Set_Script_List_Parameter (script_list_param);
		prop_sheet.Add_Page (&scripts_tab);
	}
	
	//
	//	Add a dialogue tab to the property sheet if this preset represents a human.
	//
	if (Is_Soldier_Preset ()) {
		prop_sheet.Add_Page (&dialogue_tab);
	}

	//
	//	Should we add a transition-list page?
	//
	TRANSITION_DATA_LIST *transition_list = Get_Transition_List ();
	if (transition_list != NULL && read_only == false) {
		transition_tab.Set_Transition_List (transition_list);
		prop_sheet.Add_Page (&transition_tab);
	}

	//
	//	Should we add a zone-list page?
	//
	ZONE_PARAM_LIST zone_list;
	Build_Zone_List (m_Definition, zone_list);
	if (zone_list.Count () > 0 && read_only == false) {
		zone_tab.Set_Zone_Param_List (&zone_list);
		prop_sheet.Add_Page (&zone_tab);		
	}

	//
	//	Make sure things are read-only if needs be
	//
	prop_sheet.Set_Read_Only (read_only);
	general_tab.Set_Read_Only (read_only);
	settings_tab.Set_Read_Only (read_only);
	dependencies_tab.Set_Read_Only (read_only);
	phys_model_tab.Set_Read_Only (read_only);
	dialogue_tab.Set_Read_Only (read_only);

	//
	// Show the property sheet
	//
	UINT ret_code = prop_sheet.DoModal ();
	
	// Return true if the user clicked OK
	return (ret_code == IDOK);
}


///////////////////////////////////////////////////////////////////////
//
//	Get_Factory
//

///////////////////////////////////////////////////////////////////////
const PersistFactoryClass &
PresetClass::Get_Factory (void) const
{
	return _PresetPersistFactory;
}


///////////////////////////////////////////////////////////////////////
//
//	Save
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Save (ChunkSaveClass &csave)
{
	bool retval = true;

	//
	//	Save the comments to their own chunk
	//
	WRITE_WWSTRING_CHUNK (csave, CHUNKID_COMMENTS, m_Comments);
	
	//
	//	Save the other variables to a micro chunk
	//
	csave.Begin_Chunk (CHUNKID_VARIABLES);
		retval &= Save_Variables (csave);
	csave.End_Chunk ();

	return retval;
}


///////////////////////////////////////////////////////////////////////
//
//	Save_Variables
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Save_Variables (ChunkSaveClass &csave)
{
	bool retval = true;

	//
	//	Write the ID of the definition to the chunk	
	//
	ASSERT (m_Definition != NULL);
	if (m_Definition != NULL) {
		m_DefinitionID = m_Definition->Get_ID ();
		WRITE_MICRO_CHUNK (csave, VARID_DEFINITIONID, m_DefinitionID);
	}

	WRITE_MICRO_CHUNK (csave, VARID_ISTEMPORARY, m_IsTemporary);

	//
	//	Write the file dependencies to their own micro-chunks
	//
	for (int index = 0; index < m_ManualDependencies.Count (); index ++) {
		StringClass filename = (LPCTSTR)m_ManualDependencies[index];
		WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_MANUALDEPENDENCY, filename);
	}

	//
	//	For pointer remapping
	//
	PresetClass *this_ptr = this;
	WRITE_MICRO_CHUNK (csave, VARID_THISPTR, this_ptr);
	
	if (m_Parent != NULL) {
		m_ParentID = m_Parent->Get_ID ();
		WRITE_MICRO_CHUNK (csave, VARID_PARENT_ID, m_ParentID);
	}

	return retval;
}


///////////////////////////////////////////////////////////////////////
//
//	Load
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Load (ChunkLoadClass &cload)
{
	bool retval = true;

	while (cload.Open_Chunk ()) {
		switch (cload.Cur_Chunk_ID ())
		{
			READ_WWSTRING_CHUNK (cload, CHUNKID_COMMENTS, m_Comments);

			case CHUNKID_VARIABLES:
				retval &= Load_Variables (cload);
				break;
		}

		cload.Close_Chunk ();
	}
	
	SaveLoadSystemClass::Register_Post_Load_Callback (this);
	return retval;
}


///////////////////////////////////////////////////////////////////////
//
//	Load_Variables
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Load_Variables (ChunkLoadClass &cload)
{
	m_DefinitionID = 0;
	PresetClass *old_this_ptr = NULL; 
	m_ManualDependencies.Delete_All ();

	//
	//	Loop through all the microchunks that define the variables
	//
	while (cload.Open_Micro_Chunk ()) {
		switch (cload.Cur_Micro_Chunk_ID ()) {
			
			READ_MICRO_CHUNK (cload, VARID_DEFINITIONID, m_DefinitionID)
			READ_MICRO_CHUNK (cload, VARID_ISTEMPORARY, m_IsTemporary)
			READ_MICRO_CHUNK_WWSTRING (cload, VARID_COMMENTS, m_Comments);

			READ_MICRO_CHUNK (cload, VARID_PARENTPTR, m_Parent)
			READ_MICRO_CHUNK (cload, VARID_THISPTR, old_this_ptr)

			READ_MICRO_CHUNK (cload, VARID_PARENT_ID, m_ParentID);

			case VARID_MANUALDEPENDENCY:
			{
				StringClass filename;
				cload.Read(filename.Get_Buffer(cload.Cur_Micro_Chunk_Length()),cload.Cur_Micro_Chunk_Length());
				m_ManualDependencies.Add ((LPCTSTR)filename);				
			}
			break;
		}

		cload.Close_Micro_Chunk ();
	}

	//
	//	Check for a recursive linkage (could happen with temp presets if the
	// user deletes his registry)...
	//
	if (m_ParentID == Get_ID ()) {
		m_IsValid = false;
	}

	//
	//	Handle pointer remapping.  LEGACY CODE -- IS NOW OBSOLETE.
	//
	WWASSERT (old_this_ptr != NULL);
	SaveLoadSystemClass::Register_Pointer (old_this_ptr, this);
	if (m_Parent != NULL) {
		REQUEST_POINTER_REMAP ((void **)&m_Parent);
	}

	//
	//	Lookup the definition pointer from the definition id
	//
	WWASSERT (m_DefinitionID != 0);
	m_Definition = DefinitionMgrClass::Find_Definition (m_DefinitionID, false);
	
	//
	//	Associate this preset with the definition
	//
	if (m_Definition != NULL) {
		m_Definition->Set_User_Data ((uint32)this);
	}

	if (m_DefinitionID == 0 || m_Definition == NULL) {
		int test = 0;
	}

	return true;
}


///////////////////////////////////////////////////////////////////////
//
//	On_Post_Load
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::On_Post_Load (void)
{
	PersistClass::On_Post_Load ();

	//
	//	Lookup the parent based on its ID (instead of its pointer)
	//
	if (m_ParentID != 0) {
		m_Parent = PresetMgrClass::Find_Preset (m_ParentID);
		ASSERT (m_Parent != NULL);
		
		//
		//	Add ourselves as a child of our parent
		//
		if (m_Parent != NULL) {
			m_Parent->Add_Child_Preset (Get_ID ());
		}

#ifdef _DEBUG
		if (m_Parent == this || m_ParentID == Get_ID ()) {
			CString message;
			message.Format ("Preset %s is recursively linked to itself.\r\n", Get_Name ());
			::Output_Message (message);
		}
#endif // _DEBUG

	}

	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Create
//
///////////////////////////////////////////////////////////////////////
NodeClass *
PresetClass::Create (void)
{
	NodeClass *node = NULL;

	StringClass error_message;
	if (m_Definition != NULL && m_Definition->Is_Valid_Config (error_message)) {
		
		uint32 class_id = m_Definition->Get_Class_ID ();
		switch (::SuperClassID_From_ClassID (class_id))
		{			
			case CLASSID_TERRAIN:
				node = new TerrainNodeClass (this);
				break;

			case CLASSID_TILE:
				node = new TileNodeClass (this);
				break;

			case CLASSID_BUILDINGS:
				node = new BuildingNodeClass (this);
				break;

			case CLASSID_GAME_OBJECTS:
				
				if (class_id == CLASSID_SPAWNER_DEF) {
					node = new SpawnerNodeClass (this);
				} else if (class_id == CLASSID_GAME_OBJECT_DEF_BUILDING) {
					node = new BuildingNodeClass (this);
				} else if (class_id == CLASSID_GAME_OBJECT_DEF_SCRIPT_ZONE) {
					node = new ZoneNodeClass (this);
				} else if (class_id == CLASSID_GAME_OBJECT_DEF_DAMAGE_ZONE) {
					node = new DamageZoneNodeClass (this);
				} else if (class_id == CLASSID_GAME_OBJECT_DEF_TRANSITION) {
					node = new TransitionNodeClass (this);
				} else if (class_id == CLASSID_GAME_OBJECT_DEF_C4) {
					::AfxGetMainWnd ()->MessageBox ("You cannot place C4 objects in the editor.", "Non-Placeable Object", MB_ICONEXCLAMATION | MB_OK);
				} else {
					node = new ObjectNodeClass (this);
				}

				break;

			case CLASSID_LIGHT:
				node = new LightNodeClass (this);
				break;

			case CLASSID_SOUND:
				node = new SoundNodeClass (this);
				break;

			case CLASSID_WAYPATH:
				node = new WaypathNodeClass (this);
				break;

			case CLASSID_DUMMY_OBJECTS:
				node = new DummyObjectNodeClass (this);
				break;

			default:
				if (class_id == CLASSID_VIS_POINT_DEF) {
					node = new VisPointNodeClass (this);
				} else if (class_id == CLASSID_PATHFIND_START_DEF) {
					node = new PathfindStartNodeClass (this);
				} else if (class_id == CLASSID_COVERSPOT) {
					node = new CoverSpotNodeClass (this);
				} else if (class_id == CLASSID_EDITOR_ONLY_OBJECTS) {
					node = new EditorOnlyObjectNodeClass (this);
				}

				break;
		}

	} else if (m_Definition != NULL) {
		
		//
		//	Warn the user
		//
		StringClass msg ("Unable to instantiate preset!\nReason: preset not configured correctly.\n\n");
		msg += error_message;
		::AfxGetMainWnd ()->MessageBox (msg, "Preset Error", MB_ICONEXCLAMATION | MB_OK);
	}

	return node;
}


///////////////////////////////////////////////////////////////////////
//
//	Copy_Properties
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Copy_Properties (const PresetClass &preset)
{
	DefinitionClass *src_def = preset.Get_Definition ();
	if ((m_Definition != NULL) && (src_def != NULL)) {

		//
		//	Simply copy the parameters from one definition to the other...
		//
		::Copy_Definition (src_def, m_Definition, m_IsTemporary);

		//
		//	Copy the transitions as well
		//
		const TRANSITION_DATA_LIST *src_list	= preset.Get_Transition_List ();
		TRANSITION_DATA_LIST *dest_list	= Get_Transition_List ();
		if (src_list != NULL && dest_list != NULL) {
			
			//
			//	Free any existing transitions
			//
			for (int index = 0; index < dest_list->Count (); index ++) {
				TransitionDataClass *data = (*dest_list)[index];
				SAFE_DELETE (data);
			}
			dest_list->Delete_All ();
			
			//
			//	Now copy each of the transitions from the source list
			//
			for (index = 0; index < src_list->Count (); index ++) {
				const TransitionDataClass *data = (*src_list)[index];
				
				//
				//	Create a new transition object and copy the src's settings
				//
				TransitionDataClass *new_data = new TransitionDataClass;
				new_data->Set_Type (data->Get_Type ());
				new_data->Set_Zone (data->Get_Zone ());
				new_data->Set_Animation_Name (data->Get_Animation_Name ());
				new_data->Set_Ending_TM (data->Get_Ending_TM ());

				//
				//	Add this new transition to our list
				//
				dest_list->Add (new_data);
			}
		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Load_All_Assets
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Load_All_Assets (void)
{
	STRING_LIST dependencies;
	Get_All_Dependencies (dependencies);

	for (int index = 0; index < dependencies.Count (); index ++) {
		CString filename		= dependencies[index];
		CString full_path		= ::Get_File_Mgr ()->Make_Full_Path (filename);
		CString path			= ::Strip_Filename_From_Path (full_path);

		//
		//	Load all the assets contained in this file
		//
		::Set_Current_Directory (path);
		if (::Is_W3D_Filename (filename)) {
			WW3DAssetManager::Get_Instance ()->Load_3D_Assets (full_path);
			RenderObjClass *model = ::Create_Render_Obj (::Asset_Name_From_Filename (full_path));
			REF_PTR_RELEASE (model);
		} else {
			
#ifndef PUBLIC_EDITOR_VER

			if (::GetFileAttributes (full_path) == 0xFFFFFFFF) {
				::Get_File_Mgr ()->Update_File (full_path);
			}

#endif //!PUBLIC_EDITOR_VER

		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Get_All_Dependencies
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Get_All_Dependencies (STRING_LIST &list) const
{
	//
	//	Start fresh
	//
	list.Delete_All ();

	//
	//	Copy the manual dependencies to the list
	//
	list = m_ManualDependencies;

	//
	//	Add the implicit dependencies to the list
	//
	Add_Definition_Dependencies (m_Definition, list);
	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Get_Implicit_Dependencies
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Get_Implicit_Dependencies (STRING_LIST &list) const
{
	//
	//	Start fresh
	//
	list.Delete_All ();

	//
	//	Add the implicit dependencies to the list
	//
	Add_Definition_Dependencies (m_Definition, list);
	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Add_Definition_Dependencies
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Add_Definition_Dependencies (DefinitionClass *definition, STRING_LIST &list)
{
	if (definition != NULL) {
		
		//
		//	Find all 'filename' parameters to this definition.
		//
		int count = definition->Get_Parameter_Count ();
		for (int index = 0; index < count; index ++) {

			ParameterClass *parameter = definition->Lock_Parameter (index);
			if (	parameter->Get_Type () == ParameterClass::TYPE_FILENAME ||
					parameter->Get_Type () == ParameterClass::TYPE_SOUND_FILENAME) {
				
				//
				//	Add this filename dependency to the list
				//
				CString filename	= ((FilenameParameterClass *)parameter)->Get_String ();
				CString full_path = ::Get_File_Mgr ()->Make_Full_Path (filename);
				if (	::Get_File_Mgr ()->Is_Path_Valid (full_path) &&
						::Get_File_Mgr ()->Is_Empty_Path (full_path) == false)
				{					
					list.Add (::Get_File_Mgr ()->Make_Relative_Path (full_path));
				}

			} else if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
				
				//
				//	If this is param references a physics-definition, then add all its dependencies as well..
				//
				DefinitionClass *phys_def = NULL;
				phys_def = DefinitionMgrClass::Find_Definition (((ModelDefParameterClass *)parameter)->Get_Value (), false);
				Add_Definition_Dependencies (phys_def, list);
			}
		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Get_Script_List_Param
//
///////////////////////////////////////////////////////////////////////
ScriptListParameterClass *
PresetClass::Get_Script_List_Param (void)
{
	ScriptListParameterClass *param = NULL;

	//
	//	Try to find a script list parameter somewhere in the preset...
	//	
	int index = m_Definition->Get_Parameter_Count ();
	while ((index --) && (param == NULL)) {
		ParameterClass *parameter = m_Definition->Lock_Parameter (index);

		//
		//	Is this the parameter we are looking for?
		//
		if (parameter->Get_Type () == ParameterClass::TYPE_SCRIPTLIST) {
			param = (ScriptListParameterClass *)parameter;
		}

		m_Definition->Unlock_Parameter (index);
	}
	
	return param;
}


///////////////////////////////////////////////////////////////////////
//
//	Get_Phys_Def_Param
//
///////////////////////////////////////////////////////////////////////
ModelDefParameterClass *
PresetClass::Get_Phys_Def_Param (void)
{
	ModelDefParameterClass *param = NULL;

	//
	//	Try to find a physics-def parameter somewhere in the preset...
	//	
	int index = m_Definition->Get_Parameter_Count ();
	while ((index --) && (param == NULL)) {
		ParameterClass *parameter = m_Definition->Lock_Parameter (index);

		//
		//	Is this the parameter we are looking for?
		//
		if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
			param = (ModelDefParameterClass *)parameter;
		}

		m_Definition->Unlock_Parameter (index);
	}
	

	return param;
}


///////////////////////////////////////////////////////////////////////
//
//	Get_Transition_List
//
///////////////////////////////////////////////////////////////////////
TRANSITION_DATA_LIST *
PresetClass::Get_Transition_List (void) const
{
	TRANSITION_DATA_LIST *list = NULL;

	if (m_Definition != NULL) {
		switch (m_Definition->Get_Class_ID ()) {
			
			//
			//	Vehicles from Combat Lib
			//
			case CLASSID_GAME_OBJECT_DEF_VEHICLE:
			{
				VehicleGameObjDef *vehicle_def = (VehicleGameObjDef *)m_Definition;
				list = vehicle_def->Get_Transition_List ();
			}
			break;

			case CLASSID_GAME_OBJECT_DEF_TRANSITION:
			{
				TransitionGameObjDef *trans_def = (TransitionGameObjDef *)m_Definition;
				list = trans_def->Get_Transition_List ();
			}
			break;
		}
	}

	return list;
}


///////////////////////////////////////////////////////////////////////
//
//	Build_Zone_List
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Build_Zone_List (DefinitionClass *definition, ZONE_PARAM_LIST &zone_list) const
{
	if (definition == NULL) {
		definition = m_Definition;
	}

	if (definition != NULL) {

		//
		//	Loop over all the parameters
		//
		int count = definition->Get_Parameter_Count ();
		for (int index = 0; index < count; index ++) {
			ParameterClass *parameter = definition->Lock_Parameter (index);

			//
			//	If this is a zone parameter, then add it to the list
			//
			if (parameter->Get_Type () == ParameterClass::TYPE_ZONE) {
				ZoneParameterClass *zone_param = (ZoneParameterClass *)parameter;
				zone_list.Add (zone_param);
			} else if (parameter->Get_Type () == ParameterClass::TYPE_MODELDEFINITIONID) {
				
				//
				//	Recurse into the physics definition (if necessary)
				//
				int def_id = ((ModelDefParameterClass *)parameter)->Get_Value ();
				DefinitionClass *model_def= DefinitionMgrClass::Find_Definition (def_id, false);
				if (model_def !=  NULL) {
					Build_Zone_List (model_def, zone_list);
				}
			}

			definition->Unlock_Parameter (index);
		}
	}

	return ;
}



///////////////////////////////////////////////////////////////////////
//
//	Add_Files_To_VSS
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Add_Files_To_VSS (void)
{
	if (::Get_File_Mgr ()->Is_VSS_Read_Only () == false) {
		HWND hdlg = Show_VSS_Update_Dialog (::AfxGetMainWnd ()->m_hWnd);

		//
		//	Build a list of dependencies
		//
		STRING_LIST dependencies;
		Get_All_Dependencies (dependencies);

		//
		//	Loop over all the files and add them to VSS
		//	
		for (int index = 0; index < dependencies.Count (); index ++) {
			CString filename		= dependencies[index];
			CString full_path		= ::Get_File_Mgr ()->Make_Full_Path (filename);		
			::Get_File_Mgr ()->Add_Files_To_Database (full_path);
		}

		::Kill_VSS_Update_Dialog (hdlg);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////
//
//	Is_Valid_Sound_Preset
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Is_Valid_Sound_Preset (void)
{
	bool retval = false;
	
	//
	//	First off, is this a sound preset at all?
	//
	if (	m_Definition != NULL &&
			m_Definition->Get_Class_ID () == CLASSID_SOUND)
	{		
		AudibleSoundDefinitionClass *definition = (AudibleSoundDefinitionClass *)m_Definition;

		//
		//	Does this preset point to a file?
		//
		CString filename = definition->Get_Filename ();
		DWORD file_attrs = ::GetFileAttributes (definition->Get_Filename ());
		if (	filename.GetLength () > 0 && 
				(file_attrs == 0xFFFFFFFF ||
				 file_attrs != FILE_ATTRIBUTE_DIRECTORY))
		{
			retval = true;
		}
	}

	return retval;
}


///////////////////////////////////////////////////////////////////////
//
//	Is_A_Parent
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Is_A_Parent (PresetClass *preset)
{
	bool retval = false;

	//
	//	Look over all the parents
	//
	for (	PresetClass *parent = this;
			parent != NULL && !retval;
			parent = parent->Get_Parent ())
	{
		retval = (parent == preset);
	}

	return retval;
}


///////////////////////////////////////////////////////////////////////
//
//	Is_A_Parent
//
///////////////////////////////////////////////////////////////////////
bool
PresetClass::Is_A_Parent (LPCTSTR parent_name)
{
	bool retval = false;

	//
	//	Look over all the parents
	//
	for (	PresetClass *parent = this;
			parent != NULL && !retval;
			parent = parent->Get_Parent ())
	{
		retval = (::lstrcmpi (parent->Get_Name (), parent_name) == 0);
	}

	return retval;
}


///////////////////////////////////////////////////////////////////////
//
//	Get_Icon_Index
//
///////////////////////////////////////////////////////////////////////
int
PresetClass::Get_Icon_Index (void) const
{
	int index = 0;

	//
	//	What type is it?
	//
	uint32 class_id = m_Definition->Get_Class_ID ();
	switch (::SuperClassID_From_ClassID (class_id))
	{			
		case CLASSID_TERRAIN:
			index = TERRAIN_ICON;
			break;

		case CLASSID_TILE:
			index = TILE_ICON;
			break;

		case CLASSID_MUNITIONS:
		case CLASSID_DUMMY_OBJECTS:
		case CLASSID_GAME_OBJECTS:
			index = OBJECT_ICON;
			break;

		case CLASSID_LIGHT:
			index = LIGHT_ICON;
			break;

		case CLASSID_SOUND:
			index = SOUND_ICON;
			break;

		case CLASSID_WAYPATH:
			index = WAYPATH_ICON;
			break;

		case CLASSID_ZONE:
			index = ZONE_ICON;
			break;

		case CLASSID_TRANSITION:
			index = TRANSITION_ICON;
			break;

		case CLASSID_BUILDINGS:
			index = BUILDING_ICON;
			break;

		case CLASSID_TWIDDLERS:
			index = RAND_ICON;
			break;

		default:
			if (class_id == CLASSID_VIS_POINT_DEF) {
				index = VIS_ICON;
			} else if (class_id == CLASSID_PATHFIND_START_DEF) {
				index = PATHFIND_ICON;
			} else if (class_id == CLASSID_COVERSPOT) {
				index = OBJECT_ICON;
			}
			break;
	}

	return index;
}


///////////////////////////////////////////////////////////////////////
//
//	Collect_Definitions
//
///////////////////////////////////////////////////////////////////////
void
PresetClass::Collect_Definitions (DEFINITION_LIST &list)
{
	if (m_Definition != NULL) {
		list.Add (m_Definition);
		
		//
		//	Get the physics definition that this definition embeds (if any)
		//
		::Build_Embedded_Definition_List (list, m_Definition);
	}

	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Is_Soldier_Preset
//
////////////////////////////////////////////////////////////////////
bool
PresetClass::Is_Soldier_Preset (void)
{
	bool is_soldier = false;
	if (m_Definition != NULL) {
		is_soldier = (m_Definition->Get_Class_ID () == CLASSID_GAME_OBJECT_DEF_SOLDIER);
	}

	return is_soldier;
}


////////////////////////////////////////////////////////////////////
//
//	Build_Node_List
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Build_Node_List (NodeClass *parent_node)
{
	Free_Node_List ();

	//
	//	Build a matrix that we can use to transform each
	// node into the coordinate system of the parent node
	//
	Matrix3D parent_tm = parent_node->Get_Transform ();
	Matrix3D world_to_parent_tm;
	parent_tm.Get_Orthogonal_Inverse (world_to_parent_tm);

	//
	//	Loop over all the nodes in the scene
	//
	for (	NodeClass *node = NodeMgrClass::Get_First ();
			node != NULL;
			node = NodeMgrClass::Get_Next (node))
	{
		//
		//	Is this a node we want to bind to this preset?
		//
		if (	node != parent_node &&
				node->Is_Proxied () == false &&
				node->Get_Parent_Node () == NULL &&
				node->Get_Type () != NODE_TYPE_WAYPOINT)
		{			
			//
			//	Make a copy of the node
			//
			NodeClass *new_node = node->Clone ();
			if (new_node != NULL) {

				//
				//	Transform the new node into the coordinate system
				// of the parent node
				//
				Matrix3D curr_tm	= node->Get_Transform ();
				Matrix3D rel_tm	= world_to_parent_tm * curr_tm;
				new_node->Set_Transform (rel_tm);
				new_node->Set_Needs_Save (false);
				new_node->Set_Container_Preset_ID (Get_ID ());

				//
				//	Add this node to our list
				//
				m_NodeList.Add (new_node);
			}
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Free_Node_List
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Free_Node_List (void)
{
	for (int index = 0; index < m_NodeList.Count (); index ++) {
		REF_PTR_RELEASE (m_NodeList[index]);
	}

	m_NodeList.Delete_All ();
	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Create_Linked_Nodes
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Create_Linked_Nodes (NodeClass *parent_node)
{
	//
	//	Build a matrix that we can use to transform each
	// node into the coordinate system of the parent node
	//
	Matrix3D parent_tm = parent_node->Get_Transform ();

	for (int index = 0; index < m_NodeList.Count (); index ++) {
		
		//
		//	Clone this node via the scene so it will get installed into
		// all the appropriate systems
		//
		NodeClass *new_node = ::Get_Scene_Editor ()->Clone_Node (m_NodeList[index]);

		//
		//	Transform the node into world space
		//
		Matrix3D rel_tm	= m_NodeList[index]->Get_Transform ();
		Matrix3D new_tm	= parent_tm * rel_tm;
		new_node->Set_Transform (new_tm);
		new_node->Lock (true);
		new_node->Set_Is_Proxied (true);
		new_node->Set_Needs_Save (false);
		new_node->Set_Container_Preset_ID (Get_ID ());

		//
		//	Release our hold on the node
		//
		REF_PTR_RELEASE (new_node);
	}

	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Get_Child_Preset
//
////////////////////////////////////////////////////////////////////
PresetClass *
PresetClass::Get_Child_Preset (int index)
{
	PresetClass *retval = NULL;

	if (index >= 0 && index < m_ChildIDList.Count ()) {
		retval = PresetMgrClass::Find_Preset (m_ChildIDList[index]);
	}

	return retval;
}


////////////////////////////////////////////////////////////////////
//
//	Set_Definition
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Set_Definition (DefinitionClass *definition)
{
	if (m_Definition != NULL) {
		m_Definition->Set_User_Data (NULL);
	}

	m_Definition		= definition;
	m_DefinitionID		= 0;

	//
	//	Store our "this" pointer in the definition so we can
	// quickly find the preset given its definition
	//
	if (m_Definition != NULL) {
		m_Definition->Set_User_Data ((uint32)this);
		m_DefinitionID = m_Definition->Get_ID ();
	}

	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Add_Child_Preset
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Add_Child_Preset (int child_id)
{
	//
	//	Don't allow ourselves to become recursively linked
	//
	if (child_id == (int)Get_ID ()) {
		return ;
	}

	//
	//	Make sure the child isn't already in our list
	//
	int index = m_ChildIDList.ID (child_id);
	WWASSERT (index == -1);

	//
	//	Add the child to the list
	//
	if (index == -1) {
		m_ChildIDList.Add (child_id);
	}

	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Remove_Child_Preset
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Remove_Child_Preset (int child_id)
{
	int index = m_ChildIDList.ID (child_id);
	if (index != -1) {
		m_ChildIDList.Delete (index);
	}
		
	return ;
}


////////////////////////////////////////////////////////////////////
//
//	Set_Parent
//
////////////////////////////////////////////////////////////////////
void
PresetClass::Set_Parent (PresetClass *parent)
{
	//
	//	If changing parents, unlink ourselves from our old parent
	//
	if (m_Parent != NULL) {
		m_Parent->Remove_Child_Preset (Get_ID ());
	}

	m_Parent = parent;

	//
	//	Cache the parent's ID
	//
	if (m_Parent != NULL) {
		m_ParentID = m_Parent->Get_ID ();
	} else {
		m_ParentID = 0;
	}
	
	return ;
}
