#include "MW4Headers.hpp"

#include "MWObject.hpp"
#include "Subsystem.hpp"
#include "Torso.hpp"
#include "AnimationState.hpp"
#include "MWDamageObject.hpp"
#include "Weapon.hpp"
#include "Sensor.hpp"
#include "Beagle.hpp"
#include "HeatManager.hpp"
#include "AMS.hpp"
#include "SearchLight.hpp"
#include "Mech_AI.hpp"
#include "MWMission.hpp"
#include "gameinfo.hpp"
#include "AI_Statistics.hpp"
#include "obstacle.hpp"
#include "ECM.hpp"
#include "VehicleInterface.hpp"
#include "SubsystemClassData.hpp"
#include "MWApplication.hpp"
#include "DamageDispatch.hpp"

// MSL 5.02 SubSystems
//#include "EnhancedOptics.hpp"
#include "IFF_Jammer.hpp"
#include "AdvancedGyro.hpp"

#include <Adept\DamageObject.hpp>
#include <Adept\EntityManager.hpp>
#include <Adept\Effect.hpp>
#include <Adept\Map.hpp>
#include <Adept\Site.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\CollisionVolume.hpp>
#include <Adept\Renderer.hpp>


extern int g_nMR;

IdleEffectObject::IdleEffectObject() :
	Plug(Plug::DefaultData),
	idleEffect(NULL),
	siteSlot(NULL)
{}

//#############################################################################
//###############################    MWObject    ##############################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject::ClassData*
	MWObject::DefaultData = NULL;

