
#include "general.h"
#include "MapFix.h"
#include "Functions.h"
#include "RawFileClass.h"

#include "scripts.h"
#include "engine.h"
#include "engine_da.h"
#include "da.h"
#include "da_settings.h"
#include "da_translation.h"
#include "GameObjManager.h"

//proto
StringClass Get_Closest_Building_Name_Translated(GameObject *obj);
StringClass Get_Closest_Building_Name(GameObject *obj);
StringClass Get_Closest_Building_Name_Translated_Dist(GameObject *obj);
StringClass Get_Closest_Building_Name_Dist(GameObject *obj);
GameObject *Find_Object_By_ID(int ObjectID);
void Debug(int Type, int Level, const char *Format, ...);

void MapFix::Init() {
	DAAccessLevel::Level ModLevel = DAAccessLevel::ADMINISTRATOR;
	DASettingsManager::Add_Settings("mapfix.ini");
	Register_Event(DAEvent::SETTINGSLOADED);
	Register_Event(DAEvent::LEVELLOADED);
	Register_Object_Event(DAObjectEvent::CREATED, DAObjectEvent::ALL);
	Register_Chat_Command((DAECC)&MapFix::ShowZones_Chat_Command, "!showzones", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::HideZones_Chat_Command, "!hidezones", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::DisplayZones_Chat_Command, "!displayzones", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::DestroyZones_Chat_Command, "!destroyzones", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::CreateZones_Chat_Command, "!createzones", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::MoveMct_Chat_Command, "!movemct", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::CreateMct_Chat_Command, "!createmct", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::DestroyMct_Chat_Command, "!destroymct", 0, ModLevel);
	Register_Chat_Command((DAECC)&MapFix::Fly_Chat_Command, "!fly", 0, ModLevel);
	zonecount = 0;
	lasercount = 0;
	mapprint = false;
	DestroyZones = false;
	DestroyLaserWalls = false;
	MctFix = false;
	CreateINI = false;
	CreateZone = false;
	FirstMap = true;
	StaticZoneList = false;
	EntireRotationGameover = false;
	Destruct = false;
	VehicleBlocker = false;
	ZoneEntrys = false;
}

void MapFix::Object_Created_Event(GameObject *obj)
{
	if (CreateINI) {
		INICreate(obj);
	}
}

void MapFix::Settings_Loaded_Event() 
{
	CreateINI = DASettingsManager::Get_Bool("CreateINI", false);
	if (CreateINI)
		DASettingsManager::Add_Settings("mctpos.ini");
	EntireRotationGameover = DASettingsManager::Get_Bool("EntireRotationGameover", false);
	StaticZoneList = DASettingsManager::Get_Bool("StaticZoneList", true);
	CreateZone = DASettingsManager::Get_Bool(The_Game()->Get_Map_Name(), "CreateZones", false);
	DestroyZones = DASettingsManager::Get_Bool(The_Game()->Get_Map_Name(), "DestroyZones", false);
	DestroyLaserWalls = DASettingsManager::Get_Bool(The_Game()->Get_Map_Name(), "DestroyLaserWalls", false);
	MctFix = DASettingsManager::Get_Bool(The_Game()->Get_Map_Name(), "Enable_MCTFix", false);
	VehicleBlocker = DASettingsManager::Get_Bool(The_Game()->Get_Map_Name(), "VehicleBlocker", false);
}

void MapFix::Level_Loaded_Event()
{
	zonecount = 0;
	lasercount = 0;
	mapprint = false;

	if (!CreateINI) {

		Destroy_Zones();
		Destroy_LaserWalls();

		INISection *Section = DASettingsManager::Get_Section(The_Game()->Get_Map_Name());
		if (Section) {
			for (INIEntry *i = Section->EntryList.First(); i && i->Is_Valid(); i = i->Next()) {
				if (stristr(i->Entry, "ZoneObjectID")) {
					zonecount++;
					ZoneObjectList.Add(atoi (i->Value));
				}
				else if (stristr(i->Entry, "LaserWallObjectID")) {
					lasercount++;
					LaserWalls.Add(atoi (i->Value));
				}
			}
		}

		Create_ZoneList();

		if (DestroyZones)
			Destroy_Zones();
		if (DestroyLaserWalls)
			Destroy_LaserWalls();
		if (CreateZone)
			Create_Zones();
		if (MctFix)
			Mct_Fix();
	}
	else
	{
		if (EntireRotationGameover)
			Gameover_Loop_Timer();
	}
}

