// ObjectManager.cpp: implementation of the ObjectManager class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MW4GameEd2.h"
#include "ObjectManager.h"
#include "EdGUIObject.h"
#include "ObjCreateInfo.h"
#include "NVGameObject.h"
#include "GUICamera.h"
#include "GUIDropZone.h"
#include "GUILattice.h"
#include "EdObjective.h"
#include "ObjPanelDlg.h"
#include "MissionPropsPanel.h"
#include "FogPropertiesPanel.h"
#include "FogColorProps.h"
#include "GameTypesPanel.h"
#include "ObjectiveListDlg.h"
#include "ObjProps.h"
#include "GUILight.h"
#include "GUIFXGenerator.h"
#include <GameOS\ToolOS.hpp>
#include <Stuff\Stuff.hpp>
#include <direct.h>

#include "CameraController.h"
#include"UndoManager.h"

#define GetTme() (GetTickCount()/1000.0)

const char *ObjectManager::MPGameTypeNames[] =	
{ 
	"SinglePlayer",		
		
		"Destruction",		
		"TeamDestruction",	
		"Attrition",			
		"TeamAttrition",	
		"CaptureTheFlag",	
		"KingOfTheHill",		
		"TeamKingOfTheHill",	
		"StealTheBacon",		
		"CaptureBase"	,	
		"Escort",
		"MasterTrial",
		"SiegeAssault",
		
		"CustomDestruction"	,	
		"CustomTeamDestruction"	,
		"CustomAttrition"	,		
		"CustomTeamAttrition",		
		"CustomCaptureTheFlag"	,
		"CustomKingOfTheHill",		
		"CustomTeamKingOfTheHill" ,
		"CustomTerritories"	,	
		"CustomStealTheBacon",		
		"CustomCaptureBase"	,	
		"CustomDestroyObjective",	
		"CustomEscort"	,		
		"CustomMasterTrial",
		"CustomSiegeAssault",
		"CustomCampaign",
		"CustomUndefined"			
		
};


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ObjectManager::ObjectManager():GUIObjectList("Map")
, m_CameraController(0)
{
	MapLoaded=false;
	Modified=false;
	DefaultAlignment=0;
	SourceMission="";
	
	SetName(CString("Map"));
	AddInfo=NULL;
	MissionBound=NULL;
	WarningBound=NULL;
	Lattice=NULL;
	UndoMan=NULL;
	LLight=NULL;
	MakeBounds();
	TagFlags=TAG_NAME;
	MapSize=Point3D(100,0,100);
	m_CameraController = new CameraController(*this);
	
	
	TerrainTexture.CreateSolid(10,10,ImgRGBColor(128,128,128),ITYPE_RGB,24);
	HField.CreateSolid(10,10,ImgRGBColor(0,0,128),ITYPE_RGB,24);
	SlopeMap.CreateSolid(10,10,ImgRGBColor(128,0,0),ITYPE_RGB,24);
}

void ObjectManager::DeleteAllObjects()
{
	GUIObjectList::DeleteAllObjects();
	MissionBound=NULL;
	WarningBound=NULL;
	Lattice=NULL;
	LLight=NULL;
	MakeBounds();
}

void ObjectManager::MakeBounds()
{
	Verify(MissionBound==NULL);
	Verify(WarningBound==NULL);
	MissionBound=new GUIBound("Mission Bounds");
	WarningBound=new GUIBound("Warning Bounds");
	AddObject(MissionBound);
	AddObject(WarningBound);
}

ObjectManager::~ObjectManager()
{
	while(GetObjectCount()>3)	//need to leave the boundsand lattice
		DeleteObject(0);
	
	if(UndoMan) {delete UndoMan; UndoMan=NULL;}
	
	if (m_CameraController != 0)
	{
		delete m_CameraController;
		m_CameraController = 0;
	}
}

void ObjectManager::DeleteObject(int i)
{
	Verify(i<GetObjectCount());
	if(GetObject(i)==MissionBound ||  
		GetObject(i)==WarningBound ||
		GetObject(i)==Lattice ||
		GetObject(i)==LLight 
		) return;
	
	GUIObjectList::DeleteObject(i);
}


void ObjectManager::ClearSelection()
{
	
	int i;
	EdGUIObject *gobj;
	EdGUIObject::DeSelect();
	for(i=0;i<GetObjectCount();i++)
	{
		gobj=GetObject(i);
		gobj->DeSelect();
	}
	
}


bool ObjectManager::CutSelection()
{
	if(!CopySelection()) return false;
	DeleteSelection();
	return true;
}

bool ObjectManager::CopySelection()
{
	ClipBoard.DeleteAllObjects();
	Point3D low,high;
	GetSelectionExtents(&low,&high);
	CopyPos.x=low.x+(high.x-low.x)*0.5f;
	CopyPos.z=low.z+(high.z-low.z)*0.5f;
	CopyPos.y=0.0f;
	try
	{
		
		CopySelectionToList(&ClipBoard);
	}
	catch(...)
	{
		ClipBoard.DeleteAllObjects();
		return false;
	}
	return true;
}

void ObjectManager::PasteClipBoardAt(Point3D pos)
{
	if(ClipBoard.GetObjectCount()<=0) return;
	Point3D offset;
	offset.x=pos.x-CopyPos.x;
	offset.y=0.0f;
	offset.z=pos.z-CopyPos.z;
	PasteClipBoard(offset);
}

