//===========================================================================//
// File:	MechLab.cpp														 //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 12/19/01  MSL  Added StandardArmor                                        //
// 01/06/02  MSL  Changed weapon groups from 6 to 3                          //
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "MW4Headers.hpp"
#pragma warning(disable:4100)	// unreferenced formal parameter

#include "MechLab.hpp"
#include <gosScript\gosScriptHeaders.hpp>

#include "Mech.hpp"
#include "MWDamageObject.hpp"
#include "Subsystem.hpp"
#include "Weapon.hpp"
#include "MWMover.hpp"
#include "Armor.hpp"
#include "SubsystemClassData.hpp"
#include "MWTable.hpp"
#include "MWApplication.hpp"
#include "Torso.hpp"
#include "Engine.hpp"
#include "HeatSink.hpp"
#include "AMS.hpp"
// MSL 5.02 SubSystems
//#include "EnhancedOptics.hpp"
#include "IFF_Jammer.hpp"
#include "AdvancedGyro.hpp"
// for campaign skin - jcem
#include "mw4shell.hpp"
// for campaign skin - jcem


#include <Adept\Entity.hpp>
#include <Adept\VideoRenderer.hpp>
#include <Adept\Site.hpp>
#include <Adept\ResourceImagePool.hpp>

#include <MissionLang\Resource.h>

#include <ElementRenderer\CameraElement.hpp>
#include <ElementRenderer\StateChange.hpp>
#include <ElementRenderer\GroupElement.hpp>

#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRClipper.hpp>

#include "..\buildnum\buildnum.h"

#include <GameOS\ToolOS.hpp>
#include <GameOS\Network.hpp>

#define VARIANTS_PATH "Resource\\Variants\\"

// jcem begin
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <WinBase.h>
#include <stdio.h>
#include <io.h>

#include <ddraw.h>
#include <d3d.h>

#include <GameOS\render.hpp>

#include "ctcls.h"
#include "ctcl.h"

extern bool g_bCOOP;
// MSL 5.03 MechView
extern void (__stdcall *g_pfnCTCL_AfterBeginScene)();
extern void __stdcall CTCL_AfterBeginScene();

#if 1 // jcem for MechView, CampaignMechLab.cpp too
#define CONN4ML             (Connection::Hermit)
#else
#define CONN4ML             (Connection::Local)
#endif

extern Stuff::SafeChainOf<Replicator*>* g_pTempReplicators;
// jcem end

MechLab
	*MechLab::Instance = NULL;
ElementRenderer::CameraElement
	*MechLab::s_MechCamera = NULL;

void MechView_Before()
{
    MechLab::s_MechCamera->ClearBackBufferBeforeDraw(true);
}