void MapFix::Create_ZoneList()
{
	Debug(3, 2, "Create ZoneList ZoneCount %d\n", zonecount);
	StringClass Map = The_Game()->Get_Map_Name();
	if (zonecount != 0) {
		ZoneEntrys = true;
		for (int i = 1; i < zonecount + 1; i++)
		{
			int ObjectID = 0;
			StringClass Script;
			StringClass Zone;
			StringClass Parameter;
			Vector3 Position;
			Vector3 Size;
			float Facing = 0.0f;
			Vector3 Defualt(0.0f, 0.0f, 0.0f);

			bool ZoneEnabled = DASettingsManager::Get_Bool(Map, StringFormat("ZoneEnabled%d", i), false);
			ObjectID = DASettingsManager::Get_Int(Map, StringFormat("ZoneObjectID%d", i), 0);
			DASettingsManager::Get_String(Zone, Map, StringFormat("Zone%d", i), "");
			DASettingsManager::Get_String(Script, Map, StringFormat("ZoneScript%d", i), "");
			DASettingsManager::Get_Vector3(Position, Map, StringFormat("ZonePosition%d", i), Defualt);
			DASettingsManager::Get_Vector3(Size, Map, StringFormat("ZoneSize%d", i), Defualt);
			DASettingsManager::Get_String(Parameter, Map, StringFormat("ZoneScriptParameter%d", i), "9.0f");
			Facing = DASettingsManager::Get_Float(Map, StringFormat("ZoneFacing%d", i), 0.0f);

			if (Zone && Script && Size.X && Position.X && ZoneEnabled) {
				//Debug(3, 2, "Zone ObjectID %d, Zone %s, Script %s, Parameter %s, Position X %f, Y %f, Z %f, Size X %f, Y %f, Z %f, Facing %f\n",
				//	ObjectID, Zone, Script, Parameter, Position.X, Position.Y, Position.Z, Size.X, Size.Y, Size.Z, Facing);
				ZoneList.Add(new ZoneFixClass(ObjectID, Zone, Script, Parameter, Position, Size, Facing));
			}
			else {
				if (ZoneEnabled)
					Debug(3, 2, "BADCONFIG ZONE %d, Zone %s, Script %s, Parameter %s, Position X %f, Y %f, Z %f, Size X %f, Y %f, Z %f, Facing %f\n", ObjectID, Zone, Script, Parameter, Position.X, Position.Y, Position.Z, Size.X, Size.Y, Size.Z, Facing);
			}
		}
	}
	else {
		ZoneEntrys = false;
		Debug(3, 2, "No Zone Entry's for map %s in mapfix.ini\n", Map);
	}
}

void MapFix::Create_Zones()
{
	Debug(3, 2, "CreateZones count %d\n", ZoneList.Count());
	if (ZoneList.Count() != 0) {
		for (int i = 0; i < ZoneList.Count(); i++) {
			int ObjectID = ZoneList[i]->Get_ID();
			StringClass Zone = ZoneList[i]->Get_Zone();
			StringClass Script = ZoneList[i]->Get_Script();
			StringClass Parameter = ZoneList[i]->Get_Parameter();
			Vector3 Position = ZoneList[i]->Get_Position();
			Vector3 Size = ZoneList[i]->Get_Size();
			float Facing = ZoneList[i]->Get_Facing();
			bool MapFixZone = false;
			GameObject *obj = Find_Object_By_ID(ObjectID);
			
			//An object with defined ObjectID exists make sure it is not a zone with defined script. 
			if (obj) {
				const SimpleDynVecClass<GameObjObserverClass *> *observers = &obj->Get_Observers();
				int x = observers->Count();
				for (int i = 0; i < x; i++) {
					if (strcmp((*observers)[i]->Get_Name(), Script) == 0) {
						//Iran_Vehicle_Ground_Kill_Zone
						MapFixZone = true;
						break;
					}
				}
			}

			if (!obj || !MapFixZone){
				Matrix3D Rotation(true);
				Rotation.Rotate_Z(DEG_TO_RADF(Facing));
				OBBoxClass zoneBox(Position, Size, Rotation);
				GameObject* z = Create_Zone(Zone, zoneBox);
				Attach_Script_Once(z, Script, Parameter);
				ZoneObjectList.Add(z->Get_ID());
				//if (!StaticZoneList)
				ZoneList[i]->Set_ID(z->Get_ID());
			}
		}
	}
	else {
		if ( ZoneEntrys ) {
			ZoneEntrys = false;
			Create_ZoneList();
			Create_Zones();
		}
	}
}

void MapFix::Create_VehicleBlocker(Vector3 Position)
{
	//Vehicle_Blocker //objects\vehicle_collision_box\vehcol2m.w3d
	//PhysicalGameObj *Marker = Create_Object("Vehicle_Blocker", Position);
}


///////////////
//Destroy Stuff
///////////////

void MapFix::Destroy_Object(int ObjectID)
{
	GameObject *obj = Find_Object_By_ID(ObjectID);
	if (obj)
		obj->Set_Delete_Pending();
}

void MapFix::Destroy_Zones()
{
	for (int i = 0; i < ZoneObjectList.Count(); i++) {
		Destroy_Object(ZoneObjectList[i]);
	}
	ZoneObjectList.Delete_All();
	Hide_Zones();
	if ( !StaticZoneList )
		Delete_ZoneList();
}

void MapFix::Destroy_LaserWalls()
{
	for (int i = 0; i < LaserWalls.Count(); i++) {
		Destroy_Object(LaserWalls[i]);
	}
	LaserWalls.Delete_All();
}

void MapFix::Delete_ZoneList() 
{
	for (int i = 0; i < ZoneList.Count(); i++) {
		delete ZoneList[i];
	}
	ZoneList.Delete_All();
}