void ObjectManager::PasteClipBoard(Point3D offset)
{
	if(ClipBoard.GetObjectCount()<=0) return;
	int i;
	EdGUIObject *gobj;
	Modify();
	
	AddCommand *addcom=NULL;
	ClearSelection();
	for(i=0;i<ClipBoard.GetObjectCount();i++)
	{
		gobj=ClipBoard.GetObject(i)->Clone();
		gobj->Select();
		AddObject(gobj);
		if(!addcom) addcom=new AddCommand(gobj);
		else
			addcom->Attach(new AddCommand(gobj));
	}
	Verify(addcom!=NULL);
	UndoMan->AddCommand(addcom);	
	SPEW(("tsteinke","Offset Paste relative to Viewwindow, but safely"));
	OffsetSelection(offset);
	if(ClipBoard.GetObjectCount()>0) Modify();	
}


EdGUIObject *ObjectManager::AddNode(Point3D &pnt,DWORD *show_flag,bool insert)
{
	EdGUIObject *ret;
	if((ret=AddNodeIfSelected(pnt,insert))==NULL)
	{
		GUIPath *path;
		path=new GUIPath(CString("Path"));
		AddObject(path);
		path->AddNodeAtEnd(pnt);
		*show_flag|=SHOW_PATHS;
		ret=path;
	}
	
	return ret;	
}


EdGUIObject *ObjectManager::AddGameObject(ObjCreateInfo *inf,EdGameObject *gmeobj,DWORD *show_flag,Point3D &pnt)
{
	CString base_name=inf->Path;
	base_name=base_name.Left(base_name.ReverseFind('.'));
	base_name=base_name.Mid(base_name.ReverseFind('\\')+1);
	
	gmeobj->SetPos(pnt);
	gmeobj->SetSnapToGround(true);
	gmeobj->BuildFrom(inf->Path,base_name);
	gmeobj->SetAlignment(DefaultAlignment);
	AddObject(gmeobj);
	gmeobj->MakeVisible(show_flag);
	return gmeobj;
}

void ObjectManager::SetObjectName(EdGUIObject *gobj,CString &name)
{
	if(gobj==MissionBound ||  
		gobj==WarningBound ||
		gobj==Lattice ||
		gobj==LLight ) return;
	
	
	Verify(InTree(gobj));
	UndoMan->AddCommand(new RenameCommand(gobj));
	gobj->SetName(name);
	
}

EdGUIObject *ObjectManager::AddAt(ObjCreateInfo *inf,AddCommand **com,DWORD *show_flag,bool flag,Point3D pnt,YawPitchRoll rot)
{
	Verify(IsLoaded());
	if(inf==NULL) return NULL;
	
	Modify();
	
	EdGUIObject *gobj=NULL;
	switch(inf->CreateType)
	{
	case ObjCreateInfo::OT_GAMEOBJ:
		gobj=AddGameObject(inf,new EdGameObject(),show_flag,pnt);
		break;
	case ObjCreateInfo::OT_NVGAMEOBJ:
		gobj=AddGameObject(inf,new NVGameObject(),show_flag,pnt);
		break;
	case ObjCreateInfo::OT_NODE:
		gobj=AddNode(pnt,show_flag,flag);
		break;
	case ObjCreateInfo::OT_DROPZONE:
		gobj=AddDropZone(pnt);
		*show_flag|=SHOW_DROPZONES;
		break;
	case ObjCreateInfo::OT_CAMERA:
		gobj=AddCamera(pnt);
		*show_flag|=SHOW_CAMERASHIPS;
		break;
	case ObjCreateInfo::OT_LIGHT:
		gobj=AddLight(inf->SubType,pnt);
		*show_flag|=SHOW_LIGHTS;
		break;
	case ObjCreateInfo::OT_FX:
		gobj=AddFX(pnt);
		*show_flag|=SHOW_FX;
		break;
	case ObjCreateInfo::OT_CLIPBOARD:
		PasteClipBoardAt(pnt);
		break;
	}
	
	if(gobj!=NULL)
	{
		UnitQuaternion quatrot;
		quatrot=rot;
		gobj->SetRot(quatrot);
		if(*com==NULL)
		{
			*com=new AddCommand(gobj);
		}
		else
		{
			(*com)->Attach(new AddCommand(gobj));
		}
	}
	
	
	return gobj;
}

EdGUIObject *ObjectManager::AddAt(AddCommand **com,DWORD *show_flag,bool flag,Point3D pnt,YawPitchRoll rot)
{
	return AddAt(AddInfo,com,show_flag,flag,pnt,rot);
}



bool ObjectManager::AddAt(Point3D &pnt,DWORD *show_flag,bool flag)
{
	if(!IsLoaded()) return true;
	Modify();
	AddCommand *com=NULL;
	EdGUIObject *gobj;
	
	try
	{
		gobj=AddAt(&com,show_flag,flag,pnt);
	}
	catch(...)
	{
		return false;
	}
	
	if(gobj) UndoMan->AddCommand(com);
	return true;
}

EdGUIObject *ObjectManager::AddLight(int subt,Point3D &pnt)
{
	GUILight *lgt=NULL;
	
	switch(subt)
	{
	case ObjCreateInfo::LST_POINT:
		lgt=new GUIPointLight("Point_Light",pnt);
		break;
	case ObjCreateInfo::LST_SPOT:
		lgt=new GUISpotLight("Spot_Light",pnt);
		break;
	case ObjCreateInfo::LST_INFINITE:
		lgt=new GUIInfiniteLight("Infinite_Light");
		break;
	case ObjCreateInfo::LST_AMBIENT:
		lgt=new GUIAmbientLight("Ambient_Light");
		break;
	default:
		STOP(("Invalid Light Type"));
	}
	lgt->Build();
	AddObject(lgt);
	return lgt;
}