const Receiver::MessageEntry
	MWObject::MessageEntries[]=
{
	MESSAGE_ENTRY(MWObject, TakeDamage)
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::InitializeClass()
{
	Check_Object(MWMover::ExecutionStateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MWObjectClassID,
	        "MechWarrior4::MWObject",
			BaseClass::DefaultData,
			ELEMENTS(MessageEntries), MessageEntries,
			(Entity::Factory)Make,
			(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
			ExecutionStateEngine::DefaultData,
			(Entity::GameModel::Factory)GameModel::ConstructGameModel,
			(Entity::GameModel::Factory)GameModel::ConstructOBBStream,
			(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
			(Entity::GameModel::ModelWrite)GameModel::WriteToText,
			(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
			AnimationStateEngine::Make
		);
	Register_Object(DefaultData);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		DeathEntityResource,
		deathEntityResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		DestroyedEffectResource,
		destroyedEffectResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		SecondaryDeathEntityResource,
		secondaryDeathEntityResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		SecondaryDestroyedEffectResource,
		secondaryDestroyedEffectResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		VehicleTonnage,
		vehicleTonnage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		MaxVehicleTonnage,
		maxVehicleTonnage,
		Scalar
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		EyeSiteName,
		eyeSiteName,
		const char *,
		CharClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		PartDestructionEffectResource,
		partDestructionEffectResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		SplashDamageRadius,
		splashDamageRadius,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		SplashDamageAmount,
		splashDamageAmount,
		Scalar
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		VehicleBattleValue,
		vehicleBattleValue,
		int,
		IntClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		CoolantEffectResource,
		coolantEffectResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		SplashHeatAmount,
		splashHeatAmount,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		EjectEffectResource,
		ejectEffectResource,
		ResourceID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		NameIndex,
		m_nameIndex,
		int,
		IntClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		MWObject__GameModel,
		OverHeatEffectResource,
		overHeatEffectResource,
		ResourceID
	);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject*
	MWObject::Make(
		CreateMessage *message,
		ReplicatorID *base_id
	)
{
	Check_Object(message);
	gos_PushCurrentHeap(Heap);
	MWObject *new_object = new
		MWObject(DefaultData, message, base_id, NULL);
	gos_PopCurrentHeap();
	Check_Object(new_object);

	return new_object;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
	MWObject::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
	Check_Object(this);
	Check_Object(stream);

	//
	//---------------------------------------------------------------------
	// Make sure there is enough room for the factory request on the stream
	//---------------------------------------------------------------------
	//
	stream->AllocateBytes(sizeof(CreateMessage));
	BaseClass::SaveMakeMessage(stream, res_file);
	CreateMessage *message =
		Cast_Pointer(CreateMessage*, stream->GetPointer());
	message->messageLength = sizeof(*message);

	//
	//--------------------------------------------
	// Create the memory stream for the subsystems
	//--------------------------------------------
	//
	DynamicMemoryStream subsystem_stream(sizeof(WORD));
	subsystem_stream << static_cast<WORD>(0);
	ReplicatorID span = ReplicatorID::Null;
	ChainIteratorOf<Subsystem *> sub_iterator(&subsystemsInVehicle);
	Subsystem *subsystem;

	while((subsystem = sub_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(subsystem);
		Replicator::CreateMessage *create_message =
			subsystem->SaveMakeMessage(&subsystem_stream, res_file);
		if (create_message)
		{
			Check_Object(create_message);
			span += create_message->replicatorID;
			subsystem_stream.AdvancePointer(create_message->messageLength);
		}
	}

	//
	//-------------------------------------------------------------------------
	// If we actually wrote out some children, rewind the stream and save it to
	// the resource.  Otherwise, just set the resourceID to NULL
	//-------------------------------------------------------------------------
	//

	//This stream must be written out to the current res_file and not core.
	if (subsystem_stream.GetBytesUsed() > sizeof(WORD))
	{
		subsystem_stream.Rewind();
		Verify(span.localID > 0);
		subsystem_stream << span.localID;
		MString sub_resource_name = instanceName;
		sub_resource_name += "{Subsystem}";
		Resource subsystem_resource((const char *)sub_resource_name, res_file);
		subsystem_resource.Save(&subsystem_stream, NULL);
		Check_Object(&subsystem_resource);
		message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
		message->replicatorID += span;
	}
	else
	{
		message->subsystemStreamResourceID = ResourceID::Null;
	}

	//
	//------------------------------------------------------
	//Need to save damage objects and Internal DamageObjects
	//------------------------------------------------------
	//
	//We need to check if we have changed or not...if we have then save to the
	//the res file given...if not then we need to just do nothing becuase we are already
	//in the core file and just set the message
	message->damageStreamResourceID = damageStreamResourceID;
	if((m_hasExecuted) && (!m_markedForSalvage))
	{
		DynamicMemoryStream damage_stream;
		DamageObject *damage_object;
		SortedChainIteratorOf<DamageObject *, int> damage_iterator(&damageObjects);
		damage_stream << damage_iterator.GetSize();
		while((damage_object = damage_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			damage_object->Save(&damage_stream);
		}

		MWInternalDamageObject *internal_damage_object;
		SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
		damage_stream << internal_iterator.GetSize();
		while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(internal_damage_object);
			internal_damage_object->Save(&damage_stream);
		}

		//
		//-------------------------------------------------------------------------
		// If we actually wrote out some children, rewind the stream and save it to
		// the resource.  Otherwise, just set the resourceID to NULL
		//-------------------------------------------------------------------------
		//
		
		if (damage_stream.GetBytesUsed())
		{
			Resource damage_resource(NULL, res_file);
			damage_resource.Save(&damage_stream, NULL);
			Check_Object(&damage_resource);
			message->damageStreamResourceID = damage_resource.GetResourceID();
		}
		else
		{
			message->damageStreamResourceID = ResourceID::Null;
		}
	}

	message->skinPrefix = m_skinPrefix;
	message->teamDecal = m_teamDecal;
	message->pilotDecal = m_pilotDecal;

	message->nameIndex = m_localizeIndex;
	message->doesHaveInstanceName = m_doesHaveInstanceName;

	return message;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::LoadSubsystemsFromResource(
		const ResourceID &subsystem_stream_id,
		ReplicatorID *base_id
	)
{
	Resource stream(subsystem_stream_id);
	Verify(stream.DoesResourceExist());
	stream.AdvancePointer(sizeof(WORD));

	while (stream.GetBytesRemaining() > 0)
	{
		Entity::CreateMessage *message =
			Cast_Pointer(Entity::CreateMessage*, stream.GetPointer());

		Entity *entity = CreateEntity(&stream, base_id);
		Check_Object(entity);

		AddChild(entity);
		Subsystem *subsystem;
		subsystem = Cast_Object(Subsystem *, entity);

		//Dave here is where you want to do a apendparentname function

		if (subsystem->IsDerivedFrom(Torso::DefaultData))
		{
			Torso* torso = Cast_Object(Torso*, subsystem);
			if (std::find(m_Torsos.begin(),m_Torsos.end(),torso) == m_Torsos.end())
			{
				m_Torsos.push_back(torso);
			}
		}
		if (subsystem->IsDerivedFrom(SearchLight::DefaultData))
		{
			searchLight = Cast_Object(SearchLight *, subsystem);
		}

		stream.AdvancePointer(message->messageLength);
	}

	//stream.UnloadData();

	m_hasExecuted = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::LoadDamageObjectsFromResource(
		const ResourceID &damage_stream_id
	)
{
	Resource stream(damage_stream_id);
	Verify(stream.DoesResourceExist());

	while (stream.GetBytesRemaining() > 0)
	{
		RegisteredClass::ClassID class_id;
		stream >> class_id;
		RegisteredClass::ClassData *class_data = NULL;
		class_data = RegisteredClass::FindClassData(class_id);
		if(class_data == DamageObject::DefaultData)
		{
			DamageObject *damage_object;
			DamageObject::ClassData *damage_class_data =
				Cast_Pointer(DamageObject::ClassData*, class_data);

			gos_PushCurrentHeap(Heap);
			damage_object = new DamageObject(
				damage_class_data,
				&stream
			);
			gos_PopCurrentHeap();
			Check_Object(damage_object);
			damageObjects.AddValue(damage_object, damage_object->armorZone);
		}
		else
		{
			MWInternalDamageObject *internal_damage_object;
			MWInternalDamageObject::ClassData *damage_class_data =
				Cast_Pointer(MWInternalDamageObject::ClassData*, class_data);

			gos_PushCurrentHeap(Heap);
			internal_damage_object = new MWInternalDamageObject(
				damage_class_data,
				&stream
			);
			gos_PopCurrentHeap();
			Check_Object(internal_damage_object);
			internalDamageObjects.AddValue(
				internal_damage_object, internal_damage_object->damageZone);
		}
	}

	stream.UnloadData();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::LoadIdleEffectsFromResource(const ResourceID &effects_stream_id)
{
	Resource stream(effects_stream_id);
	Verify(stream.DoesResourceExist());

	while (stream.GetBytesRemaining() > 0)
	{
				
		IdleEffectObject *idle_effect_object;
		idle_effect_object = new IdleEffectObject();
		stream >> idle_effect_object->effectResourceID;
		MString site_name;
		stream >> site_name;
		idle_effect_object->siteSlot.Remove();
		Site *site_pointer = FindSite(site_name);
		Check_Object(site_pointer);
		idle_effect_object->siteSlot.Add(site_pointer);
		idle_effect_object->idleEffect.Remove();
		Effect *idle_effect = CreateIdleEffect(idle_effect_object);
		Check_Object(idle_effect);
		idle_effect_object->idleEffect.Add(idle_effect);
		idleEffects.Add(idle_effect_object);
	}

	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
	MWObject::CreateIdleEffect(IdleEffectObject *effect_object)
{
	Check_Object(effect_object);
	
	if(effect_object->effectResourceID == ResourceID::Null)
		return NULL;

	Resource idle_resource(effect_object->effectResourceID);
	if(idle_resource.DoesResourceExist())
	{
		ClassID class_ID;
		class_ID = GetClassIDFromDataListID(effect_object->effectResourceID);
		Verify(class_ID != NullClassID);

		LinearMatrix4D effect_position = LinearMatrix4D::Identity;
		UnitVector3D unit_forward;
		Site *site_pointer = effect_object->siteSlot.GetCurrent();
		Check_Object(site_pointer);
		LinearMatrix4D site_position = site_pointer->GetLocalToWorld();
		site_position.GetLocalForwardInWorld(&unit_forward);
		effect_position.AlignLocalAxisToWorldVector(unit_forward, Y_Axis, X_Axis, Z_Axis);
		Point3D effect_translation;
		effect_translation = site_pointer->GetLocalToWorld();
		effect_position.BuildTranslation(effect_translation);

		Effect::CreateMessage effect_create_message(
			sizeof(Effect::CreateMessage),
			DefaultEventPriority,
			CreateMessage::DefaultFlags,
			class_ID,
			Effect::DefaultFlags|Effect::LoopFlag,
			effect_object->effectResourceID,
			effect_position,
			0.0f,
			ExecutionStateEngine::AlwaysExecuteState,
			NameTable::NullObjectID,
			Entity::DefaultAlignment
		);
		MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

		Entity *entity;
		ReplicatorID effect_id = Connection::Hermit->GetNextReplicatorID();
		entity = CreateEntity(&stream, &effect_id, false);
		Check_Object(Map::GetInstance());
		Map::GetInstance()->AddChild(entity);
		Effect *effect;
		effect = Cast_Object(Effect *, entity);
		effect->SetFollowEntity(site_pointer);
		entity->SyncMatrices(true);

	
		return effect;
	}
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject::MWObject(
	ClassData *class_data,
	CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	MWMover(class_data, message, base_id, element),
	armatureChain(NULL),
	subsystemsInVehicle(NULL),
	executingSubsystems(NULL),
	damageObjects(NULL, false),
	internalDamageObjects(NULL, true),
	idleEffects(NULL),
	weaponChain(NULL),
	eyeSitePointer(NULL),
	sensor(NULL),
	beagle(NULL),
	ams(NULL),
	m_TargetDesirability(desirability_invalid),
	entitiesToSync(NULL),
	m_FindObjectCache(NULL),
	m_FindObjectList(NULL),
	m_VisibleOnSensors(true),
	splashedEntities(NULL),
// MSL 5.02 SubSystems
//	enhancedOptics(NULL),
	advancedGyro(NULL),
	iff_jammer(NULL)
	{
	Check_Pointer(this);
	Check_Object(message);

	CommonCreation(message);

	m_AI = NULL;
	m_bHasAI = false;

	ecm = NULL;
	beagle = NULL;
	searchLight = NULL;
	vehicleInterface = NULL;
	invulnerable=false;

	m_markedForSalvage = false;

	m_localizeIndex = message->nameIndex;
	m_doesHaveInstanceName = message->doesHaveInstanceName;

	//
	//----------------------
	// Create the subsystems
	//----------------------
	//
	subsystemStreamResourceID = message->subsystemStreamResourceID;

	if(message->subsystemStreamResourceID != ResourceID::Null)
	{
		LoadSubsystemsFromResource(
			message->subsystemStreamResourceID,
			base_id
		);
	}

	//
	//--------------------------
	// Create the damage Objects
	//--------------------------
	//
	damageStreamResourceID = message->damageStreamResourceID;

	if(message->damageStreamResourceID != ResourceID::Null)
	{
		LoadDamageObjectsFromResource(
			message->damageStreamResourceID
		);
	}

	const GameModel *game_model = GetGameModel();
	Check_Object(game_model);

	m_heatManager = NULL;

	m_skinPrefix = message->skinPrefix;
	m_pilotDecal = message->pilotDecal;
	m_teamDecal = message->teamDecal;


	MakeArmatureChain();
    MakeAnimationArray();
	ConnectDamageObjects();
	HookUpSubsystems();

	InitializeArmorArray ();

	//
	//------------------------
	// Create the Idle Effects
	//------------------------
	//
	if(game_model->idleEffectResourceID != ResourceID::Null)
	{
		LoadIdleEffectsFromResource(game_model->idleEffectResourceID);
	}

	//
	//------------------------------
	// Load up the animation engines
	//------------------------------
	//
	AnimationStateEngine::FactoryRequest request;
	request.currentState = AnimationStateEngine::UninitializedState;
	animStateEngine = (*((MWObject::ClassData*)GetClassData())->animationStateFactory)(this, &request);
	Register_Object(animStateEngine);


	

	const GameModel *model = GetGameModel();
	Check_Object(model);
	MWApplication *app = MWApplication::GetInstance();

	if (game_model->animScriptName[0] != NULL)
	{
		app->AddToAnimationLoadQue(this);
	}

	MWMover* eye = FindChildMover(model->eyeSiteName);
	if(eye)
		eyeSitePointer.Add(eye);

	originalCollisionMask = GetCollisionMask();
	originalCullMode = GetElement()->GetCullMode();
	jointRunningLight = NULL;
	jointRunningLight = FindChildMover("joint_runninglights");
}

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


int	temporaryQuickIDLookup[COMPRESS_JOINT_COUNT];

void
	MWObject::LoadAnimationScripts()
{


	for (int i = 0; i < COMPRESS_JOINT_COUNT; ++i)
	{
		temporaryQuickIDLookup[i] = -1;
	}

	Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
	MWMover *mover;

	i = 0;
	while ((mover = iterator.ReadAndNext()) != NULL)
	{
		MString temp;
		int index = MW4Animation::CompressName(mover->instanceName, temp);
		if (index != -1)
		{
			Verify(index < COMPRESS_JOINT_COUNT);
			Verify(index >= 0);

			temporaryQuickIDLookup[index] = i;
		}

		++i;
	}



	const GameModel *model = GetGameModel();
	Check_Object(model);
	if (model->animScriptName[0] != NULL && !animStateEngine->alreadyLoaded)
	{
		animStateEngine->LoadScript(model->animScriptName);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::InitializeArmorArray()
{
	Check_Object(this);

	m_HitPoints = 0;
	SortedChainIteratorOf<Adept::DamageObject*,int> iter(&damageObjects);
	DamageObject *fred;
	while ((fred = iter.ReadAndNext ()) != NULL)
	{
		m_HitPoints += fred->currentArmorValue;
		if (fred->internalDamageObject)
		{
			m_HitPoints += fred->internalDamageObject->currentInternalDamage;
			fred->internalDamageObject->SetHitPointPointer (&m_HitPoints);
		}
		fred->SetHitPointPointer (&m_HitPoints);
	}
	if (m_HitPoints == 0)
		m_HitPoints = 1;
	m_MaxHitPoints = m_HitPoints;
	for(int i=0; i<12; i++)
	{
		armorArray[i] = -1.0f;
		DamageObject *damage_object = damageObjects.Find(i);
		if(damage_object)
		{
			armorArray[i] = damage_object->armorLevel;
			damage_object->SetArmorArrayEntry(&armorArray[i]);
		}
		else
		{
			armorArray[i] = -1;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::CommonCreation(CreateMessage *message)
{
	Check_Object(this);
	Check_Object(message);

	for (int i=0;i<11;i++)
		armorArray[i] = -1.0f;

	const GameModel *game_model = GetGameModel();
	Check_Object(game_model);

	vehicleShutDown = false;
	vehicleJustPoweredUp = false;

	animationVelocity = Vector3D::Identity;
	
	tonage = game_model->vehicleTonnage;
	battleValue = game_model->vehicleBattleValue;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::Respawn(Entity::CreateMessage *message)
{
	Check_Object(this);
	Check_Object(message);

	BaseClass::Respawn(message);
	CreateMessage *object_message = Cast_Pointer(CreateMessage *, message);
	CommonCreation(object_message);
	
	animStateEngine->Reset();

	//
	//-----------------------------------------
	//Load up the Damage Objects and Subsystems
	//-----------------------------------------
	//
	ReuseDamageObjects();

	if(object_message->subsystemStreamResourceID != ResourceID::Null)
	{
		Resource stream(object_message->subsystemStreamResourceID);
		Verify(stream.DoesResourceExist());
		ReuseSubsystems(&stream);
	}
	
	ReuseArmature();



	//
	// If you set to NeverCullMode, it screws up the sphere sync method.
	// this results in splash damage not working after a respawn.
	//
//	entityElement->SetNeverCullMode();
	GetElement()->SetCullMode(originalCullMode );

	
	SetCollisionMask(originalCollisionMask);

	if (GetAI() != 0)
	{
		if (MechWarrior4::AI::GetGraveyard() != 0)
		{
			MechWarrior4::AI::GetGraveyard()->NotifyCreated(objectID);
		}

		GetAI()->NotifyRespawned();
	}
}

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

MWObject::~MWObject()
{

	DESTRUCTOR("MWObject");

	Unregister_Object(animStateEngine);
	delete animStateEngine;
	
	if (animationArray != NULL)
	{

		Unregister_Pointer(animationArray);
		delete[] animationArray;

	}

	if (lastTriggerArray != NULL)
	{
		Unregister_Pointer(lastTriggerArray);
		delete[] lastTriggerArray;
	}


	damageObjects.DeletePlugs();
	internalDamageObjects.DeletePlugs();
	idleEffects.DeletePlugs();

	if(m_heatManager)
		delete m_heatManager;

	if (m_FindObjectCache)
		delete m_FindObjectCache;

	if (m_FindObjectList)
		delete m_FindObjectList;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::MakeAnimationArray()
{
	Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
	MWMover *mover;

	animationArrayCount = iterator.GetSize();
	if (animationArrayCount == 0)
	{
		animationArray = NULL;
		lastTriggerArray = NULL;
		return;
	}
	animationArray = new MWMover *[animationArrayCount];
	Register_Pointer(animationArray);


	lastTriggerArray = new int [animationArrayCount];
	Register_Pointer(lastTriggerArray);

	for (int counter = 0; counter < animationArrayCount; counter++)
	{
		lastTriggerArray[counter] = 0;
	}



	int i = 0;
	while ((mover = iterator.ReadAndNext()) != NULL)
	{
		animationArray[i] = mover;
		i++;
	}

}

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

void
	MWObject::ApplyChannel
	(
		MW4Animation::ChannelApplication &channel_data,
		int joint_index,
		void *user_data
	)
{

	MWObject *mw_object;
	mw_object = Cast_Object(MWObject*, user_data);

	Stuff::UnitQuaternion rotation;
	Stuff::Point3D position;

	LinearMatrix4D new_local_to_parent;
	MWMover *mover = mw_object->animationArray[joint_index];


	Check_Object(mover);

#if 0
	const char *compare_name = mover->instanceName;
	if((compare_name = strstr(compare_name, "::")) != NULL)
	{
		compare_name += 2;
	}
	else
	{
		compare_name = mover->instanceName;
	}
	if(!_stricmp(mover->instanceName, "site_eyepoint"))
	{
		SPEW(("jerryeds", "Animation trying to mess with the eye...bad bad bad!!!!"));
		return;
	}
#endif


	if (channel_data.hasTrigger)
	{
		if (channel_data.triggerValue != mw_object->lastTriggerArray[joint_index])
		{
			mw_object->animationTriggerManager.DispatchTriggerMessage(joint_index, channel_data.triggerValue, mw_object);
			mw_object->lastTriggerArray[joint_index] = channel_data.triggerValue;
		}
	}
	


	if (channel_data.hasVelocity)
	{
		//channel_data.velocityValue.y = 0.0f;
		//channel_data.velocityValue.x = 0.0f;

		//position.y = channel_data.positionValue.y;
		//position.x = channel_data.positionValue.x;

		position = mover->GetLocalToParent();
		mw_object->animationVelocity = channel_data.velocityValue;

		//vehicle->animationVelocity;

	}
	else
	{
		if (channel_data.hasPosition)
		{
			position = channel_data.positionValue;
		}
		else
		{
			position = mover->GetLocalToParent();
		}
	}


	if (channel_data.hasAngularVelocity)
	{
		mw_object->instantaniousAngularVelocity = channel_data.angularVelocityValue;
		rotation = mover->GetLocalToParent();
	}
	else
	{
		if (channel_data.hasRotation)
		{
			rotation = channel_data.rotationValue;
		}
		else
		{
			rotation = mover->GetLocalToParent();
		}
	}



	Stuff::Scalar small_backup = Stuff::SMALL;
	Stuff::SMALL = 1e-3f;

	rotation.Normalize();
	new_local_to_parent.BuildTranslation(position);
	new_local_to_parent.BuildRotation(rotation);
	


	#if defined(_ARMOR)
		new_local_to_parent.TestInstance();
	#endif

	
	mover->SetNewLocalToParent(new_local_to_parent);


	Stuff::SMALL = small_backup;


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::MakeArmatureChain()
{
	Check_Object(this);

	ChainIteratorOf<Entity *> child_iterator(&childEntityChain);
	Entity *entity;

	//
	//Step Through until we find a root mover object
	//

	while((entity = child_iterator.ReadAndNext()) != NULL)
	{
		if(entity->IsDerivedFrom(MWMover::DefaultData))
		{
			MWMover *mover;
			mover = Cast_Object(MWMover *, entity);
			ConnectMWMover(mover);
			entitiesToSync.Add(mover);
		}
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ConnectMWMover(MWMover *mover)
{
	Check_Object(this);

	ChainIteratorOf<Entity *> child_iterator(mover->GetChildEntityChain());
	Entity *entity;

	while((entity = child_iterator.ReadAndNext()) != NULL)
	{
		if(entity->IsDerivedFrom(MWMover::DefaultData))
		{
			MWMover *child_mover;
			child_mover = Cast_Object(MWMover *, entity);
			ConnectMWMover(child_mover);
		}
	}

	SortedChainIteratorOf<Site *, MString> site_iterator(&mover->m_sites);
	Site *site;
	while((site = site_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(site);
		m_sites.AddValue(site, site->GetName());
	}
	armatureChain.Add(mover);
	mover->myParentVehicle = this;
	mover->SetSkinPrefix(m_skinPrefix);
	mover->SetTeamDecal(m_teamDecal);
	mover->SetPilotDecal(m_pilotDecal);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MWObject::FindChildMoverIndexUserData(
		const char *joint_name,
		void *user_data
	)
{
	MWObject *mw_object = (MWObject *)user_data;
	Verify(mw_object->IsDerivedFrom(MWObject::DefaultData));


	return mw_object->FindChildMoverIndex(joint_name);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MWObject::FindChildMoverIndex(
		const char *temp_name
	)
{
	
	MString joint_name;

	int index = MW4Animation::UncompressName(temp_name, joint_name);

	if (index != -1)
	{
		if (temporaryQuickIDLookup[index] != -1)
		{
			return temporaryQuickIDLookup[index];
		}
	}
	else
	{
		Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
		MWMover *mover;

		int i = 0;
		while ((mover = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(mover);
			const char *compare_name = mover->instanceName;

			if (!_stricmp(compare_name, joint_name))
			{
				Verify(mover == animationArray[i]);
				return i;
			}

			++i;
		}
	}

	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover*
	MWObject::FindChildMover(
		const char *joint_name
	)
{
	Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
	MWMover *mover;

	while ((mover = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mover);
		const char *compare_name = mover->instanceName;
		if((compare_name = strstr(compare_name, "::")) != NULL)
		{
			compare_name += 2;
		}
		else
		{
			compare_name = mover->instanceName;
		}
		if (!_stricmp(compare_name, joint_name))
		{
			return mover;
		}
	}

	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ReuseDamageObjects()
{
	Check_Pointer(this);

	SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);

	DamageObject *damage_object;

	while((damage_object = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		damage_object->Reuse();
	}

	InternalDamageObject *internal_object;
	while((internal_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_object);
		internal_object->Reuse();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ConnectDamageObjects()
{
	Check_Pointer(this);

	SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);

	DamageObject *damage_object;


	while((damage_object = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
	
		MWMover *mover;
		mover = FindChildMover(damage_object->damageObjectName);
		if(mover)
		{
			Check_Object(mover);
			//
			//-----------------------------------------------
			//Assign Damage Object its internal damage object
			//-----------------------------------------------
			//
			damage_object->internalDamageObject =
				internalDamageObjects.Find(damage_object->internalDamageObjectID);
			
			Check_Object(damage_object->internalDamageObject);

			damage_object->internalDamageObject->parentEntity =
				FindChildMover(damage_object->internalDamageObject->parentEntityName);
			damage_object->internalDamageObject->damagePropagationObject =
				internalDamageObjects.Find(damage_object->internalDamageObject->damagePropagationZoneID);

			mover->SetDamageObject(damage_object);
			damage_object->Initialize(mover);
		}
		else
		{
			//
			//-------------------------------------------------------
			//No Name means it is tied to us not part of the armature
			//-------------------------------------------------------
			//
			damage_object->internalDamageObject =
				internalDamageObjects.Find(damage_object->internalDamageObjectID);
			
			Check_Object(damage_object->internalDamageObject);
			damage_object->internalDamageObject->parentEntity = this;
			damage_object->internalDamageObject->damagePropagationObject =
				internalDamageObjects.Find(damage_object->internalDamageObject->damagePropagationZoneID);
			SetDamageObject(damage_object);
			damage_object->Initialize(this);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::AddChild(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);

	Entity::AddChild(entity);
	if (entity->IsDerivedFrom(MWMover::DefaultData))
	{
		//We must make sure that we are on the armature chain
		if(!armatureChain.IsPlugMember(entity))
		{
			MWMover *mover;
			mover = Cast_Object(MWMover *, entity);
			armatureChain.Add(mover);
		}
	}
	if(entity->IsDerivedFrom(Subsystem::DefaultData))
	{
		if(!subsystemsInVehicle.IsPlugMember(entity))
		{
			Subsystem *subsystem;
			subsystem = Cast_Object(Subsystem *, entity);
			subsystemsInVehicle.Add(subsystem);

			if(subsystem->executionState->GetState() != ExecutionStateEngine::NeverExecuteState)
			{
				executingSubsystems.Add(subsystem);
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::RemoveChild(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);

	if(entity->IsDerivedFrom(Subsystem::DefaultData))
	{
		Subsystem *subsystem;
		subsystem = Cast_Object(Subsystem *, entity);
	
		subsystemsInVehicle.Remove(subsystem);
		executingSubsystems.Remove(subsystem);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ChildPreCollisionChanged(Entity *entity)
{
	Check_Object(this);
	Check_Object(entity);
	if(entity->IsDerivedFrom(Subsystem::DefaultData))
	{
		Subsystem *subsystem;
		subsystem = Cast_Object(Subsystem *, entity);

		if((subsystem->executionState->GetOldState() == ExecutionStateEngine::NeverExecuteState)
			&&(subsystem->executionState->GetState() != ExecutionStateEngine::NeverExecuteState))
		{
			executingSubsystems.Add(subsystem);
		}
		else if((subsystem->executionState->GetOldState() != ExecutionStateEngine::NeverExecuteState)
			&&(subsystem->executionState->GetState() == ExecutionStateEngine::NeverExecuteState))
		{
			executingSubsystems.Remove(subsystem);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static Entity*
	Find_Child(
		Entity *parent,
		const char* name
	)
{
	Check_Object(parent);
	Check_Pointer(name);
	return Cast_Object(MWObject*, parent)->FindChildMover(name);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::BecomeInteresting(bool render_me)
{
	Check_Object(this);
	LOAD_LOGIC("Become Interesting::MWObject");

	//
	//------------------------------------------------------------------------
	// The entity version will just load the solid volumes.  Go ahead and load
	// the stream resource that should be indicated in the game model
	//------------------------------------------------------------------------
	//
	if (!solidVolume && !hierarchicalVolume)
	{
		const GameModel *game_model = GetGameModel();
		Check_Object(game_model);

		//
		//-------------------------------
		// Load in the solid if it exists
		//-------------------------------
		//
		#if defined(LAB_ONLY)
			extern char g_LastEntity[255];
			if (!instanceName)
				g_LastEntity[0] = '\0';
			else
			{
				strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1);
				g_LastEntity[sizeof(g_LastEntity)-1] = '\0';
			}
		#endif
		if (game_model->obbStreamResourceID != ResourceID::Null)
		{
			gos_PushCurrentHeap(Adept::Entity::s_CollisionHeap);
			Resource obb_stream(game_model->obbStreamResourceID);
			Verify(obb_stream.DoesResourceExist());
			solidVolume =
				new CollisionVolume(
					this,
					&obb_stream,
					CollisionVolume::ReadOBBVersion(&obb_stream)
				);
			Check_Object(solidVolume);
			gos_PopCurrentHeap();
		}

		if (game_model->hierarchicalOBBStreamResourceID != ResourceID::Null)
		{
			gos_PushCurrentHeap(Adept::Entity::s_CollisionHeap);
			Resource obb_stream(game_model->hierarchicalOBBStreamResourceID);
			Verify(obb_stream.DoesResourceExist());
			if (!armatureChain.IsEmpty())
			{
				hierarchicalVolume =
					new CollisionVolume(
						this,
						Find_Child,
						this,
						&obb_stream,
						CollisionVolume::ReadOBBVersion(&obb_stream)
					);
				Check_Object(hierarchicalVolume);
			}
			else
			{
#ifdef LAB_ONLY
				PAUSE(("Error: %s is missing its armature!", (char*)instanceName));
#endif
				if (!solidVolume)
				{
					solidVolume =
						new CollisionVolume(
							this,
							&obb_stream,
							CollisionVolume::ReadOBBVersion(&obb_stream)
						);
					Check_Object(solidVolume);
				}
			}
			gos_PopCurrentHeap();
		}
	}

	if(!Mission::GetInstance()->DoesAllowRunningLights())
	{
		DestroyRunningLight();
	}

	BaseClass::BecomeInteresting(render_me);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::CheckVideoStates(bool render_me)
{
	if(render_me && IsDestroyed())
	{
		entityElement->SetAlwaysCullMode();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::DestroyRunningLight()
{
	Check_Object(this);

	if(jointRunningLight)
	{
		Check_Object(jointRunningLight);
		jointRunningLight->GetElement()->SetAlwaysCullMode();
		if(jointRunningLight->GetSolidVolume() &&
      !jointRunningLight->GetSolidVolume()->IsDestroyed())
			jointRunningLight->GetSolidVolume()->Destroy();
		if(jointRunningLight->GetHierarchicalVolume() &&
      !jointRunningLight->GetHierarchicalVolume()->IsDestroyed())
			jointRunningLight->GetHierarchicalVolume()->Destroy();

//		jointRunningLight->GetElement()->SetAlwaysCullMode();
//		jointRunningLight->SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);
//		jointRunningLight->SentenceToDeathRow();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ReuseSubsystems(MemoryStream *stream)
{
	Check_Pointer(this);

	Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
	Subsystem *subsystem;
	stream->AdvancePointer(sizeof(WORD));
	while (((subsystem = iterator.ReadAndNext()) != NULL) &&
		(stream->GetBytesRemaining() > 0))
	{
		Verify(subsystem->IsDerivedFrom(Subsystem::DefaultData));
		Entity::CreateMessage *message =
			Cast_Pointer(Entity::CreateMessage*, stream->GetPointer());
		subsystem->Respawn(message);
// MSL 5.02 headshot
		// bug fix: didn't re-hook these up - note we are explicitly calling the MWObject version
		MWObject::AddSubsystem(subsystem);
		stream->AdvancePointer(message->messageLength);
	}
	
	if(sensor)
	{
		sensor->SetSensorMode(Sensor::ActiveMode, DoesHaveBeagle());
	}		
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::HookUpSubsystems()
{
	Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
	Subsystem *subsystem;
	int weapon_id = 0;
	while ((subsystem = iterator.ReadAndNext()) != NULL)
	{
		Verify(subsystem->IsDerivedFrom(Subsystem::DefaultData));
		if(subsystem->ConnectSubsystem())
		{

			//
			//-----------------------------------------------
			//Connect the weapons to the correct weapon group
			//-----------------------------------------------
			//
			if(subsystem->IsDerivedFrom(Weapon::DefaultData))
			{
				Weapon *weapon;
				weapon = Cast_Object(Weapon *, subsystem);
				weaponChain.Add(weapon);
				weapon->SetWeaponID(weapon_id);
				++weapon_id;

			}
			AddSubsystem(subsystem);
		}
		else
		{
			RemoveChild(subsystem);
		}
	}
	if(sensor)
	{
		sensor->SetSensorMode(Sensor::ActiveMode, DoesHaveBeagle());
	}		
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::AddSubsystem(Subsystem *subsystem)
{
	Check_Object(this);
	Check_Object(subsystem);


	if(subsystem->IsDerivedFrom(Sensor::DefaultData))
	{
		sensor = Cast_Object(Sensor *, subsystem);
	}
	else if (subsystem->IsDerivedFrom(Beagle::DefaultData))
	{
		beagle = Cast_Object(Beagle *, subsystem);
	}
	else if (subsystem->IsDerivedFrom(AMS::DefaultData))
	{
		ams = Cast_Object(AMS *, subsystem);
	}
	else if(subsystem->IsDerivedFrom(ECM::DefaultData))
	{
		ecm = Cast_Object(ECM *, subsystem);
	}
// MSL 5.02 SubSystems
//	else if(subsystem->IsDerivedFrom(EnhancedOptics::DefaultData))
//	{
//		enhancedOptics = Cast_Object(EnhancedOptics *, subsystem);
//	}
	else if(subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
	{
		iff_jammer = Cast_Object(IFF_Jammer *, subsystem);
	}
	else if(subsystem->IsDerivedFrom(AdvancedGyro::DefaultData))
	{
		advancedGyro = Cast_Object(AdvancedGyro *, subsystem);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::RemoveSubsystem(Subsystem *subsystem)
{
	Check_Object(this);
	Check_Object(subsystem);

	if(subsystem->IsDerivedFrom(Weapon::DefaultData))
	{
		Weapon *weapon;
		weapon = Cast_Object(Weapon *, subsystem);
		weaponChain.Remove(weapon);
	}
	else if(subsystem->IsDerivedFrom(Sensor::DefaultData))
	{
		sensor = NULL;
	}
	else if (subsystem->IsDerivedFrom(Beagle::DefaultData))
	{
		beagle = NULL;
	}
	else if (subsystem->IsDerivedFrom(AMS::DefaultData))
	{
		ams = NULL;
	}
	else if(subsystem->IsDerivedFrom(ECM::DefaultData))
	{
		ecm = NULL;
	}
// MSL 5.02 SubSystems
//	else if(subsystem->IsDerivedFrom(EnhancedOptics::DefaultData))
//	{
//		enhancedOptics = NULL;
//	}
	else if(subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
	{
		iff_jammer = NULL;
	}
	else if(subsystem->IsDerivedFrom(AdvancedGyro::DefaultData))
	{
		advancedGyro = NULL;
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ReactToDestruction(int damage_mode, int damage_type)
{
	Check_Object(this);

	switch(damage_mode)
	{
	case InternalDamageObject::DestructionDamageMode:
		{

			if(!IsDestroyed())
			{
				Check_Object(executionState);
//				executionState->RequestState(ExecutionStateEngine::DestroyedState);
				if(m_AI)
				{
					Check_Object(m_AI);
					m_AI->Die();
				}
				else
				{
					MW4AI::g_Rect4DHash->RemovePermRect (this);
				}
				
				SetDestroyedFlag(damage_mode);

				if (damage_type != SplashDamageType)
					DealSplashDamage();

				const GameModel *model = GetGameModel();
				Check_Object(model);
				
				CreateEffect(model->destroyedEffectResource, this, false);
				if(!m_deathEntity.GetCurrent())
				{
					Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
					if(death_entity) 
					{
						m_deathEntity.Remove();
						m_deathEntity.Add(death_entity);
					}
				}
				

				RemoveFromExecution();
//				SentenceToDeathRow();
				DestroyChildren(damage_mode);
				break;
			}
		}
	}

	Entity::ReactToDestruction(damage_mode, damage_type);

	#ifdef LAB_ONLY
	if (MW4AI::Statistics::Enabled() == true)
	{
		MW4AI::Statistics::NotifyDestroyed(objectID);
	}
	#endif
}


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


void MWObject::DestroyDamageObjects()
{
	
	SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);

	DamageObject *damage_object;

	while((damage_object = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		damage_object->SilentDestruction();
	}

	InternalDamageObject *internal_object;
	while((internal_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_object);
		internal_object->SilentDestruction();
	}

}

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

void MWObject::DealSplashDamage()
{
	Check_Object(this);
	Check_Object(CollisionGrid::Instance);
	
    extern g_nMR;
    if (g_nMR == 2)
        return;

	if (!Network::GetInstance()->AmIServer())
		return;

	NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
	if (!params->m_splashOn)
		return;

	const GameModel *model = GetGameModel();
	Check_Object(model);
	Verify(splashedEntities.IsEmpty());
	splashSize = 0;
	if (model->splashDamageAmount > 0.0f)
	{

		//
		// Need to see if the target has a solid volume and if so, use that for the positioning of the target
		// bracket.
		CollisionVolume * volume;
		//
		// This code was just getting the torso and using that local to world but the torso location
		// was whacked. That should be fixed as a secondary issue, but for here the solid volume is
		// good since that is what would be doing ramming damage, etc... anyway.
		//
		
		volume = GetSolidVolume();
		if (!volume)
		{
			if (GetTorso())
				volume = GetTorso()->GetHierarchicalVolume();
			else
				volume = GetHierarchicalVolume();

		}
		Stuff::Sphere sphere;
		if (volume)
		{
			OBB world_bounds;
			world_bounds.Multiply(volume->m_localSpaceBounds, GetLocalToWorld());
			sphere.center = world_bounds.localToParent;
		}
		else
		{
			sphere.center = GetLocalToWorld();
		}
		sphere.radius = model->splashDamageRadius;
		splashSize = 0;

		CollisionGrid::Instance->FindEntitiesWithin(sphere, (Adept::CollisionGrid::WithinCallback)SplashCallBack, this);

		if (splashSize == 0)
			return;
		ChainIteratorOf<Entity *> splashed_entities(&splashedEntities);
		//
		// First, iterate through the list once to clear the been hit flag so we don't do
		// double/or more damage to multiple entities, connected to the same damage zones
		//
		Entity *hit_entity;
		while((hit_entity = splashed_entities.ReadAndNext()) != NULL)
		{	
			if (hit_entity->damageObject)
				hit_entity->damageObject->ClearTakenDamageFromThisEvent();
		}
		splashed_entities.First();

		NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
		
		while((hit_entity = splashed_entities.GetCurrent()) != NULL)
		{	
			if (hit_entity->damageObject)
			{
				//
				// If there is a damage object verify we aren't hitting it twice
				//
				if (!hit_entity->damageObject->GetTakenDamageFromThisEvent())
				{
					hit_entity->damageObject->SetTakenDamageFromThisEvent() ;
				}
				else
				{
				 splashed_entities.Remove();
				 continue;
				}
			}
			Stuff::Point3D ltwEntity;
			ltwEntity = hit_entity->GetLocalToWorld();

// MSL 5.06 Armor Mode
			MWApplication *m_App;
			m_App = MWApplication::GetInstance ();
			m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;

			Adept::Entity__TakeDamageMessage message(
					hit_entity->GetReplicatorID(),
					this->GetReplicatorID(),
					model->splashDamageAmount * ((Scalar)params->m_splashPercentage*0.01f),
					m_ArmorMode,
					SplashDamageType,
					Normal3D(0.0f, 0.0f, 1.0f),
					ltwEntity,
					model->splashHeatAmount,
					false,
					TakeDamageMessage::DefaultWeaponType
				);
			hit_entity->Receive(&message);
			splashed_entities.Remove();
		}

	}

}

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

void MWObject::SplashCallBack(Adept::Entity *entity, Adept::Entity *original_caller, const Stuff::Sphere &sphere)
{

	Check_Object(entity);
	Check_Object(original_caller);

	
	MWObject *mwobject = Cast_Object( MWObject*, original_caller);


	if (!entity->IsDestroyed())
	{
		
		CollisionVolume *volume = entity->GetHierarchicalVolume();
		if (volume)
		{

			volume->FindSolidsWithin(
				sphere,
				(Adept::CollisionVolume::WithinCallback)SubSplashCallBack,
				mwobject,
				entity,
				entity->GetLocalToWorld()
			);	
		}
		else
		{
			mwobject->splashedEntities.Add(entity);
			++mwobject->splashSize;
		}
	}
	
}

void MWObject::SubSplashCallBack(CollisionVolume *solid, Entity *original_caller, const Stuff::Sphere &sphere)
{

	Check_Object(solid);
	Check_Object(original_caller);

	MWObject *mwobject = Cast_Object( MWObject*, original_caller);

	if (solid->m_entity && !solid->m_entity->IsDestroyed())
	{
			

		mwobject->splashedEntities.Add(solid->m_entity);

		++mwobject->splashSize;
	}

}

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

void MWObject::TakeSplashDamage(Adept::Entity__TakeDamageMessage *message)
{
	Check_Object(this);
	Check_Object(CollisionGrid::Instance);

	// go thru my damage objects and deal the damage

	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&damageObjects);
	DamageObject *damage_object;
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		damage_object->TakeDamage(message, NULL);
	}


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::RemoveFromExecution()
{
	Check_Object(this);
	Check_Object(entityElement);
	Check_Object(executionState);

	if (newCollisions)
	{
		delete newCollisions;
		newCollisions = NULL;
	}
	executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
	entityElement->SetAlwaysCullMode();
	EntityManager::GetInstance()->RemovePostCollisionExecution(this);
	RemoveCollision();

	SyncMatrices(true);

	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::PreCollisionExecute(Stuff::Time till)
{
	Check_Object(this);

	PRECOLLISION_LOGIC("MWObject");
	m_hasExecuted = true;
#if defined(LAB_ONLY)
		if (!instanceName)
			MWGameInfo::g_LastMWObject[0] = '\0';
		else
		{
			strncpy(MWGameInfo::g_LastMWObject, instanceName, sizeof(MWGameInfo::g_LastMWObject)-1);
			MWGameInfo::g_LastMWObject[sizeof(MWGameInfo::g_LastMWObject)-1] = '\0';
		}
		MWGameInfo::g_LastMWObjectPos = GetLocalToWorld();
#endif

	//
	//----------------------------------------------
	// All MWObjects that execute use post collision
	//----------------------------------------------
	//
	UsePostCollision();
	BaseClass::PreCollisionExecute(till);

	//
	//-------------------------------------------------
	// Run the ubsystems, then finally the heat manager
	//-------------------------------------------------
	//
	{
		ChainIteratorOf<Subsystem *> sub_iterator(&executingSubsystems);
		Subsystem *subsystem;
		while((subsystem = sub_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(subsystem);
			subsystem->PreCollisionExecute(till);
			Verify(!subsystem->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(subsystem));
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::SyncMatrices(bool update_matrix)
{
	Check_Object(this);
	SYNC_LOGIC("MWObject");

	#if defined(HUNT_BUG)
		bool old_update=update_matrix;
		if (update_matrix)
		{
			SPEW((0, "MWObject::SyncMatrices %s(+", GetClassString()));
			Spew(0, GetReplicatorID());
			SPEW((0, ")"));
		}
	#endif
	Set_Statistic(s_EntitiesSynced, s_EntitiesSynced);

	//
	//-----------------------------------------
	// If we have a dirty locator, sync with it
	//-----------------------------------------
	//
	if (IsMatrixDirty())
	{
		if (update_matrix)
		{
			Check_Object(entityElement);
			entityElement->Sync();
			update_matrix = false;
		}
		ClearNeedMatrixSync();
	}

	//
	//-----------------------------
	// Sync our children's locators
	//-----------------------------
	//
	if (!entitiesToSync.IsEmpty())
	{
		ChainIteratorOf<MWMover*> children(&entitiesToSync);
		Entity *child;
		while ((child = children.ReadAndNext()) != NULL)
		{
			Check_Object(child);
			child->SyncMatrices(update_matrix);
		}
	}

	#if defined(HUNT_BUG)
		if (old_update)
			SPEW((0, ""));
	#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::PostCollisionExecute(Time till)
{
	Check_Object(this);
	Check_Object(executionState);

	POSTCOLLISION_LOGIC("MWObject");

	{for (std::vector<Torso*>::iterator i = m_Torsos.begin();
		  i != m_Torsos.end();
		  ++i)
	{
		if ((*i)->followTorsoRequest)
		{
			gosREPORT(*i,"somehow a mwobject got a follow torso request when it has no torso");
			Check_Object(*i);
			Point3D target_position = (*i)->torsoRequest;

			Point3D distance_to_target;
			distance_to_target.MultiplyByInverse(target_position,(*i)->GetTwistJointMatrix());
	#if 0
			MWMover *eye_site = eyeSitePointer.GetCurrent();
			YawPitchRoll twist_offset = YawPitchRoll::Identity;

			Point3D local_eye_site_offset_pitch = Point3D::Identity;
			Point3D local_eye_site_offset_twist = Point3D::Identity;
			if(eye_site)
			{
				Check_Object(eye_site);
				Point3D world_eye_site = (Point3D) eye_site->GetLocalToWorld();
	//			LinearMatrix4D world_eye_site = eye_site->GetLocalToWorld();
			//	world_eye_site.Invert();
	//			LinearMatrix4D local_eye_site_offset = LinearMatrix4D::Identity;
				local_eye_site_offset_twist.MultiplyByInverse(world_eye_site, (*i)->GetTwistJointMatrix());
				local_eye_site_offset_pitch.MultiplyByInverse(world_eye_site, (*i)->GetPitchJointMatrix());
	//			twist_offset = (YawPitchRoll) local_eye_site_offset;
			}
	#endif
			Scalar heading_adjustment;
			Point3D distance_to_target_pitch;
			distance_to_target_pitch.MultiplyByInverse(target_position,(*i)->GetPitchJointMatrix());
			if(!Small_Enough(distance_to_target_pitch.z))
			{
	//			heading_adjustment = Arctan(distance_to_target_pitch.y, distance_to_target_pitch.z) - (Arctan(local_eye_site_offset_pitch.y, local_eye_site_offset_pitch.z));;
				heading_adjustment = Arctan(distance_to_target_pitch.y, distance_to_target_pitch.z);
				if(!Small_Enough(heading_adjustment))
				{
					Scalar speed_demand;
					if (heading_adjustment > (*i)->GetPitchSpeed())
					{
						speed_demand = 1.0;
					}
					else
					{
						speed_demand = heading_adjustment / (*i)->GetPitchSpeed();
						speed_demand = Abs(speed_demand);
					}
					if(heading_adjustment > 0.02) // down
						(*i)->pitchDemand = -speed_demand;
					if(heading_adjustment < -0.02) // up
						(*i)->pitchDemand = speed_demand;
				}
			}

	#if 0
			if(eye_site)
			{
				Check_Object(eye_site);
				Point3D world_eye_site = (Point3D) eye_site->GetLocalToWorld();
	//			LinearMatrix4D world_eye_site = eye_site->GetLocalToWorld();
			//	world_eye_site.Invert();
	//			LinearMatrix4D local_eye_site_offset = LinearMatrix4D::Identity;
				local_eye_site_offset_twist.MultiplyByInverse(world_eye_site, (*i)->GetTwistJointMatrix());
				local_eye_site_offset_pitch.MultiplyByInverse(world_eye_site, (*i)->GetPitchJointMatrix());
	//			twist_offset = (YawPitchRoll) local_eye_site_offset;
			}
	#endif			

			if(!Small_Enough(distance_to_target.z))
			{
	//			heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z)) + twist_offset.yaw;
	//			heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z)) - (Arctan(local_eye_site_offset_twist.x, local_eye_site_offset_twist.z));
				heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z));
				if(!Small_Enough(heading_adjustment))
				{
					Scalar speed_demand;
					if (heading_adjustment > (*i)->GetTwistSpeed())
					{
						speed_demand = 1.0;
					}
					else
					{
						speed_demand = heading_adjustment / (*i)->GetTwistSpeed();
						speed_demand = Abs(speed_demand);
					}

					if(heading_adjustment > 0.02) //left
						(*i)->yawDemand = speed_demand;
						
					if(heading_adjustment < -0.02) //right
						(*i)->yawDemand = -speed_demand;
						
				}
			}
		}
	}}
	BaseClass::PostCollisionExecute(till);
}


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

Effect*
	MWObject::CreateEffect(const Adept::ResourceID& effect_id, MWMover *parent_part, bool follow_joint)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = GetLocalToWorld();
	if(parent_part)
	{
		Check_Object(parent_part);
		effect_location = parent_part->GetLocalToWorld();
	}

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);

	if (parent_part != NULL && follow_joint)
	{
		entity->SetFollowEntity(parent_part);
		entity->PlaceOnEntity();
	}
	
	entity->SyncMatrices(true);

	return entity;
	
}

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

Effect*
	MWObject::CreateEffect(const Adept::ResourceID& effect_id, Site *parent_part, bool follow_joint)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = GetLocalToWorld();
	if(parent_part)
	{
		Check_Object(parent_part);
		effect_location = parent_part->GetLocalToWorld();
	}

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);

	if (parent_part != NULL && follow_joint)
	{
		entity->SetFollowEntity(parent_part);
		entity->PlaceOnSite();
	}
	
	entity->SyncMatrices(true);

	return entity;
	
}

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

Effect*
	MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, MWMover *parent_part, bool follow_joint)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = GetLocalToWorld();
	if(parent_part)
	{
		Check_Object(parent_part);
		effect_location = parent_part->GetLocalToWorld();
	}

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags|Effect::LoopFlag,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);

	if (parent_part != NULL && follow_joint)
	{
		entity->SetFollowEntity(parent_part);
		entity->PlaceOnEntity();
	}
	
	entity->SyncMatrices(true);

	return entity;
	
}

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

Effect*
	MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, const Point3D &location)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = LinearMatrix4D::Identity;
	effect_location.BuildTranslation(location);

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags|Effect::LoopFlag,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);
	
	entity->SyncMatrices(true);

	return entity;
	
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

Effect*
	MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, Site *parent_part, bool follow_joint)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = GetLocalToWorld();
	if(parent_part)
	{
		Check_Object(parent_part);
		effect_location = parent_part->GetLocalToWorld();
	}

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags|Effect::LoopFlag,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);

	if (parent_part != NULL && follow_joint)
	{
		entity->SetFollowEntity(parent_part);
		entity->PlaceOnSite();
	}
	
	entity->SyncMatrices(true);

	return entity;
	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
	MWObject::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = LinearMatrix4D::Identity;
	effect_location.BuildTranslation(location);



	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);


	
	entity->SyncMatrices(true);

	return entity;
	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.03 Glass
Effect*
	MWObject::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location, const Vector3D &vector)
{

	if (effect_id == ResourceID::Null)
		return NULL;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = LinearMatrix4D::Identity;
	effect_location.AlignLocalAxisToWorldVector(vector, Y_Axis, X_Axis, Z_Axis);
	effect_location.BuildTranslation(location);



	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

	Effect *entity;
	ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
	entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
	Check_Object(entity);
	Check_Object(Map::GetInstance());
	Map::GetInstance()->AddChild(entity);


	
	entity->SyncMatrices(true);

	return entity;
	
}

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

Entity *
	MWObject::CreateStaticHermitEntity(ResourceID entity_id)
{

	if(entity_id == ResourceID::Null)
		return false;


	ClassID class_ID;
	class_ID = GetClassIDFromDataListID(entity_id);
	Verify(class_ID != NullClassID);

	unsigned flags = HermitMode;

	Entity::CreateMessage entity_create_message(
		sizeof(Entity::CreateMessage),
		DefaultEventPriority,
		CreateMessage::DefaultFlags,
		class_ID,
		flags,
		entity_id,
		GetLocalToWorld(),
		0.0f,
		ExecutionStateEngine::NeverExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&entity_create_message, entity_create_message.messageLength);

	Entity *entity;
	ReplicatorID beam_id = Connection::Hermit->GetNextReplicatorID();
	entity = CreateEntity(&stream, &beam_id, false);
	Check_Object(entity);
	entity->SetPropType(MissionPropType);
	Map::GetInstance()->AddChild(entity);
	entity->SyncMatrices(true);



	return entity;

}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

void MWObject::AttachAI (AI *ai)
{
	Check_Object (this);

	if (ai != 0)
	{
		Check_Object (ai);
	}

	m_AI = ai;
}

void MWObject::SentenceToDeathRow()
{
	Check_Object(this);

	if (m_AI)
		m_AI->SentenceToDeathRow ();

	BaseClass::SentenceToDeathRow ();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const MWObject::GroupList&
	MWObject::GetGroups() const
{
	return m_groups;
}

MWObject::GroupList&
	MWObject::GetGroups()
{
	return m_groups;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MWObject::GetSensorMode()
{
	Check_Object(this);
	if(sensor)
	{
		Check_Object(sensor);
		return sensor->sensorMode;
	}
	return Sensor::ActiveMode;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MWObject::DoesHaveBeagle()
{
	Check_Object(this);

	if(beagle)
		return true;
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::AddStatsToString(std::string& s)
{
	s += instanceName;

	if ((DamageDispatch::GetGlobalInvulnerability() == true) &&
		(IsPlayerVehicle() == true))
	{
		s += " (INVULNERABLE)";
	}

	if (GetTargetDesirability() == desirability_never)
	{
		s += " (IGNORE)";
	}

	if (IsDestroyed() == true)
	{
		s += " (DEAD)";
	}

	char temp[80];

	if(isPlayerVehicle)
	{
		if(VehicleInterface::GetInstance())
		{
			s += "\nTARGETMATERIAL: ";
			int material_num = VehicleInterface::GetInstance()->targetQuery.m_material;
			const char *material = MaterialTypeAsciiToText(material_num);
			sprintf(temp,"%s\n",(char *)material);
			s += temp;
		}
	}

	s += "\nTONNAGE: ";
	sprintf(temp,"%d",(int)GetTonage());
	s += temp;

	s += "\nBATTLEVALUE: ";
	sprintf(temp,"%d",(int)GetBattleValue());
	s += temp;

	s += "\nHEAT: ";
	if(m_heatManager)
		sprintf(temp,"%f",m_heatManager->GetHeat());
	else
		sprintf(temp,"NA");
	s += temp;

	s += "\nCOOLANT: ";
	if(m_heatManager)
		sprintf(temp,"%f",m_heatManager->GetCoolant());
	else
		sprintf(temp, "NA");
	s += temp;

	s += "\nPOSITION: x=";
	Point3D pos = (Point3D)GetLocalToWorld();
	s += ScalarToString(pos.x);
	s += ", z=";
	s += ScalarToString(pos.z);
	s += "\n";

	if (GetTorso() != 0)
	{
		s += "Torso: y=";
		sprintf(temp,"%.2f p=%.2f\n",GetTorso()->yawValue,GetTorso()->pitchValue);
		s += temp;
	}

	if (GetTargetDesirability() >= 0)
	{
		sprintf(temp,"Target Desirability: %d\n",(int)(GetTargetDesirability() * 100));
		s += temp;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::AddDamageInfoToString(std::string& s)
{
	Check_Object(this);

	char temp[80];
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
	SortedChainIteratorOf<DamageObject*, int> damage_iterator(&damageObjects);

	s += "\nARMOR\n";
	DamageObject *damage_object;
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		s += damage_object->damageObjectName;
		sprintf(temp, "base: %.2f current: %.2f\n", damage_object->baseArmorValue, damage_object->currentArmorValue);
		s += temp;
	}

	s += "\nINTERNAL\n";
	MWInternalDamageObject *internal_object;
	while((internal_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_object);
		s += InternalDamageObject::InternalZoneAsciiToText(internal_object->damageZone);
		sprintf(temp, "Mode: %s\n", InternalDamageObject::DamageModeAsciiToText(internal_object->damageMode));
		s += temp;
		sprintf(temp, "base: %.2f current: %.2f\n", internal_object->baseInternalDamage, internal_object->currentInternalDamage);
		s += temp;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::NotifyProjectileApproaching(const Stuff::Point3D& origin)
{
	BaseClass::NotifyProjectileApproaching(origin);

	if (GetAI() != 0)
	{
		GetAI()->NotifyProjectileApproaching(origin);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::NotifyOfMissileLock()
{
	Check_Object(this);

	if(vehicleInterface)
		vehicleInterface->ReactToEvent (VehicleInterface::MISSILE_LOCKED_ON_ME);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceID
	MWObject::ReactToMissileApproach(Scalar distance, const Point3D& current_position)
{
	Check_Object(this);
	if(GetAMS())
	{
		const AMS__GameModel *model = GetAMS()->GetGameModel();
		Check_Object(model);
		if(GetAMS()->DoesHaveAmmo())
		{
			GetAMS()->SubtractAmmo(1);
			return model->amsEffectResource;
		}
	}

	return ResourceID::Null;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::SetTargetDesirability(Stuff::Scalar desirability)
{
	if (desirability == desirability_never)
	{
		Verify(Adept::EntityManager::GetInstance() != 0);

		NameTable *table = NameTable::GetInstance();
		{
			int size(table->nameTableArray[NameTable::VehicleArray].GetLength());

			{for (int i = 0;
				  i < size;
				  ++i)
			{
				NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
				Adept::Entity* ent = data->dataPointer->GetCurrent ();

				if ((ent != 0) &&
					(ent->IsDerivedFrom(MWObject::DefaultData) == true))
				{
					MWObject* mwobject = Cast_Object(MWObject*,ent);
					if (mwobject->GetAI() != 0)
					{
						mwobject->GetAI()->EnsureNotTargeting(objectID);
					}
				}
			}}
		}

		{
			int size(table->nameTableArray[NameTable::TurretArray].GetLength());

			{for (int i = 0;
				  i < size;
				  ++i)
			{
				NameTableEntry *data = &table->nameTableArray [NameTable::TurretArray][i];
				Adept::Entity* ent = data->dataPointer->GetCurrent ();

				if ((ent != 0) &&
					(ent->IsDerivedFrom(MWObject::DefaultData) == true))
				{
					MWObject* mwobject = Cast_Object(MWObject*,ent);
					if (mwobject->GetAI() != 0)
					{
						mwobject->GetAI()->EnsureNotTargeting(objectID);
					}
				}
			}}
		}
	}
	else
	{
		if (desirability != desirability_invalid)
		{
			Verify(desirability >= 0);
			Verify(desirability <= 1);
		}
	}

	m_TargetDesirability = desirability;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
	MWObject::GetTargetDesirability() const
{
	return (m_TargetDesirability);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::NotifyFired(const Adept::Entity::CollisionQuery& query)
{
	if (GetAI() != 0)
	{
		GetAI()->NotifyShotFired(query,*this);
	}

	if ((GetSensor() == 0) ||
		(query.m_line == 0))
	{
		return;
	}

	const MechWarrior4::Sensor::sensorDataArray& sensed_data = GetSensor()->GetSensorData();
	{for (int i = 0;
		  i < sensed_data.GetLength();
		  ++i)
	{
		MechWarrior4::SensorData* d = sensed_data[i];
		if ((d != 0) &&
			(d->object.GetCurrent() != 0) &&
			(d->object.GetCurrent() != this) &&
			(d->object.GetCurrent()->IsDerivedFrom(MWObject::DefaultData)))
		{
			MWObject* that = Cast_Object(MWObject*,d->object.GetCurrent());
			Check_Object(that);

			if (that->GetAI() != 0)
			{
				that->GetAI()->NotifyShotFired(query,*this);
			}
		}
	}}

															// special case for shutdown mechs since they don't appear on sensors
	MechAI::NotifyShutDownMechsShotFired(query,*this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::NotifyInTargetingReticule(MWObject& who)
{
	if (GetAI() != 0)
	{
		GetAI()->NotifyInTargetingReticule(who);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MWObject::CollisionHandler(
		Stuff::LinearMatrix4D *new_position,
		Stuff::DynamicArrayOf<CollisionData> *collisions
	)
{
	Check_Object(this);
	Verify(GetInterestLevel() != DormantInterestLevel);
	Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));

	STOP(("What are we doing here?!?!"));
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::GetLineOfSight(Stuff::LinearMatrix4D& line_of_sight)
{
	if ((GetTorso()) &&
		(GetTorso()->twistJoint))
	{
		line_of_sight = GetTorso()->twistJoint->GetLocalToWorld();
	}
	else
	{
		if (eyeSitePointer.GetCurrent())
		{
			line_of_sight = eyeSitePointer.GetCurrent()->GetLocalToWorld();
		}
		else
		{
			line_of_sight = GetLocalToWorld();
		}
	}

	Adept::InternalDamageObject* torso_zone = internalDamageObjects.Find(Adept::InternalDamageObject::CenterTorsoZone);

	if ((torso_zone != 0) &&
		(torso_zone->parentEntity != 0))
	{
		line_of_sight.BuildTranslation((Stuff::Point3D)torso_zone->parentEntity->GetLocalToWorld());
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Point3D
	MWObject::GetLineOfSight()
{
	Adept::InternalDamageObject* torso_zone = internalDamageObjects.Find(Adept::InternalDamageObject::CenterTorsoZone);

	if ((torso_zone != 0) &&
		(torso_zone->parentEntity != 0))
	{
		return (torso_zone->parentEntity->GetLocalToWorld());
	}

	if ((GetTorso()) &&
		(GetTorso()->twistJoint))
	{
		return (GetTorso()->twistJoint->GetLocalToWorld());
	}

	if (eyeSitePointer.GetCurrent())
	{
		return (eyeSitePointer.GetCurrent()->GetLocalToWorld());
	}

	Point3D p(GetLocalToWorld());
	p.y += 1.0f;

	return (p);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
{
	Check_Object(this);
	Check_Object(message);

    if (g_nMR == 2)
        return;

	if (IsDestroyed())
		return;

	#ifdef LAB_ONLY
	if ((GetOwner() != 0) &&
		(MW4AI::Statistics::Enabled() == true))
	{
		Connection	*connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);

		if (connection == NULL)
			return;

		Replicator* r = connection->FindReplicator(message->inflictingEntityID);
		if (r != 0)
		{
			Verify(r->IsDerivedFrom(Entity::DefaultData));
			Entity* e = Cast_Object(Entity*,r);

			MW4AI::Statistics::NotifyDamageTaken(objectID,e->objectID,message->amountOfDamage,message->typeOfDamage);
		}
	}
	#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Point3D&
	MWObject::EstimateFuturePosition(
		Stuff::Point3D* new_position,
		Stuff::Scalar seconds,
		bool consider_terrain
	)
{
	Check_Object(this);
	return *new_position = GetLocalToWorld();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::Reuse(
		const CreateMessage *message,
		ReplicatorID *base_id
	)
{
	Check_Object(this);
	Check_Object(message);

	STOP(("Not implemented"));
	BaseClass::Reuse(message, base_id);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::ToggleSearchLight()
{
	Check_Object(this);
	Check_Object(Mission::GetInstance());

	if(Mission::GetInstance()->DoesAllowSearchLights())
	{
		if(searchLight)
		{
			if(IsSearchLightOn())
			{
	//
	// [johnyo] 08/27/00 PreviousSearchLight code is experimental code that I have checked in to keep a backup
	//									 of only. It may be ripped out shortly if the effect that it was intended to have isn't
	//									 put into the game
	//
//				if (IsPlayerVehicle())
//					Mission::GetInstance()->ResetMissionLights();
				searchLight->HideBeam();
//				SetSearchLightMode(true);
			}
			else
			{
//				if (IsPlayerVehicle())
//					Mission::GetInstance()->SetSearchLightMissionLights();
				searchLight->ShowBeam();
//				SetSearchLightMode(false);
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::TurnOnSearchLight()
{
	Check_Object(this);	
	Check_Object(Mission::GetInstance());

// MSL 5.02 SearchLight
//	if(Mission::GetInstance()->m_isNightMission)
	if(Mission::GetInstance()->DoesAllowSearchLights())
	{
//		if (IsPlayerVehicle())
//			Mission::GetInstance()->SetSearchLightMissionLights();
		if(searchLight)
			searchLight->ShowBeam();
//		SetSearchLightMode(true);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::TurnOffSearchLight()
{
	Check_Object(this);
//	MWMission *mw_mission = Cast_Object(MWMission *, MWMission::GetInstance());
//	mw_mission->ResetMissionLights();
	if(searchLight)
		searchLight->HideBeam();
//	SetSearchLightMode(false);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MWObject::IsSearchLightOn()
{
	Check_Object(this);

	if(searchLight)
		return searchLight->isLightOn;

	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
	MWObject::FriendlyFireDamageMultiplier() const
{
	return (1);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::TakeDamageMessageHandler(const TakeDamageMessage *message)
{
	Check_Object(this);
	Check_Object(message);
	Verify(message->messageID == TakeDamageMessageID);

	if(damageObject)
	{
		damageObject->TakeDamage((TakeDamageMessage *)message, this);
	}

	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);

	while((damage_object = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		if(damage_object != damageObject)
		{
			damage_object->TakeDamage((TakeDamageMessage *)message, NULL);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
char*
	MWObject::GetObjectName()
{
	Check_Object(this);
	Check_Object(MWApplication::GetInstance());

	if(m_doesHaveInstanceName)
	{
		if((m_localizeIndex > -1) && (!isPlayerVehicle))
		{
			return MWApplication::GetInstance()->GetLocString(m_localizeIndex);
		}
		else
		{
			return (char *)instanceName;
		}
	}
	else
	{
		if(isPlayerVehicle)
			return (char *)instanceName;
	}
	const GameModel *model = GetGameModel();
	Check_Object(model);

	return MWApplication::GetInstance()->GetLocString(model->m_nameIndex);
}

char* MWObject::GetModelName()
{
	Check_Object(this);
	Check_Object(MWApplication::GetInstance());

	const GameModel *model = GetGameModel();
	Check_Object(model);

	return MWApplication::GetInstance()->GetLocString(model->m_nameIndex);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MWObject::GetVisibleOnSensors() const
{
	return (m_VisibleOnSensors);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWObject::SetVisibleOnSensors(bool visible)
{
	m_VisibleOnSensors = visible;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MWObject::DoesHaveAvailableTonage(Stuff::Scalar tons)
{
	Check_Object(this);

	const GameModel *model = GetGameModel();
	Check_Object(model);

	return (tonage + tons) <= model->maxVehicleTonnage + 0.01f;
}

void MWObject::EngineDead (void)
{
	STOP (("Only a drop ship should handle this function"));
}

#ifdef _DEBUG
Adept::Site* MWObject::FindSite(const char *site_name)
{
    Check_Object(this);
    Check_Pointer(site_name);
    Adept::Site* pSite = m_sites.Find(site_name);
    if (pSite) {
        Check_Object(pSite->GetParent());
    }
    return pSite;
}
#endif // _DEBUG
void MWObject::SetDmgModifier (int nIdx, int nDmgFactor)
{
	// nIdx : 0: default, 1: splash
	gosASSERT((0 <= nIdx) && (nIdx < 2));
	// nDmgFactor:  < 0 - restore
	// nDmgFactor: == 0 - store
	// nDmgFactor:  > 0 - set damage modifier as (nDmgFactor/10000.0)
	Check_Pointer(this);

	SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);

	DamageObject *damage_object;

	nIdx *= 2;
	if (nDmgFactor < 0) { // restore
		while((damage_object = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			damage_object->SetDamageModifier(nIdx, damage_object->GetDamageModifier(nIdx + 1));
		}
	} else if (nDmgFactor == 0) {
		while((damage_object = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			damage_object->SetDamageModifier(nIdx + 1, damage_object->GetDamageModifier(nIdx));
		}
	} else {
		Stuff::Scalar f = static_cast<Stuff::Scalar>(nDmgFactor / 10000.0);
		while((damage_object = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			damage_object->SetDamageModifier(nIdx, f);
		}
	}
}

void MWObject::RepairDamage (Stuff::Scalar fRepair)
{
    // jcem
	Check_Pointer(this);
    if (fRepair <= 0.0f)
        return;
    if (1.0f < fRepair)
        fRepair = 1.0f;

	SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);

	DamageObject *damage_object;

	while((damage_object = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		damage_object->RepairDamage(fRepair);
    }
}