void MapFix::Delete_ZoneList_Entry(int Position) 
{
	delete ZoneList[Position];
	ZoneList.Delete(Position);
}

void MapFix::Delete_ZoneList_Entry_By_ID(int ObjectID)
{
	for (int i = 0; i < ZoneList.Count(); i++) {
		if (ZoneList[i]->Get_ID() == ObjectID) {
			delete ZoneList[i];
			ZoneList.Delete(i);
			break;
		}
	}
}

MapFix::~MapFix() {
	Destruct = true;
	Destroy_Zones();
	Destroy_LaserWalls();
	Delete_ZoneList();
}

Register_Game_Feature(MapFix, "MapFixes", "EnableMapFix", 0);


///////////////
//Chat Commands
///////////////


class ShowZoneObserverClass : public DAGameObjObserverClass {
public:
	virtual const char *Get_Name() {
		return "ShowZoneObserverClass";
	}

	ShowZoneObserverClass(int Number) {
		this->Number = Number;
	}

	virtual void Poked(GameObject *obj, GameObject *Poker) {
		Vector3 Position;
		Get_Owner()->Get_Position(&Position);
		StringClass NearBuilding = Get_Closest_Building_Name_Translated(obj);
		DA::Host_Message("Zone #%d at %f %f %f %s", Number, Position.X, Position.Y, Position.Z, NearBuilding);
	}

	int Number;
};


bool MapFix::ShowZones_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	HideZones_Chat_Command(Player, Text, ChatType);
	int i = 0;
	for (; i < ZoneList.Count(); i++) {
		Vector3 Test = ZoneList[i]->Get_Position();
		PhysicalGameObj *Marker = Create_Object("Invisible_Object", Test);
		Marker->Set_Collision_Group(TERRAIN_AND_BULLET_COLLISION_GROUP);
		Marker->Peek_Physical_Object()->Set_Immovable(true);
		Commands->Set_Model(Marker, "dsp_holo");
		Marker->Add_Observer(new ShowZoneObserverClass(i + 1));
	}
	if ( ZoneList.Count() == 0 )
		DA::Host_Message("No Zones on map", i);
	else
		DA::Host_Message("Created markers for %d zones.", i);
	return true;
}

bool MapFix::HideZones_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	Hide_Zones();
	return true;
}

void MapFix::Hide_Zones()
{
	cGameDataCnc *Game = The_Cnc_Game();
	bool gameover = Game->Is_Game_Over();
	if (Game && !gameover && !Destruct) {
		for (SLNode<BaseGameObj> *x = GameObjManager::GameObjList.Head(); x; x = x->Next()) {
			if (x->Data()->As_ScriptableGameObj() && ((ScriptableGameObj*)x->Data())->Find_Observer("ShowZoneObserverClass")) {
				x->Data()->Set_Delete_Pending();
			}
		}
	}
}

bool MapFix::DisplayZones_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	DisplayZoneList();
	return true;
}

bool MapFix::DestroyZones_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	Destroy_Zones();
	DA::Host_Message("Zones Destroyed\n");
	return true;
}


bool MapFix::CreateZones_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	Create_Zones();
	DA::Host_Message("Zones Created\n");
	return true;
}

bool MapFix::Fly_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	GameObject *obj = Player->Get_GameObj();
	GameObject *Veh = Get_Vehicle(obj);

	if (Veh)
	{
		if (Get_Vehicle_Driver(Veh) == obj)
		{
			DA::Host_Message("Cant set Fly in vehicle.\n");
			return false;
		}
	}
	else
	{
		if (Get_Fly_Mode(obj))
			DA::Host_Message("No Fly.\n");
		else
			DA::Host_Message("Can Now Fly.\n");
		Toggle_Fly_Mode(obj);
	}
	return false;
}

void MapFix::DisplayZoneList2()
{
	for (int i = 0; i < ZoneList.Count(); i++) {
		Vector3 pos = ZoneList[i]->Get_Position();
		Vector3 size = ZoneList[i]->Get_Size();
		DA::Host_Message("ZoneFix ObjectID %d, Zone %s, Script %s, Parameter %s, Position X %f, Y %f, Z %f, Size X %f, Y %f, Z %f, Facing %f",
			ZoneList[i]->Get_ID(), ZoneList[i]->Get_Zone(), ZoneList[i]->Get_Script(), ZoneList[i]->Get_Parameter(), pos.X, pos.Y, pos.Z, size.X, size.Y, size.Z, ZoneList[i]->Get_Facing());
	}
}