EdGUIObject *ObjectManager::AddCamera(Point3D &pnt)
{
	GUICamera *cam=new GUICamera(CString("CameraShip"),pnt);
	AddObject(cam);
	return cam;
}

EdGUIObject *ObjectManager::AddFX(Point3D &pnt)
{
	GUIFXGenerator *fx=new GUIFXGenerator(CString("Effect"),pnt);
	AddObject(fx);
	return fx;
}


EdGUIObject *ObjectManager::AddDropZone(Point3D &pnt)
{
	GUIDropZone *obj=new GUIDropZone("DropZone",pnt);
	AddObject(obj);
	return obj;
}

void ObjectManager::SetProperties(Point3D &pnt,CWnd *parent)
{
	
	EdGUIObject *gobj;
	gobj=GetObjAtPoint(pnt);
	
	SetProperties(gobj,parent);
}

void ObjectManager::SetProperties(EdGUIObject *gobj,CWnd *parent)
{
	if(gobj!=NULL && IsLoaded())
	{
		CObjPanelDlg pan_dlg(parent);
		UndoCommand *com=NULL;
		gobj->AddPanel(&pan_dlg,&com);
		
		pan_dlg.DoModal();
		OffsetSelection(Point3D(0.0f,0.0f,0.0f)); // This will make Paths and Drop Nodes Sync up.
		
		if(com!=NULL)
			UndoMan->AddCommand(com);
		
	}
	
}

void ObjectManager::SetPropertiesOfSelected(CWnd *parent)
{
	int selcount=SelectionCount();	
	if(selcount>0)
	{
		UndoCommand *com=NULL;
		
		if(selcount==1)
		{
			SetProperties(FindFirstSelected(),parent);
		}
		else
		{
			CObjPanelDlg pan_dlg(parent);
			CObjProps mprops;
			GetMultiPropsIfSelected(&mprops);
			mprops.AddPanel(&pan_dlg);
			
			
			if(pan_dlg.DoModal()==IDOK)
			{
				SetMultiPropsIfSelected(&mprops,&com);
			}
		}
		
		
		if(com!=NULL)
			UndoMan->AddCommand(com);
		
	}
	
}

void ObjectManager::SaveTextInfo(NotationFile *not_file)
{
	SortChildren();
	GUIObjectList::SaveTextInfo(not_file);
	
}


void ObjectManager::LoadTextInfo()
{
	SortChildren();
	CString mis_name=GetName();
	
	NotationFile not_file((LPCSTR)("Content\\Missions\\"+GetName()+"\\"+GetName()+".ini"));	
	Page *mis_page=not_file.FindPage((LPCSTR)mis_name);
	if(!mis_page) return;
	DefaultExtraData();
	BuildGroup(this,mis_page);
	LoadNFOFile();
}

void ObjectManager::BuildGroup(GUIObjectList *new_list,Page *group_page)
{
	NotationFile mem_file;
	group_page->GetEntry("Members",&mem_file);
	
	NotationFile ::PageIterator *member_list=mem_file.MakePageIterator();
	Check_Object(member_list);
	
	Page		*member_page;
	member_list->First();
	
	while((member_page=member_list->ReadAndNext())!=NULL)
	{
		Check_Object(member_page);
		const char *tmpstr;
		member_page->GetEntry("Type",&tmpstr);
		CString type(tmpstr);
		CString member_name(member_page->GetName()); 
		
		if(!type.CompareNoCase("Group"))
		{
			GUIObjectList *next_list=new GUIObjectList;
			next_list->SetName(member_name);
			AddObject(next_list);
			BuildGroup(next_list,member_page);
		}
		else
		{
			
			int idx=FindObjectIdxByName(member_name);
			if(idx!=-1)
			{
				EdGUIObject *gobj=GetObject(idx);
				gobj->SetInfo(member_page);
				if(new_list!=this)
				{
					RemoveObject(gobj);
					new_list->AddObject(gobj);
				}
			}
		}
		
	}
	
	
}


void ObjectManager::Draw(DrawInfo &dinf)
{
	
	for(int i=0;i<GetObjectCount();i++)
		GetObject(i)->Draw(dinf);
	
	
}


void ObjectManager::DrawTag(DrawInfo &dinf, unsigned long tag_flags)
{
	for(int i=0;i<GetObjectCount();i++)
		GetObject(i)->DrawTag(dinf,tag_flags);
}

void ObjectManager::UnGroupSelected()
{
	if(!IsLoaded()) return;
	UndoCommand *cmd=NULL;
	GUIObjectList::UnGroupSelected(&cmd);
	
	RemoveObject(MissionBound);
	RemoveObject(WarningBound);
	RemoveObject(Lattice);
	RemoveObject(LLight);
	
	PruneEmpty(&cmd);
	
	AddObject(MissionBound);
	AddObject(WarningBound);
	AddObject(Lattice);
	AddObject(LLight);
	
	if(cmd) UndoMan->AddCommand(cmd);	
}

int ObjectManager::GroupSelected()
{
	if(!IsLoaded()) return true;
	
	int ret;
	UndoCommand *cmd=NULL;
	
	RemoveObject(MissionBound);
	RemoveObject(WarningBound);
	RemoveObject(Lattice);
	RemoveObject(LLight);
	
	ret=GUIObjectList::GroupSelected(&cmd);
	
	AddObject(MissionBound);
	AddObject(WarningBound);
	AddObject(Lattice);
	AddObject(LLight);
	
	if(cmd) UndoMan->AddCommand(cmd);	
	return ret;
}