void MechView_After()
{
    MechLab::s_MechCamera->ClearBackBufferBeforeDraw(false);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MechLab::MechLab() :
	m_subsystemsAvailable(NULL, true),
	m_mechResourceFile(NULL)
{
//	StartUp();
	m_isCampaign = 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MechLab::~MechLab()
{
	ShutDown();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::StartUp()
{
    Stuff::SafeChainOf<Replicator*>* pOld = g_pTempReplicators;
    g_pTempReplicators = &m_TempReplicators;

	m_mechIDs = NULL;
	m_chassisIDs = NULL;
	m_workingMech = NULL;
    m_workingEntity = NULL;

	m_workingMechName = NULL;

	m_mechResourceFile.Remove();

	m_mode = ChassisTabMode;

	m_mechLabCount = GetMechCount();
	m_chassisCount = GetChassisCount();

	InitializeSubsystemsAvailable();

	gosScript_RegisterCallback("ML_CallbackHandler",&ML_CallbackHandler,GOSVAR_INT,0,NULL);

	gosScript_RegisterVariable("m_mechLabCount", &m_mechLabCount, GOSVAR_INT, 0, NULL);
	gosScript_RegisterVariable("m_chassisCount", &m_chassisCount, GOSVAR_INT, 0, NULL);	
	gosScript_RegisterVariable("m_isCampaign", &m_isCampaign, GOSVAR_INT, 0, NULL);

	if(s_MechCamera)
	{
		delete s_MechCamera;
		s_MechCamera = NULL;
	}

	//
	//---------------
	// Build a camera
	//---------------
	//
	ElementRenderer::StateChange *Camera_State = 
		new ElementRenderer::StateChange();
	Check_Object(Camera_State);
	Camera_State->EnableBackfaceCulling();
	Camera_State->EnableDithering();
	Camera_State->EnablePerspectiveCorrection();
	Camera_State->EnableZBufferWrite();
	Camera_State->EnableZBufferCompare();

	s_MechCamera = new ElementRenderer::CameraElement(Camera_State);
	Check_Object(s_MechCamera);
	s_MechCamera->SetPerspective(1.0f, 1100.0f, Stuff::Pi_Over_3);
	s_MechCamera->SetViewport(0.0f, 0.0f, 1.0f, 1.0f);
//	s_MechCamera->SetSecondaryCamera();
	s_MechCamera->ClearZBeforeDraw(false);
	s_MechCamera->ClearBackBufferBeforeDraw(false);

	m_sceneRoot = new ElementRenderer::GroupElement;
	m_sceneRoot->SetRootMode();
	m_sceneRoot->AttachChild(s_MechCamera);
	m_sceneRoot->SetRootMode();
//	s_MechCamera->SetRootMode();
//	Camera->SetScene(Scene);

    g_pTempReplicators = pOld;
}

void MechLab::FreeReplicators()
{
    SafeChainIteratorOf<Replicator*> replicators(&m_TempReplicators);
	Replicator *replicator;
	while ((replicator = replicators.GetCurrent()) != NULL)
	{
		Check_Object(replicator);
		Unregister_Object(replicator);
        Connection::DeleteReplicator(replicator);
		replicators.First();
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::ShutDown()
{
	gosScript_UnregisterCallback("ML_CallbackHandler");

	gosScript_UnregisterVariable("m_mechLabCount");
	gosScript_UnregisterVariable("m_chassisCount");
	gosScript_UnregisterVariable("m_isCampaign");

	m_subsystemsAvailable.DeletePlugs();
	if(m_mechResourceFile.GetCurrent())
	{
		m_mechResourceFile.GetCurrent()->Save();
		delete m_mechResourceFile.GetCurrent();
		m_mechResourceFile.Remove();
	}

    if (MidLevelRenderer::MLRTexturePool::Instance) {
	gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
	Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
	delete MidLevelRenderer::MLRTexturePool::Instance;
	ResourceImagePool *pool = new ResourceImagePool;
	Check_Object(pool);
	MidLevelRenderer::MLRTexturePool::Instance = new MidLevelRenderer::MLRTexturePool(pool);
	Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
	gos_PopCurrentHeap();
    }

	if(m_mechIDs)
	{
		gos_Free(m_mechIDs);
	}
	if(m_chassisIDs)
	{
		gos_Free(m_chassisIDs);
	}
	if(s_MechCamera)
	{
		delete s_MechCamera;
		s_MechCamera = NULL;
	}
	if(m_sceneRoot)
	{
		delete m_sceneRoot;
		m_sceneRoot = NULL;
	}

	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Uninit();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::Execute()
{
	Check_Pointer(this);
	if(m_mode == ChassisTabMode)
	{
		if(GetWorkingEntity())
		{
            Stuff::SafeChainOf<Replicator*>* pOld = g_pTempReplicators;
            g_pTempReplicators = &MechLab::Instance->m_TempReplicators;

			Check_Object(GetWorkingEntity());
			ElementRenderer::Element *element = GetWorkingEntity()->GetElement();
			Check_Object(element);
			LinearMatrix4D new_local = element->GetLocalToWorld();
			YawPitchRoll current_rotation;
			current_rotation = element->GetLocalToWorld();
// MSL 5.03 Mechview
			// begin of MechView - jcem
            if (g_pfnCTCL_AfterBeginScene == CTCL_AfterBeginScene)
			{
                int nXCount = radar_device.m_ptMechViewDim.x / radar_device.m_ptMechViewSize.x;
                int nYCount = radar_device.m_ptMechViewDim.y / radar_device.m_ptMechViewSize.y;
                int nCount = nXCount * nYCount;
                current_rotation.yaw = (2 * Stuff::Pi * radar_device.m_nMechViewMax) / nCount;
            }
			else
			{
                // end of MechView
				current_rotation.yaw += 0.02f;
            }
			current_rotation.Normalize();
			new_local.BuildRotation(current_rotation);
			element->SetLocalToParent(new_local);
			element->Sync();

            g_pTempReplicators = pOld;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int _stdcall MechLab::ML_CallbackHandler(void* instance, int count, void* data[])
{
	Check_Pointer(MechLab::Instance);

    Stuff::SafeChainOf<Replicator*>* pOld = g_pTempReplicators;
    g_pTempReplicators = &MechLab::Instance->m_TempReplicators;

    int nRet = ML_CallbackHandlerReal(instance, count, data);

    g_pTempReplicators = pOld;

    return nRet;
}

int _stdcall MechLab::ML_CallbackHandlerReal(void* instance, int count, void* data[])
{
	Check_Pointer(MechLab::Instance);

	switch(CALLBACKID)
	{
	case MLGetDummyData:
		return MechLab::Instance->GetDummyData(data, count);
	case MLDataSetupLeftArm:
		return MechLab::Instance->GetLeftArmWeapons(data, count);
	case MLDataSetupRightArm:
		return MechLab::Instance->GetRightArmWeapons(data, count);
	case MLDataSetupLeftLeg:
		return MechLab::Instance->GetLeftLegWeapons(data, count);
	case MLDataSetupRightLeg:
		return MechLab::Instance->GetRightLegWeapons(data, count);
	case MLDataSetupLeftTorso:
		return MechLab::Instance->GetLeftTorsoWeapons(data, count);
	case MLDataSetupRightTorso:
		return MechLab::Instance->GetRightTorsoWeapons(data, count);
	case MLDataSetupCenterTorso:
		return MechLab::Instance->GetCenterTorsoWeapons(data, count);
	case MLDataSetupHead:
		return MechLab::Instance->GetHeadWeapons(data, count);
	case MLDataSetupSpecial1:
		return MechLab::Instance->GetSpecial1Weapons(data, count);
	case MLDataSetupSpecial2:
		return MechLab::Instance->GetSpecial2Weapons(data, count);
	case MLDataSetupMechSelection:
		return MechLab::Instance->GetMechs(data, count);
	case MLDataSetupChassisSelection:
		return MechLab::Instance->GetChassis(data, count);
	case MLCreateNewMech:
		return MechLab::Instance->CreateNewMech(data, count, VARIANTS_PATH);
	case MLSelectNewMech:
		return MechLab::Instance->SelectMech(data, count, VARIANTS_PATH);
	case MLInitChassisTab:
		return MechLab::Instance->InitChassisTab(data, count);
	case MLInitWeaponsTab:
		return MechLab::Instance->InitWeaponsTab(data, count);
	case MLInitArmorTab:
		return MechLab::Instance->InitArmorTab(data, count);
	case MLDataSetupAllWeapons:
		return MechLab::Instance->GetAllWeapons(data, count);
	case MLDataSetupBeamWeapons:
		return MechLab::Instance->GetBeamWeapons(data, count);
	case MLDataSetupProjectileWeapons:
		return MechLab::Instance->GetProjectileWeapons(data, count);
	case MLDataSetupMissileWeapons:
		return MechLab::Instance->GetMissileWeapons(data, count);
	case MLDataSetupGetMechData:
		return MechLab::Instance->GetCurrentMechData(data, count);
	case MLDataSetupGetMechArmor:
		return MechLab::Instance->GetCurrentMechArmorData(data, count);
	case MLAddSubsystem:
		return MechLab::Instance->AddSubsystem(data, count);
	case MLRemoveSubsystem:
		return MechLab::Instance->RemoveSubsystem(data, count);
	case MLRemoveAllSubsystems:
		return MechLab::Instance->RemoveAllSubsystems();
	case MLAutoAddSubsystem:
		return MechLab::Instance->AutoAddSubsystem(data, count);
	case MLDataGetWeaponGroups:
		return MechLab::Instance->GetWeaponGroups(data, count);
	case MLSetWeaponGroup:
		return MechLab::Instance->SetWeaponGroup(data, count);
	case MLClearWeaponGroup:
		return MechLab::Instance->ClearWeaponGroup(data, count);
	case MLSetAllWeaponGroups:
		return MechLab::Instance->SetAllWeaponGroups(data, count);
	case MLSave:
		return MechLab::Instance->SaveMech();
	case MLExit:
		return MechLab::Instance->Exit();
	case MLDeleteMech:
		return MechLab::Instance->DeleteMech();
	case MLRestore:
		return MechLab::Instance->Restore();
	case MLDataSetupGetMechNoEditData:
		return MechLab::Instance->GetCurrentMechNoEditData(data, count);
	case MLDataSetupGetEngineSpeed:
		return MechLab::Instance->GetEngineSpeed(data, count);
	case MLSetEngineUpgrade:
		return MechLab::Instance->UpgradeEngine();
	case MLSetEngineDegrade:
		return MechLab::Instance->DegradeEngine();
	case MLDataSetupGetHeatSinks:
		return MechLab::Instance->GetHeatSinkCount(data, count);
	case MLAddHeatSink:
		return MechLab::Instance->AddHeatSink();
	case MLRemoveHeatSink:
		return MechLab::Instance->RemoveHeatSink();
	case MLGetJumpJets:
		return MechLab::Instance->GetJumpJets(data, count);
	case MLSetJumpJets:
		return MechLab::Instance->SetJumpJets(data, count);
	case MLGetECM:
		return MechLab::Instance->GetECM(data, count);
	case MLSetECM:
		return MechLab::Instance->SetECM(data, count);
	case MLGetBeagle:
		return MechLab::Instance->GetBeagle(data, count);
	case MLSetBeagle:
		return MechLab::Instance->SetBeagle(data, count);
	case MLSetArmorType:
		return MechLab::Instance->SetArmorType(data, count);
	case MLAddArmorToZone:
		return MechLab::Instance->AddArmorZoneValue(data, count);
	case MLRemoveArmorFromZone:
		return MechLab::Instance->RemoveArmorZoneValue(data, count);
	case MLRename:
		return MechLab::Instance->Rename(data, count, VARIANTS_PATH);
	case MLDataGetWeaponAmmo:
		return MechLab::Instance->GetWeaponAmmo(data, count);
	case MLAddWeaponAmmo:
		return MechLab::Instance->AddWeaponAmmo(data, count);
	case MLRemoveWeaponAmmo:
		return MechLab::Instance->RemoveWeaponAmmo(data, count);
	case MLGetSkinListCount:
		return MechLab::Instance->GetSkinListCount(data, count);
	case MLDataGetSkinList:
		return MechLab::Instance->GetSkinList(data, count);
	case MLSetMechSkin:
		return MechLab::Instance->SetMechSkin(data, count);
	case MLGetLightAmp:
		return MechLab::Instance->GetLightAmp(data, count);
	case MLSetLightAmp:
		return MechLab::Instance->SetLightAmp();
	case MLSetArmorZoneValue:
		return MechLab::Instance->SetArmorValue(data, count);
	case MLDistributeArmor:
		return MechLab::Instance->DistributeAllArmor();
	case MLGetAMS:
		return MechLab::Instance->GetAMS(data, count);
	case MLSetAMS:
		return MechLab::Instance->SetAMS();
	case MLGetLAMS:
		return MechLab::Instance->GetLAMS(data, count);
	case MLSetLAMS:
		return MechLab::Instance->SetLAMS();
	case MLGetBaseMechName:
		return MechLab::Instance->GetBaseMechName(data, count);
// MSL 5.02 SubSystems
//	case MLGetEnhancedOptics:
//		return MechLab::Instance->GetEnhancedOptics(data, count);
//	case MLSetEnhancedOptics:
//		return MechLab::Instance->SetEnhancedOptics();
	case MLGetIFF_Jammer:
		return MechLab::Instance->GetIFF_Jammer(data, count);
	case MLSetIFF_Jammer:
		return MechLab::Instance->SetIFF_Jammer();
	case MLGetAdvancedGyro:
		return MechLab::Instance->GetAdvancedGyro(data, count);
	case MLSetAdvancedGyro:
		return MechLab::Instance->SetAdvancedGyro();

	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetLeftArmWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::LeftArmZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetRightArmWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::RightArmZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetLeftLegWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::LeftLegZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetRightLegWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::RightLegZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetLeftTorsoWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::LeftTorsoZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetRightTorsoWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::RightTorsoZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetCenterTorsoWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::CenterTorsoZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetHeadWeapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::HeadZone, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetSpecial1Weapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::SpecialZone1, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetSpecial2Weapons(void* data[], int count)
{
	return FillPartWeaponData(InternalDamageObject::SpecialZone2, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::FillPartWeaponData(int part_id, void *data[])
{
	if(GetWorkingMech() == NULL)
		return -1;

	//char **name_array
	int *id_array = INTARRAYPARAM(1);
	int *weapon_id_array = INTARRAYPARAM(2);
	int *slot_array = INTARRAYPARAM(3);
	int *slot_size_array = INTARRAYPARAM(4);
	Scalar *tonage_array = SCALARARRAYPARAM(5);
	Scalar *damage_array = SCALARARRAYPARAM(6);
	Scalar *range_array = SCALARARRAYPARAM(7);
	Scalar *heat_array = SCALARARRAYPARAM(8);
	Scalar *recycle_array = SCALARARRAYPARAM(9);
	int *num_weapons = INTARRAYPARAM(10);
	#if defined(_ARMOR)
		int array_size = VALUEPARM(11);
	#endif

	MWInternalDamageObject *part = 
	m_workingMech->internalDamageObjects.Find(part_id);

	if(!part)
	{
		*num_weapons = 0;
		return -1;
	}

	Check_Object(part);

	ChainIteratorOf<Subsystem *> iterator(&part->subsystemChain);
	Subsystem *subsystem;
	int weapon_count = 0;
	int valid_weapon_id = 0;

	for(int i=MWInternalDamageObject::MissileSlotType; i<=MWInternalDamageObject::OmniSlotType; i++)
	{
		valid_weapon_id = 0;
		iterator.First();
		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);
			
			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				Weapon *weapon;
				Verify(weapon_count < array_size);
				weapon = Cast_Object(Weapon *, subsystem);
				if(weapon->containedInSlotType == i)
				{
					const Weapon::GameModel *weapon_model = weapon->GetGameModel();
					id_array[weapon_count] = weapon_model->itemID;
					slot_array[weapon_count] = weapon_model->slotType;
					slot_size_array[weapon_count] = weapon_model->totalSlotsTaken;
					tonage_array[weapon_count] = weapon_model->tonage;
					damage_array[weapon_count] = weapon_model->damageAmount * weapon_model->numFire;
					if(weapon_model->itemID == W_ArtilleryStrike)
						damage_array[weapon_count] = 40.0f;
					range_array[weapon_count] = weapon_model->maxDistance;
					heat_array[weapon_count] = weapon_model->heat * 2.0f;
					weapon_id_array[weapon_count] = valid_weapon_id;
					recycle_array[weapon_count] = weapon_model->reloadTime;
					weapon_count++;
				}
				valid_weapon_id++;
			}
		}
		
		//Now we need to check to see if we have anything empty in that slot type
		int slots_available = 0;
		switch(i)
		{
		case MWInternalDamageObject::MissileSlotType:
			slots_available = part->GetMissileSlotsAvailable();
			break;
		case MWInternalDamageObject::ProjectileSlotType:
			slots_available = part->GetProjectileSlotsAvailable();
			break;
		case MWInternalDamageObject::BeamSlotType:
			slots_available = part->GetBeamSlotsAvailable();
			break;
		case MWInternalDamageObject::OmniSlotType:
			slots_available = part->GetOmniSlotsAvailable();
			break;
		}
		
		if(slots_available > 0)
		{
			id_array[weapon_count] = EmptyWeaponID;
			slot_array[weapon_count] = i;
			slot_size_array[weapon_count] = slots_available;
			tonage_array[weapon_count] = -1;
			damage_array[weapon_count] = -1;
			range_array[weapon_count] = -1;
			heat_array[weapon_count] = -1;
			weapon_count++;
		}
	}
	*num_weapons = weapon_count;
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetAllWeapons(void *data[], int count)
{
	return FillWeaponListData(AllWeapons, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetBeamWeapons(void *data[], int count)
{
	return FillWeaponListData(BeamWeapons, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetProjectileWeapons(void *data[], int count)
{
	return FillWeaponListData(ProjectileWeapons, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetMissileWeapons(void *data[], int count)
{
	return FillWeaponListData(MissileWeapons, data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::FillWeaponListData(int weapon_list, void *data[])
{
	//char **name_array
	int *id_array = INTARRAYPARAM(1);
	int *slot_array = INTARRAYPARAM(2);
	int *slot_size_array = INTARRAYPARAM(3);
	Scalar *tonage_array = SCALARARRAYPARAM(4);
	Scalar *damage_array = SCALARARRAYPARAM(5);
	Scalar *range_array = SCALARARRAYPARAM(6);
	Scalar *heat_array = SCALARARRAYPARAM(7);
	Scalar *recycle_array = SCALARARRAYPARAM(8);
	int *inventory_array = INTARRAYPARAM(9);
	int *num_weapons = INTARRAYPARAM(10);
	#if defined(_ARMOR)
		int array_size = VALUEPARM(11);
	#endif

	int weapon_count = 0;
	
	SubsystemResource *sub_resource;
	SortedChainIteratorOf<SubsystemResource *, int> iterator(&m_subsystemsAvailable);

	int low_range = FirstWeaponID;
	int high_range = LastWeaponID;

	switch (weapon_list)
	{
	case MissileWeapons:
		low_range = FirstMissileID;
		high_range = LastMissileID;
		break;
	case ProjectileWeapons:
		low_range = FirstProjectileID;
		high_range = LastProjectileID;
		break;
	case BeamWeapons:
		low_range = FirstBeamID;
		high_range = LastBeamID;
		break;
	}
	
	while((sub_resource = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(sub_resource);
		if((sub_resource->GetSubsystemType() >= low_range) &&
			(sub_resource->GetSubsystemType() <= high_range) &&
			(sub_resource->GetNumberAvailable() != 0))
		{
			Resource model_resource(sub_resource->GetGameModelID());
			Verify(model_resource.DoesResourceExist());

			Weapon::GameModel *weapon_model = 
				Cast_Pointer(Weapon::GameModel *, model_resource.GetPointer());

			Verify(weapon_count < array_size);
			id_array[weapon_count] = weapon_model->itemID;
			slot_array[weapon_count] = weapon_model->slotType;
			slot_size_array[weapon_count] = weapon_model->totalSlotsTaken;
			tonage_array[weapon_count] = weapon_model->tonage;
			damage_array[weapon_count] = weapon_model->damageAmount * weapon_model->numFire;
			if(weapon_model->itemID == W_ArtilleryStrike)
				damage_array[weapon_count] = 40.0f;
			range_array[weapon_count] = weapon_model->maxDistance;
			heat_array[weapon_count] = weapon_model->heat * 2.0f;
			recycle_array[weapon_count] = weapon_model->reloadTime;
			inventory_array[weapon_count] = sub_resource->GetNumberAvailable();
			weapon_count++;		
		}
	}

	*num_weapons = weapon_count;
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetCurrentMechData(void *data[], int count)
{
	if(GetWorkingMech())
	{
		int *id = INTARRAYPARAM(1);
		Scalar *ton = SCALARARRAYPARAM(2);
		Scalar *max_ton = SCALARARRAYPARAM(3);
		int *battle_value = INTARRAYPARAM(4);
		int *heat_effic = INTARRAYPARAM(5);
		int *speed_bar = INTARRAYPARAM(6);
		int *armor_bar = INTARRAYPARAM(7);
		
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*id = mech_model->mechID;
		*ton = m_workingMech->GetTonage();
		*max_ton = mech_model->maxVehicleTonnage;

// MSL 5.04 Modified Firepower bar
//		*battle_value =  (int)(m_workingMech->GetBattleValue());
//		*battle_value =  (int)(m_workingMech->GetBattleValue() / 4);
		*battle_value =  (int)(((m_workingMech->GetBattleValue()) / 80.0) * 100.0);
		Clamp(*battle_value, 0, 100);

// MSL 5.04 Modified Speed bar
		Engine *engine = m_workingMech->GetEngine();
		Check_Object(engine);
		Verify(mech_model->maxSpeed > mech_model->minMaxSpeed);
//		Scalar speed_ratio = (engine->GetMaxSpeed()- mech_model->minMaxSpeed) / (mech_model->maxSpeed - mech_model->minMaxSpeed);
		Scalar speed_ratio = (engine->GetMaxSpeed() / mech_model->maxSpeed);
		*speed_bar = (int)(speed_ratio * 100);
		Clamp(*speed_bar, 0, 100);

// MSL 5.04 Modified Armor bar
		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);
//		*armor_bar = (int)armor->GetTotalTonage() * 5;
//		Clamp(*armor_bar, 0, 100);
//		*armor_bar = (int)((armor->GetTotalArmor() / 307.0) * 100.0);
// MSL 5.05 Mofified Armor bar
		*armor_bar = (int)((armor->GetTotalArmor() / 535.0) * 100.0);
		Clamp(*armor_bar, 0, 100);

		*heat_effic = m_workingMech->GetHeatEffic();
#if 0
		int num_weapons = m_workingMech->weaponChain.GetSize();
		int num_heat_sinks = m_workingMech->m_numHeatSinks + engine_model->m_numHeatSinks;

		if(num_weapons > 0)
				*heat_effic = (int)(num_heat_sinks / (num_weapons * 2.5f));
		else
			*heat_effic = 0;
#endif
		Clamp(*heat_effic, 0, 100);
	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetCurrentMechNoEditData(void *data[], int count)
{
	if(GetWorkingMech())
	{
		Scalar *accel = SCALARARRAYPARAM(1);
		Scalar *deaccel = SCALARARRAYPARAM(2);
		Scalar *turn_rate = SCALARARRAYPARAM(3);
		Scalar *twist = SCALARARRAYPARAM(4);
		Scalar *twist_speed = SCALARARRAYPARAM(5);
		int *tech_type = INTARRAYPARAM(6);

		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*accel = mech_model->acceleration;
		*deaccel = mech_model->decceleration;
		*turn_rate = mech_model->topSpeedTurnRate;
		const Torso::GameModel *torso_model = m_workingMech->GetTorso()->GetGameModel();
		*twist = torso_model->twistRadius * Degrees_Per_Radian;
		*twist_speed = torso_model->twistSpeed * Degrees_Per_Radian;
		*tech_type = mech_model->techType;

	}
	return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetCurrentMechArmorData(void *data[], int count)
{

	if(GetWorkingMech())
	{
		Scalar *armor_array = SCALARARRAYPARAM(1);
		int *armor_max_array = INTARRAYPARAM(2);
		Scalar *tonnage_array = SCALARARRAYPARAM(3);
		int *armor_type = INTARRAYPARAM(4);
		int *internal_type = INTARRAYPARAM(5);
		int *points_per = INTARRAYPARAM(6);
		Scalar *tons = SCALARARRAYPARAM(7);
		int *total_armor = INTARRAYPARAM(8);

		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);

		const Armor::GameModel *armor_model = armor->GetGameModel();
		switch(armor->GetArmorType())
		{
// MSL 5.00 Armor
		case Armor::StandardArmor:
			{
				*points_per = armor_model->m_pointsPerStandardTon;
				break;
			}
		case Armor::FerroFiberusArmor:
			{
				*points_per = armor_model->m_pointsPerFerroTon;
				break;
			}
		case Armor::ReactiveArmor:
			{
				*points_per = armor_model->m_pointsPerReactiveTon;
				break;
			}
		case Armor::ReflectiveArmor:
			{
				*points_per = armor_model->m_pointsPerReflectiveTon;
				break;
			}
		case Armor::SolarianArmor:
			{
				*points_per = armor_model->m_pointsPerSolarianTon;
				break;
			}
		}

		for(int i=0; i<=A_Head; i++)
		{
			armor_array[i] = armor->GetArmorValue(i);
			tonnage_array[i] = armor_array[i] / *points_per;
		}
		for(i=0; i<= A_Head; i++)
		{
			DamageObject *armor_zone = m_workingMech->damageObjects.Find(i);
			Check_Object(armor_zone);
			armor_max_array[i] = (int)armor_zone->maxArmorValue;
		}

		*armor_type = armor->GetArmorType();
		*internal_type = armor->GetInternalType();
		

		*tons = armor->GetTotalTonage();
		*total_armor = armor->GetTotalArmor();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetArmorType(void *data[], int count)
{
	int *new_type = INTARRAYPARAM(1);

	if(GetWorkingMech())
	{
		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);

		armor->SetArmorType(*new_type);
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::AddArmorZoneValue(void *data[], int count)
{
	int *new_type = INTARRAYPARAM(1);

	if(GetWorkingMech())
	{
		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);

		armor->ApplyZoneBasedArmor(*new_type, 0.1f);
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::RemoveArmorZoneValue(void *data[], int count)
{
	int *new_type = INTARRAYPARAM(1);

	if(GetWorkingMech())
	{
		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);

		armor->ApplyZoneBasedArmor(*new_type, -0.1f);
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetArmorValue(void *data[], int count)
{
	int *zone = INTARRAYPARAM(1);
	Scalar *new_amount = SCALARARRAYPARAM(2);

	if(GetWorkingMech())
	{
		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);

		armor->SetZoneBasedArmor(*zone, *new_amount);
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::DistributeAllArmor()
{
	if(GetWorkingMech())
	{
		Armor *armor = m_workingMech->GetArmor();
		Check_Object(armor);

		return armor->ApplyDistributiveArmor();
	}

	return 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetMechs(void* data[], int count)
{
	Check_Pointer(this);

	char **name_array = STRARRAYPARAM(1);
	int *selected_mech = INTARRAYPARAM(2);

	*selected_mech = 0;

	if(m_mechLabCount == 0)
	{
		return 1;
	}

	if(m_mechIDs)
	{
		gos_Free(m_mechIDs);
		m_mechIDs = NULL;
	}
	m_mechIDs = (ResourceID *)gos_Malloc(m_mechLabCount * sizeof(ResourceID));

	SortedChainOf<PlugOf<MString>*, MString> alpha_mech_names(NULL, true);
	MString* alpha_mech_names_with_mc = new MString[m_mechLabCount];

	Stuff::MString mechs_path = VARIANTS_PATH"*.mw4";
	Stuff::Directory *resource_directory;
	resource_directory = new Stuff::Directory(mechs_path, true);
	Check_Object(resource_directory);
	const char *file_name;
	while((file_name = resource_directory->GetCurrentFileName()) != NULL)
	{
		MString mech_name;
		mech_name = file_name;
		mech_name.StripDirectory().StripExtension();

		PlugOf<MString> *name_plug = new PlugOf<MString>(mech_name);
		alpha_mech_names.AddValue(name_plug, mech_name);

		resource_directory->AdvanceCurrentFile();
	}
	
	// Sort Mad Cat correctly
	SortedChainIteratorOf<PlugOf<MString> *, MString> mech_name_iterator(&alpha_mech_names);
	PlugOf<MString> *mstring_plug;
	int mech_index = 0;
	while((mstring_plug = mech_name_iterator.ReadAndNext()) != NULL)
	{
		if (mech_index == m_mechLabCount)
			break;	// Boundary Check

		alpha_mech_names_with_mc[mech_index] = mstring_plug->GetItem();
		mech_index ++;
	}
	int mc2_start = 0;
	while (_strnicmp(alpha_mech_names_with_mc[mc2_start], "Mad Cat MKII", 12) != 0)
	{
		mc2_start++;
		
		if (mc2_start == m_mechLabCount)
			break;	// Boundary Check
	}
	int mc2_end = mc2_start;
	if (mc2_start < m_mechLabCount)
	{
		while (_strnicmp(alpha_mech_names_with_mc[mc2_end], "Mad Cat MKII", 12) == 0)
		{
			mc2_end++;
			
			if (mc2_end == m_mechLabCount)
				break;	// Boundary Check
		}
	}
	int mc_end = mc2_end;
	if (mc_end < m_mechLabCount)
	{
		while (_strnicmp(alpha_mech_names_with_mc[mc_end], "Mad Cat", 7) == 0)
		{
			mc_end++;

			if (mc_end == m_mechLabCount)
				break;	// Boundary Check
		}
	}
	int mc2_i = mc2_end - mc2_start;
	int mc_i = mc_end - mc2_end;
	if ((mc2_i > 0) && (mc_i > 0))
	{
		MString* mc2_string = new MString[mc2_i];
		for (int i = 0; i < mc2_i; i++)
			mc2_string[i] = alpha_mech_names_with_mc[mc2_start + i];
		for (i = 0; i < mc_i; i++)
			alpha_mech_names_with_mc[mc2_start + i] = alpha_mech_names_with_mc[mc2_end + i];
		for (i = 0; i < mc2_i; i++)
			alpha_mech_names_with_mc[mc2_start + mc_i + i] = mc2_string[i];
		delete [] mc2_string;
	}

	// now return the sorted strings
	mech_index = 0;
	while (mech_index < m_mechLabCount)
	{
		MString mech_name = alpha_mech_names_with_mc[mech_index];
		FREEANDNULL(name_array[mech_index]);
		name_array[mech_index] = (char *)gos_Malloc(128);
		Str_Copy(
			name_array[mech_index],
			(const char *)mech_name,
			mech_name.GetLength() + 1
		);
		if(m_workingMechName)
		{
			MString compare_name = m_workingMechName;
			compare_name.StripDirectory();
			if(compare_name == mech_name)
				*selected_mech = mech_index;
		}

		m_mechIDs[mech_index] = ResourceID::Null;
		mech_index++;
	}

	alpha_mech_names.DeletePlugs();
	delete [] alpha_mech_names_with_mc;
	delete resource_directory;
	return 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetChassis(void* data[], int count)
{
	Check_Pointer(this);

	char **name_array = STRARRAYPARAM(1);

	if(m_chassisIDs)
	{
		gos_Free(m_chassisIDs);
		m_chassisIDs = NULL;
	}
	m_chassisIDs = (ResourceID *)gos_Malloc(m_chassisCount * sizeof(ResourceID));

	int i = 0;

	MWTable::TableIterator *mech_iterator;
	Check_Object(MWApplication::GetInstance()->m_mechTable);

	mech_iterator = MWApplication::GetInstance()->m_mechTable->MakeTableIterator();
	MWTableEntry *mech_entry;
	while((mech_entry = mech_iterator->ReadAndNext()) != NULL)
	{
		Check_Object(mech_entry);
		
		FREEANDNULL(name_array[i]);
		name_array[i] = (char *)gos_Malloc(128);
		Str_Copy(
			name_array[i], 
			(const char *)mech_entry->GetEntryName(), 
			mech_entry->GetEntryName().GetLength() + 1
		); 
		m_chassisIDs[i] = mech_entry->GetEntryResourceID();
		i++;
	}
	
	delete mech_iterator;
	return 1;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetMechCount()
{
	Check_Pointer(this);

	int i = 0;
	Stuff::MString mechs_path = VARIANTS_PATH"*.mw4";
	Stuff::Directory *resource_directory;
	resource_directory = new Stuff::Directory(mechs_path, true);
	Check_Object(resource_directory);
	i += resource_directory->fileWalker->GetSize();
	delete resource_directory;

	return i;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetChassisCount()
{
	Check_Pointer(this);

	int i = 0;

	Check_Object(MWApplication::GetInstance()->m_mechTable);
	i += MWApplication::GetInstance()->m_mechTable->GetTableSize();

	return i;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetMech(int mech_id, const char *mech_name, const char *path)
{
	//For right now we are going to just create a known mech
	ResourceID mech_resource_id = m_mechIDs[mech_id];

	return SetMech(mech_resource_id, mech_name, path);
}

int MechLab::SetMech(ResourceID mech_resource_id, const char *mech_name, const char *path)
{
	Entity *entity;

    Stuff::SafeChainOf<Replicator*>* pOld = g_pTempReplicators;
    g_pTempReplicators = &MechLab::Instance->m_TempReplicators;

	DestroyWorkingEntity();

	if(mech_resource_id == ResourceID::Null)
	{	

		//
		//-----------------------------------------------------------------
		//This means that we have a user made mech in its own resource file
		//-----------------------------------------------------------------
		//
		MString path_name = path;
		path_name += mech_name;
		MString res_name = path_name;
		m_workingMechName = res_name;
		res_name += ".mw4";
		Check_Object(ResourceManager::Instance);
		if(m_mechResourceFile.GetCurrent())
		{
			m_mechResourceFile.GetCurrent()->Save();
			delete m_mechResourceFile.GetCurrent();
			m_mechResourceFile.Remove();
		}
		ResourceFile *res_file;
		res_file = ResourceManager::Instance->OpenResourceFile(
			res_name,
			NULL,
			MechResourceFileID,
			VER_CONTENTVERSION,
			false,
			false
		);
		Check_Object(res_file);
		m_mechResourceFile.Add(res_file);
		
		ResourceID mech_id(MechResourceFileID, 1);
		Resource mech_resource(mech_id);
		Verify(mech_resource.DoesResourceExist());
		
		
// MSL 5.03 MechView
		ReplicatorID base_id(CONN4ML->GetNextReplicatorID());
		entity = Entity::CreateEntity(&mech_resource, &base_id);
	}
	else
	{
		Resource mech_resource(mech_resource_id);
		Verify(mech_resource.DoesResourceExist());
// MSL 5.03 MechView
		ReplicatorID base_id(CONN4ML->GetNextReplicatorID());
		entity = Entity::CreateEntity(&mech_resource, &base_id);
	}
	Check_Object(entity);
	SetUpWorkingMech(entity);


	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Init();

	if(!m_isCampaign)
	{
		app->m_lastMechID = -1;
		app->m_lastMechName = mech_name;
	}

    g_pTempReplicators = pOld;


	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::CreateNewMech(void *data[], int count, const char *path)
{
	Check_Pointer(this);

	const char *chassis_name = STRPARM(1);
	int chassis_index = INTPARM(2);
	const char *mech_name = STRPARM(3);
	int overwrite = INTPARM(4);

	if(!MWApplication::ValidateName((char*)mech_name, true))
		return -1;

	Verify(chassis_index >= 0);
	Verify(chassis_index < m_chassisCount);
	ResourceID chassis_resource_id = m_chassisIDs[chassis_index];
	Resource chassis_resource(chassis_resource_id);
	Verify(chassis_resource.DoesResourceExist());
	MString path_name = path;
	path_name += chassis_name;
	path_name += " ";
	path_name += mech_name;
	MString res_name = path_name;
	m_workingMechName = res_name;
	res_name += ".mw4";
	if (!gos_DoesFileExist(VARIANTS_PATH))
		gos_CreateDirectory(VARIANTS_PATH);

	if(gos_DoesFileExist(res_name) && !overwrite)
		return E_MechAlreadyExists;

	//Parameter [1] is the new mech name
	//Parameter [2] is the new mech chassis ID
	if(m_mechResourceFile.GetCurrent())
	{
		m_mechResourceFile.GetCurrent()->Save();
		delete m_mechResourceFile.GetCurrent();
		m_mechResourceFile.Remove();
	}

	if(!MWApplication::ValidatePath(res_name, true))
		return -1;

	Check_Object(ResourceManager::Instance);
	ResourceFile *res_file;
	res_file = ResourceManager::Instance->OpenResourceFile(
		res_name,
		NULL,
		MechResourceFileID,
		VER_CONTENTVERSION,
		false,
		true
	);
	Check_Object(res_file);
	m_mechResourceFile.Add(res_file);
// MSL 5.03 MechView
	ReplicatorID base_id(CONN4ML->GetNextReplicatorID());

	DestroyWorkingEntity();

	Entity *template_entity = Entity::CreateEntity(&chassis_resource, &base_id);
	Check_Object(template_entity);


	//We need to write in a dep resource and a texture hint file resource
	//The we can write this resource in....
	Resource dep_resource(m_workingMechName, m_mechResourceFile.GetCurrent());
	DynamicMemoryStream dep_stream;
	MString dep = "";
	dep_stream << dep;
	dep_resource.Save(&dep_stream, NULL);
	
	Resource mech_resource("{Mech}", m_mechResourceFile.GetCurrent());
	mech_resource.Save(NULL, NULL);

	DynamicMemoryStream game_stream;
	Check_Object(template_entity);

	template_entity->SaveMakeMessage(&game_stream, m_mechResourceFile.GetCurrent());

	game_stream.Rewind();
	Stuff::FileDependencies dependancies;
	dependancies.AddDependency("");
	mech_resource.Save(&game_stream, &dependancies);

	template_entity->Destroy();

// MSL 5.03 MechView
	base_id = CONN4ML->GetNextReplicatorID();
	
	Entity *entity = Entity::CreateEntity(&mech_resource, &base_id);
	Check_Object(entity);
	SetUpWorkingMech(entity);



	// mark the mech to detect hex editing
	{

		Resource crc_resource("icuedbdii", m_mechResourceFile.GetCurrent());
		crc_resource.Save(NULL, NULL);

	}


	ResourceID crc_id(MechResourceFileID, 3);
	Resource crc_resource(crc_id);

	MD5_CTX resource_context;
	GUID resource_hash;
	unsigned char * buff=(unsigned char *) &resource_hash;

	MD5Init(&resource_context);
	int key = 0xa1252388;
	mech_resource.Rewind();
	MD5Update(&resource_context, (unsigned char *) &key, 4);
	MD5Update(&resource_context, (unsigned char *) mech_resource.GetPointer(), mech_resource.GetBytesRemaining());
	
	MD5Final(buff, &resource_context);

	DynamicMemoryStream hash_stream;
	hash_stream.WriteBytes(&resource_hash,16);
	hash_stream.Rewind();

	crc_resource.Save(&hash_stream, &dependancies);



	m_mechResourceFile.GetCurrent()->Save();
	m_mechLabCount = GetMechCount();


	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Init();

	if(!m_isCampaign)
	{
		app->m_lastMechID = -1;
		app->m_lastMechName = MString(chassis_name)+" "+mech_name;
	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::SetUpWorkingMech(Entity *entity)
{
	Check_Pointer(this);
	Check_Object(entity);
	Check_Object(s_MechCamera);
	//Verify(entity->IsDerivedFrom(Mech::DefaultData));//jcem camera-ship could be setted for loading time

	s_MechCamera->SetScene(NULL);
	DestroyWorkingEntity();
    if (entity->IsDerivedFrom(Mech::DefaultData))
	{
		m_workingMech = Cast_Object(Mech *, entity);
		extern char g_SkinSet;
		g_SkinSet = m_workingMech->GetSkinPrefix();
		extern int g_PilotDecal;
		g_PilotDecal = m_workingMech->GetPilotDecal();
		extern int g_TeamDecal;
		g_TeamDecal = m_workingMech->GetTeamDecal();
    }
    m_workingEntity = entity;
	ElementRenderer::Element *mech_element = m_workingEntity/*m_workingMech*/->GetElement();
	Check_Object(mech_element);
	Check_Object(m_sceneRoot);
	m_sceneRoot->AttachChild(mech_element);
	Check_Object(VideoRenderer::Instance);	
	ChainIteratorOf<Entity*> children(&m_workingEntity/*m_workingMech*/->childEntityChain);
	Entity *child_entity;
	while ((child_entity = children.ReadAndNext()) != NULL)
	{
		Check_Object(child_entity);
		if(child_entity->IsDerivedFrom(MWMover::DefaultData))
		{
			MWMover *mover = Cast_Object(MWMover *, child_entity);
			MakeMoverInteresting(mover);
		}
	}
	Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
	MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
	s_MechCamera->SetScene(mech_element);
	Stuff::LinearMatrix4D origin = LinearMatrix4D::Identity;
	origin.BuildRotation(Stuff::YawPitchRoll(-Pi + 0.1f, 0.0, Pi));

	MWApplication* app = MWApplication::GetInstance ();
// MSL 5.03 Mechview
    if (g_pfnCTCL_AfterBeginScene == CTCL_AfterBeginScene)
	{
        origin.BuildTranslation(Stuff::Point3D(0.0f, 6.0f, 45.0f)); // MechView Param - relative look position
    }
	else
	{
		if (app->GetApplicationState() == ApplicationStateEngine::LoadingGameState)
		{
			// jcem - if single campaign, centering mech...
//			origin.BuildTranslation(Stuff::Point3D(0.0f, 6.0f, 23.0f));
			origin.BuildTranslation(Stuff::Point3D(0.0f, 6.0f, 30.0f)); // This affects Secondary View Size
		}
		else
		{
			origin.BuildTranslation(Stuff::Point3D(0.0f, 6.0f, 23.0f));
	    }
	}
	mech_element->SetLocalToParent(origin);
	mech_element->Sync();
	s_MechCamera->Sync();
	m_sceneRoot->SetRootMode();
	m_sceneRoot->Sync();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::MakeMoverInteresting(MWMover *mover)
{
	Check_Pointer(this);
	Check_Object(mover);

	ChainIteratorOf<Entity*> children(&mover->childEntityChain);
	Entity *child_entity;
	while ((child_entity = children.ReadAndNext()) != NULL)
	{
		Check_Object(child_entity);
		MakeInteresting(child_entity);
	}

	VideoRenderer::Instance->EntityIsInteresting(mover, true);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::MakeInteresting(Entity *entity)
{
	Check_Pointer(this);
	Check_Object(entity);

	ChainIteratorOf<Entity*> children(&entity->childEntityChain);
	Entity *child_entity;
	while ((child_entity = children.ReadAndNext()) != NULL)
	{
		Check_Object(child_entity);
		MakeInteresting(child_entity);
	}

	VideoRenderer::Instance->EntityIsInteresting(entity, true);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::MakeMoverUnInteresting(MWMover *mover)
{
	Check_Pointer(this);
	Check_Object(mover);

	ChainIteratorOf<Entity*> children(&mover->childEntityChain);
	Entity *child_entity;
	while ((child_entity = children.ReadAndNext()) != NULL)
	{
		Check_Object(child_entity);
		MakeUnInteresting(child_entity);
	}

	//This is a hack to force a re-load of the web
	RendererComponentWeb *web = mover->GetComponentWeb(RendererManager::VideoRendererType);
	if(web)
		mover->SetComponentWeb(RendererManager::VideoRendererType, NULL);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechLab::MakeUnInteresting(Entity *entity)
{
	Check_Pointer(this);
	Check_Object(entity);

	ChainIteratorOf<Entity*> children(&entity->childEntityChain);
	Entity *child_entity;
	while ((child_entity = children.ReadAndNext()) != NULL)
	{
		Check_Object(child_entity);
		MakeUnInteresting(child_entity);
	}

	RendererComponentWeb *web = entity->GetComponentWeb(RendererManager::VideoRendererType);
	if(web)
		entity->SetComponentWeb(RendererManager::VideoRendererType, NULL);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::SelectMech(void *data[], int count, const char *path)
{
	Check_Pointer(this);

	//Parameter 1 is the mech's id in the mech array
	int mech_index = INTPARM(1);
	const char *mech_name = STRPARM(2);
	Verify(mech_index >= 0);
	Verify(mech_index < m_mechLabCount);

	return SetMech(mech_index, mech_name, path);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::UpdateDisplay()
{
		
	if(s_MechCamera)
	{
		s_MechCamera->DrawScene(true);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::InitChassisTab(void *data[], int count)
{
	Check_Pointer(this);
	m_mode = ChassisTabMode;

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::InitWeaponsTab(void *data[], int count)
{
	Check_Pointer(this);
	m_mode = WeaponsTabMode;
	if(GetWorkingMech())
	{
		ElementRenderer::Element *mech_element = m_workingMech->GetElement();
		Stuff::LinearMatrix4D origin = LinearMatrix4D::Identity;
		origin.BuildRotation(Stuff::YawPitchRoll(-Pi + 0.1f, 0.0, Pi));
		origin.BuildTranslation(Stuff::Point3D(5.5f, 6.0f, 23.0f));
		mech_element->SetLocalToParent(origin);
		mech_element->Sync();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::InitArmorTab(void *data[], int count)
{
	Check_Pointer(this);
	m_mode = ArmorTabMode;
	if(GetWorkingMech())
	{
		ElementRenderer::Element *mech_element = m_workingMech->GetElement();
		Stuff::LinearMatrix4D origin = LinearMatrix4D::Identity;
		origin.BuildRotation(Stuff::YawPitchRoll(-Pi + 0.1f, 0.0, Pi));
		origin.BuildTranslation(Stuff::Point3D(5.5f, 6.0f, 23.0f));
		mech_element->SetLocalToParent(origin);
		mech_element->Sync();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::InitializeSubsystemsAvailable()
{

	MWTable::TableIterator *weapon_iterator;
	Check_Object(MWApplication::GetInstance()->m_weaponsTable);

	weapon_iterator = MWApplication::GetInstance()->m_weaponsTable->MakeTableIterator();
	MWTableEntry *weapon_entry;
	while((weapon_entry = weapon_iterator->ReadAndNext()) != NULL)
	{
		Check_Object(weapon_entry);
		Resource model_resource;
		Entity::GetGameModelResourceFromDataListID(&model_resource, weapon_entry->GetEntryResourceID());
		Verify(model_resource.DoesResourceExist());
		Weapon::GameModel *weapon_model = 
			Cast_Pointer(Weapon::GameModel *, model_resource.GetPointer());
		SubsystemResource *sub_resource;
		sub_resource = AddAvailableSubsystem(
			weapon_entry->GetEntryResourceID(), 
			model_resource.GetResourceID(), 
			weapon_model->itemID
		);
		Check_Object(sub_resource);
		sub_resource->SetUnlimited();
	}
	MWTable::TableIterator *sub_iterator;
	Check_Object(MWApplication::GetInstance()->m_subsystemTable);

	sub_iterator = MWApplication::GetInstance()->m_subsystemTable->MakeTableIterator();
	MWTableEntry *sub_entry;
	while((sub_entry = sub_iterator->ReadAndNext()) != NULL)
	{
		Check_Object(sub_entry);
		Resource model_resource;
		Entity::GetGameModelResourceFromDataListID(&model_resource, sub_entry->GetEntryResourceID());
		Verify(model_resource.DoesResourceExist());
		Subsystem::GameModel *sub_model = 
			Cast_Pointer(Subsystem::GameModel *, model_resource.GetPointer());
		SubsystemResource *sub_resource;
		sub_resource = AddAvailableSubsystem(
			sub_entry->GetEntryResourceID(), 
			model_resource.GetResourceID(), 
			sub_model->itemID
		);
		Check_Object(sub_resource);
		sub_resource->SetUnlimited();
	}

	delete weapon_iterator;
	delete sub_iterator;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SubsystemResource*
	MechLab::AddAvailableSubsystem(const Adept::ResourceID& data_list, const Adept::ResourceID& model_id, int type)
{
	SubsystemResource *sub_resource = m_subsystemsAvailable.Find(type);
	if(sub_resource) //Just add another available
	{
		if(sub_resource->GetNumberAvailable() != -1) //if not unlimmited
			sub_resource->AddNumberAvailable();
	}
	else
	{
		sub_resource = new SubsystemResource(data_list, model_id, type);
		Check_Object(sub_resource);
		m_subsystemsAvailable.AddValue(sub_resource, type);
	}

	return sub_resource;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SubsystemResource*
	MechLab::AddAvailableSubsystem(Subsystem *subsystem)
{
	ResourceID data_list;
	ResourceID model_id;
	int type;

	data_list = subsystem->GetDataListResourceID();
	model_id = subsystem->GetGameModelResourceID();
	const Subsystem::GameModel *model = subsystem->GetGameModel();
	Check_Object(model);
	type = model->itemID;

	return AddAvailableSubsystem(data_list, model_id, type);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::RemoveAvailableSubsystem(int type)
{
	SubsystemResource *sub_resource = m_subsystemsAvailable.Find(type);
	if(sub_resource)
	{
		if(sub_resource->GetNumberAvailable() >= 1)
		{
			sub_resource->RemoveNumberAvailable();
		}
		else if(sub_resource->GetNumberAvailable() != -1) //Check to see if we are unlimited
		{
			delete sub_resource;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MechLab::DoesHaveAvailableSubsystem(int type)
{
	if(m_subsystemsAvailable.Find(type))
		return true;

	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::AddSubsystem(void *data[], int count)
{
	int *sub_type = INTARRAYPARAM(1);
	int *zone = INTARRAYPARAM(2);
	int *error = INTARRAYPARAM(3);

	AddSubsystemToMech(sub_type, zone, error);

	return *error;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::AddSubsystemToMech(int *sub_type, int *zone, int *error)
{
	*error = 1;

	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		SubsystemResource *sub_resource = m_subsystemsAvailable.Find(*sub_type);
		if(sub_resource)
		{
			Check_Object(sub_resource);
			RegisteredClass::ClassID class_id = Entity::GetClassIDFromDataListID(sub_resource->GetDataListID());
			Subsystem::ClassData *class_data =
				Cast_Pointer(Subsystem::ClassData*, RegisteredClass::FindClassData(class_id));
			Check_Object(class_data);
			DynamicMemoryStream stream;
			(*class_data->streamCreate)(sub_resource->GetDataListID(), &stream);
// MSL 5.03 MechView
			ReplicatorID base_id(CONN4ML->GetNextReplicatorID());
			
			Subsystem__CreateMessage *create_message = 
				Cast_Pointer(Subsystem__CreateMessage *, stream.GetPointer());
			create_message->locationID = (char)*zone;

			Subsystem *subsystem = 
				Cast_Object(Subsystem *, Entity::CreateEntity(&stream, &base_id));
			Check_Object(subsystem);

			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				Weapon *weapon = Cast_Object(Weapon *, subsystem);
				MWInternalDamageObject *zone_object = m_workingMech->internalDamageObjects.Find(*zone);
				Check_Object(zone_object);
				Site *site = zone_object->GetNextWeaponSite();
				if(!site)
				{
					*error = 0;
#if defined(LAB_ONLY)
					PAUSE(("This location does not have a child site!"));
#endif
					subsystem->Destroy();
					return;
				}
				Site *eject_site = zone_object->GetNextEjectSite();
				if(eject_site)
				{
					weapon->ejectSiteName = eject_site->GetName();
				}
				weapon->siteName = site->GetName();
			}

			m_workingMech->AddChild(subsystem);
			m_workingMech->SyncMatrices(true);

			if(subsystem->ConnectSubsystem())
			{
				m_workingMech->AddSubsystem(subsystem);
				RemoveAvailableSubsystem(*sub_type);
			}
			else
			{
				subsystem->Destroy();
				*error = 0;
				return;
			}
		}
		else
		{
			*error = 0;
			return;
		}
	}

	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Init();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::RemoveSubsystem(void *data[], int count)
{
	int *sub_id = INTARRAYPARAM(1);
	int *zone = INTARRAYPARAM(2);

	RemoveWeaponFromMech(sub_id, zone);

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::RemoveWeaponFromMech(int *sub_id, int *zone)
{
	if(GetWorkingMech())
	{
		MWInternalDamageObject *part = 
		m_workingMech->internalDamageObjects.Find(*zone);
		if(!part)
		{
			return;
		}
		Check_Object(part);

		ChainIteratorOf<Subsystem *> iterator(&part->subsystemChain);
		Subsystem *subsystem;
		int weapon_count = 0;
		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);
			
			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				if(weapon_count == *sub_id)
				{
					//we found it!
					subsystem->DisconnectSubsystem();
					m_workingMech->RemoveSubsystem(subsystem);
					AddAvailableSubsystem(subsystem);
					subsystem->Destroy();
				}
				weapon_count ++;
			}
		}
	}

	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Init();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MechLab::RemoveSubsystemFromMech(int *sub_type, int *zone)
{
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		MWInternalDamageObject *internal_zone;

		internal_zone = m_workingMech->internalDamageObjects.Find(*zone);
		Check_Object(internal_zone);
		
		Subsystem *subsystem = internal_zone->GetSubsystem(*sub_type);
		if(subsystem)
		{
			//Disconnect, add to our reserves, and delete
			subsystem->DisconnectSubsystem();
			m_workingMech->RemoveSubsystem(subsystem);
			AddAvailableSubsystem(subsystem);
			subsystem->Destroy();
		}
	}

	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Init();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::SaveMech()
{
	if(GetWorkingMech() && (m_mechResourceFile.GetCurrent())) //Can't save something in the core!
	{
		Check_Object(m_workingMech);
		Check_Object(m_mechResourceFile.GetCurrent());

		DynamicMemoryStream stream;
		m_workingMech->SaveMakeMessage(&stream, m_mechResourceFile.GetCurrent());

		stream.Rewind();
		Stuff::FileDependencies dependancies;
		dependancies.AddDependency("");
		ResourceID mech_id(MechResourceFileID, 1);
		Resource mech_resource(mech_id);
		mech_resource.Save(&stream, &dependancies);



		// mark the mech to detect hex editing
		{

			Resource crc_resource("icuedbdii", m_mechResourceFile.GetCurrent());
			crc_resource.Save(NULL, NULL);

		}

	
		ResourceID crc_id(MechResourceFileID, 3);
		Resource crc_resource(crc_id);

		MD5_CTX resource_context;
		GUID resource_hash;
		unsigned char * buff=(unsigned char *) &resource_hash;

		MD5Init(&resource_context);
		int key = 0xa1252388;
		stream.Rewind();
		MD5Update(&resource_context, (unsigned char *) &key, 4);
		MD5Update(&resource_context, (unsigned char *) stream.GetPointer(), stream.GetBytesRemaining());
		
		MD5Final(buff, &resource_context);

		DynamicMemoryStream hash_stream;
		hash_stream.WriteBytes(&resource_hash,16);
		hash_stream.Rewind();

		crc_resource.Save(&hash_stream, &dependancies);


		// save the mech

		m_mechResourceFile.GetCurrent()->Save();

		return 1;
	}
	return 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::AutoAddSubsystem(void *data[], int count)
{
	int *sub_type = INTARRAYPARAM(1);
	int *error = INTARRAYPARAM(2);

	*error = 1;
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		SubsystemResource *sub_resource = m_subsystemsAvailable.Find(*sub_type);
		if(sub_resource)
		{
			Check_Object(sub_resource);
			RegisteredClass::ClassID class_id = Entity::GetClassIDFromDataListID(sub_resource->GetDataListID());
			Subsystem::ClassData *class_data =
				Cast_Pointer(Subsystem::ClassData*, RegisteredClass::FindClassData(class_id));
			Check_Object(class_data);
			DynamicMemoryStream stream;
			(*class_data->streamCreate)(sub_resource->GetDataListID(), &stream);
// MSL 5.03 MechView
			ReplicatorID base_id(CONN4ML->GetNextReplicatorID());
			
			Subsystem__CreateMessage *create_message = 
				Cast_Pointer(Subsystem__CreateMessage *, stream.GetPointer());


			//Ok now we have the subsystem stream...before we create we need to know where
			//we want to put the thing.  

			Resource sub_model_resource(sub_resource->GetGameModelID());
			Verify(sub_model_resource.DoesResourceExist());

			Subsystem::GameModel *sub_model = Cast_Pointer(
				Subsystem::GameModel *, sub_model_resource.GetPointer());

			int slots_needed = sub_model->totalSlotsTaken;
			int slot_type = sub_model->slotType;

			//First check for a slot with the correct type, starting with the arms
			int location = FindInternalLocation(slot_type, slots_needed);
			//Next check for an omni slot starting with the arms
			if(location == -1)
				location = FindInternalLocation(MWInternalDamageObject::OmniSlotType, slots_needed);

			if(location == -1)
			{
				*error = 0;
				return 0;
			}
			//if no zone then exit!
			create_message->locationID = (char)location;

			Subsystem *subsystem = 
				Cast_Object(Subsystem *, Entity::CreateEntity(&stream, &base_id));
			Check_Object(subsystem);

			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				Weapon *weapon = Cast_Object(Weapon *, subsystem);
				MWInternalDamageObject *zone_object = m_workingMech->internalDamageObjects.Find(location);
				Check_Object(zone_object);
				Site *site = zone_object->GetNextWeaponSite();
				if(!site)
				{
					*error = 0;
					subsystem->Destroy();
					return 0;
				}
				weapon->siteName = site->GetName();
			}

			m_workingMech->AddChild(subsystem);
			m_workingMech->SyncMatrices(true);
			if(subsystem->ConnectSubsystem())
			{
				m_workingMech->AddSubsystem(subsystem);
				RemoveAvailableSubsystem(*sub_type);
			}
			else
			{
				subsystem->Destroy();
				*error = 0;
				return 0;
			}
		}
		else
		{
			*error = 0;
			return 0;
		}
	}

	MWApplication *app = MWApplication::GetInstance();
	app->memoryDiffKiller.Init();
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::RemoveAllSubsystems()
{
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		ChainIteratorOf<Subsystem *> iterator(&m_workingMech->subsystemsInVehicle);	
		Subsystem *subsystem;

		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);

			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				//Disconnect, add to our reserves, and delete
				subsystem->DisconnectSubsystem();
				m_workingMech->RemoveSubsystem(subsystem);
				AddAvailableSubsystem(subsystem);
				subsystem->Destroy();
			}
		}

		//SaveMech();
		return 1;
	}
	return 0;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::FindInternalLocation(int slot_type, int slots_needed)
{
	Check_Object(m_workingMech);
	
	SortedChainIteratorOf<MWInternalDamageObject *, int> iterator(&m_workingMech->internalDamageObjects);
	MWInternalDamageObject *zone;

	while((zone = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(zone);
		if(zone->DoesHaveAvailableSlots(slot_type, slots_needed, false, false) > -2)
		{
			return zone->damageZone;
		}
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::GetWeaponGroups(void *data[], int count)
{
	int *type_array = INTARRAYPARAM(1);
	int *id_array = INTARRAYPARAM(2);
	int *loc_array = INTARRAYPARAM(3);
	int *group1_array = INTARRAYPARAM(4);
	int *group2_array = INTARRAYPARAM(5);
	int *group3_array = INTARRAYPARAM(6);
	int *group4_array = INTARRAYPARAM(7);
	int *group5_array = INTARRAYPARAM(8);
	int *group6_array = INTARRAYPARAM(9);
// MSL 5.06
	int *facing1 = INTARRAYPARAM(10);
	int *facing2 = INTARRAYPARAM(11);
	int *facing3 = INTARRAYPARAM(12);
	int *num_weapons = INTARRAYPARAM(13);

#if defined(_ARMOR)
	int array_size = VALUEPARM(14);
#endif

	int num = 0;
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		ChainIteratorOf<Subsystem *> iterator(&m_workingMech->subsystemsInVehicle);	
		Subsystem *subsystem;

		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);

			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				Weapon *weapon = Cast_Object(Weapon *, subsystem);
				const Weapon::GameModel *weapon_model = weapon->GetGameModel();
				Verify(num < array_size);
				type_array[num] = weapon_model->itemID;
				id_array[num] = num;
				loc_array[num] = subsystem->internalLocation;
				group1_array[num] = weapon->IsInWeaponGroup1();
				group2_array[num] = weapon->IsInWeaponGroup2();
				group3_array[num] = weapon->IsInWeaponGroup3();
				group4_array[num] = weapon->IsInWeaponGroup4();
				group5_array[num] = weapon->IsInWeaponGroup5();
				group6_array[num] = weapon->IsInWeaponGroup6();
				if (weapon->GetWeaponFacing() == 0)
				{
					facing1[num] = 1;
					facing2[num] = 0;
					facing3[num] = 0;
				}
				if (weapon->GetWeaponFacing() == 1)
				{
					facing1[num] = 0;
					facing2[num] = 1;
					facing3[num] = 0;
				}
				if (weapon->GetWeaponFacing() == 2)
				{
					facing1[num] = 0;
					facing2[num] = 0;
					facing3[num] = 1;
				}
				num++;
			}
		}
	}
	
	*num_weapons = num;
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int 
	MechLab::SetWeaponGroup(void *data[], int count)
{
	int *id = INTARRAYPARAM(1);
	int *group = INTARRAYPARAM(2);
	int *facing = INTARRAYPARAM(3);

	int num = 0;
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		ChainIteratorOf<Subsystem *> iterator(&m_workingMech->subsystemsInVehicle);	
		Subsystem *subsystem;

		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);
			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				if(num == *id)
				{
					//we found the weapon!
					Weapon *weapon = Cast_Object(Weapon *, subsystem);
					weapon->SetWeaponGroup(*group);
					weapon->SetWeaponFacing(*facing);
					return 1;
				}
				num++;
			}
		}
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int 
	MechLab::SetAllWeaponGroups(void *data[], int count)
{
	
	int *group1_array = INTARRAYPARAM(1);	//in group 1?
	int *group2_array = INTARRAYPARAM(2);	
	int *group3_array = INTARRAYPARAM(3);
	int *group4_array = INTARRAYPARAM(4);
	int *group5_array = INTARRAYPARAM(5);
	int *group6_array = INTARRAYPARAM(6);
	int *facing1 = INTARRAYPARAM(7);
	int *facing2 = INTARRAYPARAM(8);
	int *facing3 = INTARRAYPARAM(9);
	int *array_size = INTARRAYPARAM(10);

	for(int i=0; i<*array_size; i++)
	{
		Weapon *weapon = FindWeapon(i);
		if(weapon)
		{
			if(group1_array[i] > 0)
				weapon->SetGroup1();
			else
				weapon->ClearGroup1();
			if(group2_array[i] > 0)
				weapon->SetGroup2();
			else
				weapon->ClearGroup2();
			if(group3_array[i] > 0)
				weapon->SetGroup3();
			else
				weapon->ClearGroup3();
			if(group4_array[i] > 0)
				weapon->SetGroup4();
			else
				weapon->ClearGroup4();
			if(group5_array[i] > 0)
				weapon->SetGroup5();
			else
				weapon->ClearGroup5();
			if(group6_array[i] > 0)
				weapon->SetGroup6();
			else
				weapon->ClearGroup6();
			if(facing1[i] == 1)
			{
				weapon->SetWeaponFacing(0);
			}
			else
			if(facing2[i] == 1)
			{
				weapon->SetWeaponFacing(1);
			}
			else
			if(facing3[i] == 1)
			{
				weapon->SetWeaponFacing(2);
			}
		}
	}
//	SaveMech();
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Weapon* 
	MechLab::FindWeapon(int id)
{
	int num = 0;
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		ChainIteratorOf<Subsystem *> iterator(&m_workingMech->subsystemsInVehicle);	
		Subsystem *subsystem;

		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);
			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				if(num == id)
				{
					return Cast_Object(Weapon *, subsystem);
				}
				num ++;
			}
		}
	}
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int 
	MechLab::ClearWeaponGroup(void *data[], int count)
{
	int *id = INTARRAYPARAM(1);
	int *group = INTARRAYPARAM(2);

	int num = 0;
	if(GetWorkingMech())
	{
		Check_Object(m_workingMech);
		ChainIteratorOf<Subsystem *> iterator(&m_workingMech->subsystemsInVehicle);	
		Subsystem *subsystem;

		while((subsystem = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);
			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				if(num == *id)
				{
					//we found the weapon!
					Weapon *weapon = Cast_Object(Weapon *, subsystem);
					weapon->ClearWeaponGroup(*group);
					return 1;
				}
				num++;
			}
		}
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetDummyData(void *data[], int count)
{
	Check_Pointer(this);

	char **name_array = STRARRAYPARAM(1);
	int array_size = VALUEPARM(2);

	for(int i=0; i<array_size; i++)
	{
		FREEANDNULL(name_array[i]);
		name_array[i] = (char *)gos_Malloc(128);
		MString mech_name = "I Love Mech 4";
		Str_Copy(
			name_array[i], 
			(const char *)mech_name, 
			mech_name.GetLength() + 1
		); 
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::Exit()
{
	s_MechCamera->SetScene(NULL);
	DestroyWorkingEntity();
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::Restore()
{
	if(GetWorkingMech() && (m_mechResourceFile.GetCurrent()))
	{
		//Ok so we need to just redo a select and such.
		m_workingMech->Destroy();
		m_workingMech = NULL;

		ResourceID mech_id(MechResourceFileID, 1);
		Resource mech_resource(mech_id);
		Verify(mech_resource.DoesResourceExist());

// MSL 5.03 MechView
		ReplicatorID base_id(CONN4ML->GetNextReplicatorID());

		Entity *entity;
		entity = Entity::CreateEntity(&mech_resource, &base_id);

		Check_Object(entity);
		SetUpWorkingMech(entity);
	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::DeleteMech()
{
	if(GetWorkingMech() && (m_mechResourceFile.GetCurrent()))
	{
		s_MechCamera->SetScene(NULL);
		DestroyWorkingEntity();

		MString resource_file_name = m_mechResourceFile.GetCurrent()->GetFileName();

		delete m_mechResourceFile.GetCurrent();

		Verify(gos_DoesFileExist(resource_file_name));
		gos_DeleteFile(resource_file_name);

		m_mechLabCount = GetMechCount();
		if(m_mechLabCount == 0)
		{
			MWApplication *app = MWApplication::GetInstance();
			if(!m_isCampaign)
			{
				app->m_lastMechID = 0;
				app->m_lastMechName = "";
			}
		}
	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetEngineSpeed(void *data[], int count)
{
	Scalar *speed = SCALARARRAYPARAM(1);
	Scalar *tonnage = SCALARARRAYPARAM(2);
	*speed = 0.0f;
	if(GetWorkingMech())
	{
		Engine *engine = m_workingMech->GetEngine();
		*speed = engine->GetMaxSpeedForDisplay();
		const Engine::GameModel *engine_model = engine->GetGameModel();
		*tonnage = (engine->GetUpgrades() + 1) * engine_model->m_tonsPerUpgrade;
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::UpgradeEngine()
{
	if(GetWorkingMech())
	{
		m_workingMech->GetEngine()->Upgrade();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::DegradeEngine()
{
	if(GetWorkingMech())
	{
		m_workingMech->GetEngine()->Degrade();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetHeatSinkCount(void *data[], int count)
{
	int *num_sinks = INTARRAYPARAM(1);
	*num_sinks = 0;
	if(GetWorkingMech())
	{
		*num_sinks = m_workingMech->m_numHeatSinks;
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::AddHeatSink()
{
	int sub_id = Sub_HeatSink;
	int zone = MLCenterTorsoZone;
	int error = 1;

	AddSubsystemToMech(&sub_id, &zone, &error);
	return error;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::RemoveHeatSink()
{
	int sub_id = Sub_HeatSink;
	int zone = MLCenterTorsoZone;

	RemoveSubsystemFromMech(&sub_id, &zone);

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetJumpJets(void *data[], int count)
{
	int *has_jump = INTARRAYPARAM(1);
	int *can_have_jump = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_jump = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_jump = mech_model->m_canLoadJumpJets;
		*tons = mech_model->m_jumpJetTonnage;

		if(m_workingMech->GetJumpJet())
		{
			*has_jump = 1;
		}
		else
		{
			*has_jump = 0;
		}
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetJumpJets(void *data[], int count)
{
	int sub_id = Sub_JumpJet;
	int zone = MLCenterTorsoZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->GetJumpJet())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}

	return error;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetECM(void *data[], int count)
{
	int *has_ecm = INTARRAYPARAM(1);
	int *can_have_ecm = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_ecm = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_ecm = mech_model->m_canLoadECM;
		*tons = 1.0f;
		*has_ecm = m_workingMech->DoesHaveECM();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetECM(void *data[], int count)
{
	int sub_id = Sub_ECM;
	int zone = MLHeadZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->DoesHaveECM())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}
	return error;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetBeagle(void *data[], int count)
{
	int *has_beagle = INTARRAYPARAM(1);
	int *can_have_beagle = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_beagle = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_beagle = mech_model->m_canLoadBeagle;
		*tons = 1.0f;
		*has_beagle = m_workingMech->DoesHaveBeagle();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetBeagle(void *data[], int count)
{
	int sub_id = Sub_Beagle;
	int zone = MLHeadZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->DoesHaveBeagle())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}
	return error;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetAMS(void *data[], int count)
{
	int *has_ams = INTARRAYPARAM(1);
	int *can_have_ams = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_ams = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_ams = mech_model->m_canLoadAMS;
		*tons = 1.5f;
		*has_ams = 0;
		//Here we need to do a check on the ams that we have
		if(m_workingMech->GetAMS())
		{
			const AMS::GameModel *ams_model = m_workingMech->GetAMS()->GetGameModel();
			Check_Object(ams_model);

			*tons = 1.5;

			if(ams_model->itemID == Sub_AMS)
				*has_ams = 1;
		}
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetAMS()
{
	int sub_id = Sub_AMS;
	int zone = MLCenterTorsoZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->GetAMS())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}
	return error;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetLAMS(void *data[], int count)
{
	int *has_ams = INTARRAYPARAM(1);
	int *can_have_ams = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_ams = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_ams = mech_model->m_canLoadLAMS;
		*tons = 1.5f;
		*has_ams = 0;
		//Here we need to do a check on the ams that we have
		if(m_workingMech->GetAMS())
		{
			const AMS::GameModel *ams_model = m_workingMech->GetAMS()->GetGameModel();
			Check_Object(ams_model);

			*tons = 1.5f;

			if(ams_model->itemID == Sub_LAMS)
				*has_ams = 1;
		}
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetLAMS()
{
	int sub_id = Sub_LAMS;
	int zone = MLCenterTorsoZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->GetAMS())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}
	return error;
}

// MSL 5.02 SubSystems
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetIFF_Jammer(void *data[], int count)
{
	int *has_IFF_Jammer = INTARRAYPARAM(1);
	int *can_have_IFF_Jammer = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_IFF_Jammer = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_IFF_Jammer = mech_model->m_canLoadIFF_Jammer;
		*has_IFF_Jammer = 0;
		*tons = 1.0f;

		if(m_workingMech->GetIFF_Jammer())
		{
			const IFF_Jammer::GameModel *iff_jammer_model = m_workingMech->GetIFF_Jammer()->GetGameModel();
			Check_Object(iff_jammer_model);

			if(iff_jammer_model->itemID == Sub_IFF_Jammer)
				*has_IFF_Jammer = 1;
		}
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetIFF_Jammer()
{
	int sub_id = Sub_IFF_Jammer;
	int zone = MLHeadZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->GetIFF_Jammer())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}
	return error;
}


// MSL 5.02 SubSystems
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetAdvancedGyro(void *data[], int count)
{
	int *has_AdvancedGyro = INTARRAYPARAM(1);
	int *can_have_AdvancedGyro = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_AdvancedGyro = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_AdvancedGyro = mech_model->m_canLoadAdvancedGyro;
		*has_AdvancedGyro = 0;
		*tons = mech_model->m_advancedGyroTonnage;

		if(m_workingMech->GetAdvancedGyro())
		{
			const AdvancedGyro::GameModel *advanced_gyro_model = m_workingMech->GetAdvancedGyro()->GetGameModel();
			Check_Object(advanced_gyro_model);

			if(advanced_gyro_model->itemID == Sub_AdvancedGyro)
				*has_AdvancedGyro = 1;
		}
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetAdvancedGyro()
{
	int sub_id = Sub_AdvancedGyro;
	int zone = MLHeadZone;
	int error = 1;

	if(GetWorkingMech())
	{
		if(m_workingMech->GetAdvancedGyro())
		{
			RemoveSubsystemFromMech(&sub_id, &zone);
		}
		else
		{
			AddSubsystemToMech(&sub_id, &zone, &error);
		}
	}
	return error;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetLightAmp(void *data[], int count)
{
	int *has_light = INTARRAYPARAM(1);
	int *can_have_light = INTARRAYPARAM(2);
	Scalar *tons = SCALARARRAYPARAM(3);

	*has_light = 0;
	if(GetWorkingMech())
	{
		const Mech::GameModel *mech_model = m_workingMech->GetGameModel();
		Check_Object(mech_model);

		*can_have_light = mech_model->m_canLoadLightAmp;
		*tons = 1.0f;
		*has_light = m_workingMech->DoesHaveLightAmp();
	}
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetLightAmp()
{
	if(GetWorkingMech())
	{
		m_workingMech->ToggleLightAmpLoad();
	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetWeaponAmmo(void *data[], int count)
{
	int *zone_id = INTARRAYPARAM(1);
	int *id = INTARRAYPARAM(2);
	int *num_packs = INTARRAYPARAM(3);
	int *num_per_pack = INTARRAYPARAM(4);

	MWInternalDamageObject *part = 
		m_workingMech->internalDamageObjects.Find(*zone_id);

	if(!part)
	{
		return -1;
	}

	Check_Object(part);

	ChainIteratorOf<Subsystem *> iterator(&part->subsystemChain);
	Subsystem *subsystem;
	int weapon_count = 0;
	while((subsystem = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(subsystem);
		
		if(subsystem->IsDerivedFrom(Weapon::DefaultData))
		{
			if(weapon_count == *id)
			{
				//we found it!
				Weapon *weapon;
				weapon = Cast_Object(Weapon *, subsystem);
				*num_packs = weapon->GetAmmoPacks();
				*num_per_pack = weapon->GetAmmoPerPack();

				return 1;
			}
			weapon_count ++;
		}
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::AddWeaponAmmo(void *data[], int count)
{
	int *zone_id = INTARRAYPARAM(1);
	int *id = INTARRAYPARAM(2);

	MWInternalDamageObject *part = 
		m_workingMech->internalDamageObjects.Find(*zone_id);

	if(!part)
	{
		return -1;
	}
	Check_Object(part);

	ChainIteratorOf<Subsystem *> iterator(&part->subsystemChain);
	Subsystem *subsystem;
	int weapon_count = 0;
	while((subsystem = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(subsystem);
		
		if(subsystem->IsDerivedFrom(Weapon::DefaultData))
		{
			if(weapon_count == *id)
			{
				//we found it!
				Weapon *weapon;
				weapon = Cast_Object(Weapon *, subsystem);
				if(weapon->AddAmmoPack())
					return 1;
				return -1;
			}
			weapon_count ++;
		}
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::RemoveWeaponAmmo(void *data[], int count)
{
	int *zone_id = INTARRAYPARAM(1);
	int *id = INTARRAYPARAM(2);

	MWInternalDamageObject *part = 
	m_workingMech->internalDamageObjects.Find(*zone_id);

	if(!part)
	{
		return -1;
	}
	Check_Object(part);

	ChainIteratorOf<Subsystem *> iterator(&part->subsystemChain);
	Subsystem *subsystem;
	int weapon_count = 0;
	while((subsystem = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(subsystem);
		
		if(subsystem->IsDerivedFrom(Weapon::DefaultData))
		{
			if(weapon_count == *id)
			{
				//we found it!
				Weapon *weapon;
				weapon = Cast_Object(Weapon *, subsystem);
				if(weapon->RemoveAmmoPack())
					return 1;

				return -1;
			}
			weapon_count ++;
		}
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetSkinListCount(void *data[], int count)
{
	int *skin_count = INTARRAYPARAM(1);

	Check_Object(MWApplication::GetInstance()->m_skinsTable);
	*skin_count = MWApplication::GetInstance()->m_skinsTable->GetTableSize();

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetSkinList(void *data[], int count)
{
	Check_Pointer(this);

	char **name_array = STRARRAYPARAM(1);
	int *current_skin = INTARRAYPARAM(2);

	int i = 0;

	MWTable::TableIterator *skin_iterator;
	MWTable *skin_table = MWApplication::GetInstance()->m_skinsTable;
	Check_Object(skin_table);

	skin_iterator = skin_table->MakeTableIterator();
	MWTableEntry *skin_entry;

	//This is hardcoded for the .dll in missionlang
	int skin_count = IDS_FIRSTSKIN + 1;
	while((skin_entry = skin_iterator->ReadAndNext()) != NULL)
	{
		Check_Object(skin_entry);

		FREEANDNULL(name_array[i]);
		name_array[i] = (char *)gos_Malloc(128);
		MString skin_name = MWApplication::GetInstance()->GetLocString(skin_count);
		Str_Copy(
			name_array[i], 
			(const char *)skin_name, 
			skin_name.GetLength() + 1
		); 
		skin_count ++;
		i++;
	}
	
	*current_skin = 0;
	if(m_workingMech)
	{
		char skin_string[2];
		*skin_string = m_workingMech->GetSkinPrefix();
		skin_string[1] = 0;
		*current_skin = skin_table->FindIndexFromDataString(skin_string);
	}
	
	Verify(*current_skin >= 0);
	Min_Clamp(*current_skin, 0);

	delete skin_iterator;
	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::SetMechSkin(void *data[], int count)
{
	int *skin_name = INTARRAYPARAM(1);
	Check_Object(MWApplication::GetInstance()->m_skinsTable);

	char skin_prefix;

	if(m_workingMech)
	{
        if (skin_name) {
		MWTableEntry *skin_plug = MWApplication::GetInstance()->m_skinsTable->GetNthItem(*skin_name);
		Check_Object(skin_plug);
		skin_prefix = *skin_plug->GetData();
        } else {
            gosASSERT(count == 3);
            skin_prefix = *(int*)data[2];
        }
// for campaign skin - jcem
		if (g_bCOOP && m_isCampaign) {
			MW4Shell::Instance->m_skinPrefix = skin_prefix;
			//MWApplication::GetInstance()->servedConnectionData[CONN4ML->GetID()].pilotSkins = skin_prefix;
		}
// for campaign skin - jcem

		m_workingMech->SetSkinPrefix(skin_prefix);
		s_MechCamera->SetScene(NULL);
		
		Check_Object(VideoRenderer::Instance);	
		ChainIteratorOf<Entity*> children(&m_workingMech->childEntityChain);
		Entity *child_entity;
		while ((child_entity = children.ReadAndNext()) != NULL)
		{
			Check_Object(child_entity);
			if(child_entity->IsDerivedFrom(MWMover::DefaultData))
			{
				MWMover *mover = Cast_Object(MWMover *, child_entity);
				MakeMoverUnInteresting(mover);
			}
		}

		gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
		Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
		delete MidLevelRenderer::MLRTexturePool::Instance;

		ResourceImagePool *pool = new ResourceImagePool;
		Check_Object(pool);
		MidLevelRenderer::MLRTexturePool::Instance = new MidLevelRenderer::MLRTexturePool(pool);
		Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
		gos_PopCurrentHeap();

		s_MechCamera->GetClipper()->SetTexturePoolInSorter(MidLevelRenderer::MLRTexturePool::Instance);

		extern char g_SkinSet;
		g_SkinSet = m_workingMech->GetSkinPrefix();
		extern int g_PilotDecal;
		g_PilotDecal = m_workingMech->GetPilotDecal();
		extern int g_TeamDecal;
		g_TeamDecal = m_workingMech->GetTeamDecal();

		Check_Object(VideoRenderer::Instance);	
		children.First();
		while ((child_entity = children.ReadAndNext()) != NULL)
		{
			Check_Object(child_entity);
			if(child_entity->IsDerivedFrom(MWMover::DefaultData))
			{
				MWMover *mover = Cast_Object(MWMover *, child_entity);
				MakeMoverInteresting(mover);
			}
		}
		ElementRenderer::Element *mech_element = m_workingMech->GetElement();
		s_MechCamera->SetScene(mech_element);

		Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
		MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
	}

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechLab::GetBaseMechName(void* data[], int count)
{
	Check_Pointer(this);

	const char *full_name = STRPARM(1);
	char **base_name = (char **)STRARRAYPARAM(2);
	char tmp_base_name[128] = "";

	if (full_name == NULL)
		return -1;

	MWTable::TableIterator *mech_iterator;
	Check_Object(MWApplication::GetInstance()->m_mechTable);

	mech_iterator = MWApplication::GetInstance()->m_mechTable->MakeTableIterator();
	MWTableEntry *mech_entry;
	while((mech_entry = mech_iterator->ReadAndNext()) != NULL)
	{
		Check_Object(mech_entry);
		
		if (strnicmp(full_name, (const char *)mech_entry->GetEntryName(), 
					 mech_entry->GetEntryName().GetLength()) == 0 &&
			mech_entry->GetEntryName().GetLength()>strlen(tmp_base_name)) {
			Str_Copy(
				tmp_base_name, 
				(const char *)mech_entry->GetEntryName(), 
				mech_entry->GetEntryName().GetLength() + 1);
			
		}
	}

	delete mech_iterator;
	
	if (strlen(tmp_base_name)>0) {
		FREEANDNULL(*base_name);
		*base_name = (char *)gos_Malloc(128);
		Str_Copy(
			*base_name, 
			tmp_base_name, 
			strlen(tmp_base_name) + 1);

		return 1;
	}

	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MechLab::Rename(void* data[], int count, const char *path)
{
	Check_Pointer(this);

	const char *chassis_name = STRPARM(1);
	const char *mech_name = STRPARM(2);
	int overwrite = INTPARM(3);

	if(!MWApplication::ValidateName((char*)mech_name, true))
		return -1;
	
	if(GetWorkingMech() && (m_mechResourceFile.GetCurrent()))
	{
		
		MString path_name = path;
		path_name += chassis_name;
		path_name += " ";
		path_name += mech_name;
		MString res_name = path_name;
		m_workingMechName = res_name;
		res_name += ".mw4";

		MString resource_file_name = m_mechResourceFile.GetCurrent()->GetFileName();

		// Don't do anything if new name is the same as old name
		if (res_name == resource_file_name)
			return 1;

		// Check if new name is already being used
		if (stricmp(res_name, resource_file_name) && gos_DoesFileExist(res_name) && !overwrite)
			return E_MechAlreadyExists;

		m_mechResourceFile.GetCurrent()->Save();
		delete m_mechResourceFile.GetCurrent();
		m_mechResourceFile.Remove();
	
		if(!MWApplication::ValidatePath(res_name, true))
			return -1;
	
		Verify(gos_DoesFileExist(resource_file_name));

		// If they are the same file name except for cases
		if (stricmp(res_name, resource_file_name) == 0) {

			DWORD size;
			BYTE * bitmap;			
			gos_GetFile(resource_file_name, &bitmap, &size);
			gos_DeleteFile(resource_file_name);
			HGOSFILE fHandle;
			gos_OpenFile(&fHandle, res_name, READWRITE);
			if (fHandle) {
				gos_WriteFile(fHandle, bitmap, size);
				gos_CloseFile(fHandle);
			}
			else {
			}
			gos_Free(bitmap);
		}

		else {
			if(gos_DoesFileExist(res_name))
				gos_DeleteFile(res_name);
			
			gos_RenameFile(resource_file_name, res_name);
		}

		Check_Object(ResourceManager::Instance);
		ResourceFile *res_file;
		res_file = ResourceManager::Instance->OpenResourceFile(
			res_name,
			NULL,
			MechResourceFileID,
			VER_CONTENTVERSION,
			false,
			false
			);
		Check_Object(res_file);
		m_mechResourceFile.Add(res_file);
		
		m_mechLabCount = GetMechCount();

		MWApplication *app = MWApplication::GetInstance();
		app->memoryDiffKiller.Init();
		
		if(!m_isCampaign)
		{
			app->m_lastMechID = -1;
			app->m_lastMechName = MString(chassis_name)+" "+mech_name;
		}
	}
	return 1;
}

Mech* MechLab::GetWorkingMech() const
{
    return m_workingMech;
}

Entity* MechLab::GetWorkingEntity() const
{
    return m_workingEntity;
}

void MechLab::DestroyWorkingEntity()
{
    if (m_workingEntity) {
        gosASSERT(!m_workingMech || (m_workingEntity == m_workingMech));

        m_workingEntity->Destroy();

        m_workingMech = NULL;
        m_workingEntity = NULL;
    } else {
        gosASSERT(!m_workingMech);
    }
}