void MapFix::DisplayZoneList()
{
	for (int i = 0; i < ZoneList.Count(); i++) {
		Vector3 pos = ZoneList[i]->Get_Position();
		Vector3 size = ZoneList[i]->Get_Size();
		DA::Host_Message("ZoneFix ObjectID %d, Zone %s, Script %s, Parameter %s, Position X %f, Y %f, Z %f, Size X %f, Y %f, Z %f, Facing %f",
			ZoneList[i]->Get_ID(), ZoneList[i]->Get_Zone(), ZoneList[i]->Get_Script(), ZoneList[i]->Get_Parameter(), pos.X, pos.Y, pos.Z, size.X, size.Y, size.Z, ZoneList[i]->Get_Facing());
		WriteINI("ZoneFix ObjectID %d, Zone %s, Script %s, Parameter %s, Position X %f, Y %f, Z %f, Size X %f, Y %f, Z %f, Facing %f",
			ZoneList[i]->Get_ID(), ZoneList[i]->Get_Zone(), ZoneList[i]->Get_Script(), ZoneList[i]->Get_Parameter(), pos.X, pos.Y, pos.Z, size.X, size.Y, size.Z, ZoneList[i]->Get_Facing());
	}
	WriteINI("ZoneObjectList");
	for (int i = 0; i < ZoneObjectList.Count(); i++) {
		WriteINI("ZoneObject %d", ZoneObjectList);
	}
}

//////////////////////////////////////////////////////
//Function used to create mapfix.ini on object created
//////////////////////////////////////////////////////

void MapFix::INICreate(GameObject *obj)
{



	Vector3 pos = Commands->Get_Position(obj);
	int ObjectID = Commands->Get_ID(obj);
	StringClass Preset = Commands->Get_Preset_Name(obj);
	StringClass Map = The_Game()->Get_Map_Name();
	int mapnum = Get_Current_Map_Index();

	if (mapnum == 0 && !FirstMap)
	{
		return;
	}

	if (!mapprint) {
		WriteINI("[%s]\n", The_Game()->Get_Map_Name());
		WriteINI("DestroyZones=0");
		WriteINI("DestroyLaserWalls=0");
		WriteINI("CreateZones=0");
		//Vehicle Blocker not used at the moment.
		WriteINI("VehicleBlocker=0");
		WriteINI("Enable_MCTFix=1");
		WriteINI("MCT_ReadINI=1");
		WriteINI("");

		Vector3 Defualt(0.0f, 0.0f, 0.0f);
		Vector3 Position;
		DASettingsManager::Get_Vector3(Position, Map, "MCT_Position", Defualt);
		float Facing = DASettingsManager::Get_Float(Map, "MCT_Facing", 0.0f);
		if (Position.X)
		{
			WriteINI("MCT_Position_X=%f", Position.X);
			WriteINI("MCT_Position_Y=%f", Position.Y);
			WriteINI("MCT_Position_Z=%f", Position.Z);
			WriteINI("MCT_Facing=%f", Facing);
			WriteINI("");
		}
		mapprint = true;
	}

	if (stristr(Commands->Get_Preset_Name(obj), "zone"))
	{
		bool ZoneFix = false;
		StringClass Script;
		float Time = 1.0f;

		//Debug(3, 2, "Zone Created Preset %s Position X %f, Y %f, Z %f\n", Preset, pos.X, pos.Y, pos.Z);
		const SimpleDynVecClass<GameObjObserverClass *> *observers = &obj->Get_Observers();
		int x = observers->Count();
		for (int i = 0; i < x; i++) {
			if (stristr((*observers)[i]->Get_Name(), "Iran")) {
				Script = (*observers)[i]->Get_Name();
				Time = ((ScriptImpClass*)(*observers)[i])->Get_Float_Parameter("Time");
				ZoneFix = true;
				break;
			}
		}

		//zone contains Irans script record it. 
		if (ZoneFix)
		{
			//Debug(3, 2, "Script %s\n", Script);
			zonecount++;
			OBBoxClass *Box = Get_Zone_Box(obj);
			Vector3	Center = Box->Center;
			Vector3	Extent = Box->Extent;
			//float Facing = Box->Basis.Get_Z_Rotation();
			Matrix3D Transform = Get_Transform(obj->As_ScriptableGameObj());
			float Facing = Transform.Get_Z_Rotation();
			StringClass NearBuilding = Get_Closest_Building_Name_Translated_Dist(obj);

			WriteINI(";%s", NearBuilding);
			WriteINI("ZoneEnabled%d=1", zonecount, Preset);
			WriteINI("Zone%d=%s", zonecount, Preset);
			WriteINI("ZoneObjectID%d=%d", zonecount, ObjectID);
			WriteINI("ZoneScript%d=%s", zonecount, Script);
			WriteINI("ZoneScriptParameter%d=%f", zonecount, Time);
			WriteINI("ZonePosition%d_X=%f", zonecount, pos.X);
			WriteINI("ZonePosition%d_Y=%f", zonecount, pos.Y);
			WriteINI("ZonePosition%d_Z=%f", zonecount, pos.Z);
			WriteINI("ZoneSize%d_X=%f", zonecount, Extent.X);
			WriteINI("ZoneSize%d_Y=%f", zonecount, Extent.Y);
			WriteINI("ZoneSize%d_Z=%f", zonecount, Extent.Z);
			WriteINI("ZoneFacing%d=%f", zonecount, Facing);
			WriteINI("");
		}
	}
	//dsp_torture_wal.w3d laserwall
	else if (obj->As_PhysicalGameObj())
	{
		if (strcmp(Preset, "Simple_Sydney_SandM_Wall") == 0) {
			lasercount++;
			WriteINI("LaserWallObjectID%d=%d", lasercount, ObjectID);
		}
	}
}