bool ObjectManager::CanOffsetSelection(Point3D &vect)
{
	Point3D tl,br,msze;
	GetSelectionExtents(&tl,&br);
	if((vect.x+br.x)>=(MapSize.x*0.5f) || 
		(vect.z+br.z)>=(MapSize.z*0.5f) || 
		(vect.x+tl.x)<(-MapSize.x*0.5f) || 
		(vect.z+tl.z)<(-MapSize.z*0.5f)) 
		return false;
	return true;
}

void ObjectManager::CreateLattice()
{
	if(!IsLoaded()) return;
	Verify(Lattice!=NULL);
	Lattice->CreateLattice((int)(MapSize.x*MapSize.z)/60000);
}

void ObjectManager::RecalcLatticeLinks()
{
	if(!IsLoaded()) return;
	Verify(Lattice!=NULL);
	Lattice->CalcLinksOnSelected();
}

void ObjectManager::ResetBounds()
{
	
	WarningBound->ResetTo(Point3D((-MapSize.x*0.5f)+(MapSize.x/10),0.0f,(-MapSize.z*0.5f)+(MapSize.z/10)),
		Point3D((MapSize.x*0.5f)-(MapSize.x/10),0.0f,(MapSize.z*0.5f)-(MapSize.z/10)));
	MissionBound->ResetTo(Point3D((-MapSize.x*0.5f)+(MapSize.x/15),0.0f,(-MapSize.z*0.5f)+(MapSize.z/15)),
		Point3D((MapSize.x*0.5f)-(MapSize.x/15),0.0f,(MapSize.z*0.5f)-(MapSize.z/15)));
	
}

void ObjectManager::CheckAlternativeScripts()
{
	for(int i=0;i<GT_TOTALGAMES;i++)
	{
		if(MPGames[i].Supported)
		{
			for(int j=0;j<MPGames[i].ScriptTotal;j++)
			{
				CheckAlternativeScript(MPGames[i].ScriptPaths[j]);
			}
		}
	}
}

void ObjectManager::CheckAlternativeScript(CString sname)
{
	if(sname=="") return;
	
	char errMessage[500];
	CString errstr;
	CString filename;
	CString cmdline,line;

	CString spath="Content\\Missions\\"+GetName()+"\\scripts\\"+sname+".abl";
	ABL::ABLError error;
	long missionScriptHandle = ABL::ABLi_preProcess((char *)(LPCSTR)spath, &error,NULL,NULL);
	if (missionScriptHandle < 0)
	{
		sprintf(errMessage, "SYNTAX ERROR %s [line %d] - (type %d) %s\n", error.File (), error.Line (),error.Code (), error.String ());
		
		MessageBox(NULL,errMessage,"ABL Error",MB_OK);
		
		filename = error.File ();
		
		//		cmdline = "c:\\vslick\\win\\vs ";
		cmdline = "vs ";
		cmdline += "\"";
		_getcwd(errMessage,500);
		if (filename[1] != ':')
		{
			cmdline += errMessage;
			cmdline += "\\";
		}
		cmdline += filename;
		cmdline += "\"";
		cmdline += " -#";
		itoa (error.Line(),errMessage,10);
		cmdline += errMessage;	
		
		//		system ((LPCTSTR) cmdline);
		if (WinExec((LPCTSTR) cmdline,SW_SHOW) <= 31)			// old function but it works
			MessageBox (NULL,"Unable to start SlickEdit.  Make sure it's in your path","Error",MB_OK);
		//		CreateProcess (NULL,cmdline,NULL,NULL,FALSE,0,NULL,NULL,NULL,NULL);
		return;
	}
	
	
}

void ObjectManager::SaveToReg()
{
	int tdat;
	CRect rct;
	CString name="ObjectMan";
	
	tdat=GetDefaultAlignment();	gos_SaveDataToRegistry((char *)(LPCSTR)(name+"DefaultAlignment"),&tdat,sizeof(tdat));
	gos_SaveDataToRegistry((char *)(LPCSTR)(name+"Tags"),&TagFlags,sizeof(TagFlags));
	m_CameraController->SaveToReg();
	
	//	bool res=GetCameraController()->GetAnimatedCamera();
	//	gos_SaveDataToRegistry((char *)(LPCSTR)(name+"Animated Camera"),&res,sizeof(res));
}

void ObjectManager::LoadFromReg()
{
	int tdat;
	unsigned long size;
	CRect rct;
	CString name="ObjectMan";
	
	size=sizeof(tdat);
	gos_LoadDataFromRegistry((char *)(LPCSTR)(name+"DefaultAlignment"),&tdat,&size);
	if(size) SetDefaultAlignment(tdat);
	
	size=sizeof(TagFlags);
	gos_LoadDataFromRegistry((char *)(LPCSTR)(name+"Tags"),&TagFlags,&size);
	
	m_CameraController->LoadFromReg();
	//	size = sizeof(m_AnimatedCamera);
	//	gos_LoadDataFromRegistry((char *)(LPCSTR)(name+"Animated Camera"),&m_AnimatedCamera,&size);
}



Stuff::Point3D ObjectManager::GetMapSize() const
{
	return (MapSize);
}

void ObjectManager::ResetCamera()
{
	if (m_CameraController != 0)
	{
		m_CameraController->Reset();
	}
}


void ObjectManager::RotateSelection( UnitQuaternion &pnt)
{
	GUIObjectList::RotateSelection(pnt);
}

void ObjectManager::OffsetSelection(Point3D &vct)
{
	if(CanOffsetSelection(vct))
	{
		GUIObjectList::OffsetSelection(vct);
	}
}

void ObjectManager::SavePosForUndo()
{
	UndoCommand *com=NULL;
	SavePosIfSelected(&com);
	SaveRotIfSelected(&com);
	if(com!=NULL) 	UndoMan->AddCommand(com);
	
}



bool ObjectManager::CanUndo()
{
	if(UndoMan==NULL) return false;
	return UndoMan->CanUndo();
}


bool ObjectManager::CanRedo()
{
	if(UndoMan==NULL) return false;
	return UndoMan->CanRedo();
}

void ObjectManager::Undo()  { if(UndoMan->CanUndo()) {UndoMan->Undo(); SyncData();} }
void ObjectManager::Redo()  { if(UndoMan->CanRedo()) {UndoMan->Redo(); SyncData();} }

void ObjectManager::DeleteSelection() 
{
	UndoCommand *cmd=NULL;
	DeleteSelected(&cmd);
	if(cmd!=NULL)
		UndoMan->AddCommand(cmd);
}


void ObjectManager::AddPanel(CObjPanelDlg *pnl,UndoCommand **cmd)
{
	GUIObjectList::AddPanel(pnl,cmd);
	pnl->AddPanel((CPanelDlg *)new CMissionPropsPanel(this,cmd,pnl));
	pnl->AddPanel((CPanelDlg *)new CFogColorProps(this,cmd,pnl));
	pnl->AddPanel((CPanelDlg *)new CFogPropertiesPanel(this,cmd,pnl));
	pnl->NameOverride="Mission Properties";
}


void ObjectManager::EditObjectives(CWnd *parent)
{
	UndoCommand *com=NULL;
	CObjectiveListDlg dlg(this,&com,parent);
	dlg.DoModal();
	if(com!=NULL)
		UndoMan->AddCommand(com);
	
}

void ObjectManager::SaveUndoCommand(UndoCommand *cmd)
{
	UndoMan->AddCommand(cmd);
}

void ObjectManager::AddObjective()
{
	if(!IsLoaded()) return;
	
	ObjectiveList.AddObject(new EdObjective("NewObjective"));
}

void ObjectManager::LoadNFOFile()
{
	int i;
	
	for(i=0;i<GT_TOTALGAMES;i++) 
	{
		MPGames[i].Alignment=MPGames[i].Team=1;
		MPGames[i].Supported=false;
	}
	
	
	CString nfo_fname="Resource\\UserMissions\\"+GetName()+".nfo";
	if(! gos_DoesFileExist(nfo_fname)) 
	{
		MPGames[GT_SinglePlayer].Supported=true;
		return;
	}
	
	NotationFile nfo_file(nfo_fname);
	Page *page=nfo_file.FindPage("ruleset");
	
	int idx=0;
	
	if(page)
	{
		Page::NoteIterator *ruleset_notes = page->MakeNoteIterator();
		Check_Object(ruleset_notes);
		Note *ruleset_note;
		while ((ruleset_note = ruleset_notes->ReadAndNext()) != NULL)
		{
			if(!strcmpi(ruleset_note->GetName(),"type"))
			{
				int type;
				ruleset_note->GetEntry(&type);
				idx=GTTypeToEnum(type);
				MPGames[idx].Supported=true;
				MPGames[idx].ScriptTotal=0;
			}
			else if(!strcmpi(ruleset_note->GetName(),"team"))
			{
				ruleset_note->GetEntry(&MPGames[idx].Team);
			}
			else if(!strcmpi(ruleset_note->GetName(),"Alignment"))
			{
				ruleset_note->GetEntry(&MPGames[idx].Alignment);
			}
			else if(!strcmpi(ruleset_note->GetName(),"ScriptName"))
			{
				const char *tcc;
				CString tpath;
				ruleset_note->GetEntry(&tcc);
				tpath=tcc;
				tpath=tpath.Left(tpath.GetLength()-4);
				tpath=tpath.Mid(tpath.ReverseFind('\\')+1);
				MPGames[idx].ScriptPaths[MPGames[idx].ScriptTotal++]=tpath;
			}
			
		}
	}
	
	
}


void ObjectManager::CreateNFOFile()
{
	CString nfo_fname="Resource\\UserMissions\\"+GetName()+".nfo";
	NotationFile nfo_file(nfo_fname, NotationFile::Raw, true);
	Page *page=nfo_file.SetPage("");
	page->SetEntry("!include","Content\\GameTypes.h");
	page->SetEntry("!preservecase","true");
	
	page=nfo_file.SetPage("info");
	
	page->SetEntry("author","YourNameHere");
	page->SetEntry("info","Standard Mission");
	page->SetEntry("link","www.yourwebsite.com");
	page->SetEntry("longname",GetName());
	nfo_file.Save();
}