void MapFix::WriteINI(StringClass Format, ...) {
	char Message[256];
	Format_String(Message);
	TextFileClass File;
	if (File.Open("mapfix.ini", 3)) {
		File.Seek(File.Size(), 0);
		File.Write_Line(Message);
		File.Close();
		//File.Open(1);
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////
//Nod Ref MCT fix.
//Definitely not the correct way to get this done. Needs to be done in leveledit. 
//I have created these w3d files based off the Single Player aggerate files, to make this work.
///////////////////////////////////////////////////////////////////////////////////////////////////

void MapFix::Mct_Fix()
{
	MCTOBJ = 0;
	for (SLNode<BuildingGameObj> *z = GameObjManager::BuildingGameObjList.Head(); z; z = z->Next())
	{
		BuildingGameObj *Building = z->Data();
		int Team = z->Data()->Get_Player_Type();
		if (Building->As_RefineryGameObj() && Team == 0)
		{
			BuildingAggregateClass *REFMCT = 0;
			REFMCT = Building->Find_MCT();
			
			if (REFMCT) {
				Debug(3, 2, "Create mnref_ag_3_n\n");
				Vector3 Defualt(0.0f, 0.0f, 0.0f);
				Vector3 Position;
				bool ReadINI = DASettingsManager::Get_Bool(The_Game()->Get_Map_Name(), "MCT_ReadINI", false);
				DASettingsManager::Get_Vector3(Position, The_Game()->Get_Map_Name(), "MCT_Position", Defualt);
				float Facing = DASettingsManager::Get_Float(The_Game()->Get_Map_Name(), "MCT_Facing", 90.0f);
				Vector3 MCTPos;
				REFMCT->Get_Position(&MCTPos);

				//Read from INI instead of getting position from MCT
				if (ReadINI) {
					MCTPos = Position;
				}

				//Canyon
				//MCTPos.X = MCTPos.X + 2.00f;
				//MCTPos.Y = MCTPos.Y - 0.04f;
				//MCTPos.Z = MCTPos.Z + 0.51f;

				//WriteINI(";MCTPOS");
				//WriteINI(";MCT_Position_X=%f", MCTPos.X);
				//WriteINI(";MCT_Position_Y=%f", MCTPos.Y);
				//WriteINI(";MCT_Position_Z=%f", MCTPos.Z);

				//Canyon 
				//MCTPos.X = MCTPos.X + 0.00f;
				//MCTPos.Y = MCTPos.Y - 0.04f;
				//MCTPos.Z = MCTPos.Z + 0.51f;

				//WriteINI(";MCT_Position_X=%f", MCTPos.X);
				//WriteINI(";MCT_Position_Y=%f", MCTPos.Y);
				//WriteINI(";MCT_Position_Z=%f", MCTPos.Z);


				PhysicalGameObj *c = Create_Object("Invisible_Object", MCTPos);
				//c->Set_Collision_Group(TERRAIN_AND_BULLET_COLLISION_GROUP);
				//c->Peek_Physical_Object()->Set_Immovable(true);
				Commands->Set_Facing(c, Facing);
				Commands->Set_Model(c, "mctfix");
				Commands->Set_Is_Visible(c, true);
				MCTOBJ = c;
				MCTPOS = MCTPos;
				Building->Add_Observer(new MCTObserverClass(c) );
			}
		}
	}
}

bool MapFix::DestroyMct_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	Commands->Destroy_Object(MCTOBJ);
	DA::Host_Message("MCT Destroyed\n");
	return true;
}


bool MapFix::CreateMct_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	Mct_Fix();
	DA::Host_Message("MCT Created\n");
	return true;
}