void ObjectManager::UpdateNFOFile()
{
	CString nfo_fname="Resource\\UserMissions\\"+GetName()+".nfo";
	if(! gos_DoesFileExist(nfo_fname)) CreateNFOFile();
	
	
	NotationFile nfo_file(nfo_fname);
	
	Page *page=nfo_file.SetPage("ruleset");
	page->DeleteAllNotes();
	
	Stuff::Page *bang_page = nfo_file.SetPage("");
	bang_page->AppendEntry("!include", "Content\\GameTypes.h");
	bang_page->AppendEntry("!preservecase", "true");
	
	Stuff::Page *sc_page = nfo_file.SetPage("scenarios");
	
	for(int i=0;i<GT_TOTALGAMES;i++) 
	{
		CString type="$("+GTEnumToType((MPGameTypes)i)+")";
		
		if(MPGames[i].Supported)
		{
			page->AddNote("type")->SetEntry(type);
			page->AddNote("Teams")->SetEntry(MPGames[i].Team);
			page->AddNote("Alignment")->SetEntry(MPGames[i].Alignment);
			for(int sidx=0;sidx<MPGames[i].ScriptTotal;sidx++)
			{
				page->AddNote("scriptname")->SetEntry("Content\\Missions\\"+GetName()+"\\Scripts\\"+MPGames[i].ScriptPaths[sidx]+".abl");
				
			}
			
		}
		if(MPGames[i].AddScenario && i!=GT_SinglePlayer)
		{
			
			Page::NoteIterator *notes=sc_page->MakeNoteIterator();
			Note *note;
			bool noadd=false;
			while(note=(Note *)notes->ReadAndNext())
			{
				NotationFile tfile;
				note->GetEntry(&tfile);
				Page *page=tfile.GetPage("server");
				if(page)
				{
					int itype;
					page->GetEntry("ruleset",&itype);
					if(GTTypeToEnum(itype)==i) noadd=true;
				}
			}			
			if(!noadd)
			{
				NotationFile sc;
				Page *serverpage=sc.SetPage("server");
				
				serverpage->SetEntry("name",GetName());
				serverpage->SetEntry("ruleset",type);
				
				if(IsTeamGame((MPGameTypes)i)) 
					serverpage->SetEntry("TeamAllowed",1);
				else
					serverpage->SetEntry("TeamAllowed",0);
				
				if(IsTeamGame((MPGameTypes)i)) 
					serverpage->SetEntry("TeamCount",MPGames[i].Team);
				else
					serverpage->SetEntry("TeamCount",0);
				
				if(MPGames[i].ScriptTotal>0)
					serverpage->SetEntry("ScriptName","Content\\Missions\\"+GetName()+"\\Scripts\\"+MPGames[i].ScriptPaths[0]+".abl");
					/*
					CString script_name="Content\\Missions\\"+GetName()+"\\Scripts\\"+GetName()+"_"+GTEnumToType((MPGameTypes)i)+".abl";
					CopyFile("Content\\AblScripts\\GenericScripts\\CustomTemplate.abl",script_name,NULL);
					serverpage->SetEntry("scriptname",script_name);
				*/
				
				
				CString str;
				str.Format("%s%i",GTEnumToType((MPGameTypes)i),rand());
				sc_page->SetEntry(str,&sc);
				sc.IgnoreChanges();
				
			}
			
		}	
	}
	nfo_file.Save();
}

CString ObjectManager::GTEnumToType(MPGameTypes type)
{
	
	
	
	switch(type)
	{
	case GT_SinglePlayer			:return  "SinglePlayer"			;	break;	
	case GT_StockDestruction		:return  "StockDestruction"		;	break;	
	case GT_StockTeamDestruction	:return  "StockTeamDestruction"	;	break;
	case GT_StockAttrition			:return  "StockAttrition"		;	break;			
	case GT_StockTeamAttrition		:return  "StockTeamAttrition"	;	break;		
	case GT_StockCaptureTheFlag		:return  "StockCaptureTheFlag"	;	break;		
	case GT_StockKingOfTheHill		:return  "StockKingOfTheHill"	;	break;		
	case GT_StockTeamKingOfTheHill	:return  "StockTeamKingOfTheHill";	break;	
	case GT_StockTerritories		 :return "StockTerritories"		;	break;		
	case GT_StockStealTheBacon		:return  "StockStealTheBacon"	;	break;	
	case GT_StockCaptureBase		:return  "StockCaptureBase"		;	break;
	case GT_StockDestroyObjective	 :return "StockDestroyObjective";	break;	
	case GT_StockEscort				 :return "StockEscort"			;	break;	
	case GT_StockMasterTrial		 :return "StockMasterTrial"		;	break;	
	case GT_StockSiegeAssault		 :return "StockSiegeAssault"	;	break;	
	case GT_StockCampaign			 :return "StockCampaign"		;	break;	
	case GT_CustomDestruction		 :return "CustomDestruction"	;	break;	
	case GT_CustomTeamDestruction	 :return "CustomTeamDestruction";	break;	
	case GT_CustomAttrition			 :return "CustomAttrition"		;	break;	
	case GT_CustomTeamAttrition		 :return "CustomTeamAttrition"	;	break;	
	case GT_CustomCaptureTheFlag	 :return "CustomCaptureTheFlag"	;	break;	
	case GT_CustomKingOfTheHill		 :return "CustomKingOfTheHill"	;	break;	
	case GT_CustomTeamKingOfTheHill	 :return "CustomTeamKingOfTheHill";	break; 
	case GT_CustomTerritories		 :return "CustomTerritories"	;	break;		
	case GT_CustomStealTheBacon		 :return "CustomStealTheBacon"	;	break;	
	case GT_CustomCaptureBase		 :return "CustomCaptureBase"	;	break;		
	case GT_CustomDestroyObjective	 :return "CustomDestroyObjective";	break;	
	case GT_CustomEscort			 :return "CustomEscort"			;	break;			
	case GT_CustomMasterTrial		 :return "CustomMasterTrial"	;	break;			
	case GT_CustomSiegeAssault		 :return "CustomSiegeAssault"	;	break;			
	case GT_CustomCampaign			 :return "CustomCampaign"		;	break;			
	case GT_CustomUndefined			 :return "CustomUndefined"		;	break;			  
		
	}
	
	return "CustomUndefined";
	
	
}