bool MapFix::MoveMct_Chat_Command(cPlayer *Player, const DATokenClass &Text, TextMessageEnum ChatType) {
	if (!Text.Size() || (Text.Size() > 2) && Text.Is_Float(2)) {
		DA::Page_Player(Player, "Usage !movemct <axis/facing/reset/save/read> <position>");
	}
	else
	{
		if (!MctFix) {
			DA::Page_Player(Player, "MctFix is Disabled.");
			return true;
		}

		
		GameObject *Mct = MCTOBJ;
		BuildingGameObj *NodRef = 0;

		if (!Mct || Mct->Is_Delete_Pending()) {
			DA::Page_Player(Player, "MctObject does not Exist!");
			return true;
		}

		if (Text.Is_Int(1))
		{
			Debug(3, 2, "Text is a number invalid\n");
			DA::Page_Player(Player, "First Parameter can't be a number.");
			DA::Page_Player(Player, "Usage !movemct <axis/facing/reset/save/read> <position>");
			return true;
		}
		StringClass Axis = Text.As_Wide(1);
		//Debug(3, 2, "Got text %s END\n", Axis.Peek_Buffer());

		float pos = 0.0f;
		if (!Text.As_Float(2, pos))
		{
			Debug(3, 2, "Float is null or not a number.\n", pos);
			//return true;
		}
		//Debug(3, 2, "Got float %f\n", pos);

		Vector3 MCTPos = Commands->Get_Position(Mct);
		if (!MCTPos.X) {
			DA::Page_Player(Player, "Mct pos Not Found.");
			return true;
		}
		else
		{
			Debug(3, 2, "Mct Position X Move %f + %f\n", MCTPos.X, pos);
		}

		if (strcmp(Axis, "x") == 0) {
			//MCTPos.X = MCTPos.X + pos;
			MCTPos.X = pos;
			DA::Page_Player(Player, "Mct Position X Set to %f", pos);
		}
		else if (strcmp(Axis, "y") == 0) {
			//MCTPos.Y = MCTPos.Y + pos;
			MCTPos.Y = pos;
			DA::Page_Player(Player, "Mct Position Y Set to %f", pos);
		}
		else if (strcmp(Axis, "z") == 0) {
			//MCTPos.Z = MCTPos.Z + pos;
			MCTPos.Z = pos;
			DA::Page_Player(Player, "Mct Position Z Set to %f", pos);
		}
		else if (strcmp(Axis, "facing") == 0) {
			Commands->Set_Facing(Mct, pos);
			Update_Network_Object(Mct);
			DA::Page_Player(Player, "Mct Facing Changed to %f ", pos);
		}
		else if (strcmp(Axis, "reset") == 0) {
			MCTPos = MCTPOS;
			DA::Page_Player(Player, "Mct Position Reset");
		}
		else if (strcmp(Axis, "save") == 0) {
			WriteINI("[%s]\n", The_Game()->Get_Map_Name());
			WriteINI(";MCT_Position_X=%f", MCTPos.X);
			WriteINI(";MCT_Position_Y=%f", MCTPos.Y);
			WriteINI(";MCT_Position_Z=%f", MCTPos.Z);
			WriteINI(";MCT_Facing=%f", MCTPos.Z);
			WriteINI("");
			DA::Page_Player(Player, "Mct Position Saved to ini.");
		}
		else if (strcmp(Axis, "read") == 0) {
			Vector3 Position;
			Vector3 Defualt(0.0f, 0.0f, 0.0f);
			DASettingsManager::Get_Vector3(Position, The_Game()->Get_Map_Name(), "MCT_Position", Defualt);
			MCTPos = Position;
			//WriteINI(";readini");
			Debug(3, 2, "Mct Position Read %f %f %f\n", Position.X, Position.Y, Position.Z);
			DA::Page_Player(Player, "Mct Position Set from ini.");
		}
		else {
			DA::Page_Player(Player, "Mct Command %s Unknown.", Axis);
			return true;
		}

		if (Mct && !Mct->Is_Delete_Pending()){
			//Destroy the Mct and Create a new one. 
			Commands->Destroy_Object(Mct);
			PhysicalGameObj *c = Create_Object("Invisible_Object", MCTPos);
			Commands->Set_Facing(c, DASettingsManager::Get_Float(The_Game()->Get_Map_Name(), "MCTFacing", 90.0f));
			Commands->Set_Model(c, "mctfix");
			Commands->Set_Is_Visible(c, true);
			//Remove the MCTObserverClass from the Building. 
			for (SLNode<BuildingGameObj> *z = GameObjManager::BuildingGameObjList.Head(); z; z = z->Next())
			{
				if (z->Data()->As_BuildingGameObj() && ((BuildingGameObj*)z->Data())->Find_Observer("MCTObserverClass")) {
					//Debug(3, 2, "Building Has MCTObserverClass 2\n");
					NodRef = z->Data()->As_BuildingGameObj();
					((BuildingGameObj*)z->Data())->Remove_Observer("MCTObserverClass");
				}
			}
			//Add the MCTObserverClass to the Building and pass the new mct object
			NodRef->Add_Observer(new MCTObserverClass(c));
			MCTOBJ = c;
			DA::Page_Player(Player, "Mct Current Position X %f Y %f Z %f", MCTPos.X, MCTPos.Y, MCTPos.Z);
		}
		else
		{
			DA::Page_Player(Player, "Mct Does not Exist.");
		}
	}
	//Debug(3, 2, "End of MCT Command\n");
	return true;
}

///////////////////////////
// MCTObserverClass
///////////////////////////

MCTObserverClass::MCTObserverClass(GameObject *obj)
{
	this->Mct = obj;
}

MCTObserverClass::MCTObserverClass(BuildingGameObj *obj)
{
	this->Building = obj;
}

//add to nod ref gameobj and pass the mctfix object
void MCTObserverClass::Timer_Expired(GameObject *obj, int Number) {

}

void MCTObserverClass::Damage_Received(ArmedGameObj *Damager, float Damage, unsigned int Warhead, float Scale, DADamageType::Type Type) {

	if (!Mct)
	{
		Debug(3, 2, "MCTObserverClass mct is null to global var\n");
		if (MCTOBJ) {
			//Mct = MCTOBJ;

		}
		else{
			Debug(3, 2, "MCTObserverClass mctfix class global var is also Null Error\n");
		}
		return;
	}

	float Health = Commands->Get_Health(Get_Owner());
	StringClass Model = Get_Model(Mct);
	//Debug(3, 2, "Ref Damaged Damaged %f HP %f\n", Damage, Health);
	if (Health > 400) {
		//Debug(3, 2, "mctfix %f\n", Health);
		if (!strcmp(Model, "mctfix") == 0)
			Commands->Set_Model(Mct, "mctfix");
	}

	if (Health < 400 && Health > 300){
		//Debug(3, 2, "mctfix2 %f\n", Health);
		if (!strcmp(Model, "mctfix2") == 0)
			Commands->Set_Model(Mct, "mctfix2");
	}

	if (Health <= 300 && Health >= 200){
		//Debug(3, 2, "mctfix3 %f\n", Health);
		if (!strcmp(Model, "mctfix3") == 0)
			Commands->Set_Model(Mct, "mctfix3");
	}
	if (Health < 200) {
		//Debug(3, 2, "mctfix4 %f\n", Health);
		if (!strcmp(Model, "mctfix4") == 0)
			Commands->Set_Model(Mct, "mctfix4");
	}
}

void MCTObserverClass::Kill_Received(ArmedGameObj *Killer, float Damage, unsigned int Warhead, float Scale, DADamageType::Type Type) {
	Commands->Set_Model(Mct, "");
	MCTOBJ = 0;
	Debug(3, 2, "mnref_ag_3_n Killed 2\n");
	Mct->Set_Delete_Pending();
	Get_Owner()->Set_Delete_Pending();
	Set_Delete_Pending();
}

void MCTObserverClass::Poked(cPlayer *Poker) {
	Vector3 Position;
	Get_Owner()->Get_Position(&Position);
	DA::Host_Message("Mct %f %f %f Facing %f", Position.X, Position.Y, Position.Z, Commands->Get_Facing(Mct));
}

void MCTObserverClass::Destroyed()
{

	Debug(3, 2, "mnref_ag_3_n Destroyed\n");
}

////////////////////////////
//ZoneFixClass Data Struct
////////////////////////////

ZoneFixClass::ZoneFixClass(int ObjectID, const char *Zone, const char *Script, const char *Parameter, Vector3 Position, Vector3 Size, float Facing)
{
	this->ObjectID = ObjectID;
	this->Zone = Zone;
	this->Script = Script;
	this->Parameter = Parameter;
	this->Position = Position;
	this->Size = Size;
	this->Facing = Facing;
}

const int &ZoneFixClass::Get_ID() {
	return ObjectID;
}
const StringClass &ZoneFixClass::Get_Zone() {
	return Zone;
}
const StringClass &ZoneFixClass::Get_Script() {
	return Script;
}
const StringClass &ZoneFixClass::Get_Parameter() {
	return Parameter;
}
const Vector3 &ZoneFixClass::Get_Size() {
	return Size;
}
const Vector3 &ZoneFixClass::Get_Position() {
	return Position;
}
const float &ZoneFixClass::Get_Facing() {
	return Facing;
}


////////////////
//Gameover Loop
///////////////

void MapFix::Gameover_Loop()
{
	//Generate mapfix.ini
	//Gameover Entire Map Rotation
	int mapnum = Get_Current_Map_Index();
	Debug(3, 2, "MapNum %d Map %s\n", mapnum, The_Game()->Get_Map_Name());
	if (FirstMap)
		FirstMap = false;
	else if ( mapnum == 0)
		Console_Input("quit");
	Debug(3, 2, "Gameover MapNum %d\n", mapnum);
	Console_Input("gameover");
}

void MapFix::Gameover_Loop2()
{
	//Generate mapfix.ini
	//Gameover Entire Map Rotation
	int mapnum = Get_Current_Map_Index();
	Debug(3, 2, "MapNum %d Map %s\n", mapnum, The_Game()->Get_Map_Name());
	if (FirstMap) {
		FirstMap = false;
		Debug(3, 2, "First Map\n");
		Console_Input("gameover");
	}
	//End of Rotation Terminate Server
	else if ( mapnum == 0)
		Console_Input("quit");
	//Keep it coming
	else {
		Debug(3, 2, "Gameover MapNum %d\n", mapnum);
		Console_Input("gameover");
	}
}

void MapFix::Gameover_Loop_Timer()
{
	//Generate mapfix.ini
	//Gameover Entire Map Rotation
	//Create a timer to make sure all objects where created on the map.
	int mapnum = Get_Current_Map_Index();
	Debug(3, 2, "MapNum %d Map %s\n", mapnum, The_Game()->Get_Map_Name());
	if (FirstMap)
		Start_Timer(3, 3.0f, 0, mapnum);
	//End of Rotation Terminate Server
	else if ( mapnum == 0)
		Start_Timer(2, 0.0f, 0, mapnum);
	//Keep it coming
	else
		Start_Timer(1, 3.0f, 0, mapnum);
}