ObjectManager::MPGameTypes ObjectManager::GTTypeToEnum(int type)
{
	
	switch(type)
	{
	case 0: return GT_StockDestruction	;		break;	
	case 1 :return GT_StockTeamDestruction	;	break;
	case 2 :return GT_StockAttrition;			break;			
	case 3 :return GT_StockTeamAttrition;		break;		
	case 4 :return GT_StockCaptureTheFlag;		break;		
	case 5 :return GT_StockKingOfTheHill;		break;		
	case 6 :return GT_StockTeamKingOfTheHill;	break;	
	case 7 :return GT_StockTerritories		;	break;
	case 8 :return GT_StockStealTheBacon	;	break;	
	case 9 :return GT_StockCaptureBase		;	break;
	case 10 :return GT_StockDestroyObjective;	break;
	case 11 :return GT_StockEscort			;	break;	
	case 12 :return GT_StockMasterTrial;		break;			
	case 13 :return GT_StockSiegeAssault;		break;			
	case 14 :return GT_StockCampaign;			break;			
	case 15 :return GT_CustomDestruction	;	break;	
	case 16 :return GT_CustomTeamDestruction;	break;	
	case 17 :return GT_CustomAttrition		;	break;	
	case 18 :return GT_CustomTeamAttrition	;	break;	
	case 19 :return GT_CustomCaptureTheFlag;	break;	
	case 20 :return GT_CustomKingOfTheHill	;	break;	
	case 21 :return GT_CustomTeamKingOfTheHill; break; 
	case 22 :return GT_CustomTerritories;		break;		
	case 23 :return GT_CustomStealTheBacon	;	break;	
	case 24 :return GT_CustomCaptureBase;		break;		
	case 25 :return GT_CustomDestroyObjective;	break;	
	case 26 :return GT_CustomEscort;			break;			
	case 27 :return GT_CustomMasterTrial;		break;			
	case 28 :return GT_CustomSiegeAssault;		break;			
	case 29 :return GT_CustomCampaign;			break;			
	case 30 :return GT_CustomUndefined;			break;			  
	case 31 :return GT_SinglePlayer;			break;			  

	
	}
	
	return GT_TOTALGAMES;
}