void MapFix::Timer_Expired(int Number, unsigned int Data) {
	if (Number == 1) {
		Debug(3, 2, "Gameover_Loop MapNum %d\n", Data);
		Console_Input("gameover");
	}
	else if (Number == 2) {
		Debug(3, 2, "End of Rotation Terminating Server\n");
		Console_Input("quit");
		//Start_Timer(4, 10.0f);
	}
	else if (Number == 3) {
		FirstMap = false;
		Debug(3, 2, "First Map\n");
		Start_Timer(1, 0.0f);
	}
	else if (Number == 4) {
		Console_Input("quit");
	}
}


//////////////////////////
//Functions used by mapfix
//////////////////////////

GameObject *Find_Object_By_ID(int ObjectID)
{
	for (SLNode<BaseGameObj> *x = GameObjManager::GameObjList.Head(); x; x = x->Next()) {
		if (x->Data()->As_ScriptableGameObj()) {
			GameObject *Z = x->Data()->As_ScriptableGameObj();
			if (ObjectID == Z->Get_ID()) {
				if (Z->Is_Delete_Pending())
					return 0;
				else
					return Z;
			}
		}
	}
	return 0;
}

StringClass Get_Closest_Building_Name_Translated(GameObject *obj) {
	float ClosestDist = FLT_MAX;
	float Dist = 0.0f;
	float Maxdist = 10.0f;
	Vector3 pos = Commands->Get_Position(obj);
	BuildingGameObj *Building = 0;
	StringClass String = "";
	for (SLNode<BuildingGameObj> *z = GameObjManager::BuildingGameObjList.Head(); z; z = z->Next()) {
		z->Data()->Find_Closest_Poly(pos, &Dist);
		if (Dist < ClosestDist) {
			ClosestDist = Dist;
			Building = z->Data();
		}
	}
	if (Building) { String.Format("Near The %s Dist %f", DATranslationManager::Translate_With_Team_Name(Building), ClosestDist); }
	if (ClosestDist > Maxdist){ String.Format("Not Near a Building Dist to closest building %f", ClosestDist); }
	return String;
}

StringClass Get_Closest_Building_Name(GameObject *obj) {
	float ClosestDist = FLT_MAX;
	float Dist = 0.0f;
	float Maxdist = 10.0f;
	Vector3 pos = Commands->Get_Position(obj);
	BuildingGameObj *Building = 0;
	StringClass String = "";
	for (SLNode<BuildingGameObj> *z = GameObjManager::BuildingGameObjList.Head(); z; z = z->Next()) {
		z->Data()->Find_Closest_Poly(pos, &Dist);
		if (Dist < ClosestDist) {
			ClosestDist = Dist;
			Building = z->Data();
		}
	}
	if (Building) { String.Format("Near Building %s", Building->Get_Definition().Get_Name()); }
	if (ClosestDist > Maxdist){ String.Format("Not Near a Building"); }
	return String;
}

StringClass Get_Closest_Building_Name_Translated_Dist(GameObject *obj) {
	float ClosestDist = FLT_MAX;
	float Dist = 0.0f;
	float Maxdist = 10.0f;
	Vector3 pos = Commands->Get_Position(obj);
	BuildingGameObj *Building = 0;
	StringClass String = "";
	for (SLNode<BuildingGameObj> *z = GameObjManager::BuildingGameObjList.Head(); z; z = z->Next()) {
		z->Data()->Find_Closest_Poly(pos, &Dist);
		if (Dist < ClosestDist) {
			ClosestDist = Dist;
			Building = z->Data();
		}
	}
	if (Building) { String.Format("Near The %s Dist %f", DATranslationManager::Translate_With_Team_Name(Building), ClosestDist); }
	if (ClosestDist > Maxdist){ String.Format("Not Near a Building Dist %f", ClosestDist); }
	return String;
}

StringClass Get_Closest_Building_Name_Dist(GameObject *obj) {
	float ClosestDist = FLT_MAX;
	float Dist = 0.0f;
	float Maxdist = 10.0f;
	Vector3 pos = Commands->Get_Position(obj);
	BuildingGameObj *Building = 0;
	StringClass String = "";
	for (SLNode<BuildingGameObj> *z = GameObjManager::BuildingGameObjList.Head(); z; z = z->Next()) {
		z->Data()->Find_Closest_Poly(pos, &Dist);
		if (Dist < ClosestDist) {
			ClosestDist = Dist;
			Building = z->Data();
		}
	}
	if (Building) { String.Format("Near Building %s Dist %f", Building->Get_Definition().Get_Name(), ClosestDist); }
	if (ClosestDist > Maxdist){ String.Format("Not Near a Building Dist %f", ClosestDist); }
	return String;
}

void Debug(int Type, int Level, const char *Format, ...)
{
	char Message[256];
	Format_String(Message);

	//SSGM
	if (Type == 0) {
		DALogManager::Write_Log("_DEBUG", "%s", Message);
	}

	//#gamelog
	else if (Type == 1) {
		DALogManager::Write_GameLog("DEBUG;%s", Message);
	}

	//renlog
	else if (Type == 2) {
		StringClass str;
		str.Format("[Debug] %s", Message);
		SSGMGameLog::Log_RenLog(str);
	}

	//console
	else if (Type == 3) {
		Console_Output("[Debug] %s", Message);
	}
}