bool ObjectManager::AddEssentialObjects(CString &msg)
{
	AddCommand *cmd=NULL;
	DWORD showflag;
	ObjCreateInfo inf;
	bool ret=false;
	
	CString nav_point_names[256];
	int navcount=0;
	
	CString drop_names[256];
	int drop_points[256];
	int dropcount=0;
	
	int flagstoadd=0;
	
	bool anymulti=false;
	int i;
	msg="The following changes have been made to this mission:\n";
	
	for(i=0;i<GT_TOTALGAMES && !anymulti;i++)	anymulti=MPGames[i].Supported;
	if(!anymulti) return false; //no multiplayer games supported
	
	nav_point_names[navcount++]="Nav Center";
	drop_names[dropcount]="PlayerStart"; drop_points[dropcount++]=36;
	
	if(MPGames[GT_StockDestruction].Supported || 
		MPGames[GT_StockAttrition].Supported   
		)
	{
	}
	
	if(MPGames[GT_StockTeamDestruction].Supported ||
		MPGames[GT_StockTeamAttrition].Supported   
		)
	{
		int tval=MPGames[GT_StockTeamDestruction].Team>MPGames[GT_StockTeamAttrition].Team?MPGames[GT_StockTeamDestruction].Team:MPGames[GT_StockTeamAttrition].Team;
		for(int tidx=1;tidx<=tval;tidx++)
		{
			CString str;
			str.Format("Team %i Drop Zone",tidx);
			nav_point_names[navcount++]=str;
			str.Format("DropTeam%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=18;
		}
	}
	
	if(MPGames[GT_StockMasterTrial].Supported)
	{
		for(int tidx=1;tidx<=MPGames[GT_StockMasterTrial].Team;tidx++)
		{
			CString str;
			str.Format("Team %i Drop Zone",tidx);
			nav_point_names[navcount++]=str;
			str.Format("DropTeam%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=18;
		}
	}

	if(MPGames[GT_StockSiegeAssault].Supported)
	{
		for(int tidx=1;tidx<=MPGames[GT_StockSiegeAssault].Team;tidx++)
		{
			CString str;
			str.Format("Team %i Drop Zone",tidx);
			nav_point_names[navcount++]=str;
			str.Format("DropTeam%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=18;
		}
	}

	if(MPGames[GT_StockCaptureTheFlag].Supported)
	{
		for(int tidx=1;tidx<=MPGames[GT_StockCaptureTheFlag].Team;tidx++)
		{
			CString str;
			str.Format("Team %i Drop Zone",tidx);
			nav_point_names[navcount++]=str;
			str.Format("DropTeam%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=18;
			str.Format("TeamCapture%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=0;
		}
		flagstoadd=4;
		
	}
	
	if(MPGames[GT_StockKingOfTheHill].Supported)
	{
		nav_point_names[navcount++]="The Hill";
		drop_names[dropcount]="Hill"; drop_points[dropcount++]=0;
	}
	
	if(MPGames[GT_StockTeamKingOfTheHill].Supported)
	{
		for(int tidx=1;tidx<=MPGames[GT_StockTeamKingOfTheHill].Team;tidx++)
		{
			CString str;
			str.Format("Team %i Drop Zone",tidx);
			nav_point_names[navcount++]=str;
			str.Format("DropTeam%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=18;
		}
		nav_point_names[navcount++]="The Hill";
		
		drop_names[dropcount]="Hill"; drop_points[dropcount++]=0;
		
	}
	
	if(MPGames[GT_StockStealTheBacon].Supported)
	{
		nav_point_names[navcount++]="The Hill";
		drop_names[dropcount]="Hill"; drop_points[dropcount++]=0;
		flagstoadd=1;
	}
	
	if(MPGames[GT_StockEscort].Supported)
	{
		nav_point_names[navcount++]="Nav Alpha";
		nav_point_names[navcount++]="Nav Beta";
		nav_point_names[navcount++]="The Hill";
		MPGames[GT_StockEscort].Team=4;
		MPGames[GT_StockEscort].Alignment=2;
		for(int tidx=1;tidx<=MPGames[GT_StockEscort].Team;tidx++)
		{
			CString str;
			str.Format("DropTeam%i",tidx);
			drop_names[dropcount]=str; drop_points[dropcount++]=18;
		}
		
	}
	
	
	int nidx,pidx;
	bool added=false;
	
	for(nidx=0;nidx<navcount;nidx++)
	{
		EdGUIObject *new_obj=NULL;
		EdGUIObject *obj=GetObjectByName(nav_point_names[nidx]);
		
		if(obj)
		{
			if(!obj->GetTypeName().CompareNoCase(("NavPoint")) )
				new_obj=obj;
			else
			{
				msg+="Object \""+obj->GetName()+"\" renamed to \"";
				obj->SetName("renamed_"+obj->GetName());
				msg+=obj->GetName()+"\"\n";
			}
		}
		
		if(!new_obj)
		{
			inf.CreateType=ObjCreateInfo::OT_NVGAMEOBJ;
			inf.Path="misc\\navpoint\\navpoint.instance";
			new_obj=AddAt(&inf,&cmd,&showflag);
			new_obj->SetName(nav_point_names[nidx]);
			new_obj->UseLocalizedName(true);
			msg+="NavPoint \""+new_obj->GetName()+"\" Added\n";
			added=true;
		}	
	}
	
	for(nidx=0;nidx<dropcount;nidx++)
	{
		GUIDropZone *dropzone=NULL;
		EdGUIObject *obj=GetObjectByName(drop_names[nidx]);
		
		if(obj)
		{
			if(!obj->GetTypeName().CompareNoCase(("DropZone")) )
				dropzone=(GUIDropZone *)obj;
			else
			{
				msg+="Object \""+obj->GetName()+"\" renamed to \"";
				obj->SetName("renamed_"+obj->GetName());
				msg+=obj->GetName()+"\"\n";
			}
		}
		
		if(!dropzone)
		{	// Object Missing
			inf.CreateType=ObjCreateInfo::OT_DROPZONE;
			inf.Path="misc\\dropzone\\dropzone.instance";
			dropzone=(GUIDropZone *)AddAt(&inf,&cmd,&showflag);
			dropzone->SetName(drop_names[nidx]);
			msg+="DropZone \""+dropzone->GetName()+"\" Added\n";
			added=true;
		}	
		
		Verify(dropzone!=NULL);
		int pointstoadd=drop_points[nidx]-dropzone->GetObjectCount();
		if(pointstoadd>0)
		{
			CString tstr;
			tstr.Format("%i DropPoints Added to DropZone \"%s\"\n",pointstoadd,dropzone->GetName());
			msg+=tstr;
		}
		
		if(pointstoadd)
		{
			float rad=350.0f,deg=0.0f,deginc=Stuff::Two_Pi/pointstoadd;
			
			for(pidx=0;pidx<pointstoadd;pidx++)
			{
				dropzone->AddDropPoint(Point3D((float)(rad*cos(deg)),0,(float)(rad*sin(deg))));
				added=true;
				deg+=deginc;
			}
			
		}
	}
	
	
	for(nidx=1;nidx<=flagstoadd;nidx++)
	{
		CString resname,flagname;
		flagname.Format("Flag_Team%i",nidx);
		EdGUIObject *new_obj=NULL;
		EdGUIObject *obj=GetObjectByName(flagname);
		
		if(obj)
		{
			if(!obj->GetTypeName().CompareNoCase(("Flag")) )
				new_obj=obj;
			else
			{
				msg+="Object \""+obj->GetName()+"\" renamed to \"";
				obj->SetName("renamed_"+obj->GetName());
				msg+=obj->GetName()+"\"\n";
			}
		}
		
		if(!new_obj)
		{
			inf.Path="misc\\"+flagname+"\\"+flagname+".instance";
			inf.CreateType=ObjCreateInfo::OT_GAMEOBJ;
			new_obj=AddAt(&inf,&cmd,&showflag);
			new_obj->UseLocalizedName(true);
			msg+="Flag \""+new_obj->GetName()+"\" Added\n";
			added=true;
		}
	}
	
	return added;
}




void ObjectManager::SaveOverViewMap(CString fname,CSize size)
{
	if(!IsLoaded()) return;
	
	Image finalimage;
	
	finalimage.CreateBlank(size.cx,size.cy,ITYPE_RGB,24,RGBMask(0xff0000,0x00ff00,0x0000ff));
	finalimage.Blt(TerrainTexture,
		CRect(
		0,
		0,
		finalimage.GetWidth(),
		finalimage.GetHeight()
		),
		CRect(
		0,
		0,
		TerrainTexture.GetWidth(),
		TerrainTexture.GetHeight()
		)
		
		);
	
	finalimage.SaveTga((char *)(LPCSTR)fname);
	
	
	
}

bool ObjectManager::IsTeamGame(MPGameTypes idx)
{
	return (
		idx==ObjectManager::GT_StockTeamDestruction	||
		idx==ObjectManager::GT_StockTeamAttrition		||	
		idx==ObjectManager::GT_StockTeamKingOfTheHill	||
		idx==ObjectManager::GT_CustomTeamDestruction	||
		idx==ObjectManager::GT_CustomTeamAttrition		||	
		idx==ObjectManager::GT_CustomTeamKingOfTheHill 
		);
	
}


