//===========================================================================//
// File:	Mech.cpp											
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 09/09/98  JSE  Inital base class based off of Shadowrun/Adept             //
// 09/22/98  BDB  Inital base Mech class based off Vehicle					 //
// 12/26/01  MSL  Added Eject Code to ReactToDestruction and changed site to //
//                "site_eject2"                                              //
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//


#include "MW4Headers.hpp"

#include "Mech.hpp"
#include "Torso.hpp"
#include "HeatManager.hpp"
#include "JumpJet.hpp"
#include "SearchLight.hpp"
#include "Engine.hpp"
#include "ECM.hpp"
// MSL 5.02 SubSystems
#include "IFF_Jammer.hpp"
#include "MoverAI.hpp"
#include "HeatSink.hpp"
#include "MechAnimationState.hpp"
#include "Blanderizer.hpp"
#include "SpringOf.hpp"
#include "VehicleInterface.hpp"
#include "MWDamageObject.hpp"
#include "EyePointManager.hpp"
#include "AI_Statistics.hpp"
#include "MFB.hpp"
#include "Armor.hpp"
#include "MWApplication.hpp"
#include "Gyro.hpp"
#include "SubsystemClassData.hpp"
#include "mwmission.hpp"
#include "bucket.hpp"
#include "Sensor.hpp"
#include "mwgame.hpp"
#include "salvage.hpp"
#include "flag.hpp"
#include "playerai.hpp"
#include "mwmap.hpp"
#include "Team.hpp"
#include "Weapon.hpp"
#include "ProjectileWeapon.hpp"
#include "mw4shell.hpp"

#include <Adept\Map.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\GUITextManager.hpp>
#include <Adept\GUITextObject.hpp>
#include <Adept\EntityManager.hpp>
#include <Adept\DamageObject.hpp>
#include <Adept\Effect.hpp>
#include <Adept\NameTable.hpp>
#include <Adept\Mission.hpp>
#include <Adept\CollisionVolume.hpp>
#include <Adept\Site.hpp>
#include <Adept\LightManager.hpp>
#include <Adept\AudioCommand.hpp>
#include <Adept\AudioRenderer.hpp>
#include "mwguimanager.hpp"
#include "hudmap.hpp"
// MSL 5.02
#include "guilightamp.hpp"
#include "guiradarmanager.hpp"
#include "hudtarg.hpp"

#include "ai_userconstants.hpp"

#include <ElementRenderer\Element.hpp>

#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRTexture.hpp>
#include <MLR\MLRShadowLight.hpp>

#include <Compost\CompostHeaders.hpp>

// ngLog addition	// JKK
#if !defined(NO_LOG)
#include "nglog_MW4.hpp"
#endif // !defined(NO_LOG)
#include "mechlabheaders.h"

// jcem - start
#include "windows.h"
#include "ctcls.h"
#include "ctcl.h"
#include "recscore.h" // jcem

extern int g_nMR;
// jcem - end

// MSL 5.02 headshot
namespace MechWarrior4
{
	extern Scalar g_HUDHeatLevel;
	extern Scalar g_HUDPPCLevel;
	extern int g_HUDHeatAlpha;
}


// MSL 5.02 SubSystems
#include "AdvancedGyro.hpp"
#include "MechLab.hpp"


const Stuff::Scalar mission_area_warning_frequency = 10.0f;
const Stuff::Scalar WALK_SPEED_SOUND = 10.0f;				// mps

// MSL 5.02 headshot
const Scalar MECH_HEAD_SHOT_FALL_MOD  =  1.3f; //the percentage to lower the damage threshold of what it takes to fall down when a mech takes a head-shot
const Scalar MECH_HEAD_SHOT_TORSO_ROCK_MOD = 1.3f;
const Scalar MECH_HEAD_SHOT_TORSO_SPIN_MOD = 1.3f;

// MSL 5.02 SubSystems
const Scalar ADVANCED_GYRO_FALL_MOD = 0.15f;
const Scalar ADVANCED_GYRO_TORSO_ROCK_MOD = 0.15f;
const Scalar ADVANCED_GYRO_TORSO_SPIN_MOD = 0.15f;

// MSL 5.04 Friendly Fire Betty
Stuff::Scalar m_FriendlyFireHit;

//#############################################################################
//##################	Mech::ExecutionStateEngine    ######################
//#############################################################################

static int Ground_Mode=2;

static bool __stdcall CheckSnapToGround() {return Ground_Mode==0;}
static void __stdcall EnableSnapToGround() {Ground_Mode = (Ground_Mode==0) ? 1 : 0;}
static bool __stdcall CheckFlying() {return Ground_Mode==2;}
static void __stdcall EnableFlying() {Ground_Mode = (Ground_Mode==2) ? 1 : 2;}

static Scalar Special_Mech_Gravity=4.0f;

static bool __stdcall Checkg1_0() {return Special_Mech_Gravity==1.0f;}
static bool __stdcall Checkg1_2() {return Special_Mech_Gravity==1.2f;}
static bool __stdcall Checkg1_4() {return Special_Mech_Gravity==1.4f;}
static bool __stdcall Checkg1_6() {return Special_Mech_Gravity==1.6f;}
static bool __stdcall Checkg1_8() {return Special_Mech_Gravity==1.8f;}
static bool __stdcall Checkg2_0() {return Special_Mech_Gravity==2.0f;}
static bool __stdcall Checkg2_5() {return Special_Mech_Gravity==2.5f;}
static bool __stdcall Checkg3_0() {return Special_Mech_Gravity==3.0f;}
static bool __stdcall Checkg4_0() {return Special_Mech_Gravity==4.0f;}
static bool __stdcall Checkg5_0() {return Special_Mech_Gravity==5.0f;}

static void __stdcall Enableg1_0() {Special_Mech_Gravity = 1.0f;}
static void __stdcall Enableg1_2() {Special_Mech_Gravity = (Special_Mech_Gravity!=1.2f) ? 1.2f : 1.0f;}
static void __stdcall Enableg1_4() {Special_Mech_Gravity = (Special_Mech_Gravity!=1.4f) ? 1.4f : 1.0f;}
static void __stdcall Enableg1_6() {Special_Mech_Gravity = (Special_Mech_Gravity!=1.6f) ? 1.6f : 1.0f;}
static void __stdcall Enableg1_8() {Special_Mech_Gravity = (Special_Mech_Gravity!=1.8f) ? 1.8f : 1.0f;}
static void __stdcall Enableg2_0() {Special_Mech_Gravity = (Special_Mech_Gravity!=2.0f) ? 2.0f : 1.0f;}
static void __stdcall Enableg2_5() {Special_Mech_Gravity = (Special_Mech_Gravity!=2.5f) ? 2.5f : 1.0f;}
static void __stdcall Enableg3_0() {Special_Mech_Gravity = (Special_Mech_Gravity!=3.0f) ? 3.0f : 1.0f;}
static void __stdcall Enableg4_0() {Special_Mech_Gravity = (Special_Mech_Gravity!=4.0f) ? 4.0f : 1.0f;}
static void __stdcall Enableg5_0() {Special_Mech_Gravity = (Special_Mech_Gravity!=5.0f) ? 5.0f : 1.0f;}

void
	FootStepPlug::SaveToStream(MemoryStream *stream)
{
	Check_Object(this);
	Check_Pointer(stream);

	*stream << m_material;
	MString texture_name = m_footTexture->GetTextureName();
	*stream << texture_name;
	*stream << m_isDefault;
}

Mech::ExecutionStateEngine::ClassData*
	Mech::ExecutionStateEngine::DefaultData = NULL;

bool Mech::DontLoadBlends = false;
bool Mech::NoBlend = false;
const Stuff::Scalar arm_re_null_time = 10.0f;



void MechWarrior4::MechSecurityCheckStart()
{
	_asm
	{
		nop
	}	
}




//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::ExecutionStateEngine::InitializeClass()
{
	Check_Object(BaseClass::DefaultData);
	Verify(!DefaultData);

	DefaultData =
		new ClassData(
			Mech__ExecutionStateEngineClassID,
			"Mech::ExecutionStateEngine",
			BaseClass::DefaultData,
			0, NULL,
			(Entity::ExecutionStateEngine::Factory)Make,
			(Entity::ExecutionStateEngine::FactoryRequest::Factory)
				&FactoryRequest::ConstructFactoryRequest
		);
	Register_Object(DefaultData);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mech::ExecutionStateEngine*
	Mech::ExecutionStateEngine::Make(
		Mech *vehicle,
		FactoryRequest *request
	)
{
	Check_Object(vehicle);
	Check_Object(request);
	gos_PushCurrentHeap(Heap);
	Mech::ExecutionStateEngine *engine =
		new Mech::ExecutionStateEngine(DefaultData, vehicle, request);
	gos_PopCurrentHeap();
	return engine;
		
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Mech::ExecutionStateEngine::RequestState(
		int new_state,
		void* data
	)
{
	Check_Object(this);
	Check_Object(owningEntity);

	//
	//-------------------------------------------
	// If there is no change of state just return
	//-------------------------------------------
	//
	if (new_state == currentState)
		return currentState;

	//
	//----------------------------------------------------------------------
	// If we are entering flying mode, take the animation velocities and jam
	// them into the mover variables
	//----------------------------------------------------------------------
	//
	Mech *mech = Cast_Object(Mech*, owningEntity);
	Check_Object(mech);
	switch (BaseClass::RequestState(new_state, data))
	{
	case DroppingState:
	case FlyingMotionState:
		mech->GetEyePointManager()->Follow(1.0f);
		mech->animStateEngine->RequestState(MechAnimationStateEngine::FlyState, Mech::NoBlend);
		break;

	//
	//-----------------------------------------------------------------------
	// If we are entering driving state, set the animation engine accordingly
	//-----------------------------------------------------------------------
	//
	case DrivingMotionState:
		if (mech->queFallState != Mech::NoFallMode)
		{
			switch(mech->queFallState)
			{
			case Mech::FallBackMode:
				mech->animStateEngine->RequestState(MechAnimationStateEngine::FallBackwardState,  Mech::NoBlend);
				break;

			case Mech::FallRightMode:
				mech->animStateEngine->RequestState(MechAnimationStateEngine::FallRightState,  Mech::NoBlend);
				break;

			case Mech::FallLeftMode:
				mech->animStateEngine->RequestState(MechAnimationStateEngine::FallLeftState,  Mech::NoBlend);
				break;

			case Mech::FallForwardMode:
				mech->animStateEngine->RequestState(MechAnimationStateEngine::FallForwardState,  Mech::NoBlend);
				break;

				
			}	
			mech->StartFall();
			mech->fallDirection = mech->queFallState;
//			mech->queFallState = Mech::NoFallMode;
		}
		else if (mech->currentSpeedMPS <= 0.0f)
			mech->animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
		else
			mech->animStateEngine->RequestState(MechAnimationStateEngine::ForwardState, Mech::NoBlend);
		break;
	}

	return currentState;
}

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

//#############################################################################
//###############################    Mech    ##############################
//#############################################################################

DWORD MechWarrior4::Executed_Mech_Count = 0;

// MSL ADD MECH
int Mech::s_mechSlots[NoMechID]={
	MechExecutionSlot+7,	// Annihilator(shares with Atlas)
	MechExecutionSlot+6,	// Archer (shares with Sunder)
	MechExecutionSlot+13,	// Arctic Wolf(shares with Uziel)
	MechExecutionSlot+1,	// Ares (shares with Chimera-Bushwacker)
	MechExecutionSlot+2,	// Argus (shares with catapult)
	MechExecutionSlot+15,	// Assassin2 (shares with crab)
	MechExecutionSlot+7,	// Atlas
	MechExecutionSlot+3,	// Avatar (shares with Vulture)
	MechExecutionSlot+0,	// Awesome (shares with Mauler)
	MechExecutionSlot+0,	// Battlemaster (Awesome)
	MechExecutionSlot+0,	// BattlemasterIIc (Awesome)
	MechExecutionSlot+15,	// Behemoth (shares with Daishi)	
	MechExecutionSlot+15,	// Behemoth II(shares with Daishi)	
	MechExecutionSlot+1,	// Black Hawk (shares with bushwacker
	MechExecutionSlot+0,	// Black Knight (shares with Mauler)
	MechExecutionSlot+3,	// Black Lanner (shares with Madcat)
	MechExecutionSlot+14,	// Brigand (shares with Commando)
	MechExecutionSlot+1,	// Bushwacker (shares with Chimera)
	MechExecutionSlot+2,	// Catapult (shares with Argus)
	MechExecutionSlot+3,	// CauldronBorn (shares with Madcat)
	MechExecutionSlot+1,	// Chimera (shares with Bushwacker)
	MechExecutionSlot+14,	// Commando
	MechExecutionSlot+8,	// Cougar
	MechExecutionSlot+7,	// Cyclops (shares with Atlas)
	MechExecutionSlot+9,	// Daishi
//	MechExecutionSlot+14,	// Dasher (shares with Commando)
	MechExecutionSlot+3,	// Deimos (shares with Madcat)
	MechExecutionSlot+6,	// Dragon (shares with Thor)
	MechExecutionSlot+0,	// Fafnir   ( Mauler )
	MechExecutionSlot+5,	// Flea (shares with Raven)
	MechExecutionSlot+0,	// Gladiator (shares with Mauler)
	MechExecutionSlot+0,	// Grizzly (shares with Awesome)
	MechExecutionSlot+9,	// Hauptmann (shares with Daishi)
	MechExecutionSlot+1,	// Hellhound (Chimera)
	MechExecutionSlot+10,	// Hellspawn,
	MechExecutionSlot+0,	// Highlander (shares with Awesome)
	MechExecutionSlot+15,	// Hollander (shares with Crab)
	MechExecutionSlot+10,	// Hunchback (shares with Hellspawn)
	MechExecutionSlot+0,	// Kodiak (shares with Awesome)
	MechExecutionSlot+6,	// Loki (shares with Thor)
	MechExecutionSlot+0,	// Longbow   (shares with Mauler)
	MechExecutionSlot+3,	// Madcat (shares with Vulture)
	MechExecutionSlot+11,	// Madcat2
	MechExecutionSlot+9,	// Masakari (shares with Daishi)
	MechExecutionSlot+0,	// Mauler (shares with Awesome)
	MechExecutionSlot+4,	// Novacat (shares with Thanatos)
	MechExecutionSlot+5,	// Osiris (shares with Raven)
	MechExecutionSlot+5,	// Owens     (shares with Raven)
	MechExecutionSlot+8,	// Puma      (shares with Cougar)
	MechExecutionSlot+5,	// Raven (shares with Osiris)
	MechExecutionSlot+6,	// Rifleman (shares with Sunder-Thor)
	MechExecutionSlot+1,	// Ryoken (shares with bushwacker
	MechExecutionSlot+12,	// Shadowcat
	MechExecutionSlot+8,	// Solitaire (Shares with Cougar)
	MechExecutionSlot+6,	// Sunder (shares with Thor)
	MechExecutionSlot+0,	// Templar (Awesome)
	MechExecutionSlot+4,	// Thanatos (shares with novacat)
	MechExecutionSlot+6,	// Thor (shares with Loki)
	MechExecutionSlot+8,	// Uller (shares with Cougar)
	MechExecutionSlot+10,	// Urbanmech (shares with Hellspawn)
	MechExecutionSlot+13,	// Uziel
	MechExecutionSlot+0,	// Victor    (shares with Mauler)
	MechExecutionSlot+3,	// Vulture (shares with Madcat)
	MechExecutionSlot+6,	// Warhammer (shares with Thor, Sunder)
	MechExecutionSlot+10,	// Wolfhound (shares with HellSpawn
	MechExecutionSlot+0 	// Zeus(shares with Awesome)
};

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::InitializeClass()
{
	Check_Object(ExecutionStateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MechClassID,
	        "MechWarrior4::Mech",
			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::Factory)MechAnimationStateEngine::Make
		);
	Register_Object(DefaultData);

	//Dave Need to add attribute entries
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TiltSpeed,
		tiltSpeed,
		Radian
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TiltDegree,
		tiltDegree,
		Radian
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		ScaleInternalTiltDegree,
		scaleInternalTiltDegree,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		FootReturnSeconds,
		footReturnSeconds,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		FallAdjustmentSeconds,
		fallAdjustmentSeconds,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		GetUpAdjustmentSeconds,
		getUpAdjustmentSeconds,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		FallAdjustmentDelaySeconds,
		fallAdjustmentDelaySeconds,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		GetUpAdjustmentDelaySeconds,
		getUpAdjustmentDelaySeconds,
		Scalar
	);


	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		PercentageOfTurnToStartTilt,
		percentageOfTurnToStartTilt,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		PercentageOfSpeedToStartTilt,
		percentageOfSpeedToStartTilt,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DampenWorldJoint,
		dampenWorldJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DampenRootJoint,
		dampenRootJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DampenTorsoJoint,
		dampenTorsoJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DampenHipJoint,
		dampenHipJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DampenTranslationJoint,
		dampenTranslationJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		UndampenWorldJoint,
		undampenWorldJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		UndampenRootJoint,
		undampenRootJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		UndampenTorsoJoint,
		undampenTorsoJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		UndampenHipJoint,
		undampenHipJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		UndampenTranslationJoint,
		undampenTranslationJoint,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TorsoScaleTakeHit,
		torsoScaleTakeHit,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		HipScaleTakeHit,
		hipScaleTakeHit,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		RootScaleTakeHit,
		rootScaleTakeHit,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		MinimumDamageForHitAnimation,
		minimumDamageForHitAnimation,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		MinimumDamageForInternalHitAnimation,
		minimumDamageForInternalHitAnimation,
		Scalar
	);



	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TorsoHitSpringMotionLimit,
		torsoHitSpringMotionLimit,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TorsoHitSpringDeceleration,
		torsoHitSpringDeceleration,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TorsoHitSpringReturnSpeed,
		torsoHitSpringReturnSpeed,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TorsoHitSpringSpeed,
		torsoHitSpringSpeed,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		HipHitSpringMotionLimit,
		hipHitSpringMotionLimit,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		HipHitSpringDeceleration,
		hipHitSpringDeceleration,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		HipHitSpringReturnSpeed,
		hipHitSpringReturnSpeed,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		HipHitSpringSpeed,
		hipHitSpringSpeed,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		RootHitSpringMotionLimit,
		rootHitSpringMotionLimit,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		RootHitSpringDeceleration,
		rootHitSpringDeceleration,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		RootHitSpringReturnSpeed,
		rootHitSpringReturnSpeed,
		Scalar
	);
	
	
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		RootHitSpringSpeed,
		rootHitSpringSpeed,
		Scalar
	);




	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		ExternalHitScaleBeamDamage,
		externalHitScaleBeamDamage,
		Scalar
	);
		
		
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		ExternalHitScaleMissileDamage,
		externalHitScaleMissileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		ExternalHitScaleProjectileDamage,
		externalHitScaleProjectileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		ExternalHitScaleSplashDamage,
		externalHitScaleSplashDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		ExternalHitScaleHeatDamage,
		externalHitScaleHeatDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalHitScaleBeamDamage,
		internalHitScaleBeamDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalHitScaleMissileDamage,
		internalHitScaleMissileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalHitScaleProjectileDamage,
		internalHitScaleProjectileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalHitScaleSplashDamage,
		internalHitScaleSplashDamage,
		Scalar
	);
	
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalHitScaleHeatDamage,
		internalHitScaleHeatDamage,
		Scalar
	);





	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalSpinHitScaleBeamDamage,
		internalSpinHitScaleBeamDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalSpinHitScaleMissileDamage,
		internalSpinHitScaleMissileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalSpinHitScaleProjectileDamage,
		internalSpinHitScaleProjectileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalSpinHitScaleSplashDamage,
		internalSpinHitScaleSplashDamage,
		Scalar
	);
	
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InternalSpinHitScaleHeatDamage,
		internalSpinHitScaleHeatDamage,
		Scalar
	);





		
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		SpinForceBeamDamage,
		spinForceBeamDamage,
		Scalar
	);
	
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		SpinForceMissileDamage,
		spinForceMissileDamage,
		Scalar
	);
	
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		SpinForceProjectileDamage,
		spinForceProjectileDamage,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		SpinForceSplashDamage,
		spinForceSplashDamage,
		Scalar
	);
	
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		SpinForceHeatDamage,
		spinForceHeatDamage,
		Scalar
	);


	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		EyeSpringMotionLimit,
		eyeSpringMotionLimit,
		Point3D
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		EyeSpringConstant,
		eyeSpringConstant,
		Point3D
	);
		
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		EyeSpringDrag,
		eyeSpringDrag,
		Point3D
	);
		
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		EyeSpringStopThreshold,
		eyeSpringStopThreshold,
		Point3D
	);


	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		JumpJetEffect,
		jumpJetEffect,
		ResourceID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		LeftJumpJetSiteName,
		leftJumpJetSiteName,
		const char *,
		CharClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		RightJumpJetSiteName,
		rightJumpJetSiteName,
		const char *,
		CharClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		SearchLightResource,
		searchLightResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		InitialJumpJetEffect,
		initialJumpJetEffect,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		MaxHeat,
		maxHeat,
		Scalar
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		MechID,
		mechID,
		int,
		IntClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadJumpJets,
		m_canLoadJumpJets,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadECM,
		m_canLoadECM,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadBeagle,
		m_canLoadBeagle,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadLightAmp,
		m_canLoadLightAmp,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadAMS,
		m_canLoadAMS,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadLAMS,
		m_canLoadLAMS,
		bool,
		BoolClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		JumpJetTonnage,
		m_jumpJetTonnage,
		Scalar
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		TechType,
		techType,
		int,
		IntClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CageDamageEffect,
		m_cageDamageEffect,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DamageNeededForCageEffect,
		damageNeededForCageEffect,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		MechRamEffect,
		m_mechRamEffect,
		ResourceID
	);

// MSL 5.03 Glass
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		MechGlassRamEffect,
		m_mechGlassRamEffect,
		ResourceID
	);


	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		WakeEffectResource,
		m_wakeEffectResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		Cradle,
		cradle,
		ResourceID
	);
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CradleDeathEffect,
		cradleDeathEffect,
		ResourceID
	);
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		DropJumpEffect,
		dropJumpEffect,
		ResourceID
	);

// MSL 5.02 SubSystems
//	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
//		Mech__GameModel,
//		CanLoadEnhancedOptics,
//		m_canLoadEnhancedOptics,
//		bool,
//		BoolClassID
//	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadIFF_Jammer,
		m_canLoadIFF_Jammer,
		bool,
		BoolClassID
	);

	CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		CanLoadAdvancedGyro,
		m_canLoadAdvancedGyro,
		bool,
		BoolClassID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Mech__GameModel,
		AdvancedGyroTonnage,
		m_advancedGyroTonnage,
		Scalar
	);


	AddDebuggerMenuItem("Libraries\\Mech\\Snap To Ground", CheckSnapToGround, EnableSnapToGround, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\Enable Jump Animation", CheckFlying, EnableFlying, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\ ",0,0,0);

	AddDebuggerMenuItem("Libraries\\Mech\\1.0 g", Checkg1_0, Enableg1_0, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\1.2 g", Checkg1_2, Enableg1_2, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\1.4 g", Checkg1_4, Enableg1_4, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\1.6 g", Checkg1_6, Enableg1_6, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\1.8 g", Checkg1_8, Enableg1_8, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\2.0 g", Checkg2_0, Enableg2_0, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\2.5 g", Checkg2_5, Enableg2_5, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\3.0 g", Checkg3_0, Enableg3_0, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\4.0 g", Checkg4_0, Enableg4_0, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\5.0 g", Checkg5_0, Enableg5_0, 0 );
	AddDebuggerMenuItem("Libraries\\Mech\\ ",0,0,0);
}

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

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

	Check_Object(EntityManager::GetInstance());
	EntityManager::GetInstance()->AddMover(new_mech);
	
	return new_mech;
}

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

	stream->AllocateBytes(sizeof(CreateMessage));
	BaseClass::SaveMakeMessage(stream, res_file);
	CreateMessage *message =
		Cast_Pointer(CreateMessage*, stream->GetPointer());
	message->messageLength = sizeof(*message);

	Check_Object(m_heatManager);
	message->currentHeat = m_heatManager->GetHeat();
	message->currentCoolant = m_heatManager->GetCoolant();
	message->maxCoolant = m_heatManager->GetMaxCoolant();
	message->m_doesHaveLightAmp = m_doesHaveLightAmp;

	//Used for Mech lab and are not read in except by the shell
// MSL 5.04 Modified Firepower bar
//	message->m_powerBar =  (int)(GetBattleValue());
//	message->m_powerBar =  (int)(GetBattleValue() / 4);
	message->m_powerBar =  (int)((GetBattleValue() / 80.0) * 100.0);
	Clamp(message->m_powerBar, 0, 100);

// MSL 5.04 Modified Speed bar
	Engine *engine = GetEngine();
	Check_Object(engine);
	const GameModel *mech_model = GetGameModel();
	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);
	message->m_speedBar = (int)(speed_ratio * 100);
	Clamp(message->m_speedBar, 0, 100);

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

	message->m_heatBar = GetHeatEffic();
	Clamp(message->m_heatBar, 0, 100);

	message->m_mechID = mech_model->mechID;
	
	return message;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mech::Mech(
	ClassData *class_data,
	CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	ejectEffect (NULL),
	BaseClass(class_data, message, base_id, element),
	m_FallDampingEnabled(false),
	m_LastFootFallTime(0),
	m_footSteps(NULL, true),
	m_LastMissionWarning(0),
	m_leftCageEffect(NULL),
	m_rightCageEffect(NULL),
	m_DropCradle (NULL),
	m_JumpEffect1 (NULL),
	m_JumpEffect2 (NULL),
	m_JumpEffect3 (NULL),
	m_JumpEffect4 (NULL),
	m_wakeEffect(NULL),
// MSL 5.02 headshot
	dwDamageFlags(0),
	m_HeadShotFallDamageMod(1.0),
	m_HeadShotTorsoRockDamageMod(1.0),
	m_HeadShotTorsoSpinDamageMod(1.0),
// MSL 5.02 SubSystems
	dwGyroDamageFlags(0),
	m_AdvancedGyroFallDamageMod(1.0),
	m_AdvancedGyroTorsoRockDamageMod(1.0),
	m_AdvancedGyroTorsoSpinDamageMod(1.0),

	m_lastHits(NULL, true)
{
	Check_Pointer(this);
	Check_Object(message);

	Verify(animStateEngine != NULL);

	initialPositions = new Origin3D[animationArrayCount];
	Register_Pointer(initialPositions);

	lancemateIndex = -1;
	m_FallDamage = 0;
	m_numHeatSinks = 0;
	m_LastSoundSpeedMPS = 0;

	m_mechTablePlug = NULL;

	m_MaxFlagsCarried = -1;

	Verify(!CanBeWalkedOn());

	for (int i = 0; i < animationArrayCount; ++i)
	{
		ElementRenderer::Element *element;

		Verify(!animationArray[i]->CanBeWalkedOn());

		element = animationArray[i]->GetElement();
		Check_Object(element);
		initialPositions[i] = element->GetNewLocalToParent();
	}

	//find the feet...


	
	jumpJet = NULL;
	HookUpSubsystems();
	jointWorld = NULL;
	jointWorld = FindChildMover("joint_WORLD");

	siteLeftFoot = NULL;
	siteRightFoot = NULL;
	leftFootNormal = Normal3D (0,1,0);
	rightFootNormal = Normal3D (0,1,0);

	jointSearchLight = NULL;
	jointSearchLight = FindChildMover("joint_searchlight");

	m_leftCageSite = NULL;
	m_rightCageSite = NULL;
	m_playLeftCageEffect = false;
	m_playRightCageEffect = false;
	m_leftCageSite = FindSite("site_cageleft");
	m_rightCageSite = FindSite("site_cageright");
	

  /* has to be redone in BecomeInteresting anyway
	
  if(Mission::GetInstance())
	{
		Check_Pointer(Mission::GetInstance());
		const Mission::GameModel *mission_model = Mission::GetInstance()->GetGameModel();
		Check_Object(mission_model);

		if(!mission_model->m_allowRunningLights)
		{
			DestroyRunningLight();
		}

		if(!mission_model->m_allowSearchLights)
		{
			DestroySearchLight();
			if(GetSearchLight())
				GetSearchLight()->HideBeam();
		}
	}
  */
	siteLeftFoot = FindSite("site_lfoot");
	siteRightFoot = FindSite("site_rfoot");
	Check_Object(siteLeftFoot);
	Check_Object(siteRightFoot);

	

	jointLeftAnkle = NULL;
	jointRightAnkle = NULL;

	jointLeftAnkle = FindChildMover("joint_lbelowankle");
	jointRightAnkle = FindChildMover("joint_rbelowankle");

	Check_Object(jointLeftAnkle);
	Check_Object(jointRightAnkle);

	worldJointIndex = FindChildMoverIndex("joint_WORLD");
	rootJointIndex = FindChildMoverIndex("joint_ROOT");
	hipJointIndex = FindChildMoverIndex("joint_hip");
	torsoJointIndex = FindChildMoverIndex("joint_torso");

	centerTorso = FindChildMover("joint_torso");

	searchLightSite = FindSite("site_light");
	Check_Object(searchLightSite);

	const GameModel *model = GetGameModel();
	Check_Object(model);
	m_mechSlot = s_mechSlots[model->mechID];
// MSL Add Mech
	Verify(m_mechSlot >= MechExecutionSlot && m_mechSlot < MechExecutionSlot+16);

	//
	//---------------------------------------------------
	//If we have a search light then we have to create it
	//---------------------------------------------------
	//
	searchLightEffect = NULL;
	if(model->searchLightResource != ResourceID::Null)
	{
		searchLightEffect = CreateEffect(model->searchLightResource, searchLightSite, true);
		Check_Object(searchLightEffect);
	}

	Verify(worldJointIndex != -1);
	Verify(rootJointIndex != -1);
	Verify(hipJointIndex != -1);
	Verify(torsoJointIndex != -1);


	torsoAboveJointIndex = FindChildMoverIndex("joint_torsoabove");
	hipAboveJointIndex = FindChildMoverIndex("joint_hipabove");
	//leftGunAboveJointIndex = FindChildMoverIndex("joint_lgunabove");
	//leftArmAboveJointIndex = FindChildMoverIndex("joint_luarmabove");
	//rightGunAboveJointIndex = FindChildMoverIndex("joint_rgunabove");

	Verify(torsoAboveJointIndex != -1);
	Verify(hipAboveJointIndex != -1);
	//Verify(leftGunAboveJointIndex != -1);
	//Verify(leftArmAboveJointIndex != -1);
	//Verify(rightGunAboveJointIndex != -1);

	leftGunJointIndex = FindChildMoverIndex("joint_lgun");
	leftArmJointIndex = FindChildMoverIndex("joint_luarm");
	rightGunJointIndex = FindChildMoverIndex("joint_rgun");
	rightArmJointIndex = FindChildMoverIndex("joint_ruarm");

	Verify(leftGunJointIndex != -1);
	Verify(leftArmJointIndex != -1);
	Verify(rightGunJointIndex != -1);
	Verify(rightArmJointIndex != -1);

	int joint_number = FindChildMoverIndexUserData("site_lfoot", this);
	animationTriggerManager.RegisterTriggerCallback(joint_number, 0, (TriggerMessageHandler)LeftFootTriggerHandler);

	joint_number = FindChildMoverIndexUserData("site_rfoot", this);
	animationTriggerManager.RegisterTriggerCallback(joint_number, 0, (TriggerMessageHandler)RightFootTriggerHandler);

	leftJumpJetSite = NULL;
	rightJumpJetSite = NULL;

	leftJumpJetSite = FindSite(model->leftJumpJetSiteName);
	rightJumpJetSite = FindSite(model->rightJumpJetSiteName);

	if(GetJumpJet())
		GetJumpJet()->SetJumpJetData(
			model->jumpJetEffect,
			model->initialJumpJetEffect,
			leftJumpJetSite,
			rightJumpJetSite
		);

	m_heatManager = new HeatManager(
		model->maxHeat,
		message->currentHeat,
		message->maxCoolant,
		message->currentCoolant,
		this,
		model->heatManagerResource
	);

	m_doesHaveLightAmp = message->m_doesHaveLightAmp;
	if(m_doesHaveLightAmp)
	{
		if(DoesHaveAvailableTonage(1.0f))
		{
			AddTonage(1.0f);
		}
		else
		{
			//no Tonnage for this!
			m_doesHaveLightAmp = false;
		}
	}

	SeedHeatManager();

	m_eyePointManager = new EyePointManager(this);

	m_gyro = new Gyro(this);

	deadReckonCurve = NULL;
	

	CommonCreation(message);

	//
	// [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 (GetSearchLight())
//	{
//		m_previousSearchLightState = GetSearchLight()->isLightOn;
//	}
//	else
//	{
//		m_previousSearchLightState = false;
//	}

	if(model->footStepsResource != ResourceID::Null)
	{
		CreateFootTextureChain(model->footStepsResource);
	}

	m_startTons = GetTonage();

// MSL 5.02 SubSystems
	if (GetAdvancedGyro())
	{
// MSL 5.03 Gyro Hit
		m_AdvancedGyroFallDamageMod = 1.0;
		m_AdvancedGyroTorsoRockDamageMod = 1.0;
		m_AdvancedGyroTorsoSpinDamageMod = 1.0;
//		m_AdvancedGyroFallDamageMod = ADVANCED_GYRO_FALL_MOD;
//		m_AdvancedGyroTorsoRockDamageMod = ADVANCED_GYRO_TORSO_ROCK_MOD;
//		m_AdvancedGyroTorsoSpinDamageMod = ADVANCED_GYRO_TORSO_SPIN_MOD;
	}
	else
	{
		m_AdvancedGyroFallDamageMod = 1.0;
		m_AdvancedGyroTorsoRockDamageMod = 1.0;
		m_AdvancedGyroTorsoSpinDamageMod = 1.0;
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::CommonCreation(CreateMessage *message)
{
	Check_Object(this);
	Check_Object(message);
	const GameModel *model = GetGameModel();
	Check_Object(model);

    ClearInterestings(); // jcem
    m_fTimeRespawnRequestEnd = 0.0f; // jcem - for delayed lancemate respawn
    m_fTimeMsgSentEnd = 0.0f; // jcem - gos_GetElapsedTime() + duration
    m_nMsgKind = 0; // 0-6(team message), 7-13(taunt, FFA), 14/15 yes/no

	m_CanStartGettingUp = false;
	m_NeedStartDrop = false;
	m_CanStartDropJetEffect = false;
	m_DropSite = NULL;
	m_JumpSite1 = NULL;
	m_JumpSite2 = NULL;
	m_JumpSite3 = NULL;
	m_JumpSite4 = NULL;
	m_NeedKillDropCradleEffect = false;

	m_gyro->AbortFall();

	if (deadReckonCurve != NULL)
	{
		delete deadReckonCurve;
		deadReckonCurve = NULL;
	}
	deadReckonScale = 0.0f;
	deadReckonCurveTime = 0.0f;

	allowedToAnimateVelocity = true;

	m_footHitEntity = NULL;

	m_lastFall = (Scalar)gos_GetElapsedTime();

	m_ForceYaw = false;
	m_ForceYawValue = 0;
	m_ForceSpeed = false;
	m_ForceSpeedValue = 0;
	m_FallDamage = 0.0f;

	m_heatMaterialMultiplier = 1.0f;
	m_sensorDinstanceMultiplier = 1.0f;

	diedBySplash = false;
	lastFramePushUp = 0.0f;
	leftFootGround = 0.0f;
	rightFootGround = 0.0f;
	leftFootReturnTimer = 0.0f;
	rightFootReturnTimer = 0.0f;
	tiltAngle = 0.0f;

	m_SavedFractionalDamage = 0.0f;
	m_SavedFractionalModDamage = 0.0f;

// MSL 5.03 Lava
	m_lastLavaTime = gos_GetElapsedTime();

	m_NeedEject = 0;

// MSL 5.03 PPC Hud Effect Reset
	g_HUDPPCLevel = 0;

	fallTimer = 0.0f;
	getUpTimer = 0.0f;
	blockFallTimer = 0.0f;

	m_needWakeEffect = 0;

	groundAngleDbg = Stuff::YawPitchRoll::Identity;

	leftFootDown = false;
	rightFootDown = false;
	
	isLeftFootDown = false;
	isRightFootDown = false;

	m_selfDestructTimer = gos_GetElapsedTime();

	pitchSmoother.SetSize(4);
	rollSmoother.SetSize(4);
	lastSpeedMPS = 0.0f;

	leftJumpJetEffect = NULL;
	rightJumpJetEffect = NULL;

	queFallState = NoFallMode;
	fallDirection = NoFallMode;

	gimpState = NotGimpedMode;

	triggerDeath = NoDeathTrigger;
	vehicleRunsInterface = false;
	
	lastHitDirection = NoHitDirection;
	takenDamageThisFrame = false;
	lastDamageTaken = 0.0f;

	currentRightFootFall = ResourceID::Null;
	currentLeftFootFall = ResourceID::Null;

	armsNulled = false;
	armBlanderizer.SetNewDampen(0.0f);
	armReNullTime = 0;

	torsoBlanderizer.SetNewDampen(0.0f);

	m_alreadyShutDown = false;

	leftFootTurnAccumulation = 0.0f;
	rightFootTurnAccumulation = 0.0f;

	leftFootState = FootNormal;
	rightFootState = FootNormal;

	YawPitchRoll motion_limit;
	YawPitchRoll motion_acceleration;
	YawPitchRoll return_speed;
	YawPitchRoll home_position;
	YawPitchRoll outward_force;

	Point3D p_motion_limit;
	Point3D p_motion_acceleration;
	Point3D p_return_speed;
	Point3D p_outward_force;

	motion_limit = YawPitchRoll(0.0f, model->rootHitSpringMotionLimit, 0.0f);
	motion_acceleration = YawPitchRoll(0.0f,model->rootHitSpringDeceleration, 0.0f);
	return_speed = YawPitchRoll(0.0f,model->rootHitSpringReturnSpeed,0.0f);
	outward_force = YawPitchRoll(0.0f,model->rootHitSpringSpeed,0.0f);
	home_position = initialPositions[rootJointIndex].angularPosition;
	rootHit.Initialize(motion_limit, motion_acceleration, return_speed, home_position, outward_force);

	motion_limit = YawPitchRoll(model->torsoHitSpringMotionLimit, 0.0f, 0.0f);
	motion_acceleration = YawPitchRoll(model->torsoHitSpringDeceleration, 0.0f, 0.0f);
	return_speed = YawPitchRoll(model->torsoHitSpringReturnSpeed,0.0f, 0.0f);
	outward_force = YawPitchRoll(model->torsoHitSpringSpeed,0.0f,0.0f);
	home_position = initialPositions[torsoAboveJointIndex].angularPosition;
	torsoHit.Initialize(motion_limit, motion_acceleration, return_speed, home_position, outward_force);

	motion_limit = YawPitchRoll(0.0f, model->hipHitSpringMotionLimit, 0.0f);
	motion_acceleration = YawPitchRoll(0.0f,model->hipHitSpringDeceleration, 0.0f);
	return_speed = YawPitchRoll(0.0f,model->hipHitSpringReturnSpeed,0.0f);
	outward_force = YawPitchRoll(0.0f,model->hipHitSpringSpeed,0.0f);
	home_position = initialPositions[hipAboveJointIndex].angularPosition;
	hipHit.Initialize(motion_limit, motion_acceleration, return_speed, home_position, outward_force);

#if 0
	motion_limit = YawPitchRoll(40.0f*Stuff::Radians_Per_Degree,50.0f*Stuff::Radians_Per_Degree,40.0f*Stuff::Radians_Per_Degree);
	motion_acceleration = YawPitchRoll(1.0f*Stuff::Radians_Per_Degree,1.0f*Stuff::Radians_Per_Degree,1.0f*Stuff::Radians_Per_Degree);
	return_speed = YawPitchRoll(50.0f*Stuff::Radians_Per_Degree,70.0f*Stuff::Radians_Per_Degree,50.0f*Stuff::Radians_Per_Degree);
	outward_force = YawPitchRoll(40.0f*Stuff::Radians_Per_Degree,50.0f*Stuff::Radians_Per_Degree,40.0f*Stuff::Radians_Per_Degree);
	home_position = initialPositions[leftGunAboveJointIndex].angularPosition;
	leftGunRecoil.Initialize(motion_limit, motion_acceleration, return_speed, home_position, outward_force);

	motion_limit = YawPitchRoll(40.0f*Stuff::Radians_Per_Degree,50.0f*Stuff::Radians_Per_Degree,40.0f*Stuff::Radians_Per_Degree);
	motion_acceleration = YawPitchRoll(1.0f*Stuff::Radians_Per_Degree,1.0f*Stuff::Radians_Per_Degree,1.0f*Stuff::Radians_Per_Degree);
	return_speed = YawPitchRoll(50.0f*Stuff::Radians_Per_Degree,70.0f*Stuff::Radians_Per_Degree,50.0f*Stuff::Radians_Per_Degree);
	outward_force = YawPitchRoll(40.0f*Stuff::Radians_Per_Degree,50.0f*Stuff::Radians_Per_Degree,40.0f*Stuff::Radians_Per_Degree);
	home_position = initialPositions[leftArmAboveJointIndex].angularPosition;
	leftArmRecoil.Initialize(motion_limit, motion_acceleration, return_speed, home_position, outward_force);

	p_motion_limit = Point3D(10.0f,10.0f,1.0f);
	p_motion_acceleration = Point3D(0.0f,0.0f,0.05f);
	p_return_speed = Point3D(0.0f,0.0f,2.0f);
	p_outward_force = Point3D(10.0f,10.0f,1.0f);
	rightGunRecoil.Initialize(p_motion_limit, p_motion_acceleration, p_return_speed, initialPositions[rightGunAboveJointIndex].linearPosition, p_outward_force);
	
#endif

	worldRotDampener.SetNewDampen(model->dampenWorldJoint);
	rootRotDampener.SetNewDampen(model->dampenRootJoint);
	rootTransDampener.SetNewDampen(model->dampenTranslationJoint);
	torsoRotDampener.SetNewDampen(model->dampenTorsoJoint);
	hipRotDampener.SetNewDampen(model->dampenHipJoint);



	eyeSpringRotation.Initialize(model->eyeSpringMotionLimit, model->eyeSpringConstant, model->eyeSpringDrag, model->eyeSpringStopThreshold);
	

	if (GetReplicatorMode() == ReplicantMode)
	{
		debugPushupOff = true;
	}
	else
	{
		debugPushupOff = true;
	}

	fastTransition = true;

	InitializeDamageArray();

	m_defaultFootStep = NULL;
	m_whoShotMeLast = Adept::ReplicatorID::Null;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::CreateFootTextureChain(ResourceID resource_id)
{
	Check_Object(this);

	Resource stream(resource_id);
	Verify(stream.DoesResourceExist());

	while(stream.GetBytesRemaining() > 0)
	{
		int material;
		stream >> material;
		MString texture_name;
		stream >> texture_name;
		bool is_default;
		stream >> is_default;

		MidLevelRenderer::MLRTexture *foot_texture;
		foot_texture = MidLevelRenderer::MLRTexturePool::Instance->Add(texture_name);
		FootStepPlug *foot_plug = new FootStepPlug(material, foot_texture, is_default);

		if(is_default)
		{
			m_defaultFootStep = foot_plug;
		}
		else
		{
			m_footSteps.AddValue(foot_plug, material);
		}
	}

}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

extern int	temporaryQuickIDLookup[COMPRESS_JOINT_COUNT];

void
	Mech::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, DontLoadBlends);

		NoBlend = DontLoadBlends;

	}

	animStateEngine->Reset();
	animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
}

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

// MSL 5.02 headshot
	//fix head-shot damage, if present

	if ((dwDamageFlags & MECH_HEAD_SHOT_RCVD) == MECH_HEAD_SHOT_RCVD)
	{
		if (vehicleInterface)
		{
			vehicleInterface->hudZoomDestroyed = false; //reinstate the zoom
		}


		dwDamageFlags = 0; //unset all the damage flags
	}

// MSL 5.03 Gyro Hit
	//fix gyro hit damage, if present

	if ((dwGyroDamageFlags & MECH_GYRO_HIT_RCVD) == MECH_GYRO_HIT_RCVD)
	{
		dwGyroDamageFlags = 0; //unset all the damage flags
	}

	//SPEW(("jerryeds", "RESPAWN"));

	BaseClass::Respawn(message);
	CreateMessage *mech_message = Cast_Pointer(CreateMessage *, message);
	CommonCreation(mech_message);

	m_heatManager->Reuse();
	m_eyePointManager->Reuse();
	//
	// [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 (m_previousSearchLightState && GetSearchLight())
//	{
//		if (IsPlayerVehicle())
//		{
//			Mission::GetInstance()->SetSearchLightMissionLights();
//		}
//		GetSearchLight()->ShowBeam();
//	}
	SetTonnage(m_startTons);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mech::~Mech()
{
	DESTRUCTOR("Mech");

	Check_Pointer(this);

	if (deadReckonCurve != NULL)
	{
		delete deadReckonCurve;
		deadReckonCurve = NULL;
	}

	delete m_eyePointManager;
	delete m_gyro;
	
	Unregister_Pointer(initialPositions);
	delete[] initialPositions;

	if (m_defaultFootStep)
	{
		Check_Object(m_defaultFootStep);
		delete m_defaultFootStep;
	}
	m_footSteps.DeletePlugs();

	if(m_leftCageEffect.GetCurrent())
		delete m_leftCageEffect.GetCurrent();
	if(m_rightCageEffect.GetCurrent())
		delete m_rightCageEffect.GetCurrent();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool Mech::PilotSkillCheck (Stuff::Scalar damage_amount,bool jump)
{
	if (m_AI)
		return m_AI->PilotSkillCheck (damage_amount,jump);
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::GetTransSpeedKPH (Stuff::Scalar& forward,Stuff::Scalar& reverse)
{
	const GameModel *model = GetGameModel();
	Check_Object(model);
	forward = model->minSpeed* 3.6f;
	reverse = model->minReverseSpeed* 3.6f;
}

void Mech::GetMaxSpeedKPH (Stuff::Scalar& forward,Stuff::Scalar& reverse)
{
	const GameModel *model = GetGameModel();
	Check_Object(model);
	forward = GetMaxSpeed () * 3.6f;
	reverse = model->maxReverseSpeed * 3.6f;
}

void Mech::GetTransSpeedNormalized (Stuff::Scalar& forward,Stuff::Scalar& reverse)
{
	const GameModel *model = GetGameModel();
	Check_Object(model);
	forward = model->minSpeed / GetMaxSpeed();
	reverse = model->minReverseSpeed / -model->maxReverseSpeed;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::TurnOn (void)
{
	lastParameterization = gos_GetElapsedTime ();
	animStateEngine->Reset();
	animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
	executionState->RequestState(m_LastState);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::TurnOff (void)
{
	m_LastState = executionState->GetState ();
	if (!IsPlayerVehicle() && !IsLanceMate())
	{
		executionState->RequestState(ExecutionStateEngine::AIMotionState);
	}
}

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

	STOP(("Not Implemented"));
//	m_previousSearchLightState = false;
	BaseClass::Reuse(message, base_id);
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::UpdateMessageHandler(const UpdateMessage *message)
{
	Check_Object(this);
	Check_Object(message);
	Verify(GetReplicatorMode() == ReplicantMode);

	BaseClass::UpdateMessageHandler(message);
	currentSpeedMPS = message->currentSpeedMPS;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Entity::UpdateMessage*
	Mech::ConstructUpdate(Stuff::MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);
	Verify(updateFlags);
	Verify(GetReplicatorMode() == MasterMode);
	Verify(owningConnection == Connection::Local);

	//
	//------------------------------------------------------------
	// Make sure there is enough room for the update on the stream
	//------------------------------------------------------------
	//
	stream->AllocateBytes(sizeof(UpdateMessage));
	UpdateMessage *message =
		Cast_Pointer(
			UpdateMessage*,
			BaseClass::ConstructUpdate(stream)
		);
	Check_Object(message);
	message->messageLength = sizeof(*message);
	message->currentSpeedMPS = currentSpeedMPS;
	return message;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::HookUpSubsystems()
{
	Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
	Subsystem *subsystem;
	while ((subsystem = iterator.ReadAndNext()) != NULL)
	{
		if (subsystem->IsDerivedFrom(Engine::DefaultData))
		{
			engine = Cast_Object(Engine *, subsystem);
		}
		else 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);
			}
		}
		else if (subsystem->IsDerivedFrom(ECM::DefaultData))
		{
			ecm = Cast_Object(ECM *, subsystem);
		}
		else if (subsystem->IsDerivedFrom(JumpJet::DefaultData))
		{
			jumpJet = Cast_Object(JumpJet *, subsystem);
		}
// MSL 5.02 SubSystems
		else if (subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
		{
			iff_jammer = Cast_Object(IFF_Jammer *, subsystem);
		}
		else if (subsystem->IsDerivedFrom(Armor::DefaultData))
		{
			armor = Cast_Object(Armor *, subsystem);
		}

		AddSubsystem(subsystem);
		//Tell the Damage Zone that holds the subsystem that it is there!!!
	}
	if(engine)
		engine->ConnectEngine(this);
}

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

	BaseClass::AddSubsystem(subsystem);
	
	if (subsystem->IsDerivedFrom(JumpJet::DefaultData))
	{
		jumpJet = Cast_Object(JumpJet *, subsystem);
	}
	else if(subsystem->IsDerivedFrom(HeatSink::DefaultData))
	{
		m_numHeatSinks++;
	}
}

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

	BaseClass::RemoveSubsystem(subsystem);
	
	if (subsystem->IsDerivedFrom(JumpJet::DefaultData))
	{
		jumpJet = NULL;
	}
	else if(subsystem->IsDerivedFrom(HeatSink::DefaultData))
	{
		m_numHeatSinks--;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Mech::GetExecutionSlot()
{
	Check_Object(this);
	return m_mechSlot;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::StartDropping (void)
{
	if (executionState->GetState() != ExecutionStateEngine::DroppingState)
		m_NeedStartDrop = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::RealStartDropping (void)
{
	m_NeedStartDrop = false;
	const GameModel *model = GetGameModel();

	m_DropSite = FindSite ("site_jcattach");
	m_JumpSite1 = FindSite ("site_jcjetport01");
	m_JumpSite2 = FindSite ("site_jcjetport02");
	m_JumpSite3 = FindSite ("site_jcjetport03");
	m_JumpSite4 = FindSite ("site_jcjetport04");

	if ((model->cradle != ResourceID::Null) && (!GetJumpJet ()) && (m_DropSite))
	{
		Entity::ClassID class_ID;
		class_ID = Entity::GetClassIDFromDataListID(model->cradle);
		Verify(class_ID != NullClassID);

		NameTable *table = NameTable::GetInstance();
		Check_Object (table);

		int aiid;
		aiid = table->AddEntry ("",NameTable::BuildingArray);

		Building::CreateMessage Building_Create_Message(sizeof(Building::CreateMessage),
													DefaultEventPriority,
													Building::CreateMessage::DefaultFlags,
													class_ID,
													Building::CreateMessage::DefaultFlags,
													model->cradle,
													GetLocalToWorld(),
													0.0f,
													Entity__ExecutionStateEngine::AlwaysExecuteState,
													aiid,
													GetAlignment(),
													Motion3D::Identity,
													Motion3D::Identity,
													"",
													ResourceID::Null,
													ResourceID::Null,
													ResourceID::Null,
													ResourceID::Null,
													DefaultSkinPrefix,
													0,
													0,
													0,
													false
													);

		MemoryStream stream(&Building_Create_Message, Building_Create_Message.messageLength);
		ReplicatorID cradle_id = Connection::Local->GetNextReplicatorID();
		Entity *cradle = Entity::CreateEntity(&stream, &cradle_id, false);

		m_DropCradle.Add (cradle);
		MWMap::GetInstance ()->AddChild (cradle);
	}

	executionState->RequestState(Vehicle__ExecutionStateEngine::DroppingState);
  m_LastState = Vehicle__ExecutionStateEngine::DroppingState;

	// Find the ground

	//
	// make a line...
	//
	Point3D curlocation (GetLocalToWorld ());
	Point3D new_translation (-1,-1,-1);
	Stuff::Line3D line;
	line.m_length = 1020.0f;
	line.m_direction = Vector3D::Down;
	line.m_origin = curlocation;

	//
	// Prepare query
	//	
	Stuff::Normal3D normal;
	Entity::CollisionQuery query(&line, &normal, Entity::CanBeWalkedOnFlag, this);

	//
	// Cast ray
	//
	Adept::Entity *entity_hit;
	Check_Object(CollisionGrid::Instance);
	entity_hit = CollisionGrid::Instance->ProjectLine(&query);

	if (entity_hit != NULL)
	{
		// if we hit ground, great!
		line.FindEnd(&new_translation);
	}
#ifdef LAB_ONLY
	else
	{
		PAUSE (("tried to start a mech drop when not above the ground"));
	}
#endif

	m_DroppingFinalY = new_translation.y;
	m_DroppingStartY = curlocation.y;
	if (m_AI)
		m_AI->AlwayActive (true);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::DroppingMovementSimulation(Stuff::Time till)
{
	Check_Object(this);

	//
	//----------------------------------------------------------
	// Put gravity into local space and compute our new position
	//----------------------------------------------------------
	//
	currentSpeedMPS = localSpaceVelocity.linearMotion.z;

	Scalar time_slice = GetTimeSlice(till);
	Check_Object(this);
	
	//
	//---------------------------------------------------------------------
	// Apply velocity/acceleration to position and acceleration to velocity
	//---------------------------------------------------------------------
	//
	const LinearMatrix4D &vehicle_to_world = GetLocalToWorld();
	Point3D world_translation(vehicle_to_world);
	Vector3D delta;
	delta.AddScaled(
		localSpaceVelocity.linearMotion,
		localSpaceAcceleration.linearMotion,
		0.5f * time_slice
	);
	Vector3D world_delta;
	world_delta.Multiply(delta, vehicle_to_world);
	Max_Clamp(world_delta.y, -5.0f*time_slice);
	Min_Clamp(world_delta.y, -40.0f);
	if (localSpaceVelocity.linearMotion.y < -40.0f)
	{
		m_CanStartDropJetEffect = true;
	}
	world_translation.AddScaled(world_translation, world_delta, time_slice);
	localSpaceVelocity.linearMotion.y += localSpaceAcceleration.linearMotion.y*time_slice;
	localSpaceVelocity.linearMotion.x = 0;
	localSpaceVelocity.linearMotion.z = 0;
//	Max_Clamp(localSpaceVelocity.linearMotion.y, -5.0f);
//	Min_Clamp(localSpaceVelocity.linearMotion.y, -40.0f);

	//
	//--------------------------------------
	// Update our turn rates and orientation
	//--------------------------------------
	//
//	const GameModel *model = GetGameModel();
//	Check_Object(model);
//	Scalar temp = Lerp(model->fullStopTurnRate, model->topSpeedTurnRate, currentSpeedMPS/GetMaxSpeed());
	YawPitchRoll new_rotation(vehicle_to_world);
//	temp *= time_slice;
//	new_rotation.yaw += yawDemand * temp;
//	new_rotation.pitch += pitchDemand * temp;
//	new_rotation.roll += rollDemand * temp;
	new_rotation.yaw = 0;
	new_rotation.pitch = 0;
	new_rotation.roll = 0;



	//
	//----------------------------------------------
	// Adjust position from network
	//----------------------------------------------
	//

	YawPitchRoll correction_angle;
	Point3D correction_position;
	
	


//	GetNetworkAdjustment(time_slice, correction_position, correction_angle);

//	new_rotation.yaw.angle += correction_angle.yaw.angle;
//	new_rotation.pitch.angle += correction_angle.pitch.angle;
//	new_rotation.roll.angle += correction_angle.roll.angle;
//	world_translation += correction_position;

	
	if (GetNetworkAdjustment(time_slice, correction_position, correction_angle))
	{
		new_rotation = correction_angle;
		world_translation = correction_position;
	}


	//
	//----------------------------------------------
	// Cast a ray down to see what we are driving on
	//----------------------------------------------
	//
	Stuff::Line3D line;
	line.m_length = 10.001f;
	line.m_direction = Vector3D::Down;
	line.m_origin = world_translation;
	line.m_origin.y += 10.0f;
	Stuff::Normal3D normal;
	CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);
	Check_Object(CollisionGrid::Instance);




	//
	//------------------------------------------------
	// If we miss the ground, go to where gravity said
	//------------------------------------------------
	//
	LinearMatrix4D new_local_to_world;
	new_local_to_world.BuildRotation(new_rotation);
	if (!CollisionGrid::Instance->ProjectLine(&query))
	{
		materialHit = MaterialCount;
		worldSpaceVelocity.linearMotion.Multiply(
			localSpaceVelocity.linearMotion,
			vehicle_to_world
		);
		Max_Clamp(worldSpaceVelocity.linearMotion.y, 0.0f);


		
		new_local_to_world.BuildTranslation(world_translation);
	}

	//
	//--------------------------------------------------
	// Otherwise, adapt the vehicle to the ground normal
	//--------------------------------------------------
	//
	else
	{
		materialHit = query.m_material;
		line.FindEnd(&world_translation);

		
		new_local_to_world.BuildTranslation(world_translation);

		//
		//--------------------------------------------------
		// Update the velocities to conform to the landscape
		//--------------------------------------------------
		//
		localSpaceVelocity.linearMotion.x = 0.0f;
		localSpaceVelocity.linearMotion.y = 0.0f;
		localSpaceVelocity.linearMotion.z = currentSpeedMPS;
		worldSpaceVelocity.linearMotion.Multiply(
			localSpaceVelocity.linearMotion,
			new_local_to_world
		);
		{
			new_local_to_world(3,1) = line.m_origin.y - line.m_length;
			SetNewLocalToParent(new_local_to_world);
			localSpaceVelocity.linearMotion.y = 0.0f;
			worldSpaceVelocity.linearMotion.y = 0.0f;

			executionState->RequestState(ExecutionStateEngine::DrivingMotionState);
		}
	}

	SetNewLocalToParent(new_local_to_world);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::PreCollisionExecute(Time till)
{
	Check_Object(this);
	PRECOLLISION_LOGIC("Mech");


	
	//
	//----------------------------------------------------------------------
	// If the we have an interface, let it adjust the time slice for network
	//----------------------------------------------------------------------
	//
	Set_Statistic(Executed_Mech_Count, Executed_Mech_Count+1);
	Scalar time_slice = GetTimeSlice(till);


	if (m_FallDamage)
	{
		m_FallDamage -= (MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::fall_damage_minus) * time_slice);
		Min_Clamp (m_FallDamage,0);
// MSL 5.02 headshot
		m_HeadShotFallDamageMod = 1.0;
		m_HeadShotTorsoRockDamageMod = 1.0;
		m_HeadShotTorsoSpinDamageMod = 1.0;
// MSL 5.02 SubSystems
		if (GetAdvancedGyro())
		{
// MSL 5.03 Gyro Hit
			m_AdvancedGyroFallDamageMod = 1.0;
//			m_AdvancedGyroFallDamageMod = ADVANCED_GYRO_FALL_MOD;
		}
		else
		{
			m_AdvancedGyroFallDamageMod = 1.0;
		}
	}

	if (vehicleInterface)
	{
		Verify(!vehicleRunsInterface);
		Check_Object(vehicleInterface);
		vehicleInterface->PreCollisionExecute(till);
		Verify(!vehicleInterface->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(vehicleInterface));
	}
	
	Verify(time_slice > 0.0f);

	blockFallTimer += time_slice;
	//
	//---------------------------------
	// Let vehicle set up the variables
	//---------------------------------
	//
	BaseClass::PreCollisionExecute(till);


	//
	//---------------------------------------
	// Figure out what motion state we are in
	//---------------------------------------
	//
	Check_Object(executionState);
	int pre_state = executionState->GetState();
	Verify(pre_state != ExecutionStateEngine::NeverExecuteState);
	switch (pre_state)
	{

	//
	//------------------------------------------------------------------------
	// If we are in the walking state, first evaluate the ground to figure out
	// our mech's speed and orientation
	//------------------------------------------------------------------------
	//
	case ExecutionStateEngine::DroppingState:
		{
			PRECOLLISION_LOGIC("Mech::DroppingState");
			//
			//-----------------------------
			// Put gravity into local space
			//-----------------------------
			//
			UnitVector3D world_down_in_local;
			GetLocalToWorld().GetWorldDownInLocal(&world_down_in_local);
			Point3D loc(GetLocalToWorld ());
			if (loc.y < (((m_DroppingStartY - m_DroppingFinalY)/2.0f)+m_DroppingFinalY))
			{
				localSpaceAcceleration.linearMotion.AddScaled(
					localSpaceAcceleration.linearMotion,
					world_down_in_local,
					-g_Gravity
				);
			}
			else
			{
				localSpaceAcceleration.linearMotion.AddScaled(
					localSpaceAcceleration.linearMotion,
					world_down_in_local,
					g_Gravity
				);
			}

			animationVelocity = Stuff::Point3D::Identity;
			instantaniousAngularVelocity = Stuff::Vector3D::Identity;
			animStateEngine->RunStates(time_slice, Mech::NoBlend);

			DroppingMovementSimulation(till);
			
			FootLockSimulation(time_slice);
			DampenMech(time_slice);
			RunSprings(time_slice);
			
			if (executionState->GetState() != ExecutionStateEngine::DroppingState)
			{
//				if (GetJumpJet ())
//				{
//					GetJumpJet ()->StopJumpJetEffectOnly ();
//				}
//				else
				{

					if (m_DropCradle.GetCurrent ())
					{
						m_NeedKillDropCradleEffect = true;
						m_DropCradle.GetCurrent ()->SentenceToDeathRow ();
					}
					if (m_JumpEffect1.GetCurrent ())
					{
						m_JumpEffect1.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
						m_JumpEffect1.Remove();
					}
					if (m_JumpEffect2.GetCurrent ())
					{
						m_JumpEffect2.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
						m_JumpEffect2.Remove();
					}
					if (m_JumpEffect3.GetCurrent ())
					{
						m_JumpEffect3.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
						m_JumpEffect3.Remove();
					}
					if (m_JumpEffect4.GetCurrent ())
					{
						m_JumpEffect4.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
						m_JumpEffect4.Remove();
					}
				}
			}
		}

		break;
	case ExecutionStateEngine::DrivingMotionState:
		{
			PRECOLLISION_LOGIC("Mech::DrivingState");
			//
			//-----------------------------
			// Put gravity into local space
			//-----------------------------
			//
			FindGroundAngles();
			ComputeForwardSpeed(time_slice);
			TiltMech(time_slice);

			//
			//------------------------------
			// Run the animation on the mech
			//------------------------------
			//
			MaintainWalkingAnimStates(Mech::NoBlend);
			Check_Object(m_gyro);
			m_gyro->Execute();
			instantaniousAngularVelocity = Stuff::Vector3D::Identity;
			animationVelocity = Stuff::Point3D::Identity;

			// if we are landing we need to have a specific speed
			if (animStateEngine->GetState() == MechAnimationStateEngine::FlyState && animStateEngine->GetTransitionState() == MechAnimationStateEngine::ForwardState)
			{
				currentSpeedMPS = GetMaxSpeed() * 0.5f;
			}

			animStateEngine->RunStates(time_slice, Mech::NoBlend);

			

			if (animStateEngine->IsTransitioning() && animStateEngine->GetTransitionState() == MechAnimationStateEngine::FlyState)
			{
				animationVelocity.z = currentSpeedMPS;	
			}
			else if (animStateEngine->GetState() == MechAnimationStateEngine::FlyState)
			{
				animationVelocity.z = currentSpeedMPS;
			}


			if (!allowedToAnimateVelocity)
			{
				animationVelocity.x = 0.0f;
				animationVelocity.z = 0.0f;
			}

			
			MovementSimulation(time_slice, animationVelocity, instantaniousAngularVelocity);
			

			FootLockSimulation(time_slice);
			DampenMech(time_slice);
			RunSprings(time_slice);
		
		}
		break;

	//
	//------------------------------------
	// Handle being in the ballistic state
	//------------------------------------
	//
	case ExecutionStateEngine::FlyingMotionState:
		{
			PRECOLLISION_LOGIC("Mech::FlyingState");
			//
			//-----------------------------
			// Put gravity into local space
			//-----------------------------
			//
			m_gyro->Execute();
			FindGroundAngles();	

			animationVelocity = Stuff::Point3D::Identity;
			instantaniousAngularVelocity = Stuff::Vector3D::Identity;
			animStateEngine->RunStates(time_slice, Mech::NoBlend);

			BallisticMovementSimulation(till);
			
			FootLockSimulation(time_slice);
			DampenMech(time_slice);
			RunSprings(time_slice);
			
			if (m_FallDampingEnabled == true)
			{
				FallDampingSimulation();
			}

		}
		break;

	//
	//----------------------------------
	// Handle being in the fallinging state
	//----------------------------------
	//
	case ExecutionStateEngine::FallingMotionState:
		{
			PRECOLLISION_LOGIC("Mech::FallingState");
			blockFallTimer = 0.0f;
			//
			//-----------------------------
			// Put gravity into local space
			//-----------------------------
			//
			UnitVector3D world_down_in_local;
			GetLocalToWorld().GetWorldDownInLocal(&world_down_in_local);
			localSpaceAcceleration.linearMotion.AddScaled(
				localSpaceAcceleration.linearMotion,
				world_down_in_local,
				g_Gravity
			);
			instantaniousAngularVelocity = Stuff::Vector3D::Identity;

			if (!animStateEngine->IsTransitioning())
			{
				switch (animStateEngine->GetState())
				{
					case MechAnimationStateEngine::FallForwardState:
					case MechAnimationStateEngine::FallBackwardState:
					case MechAnimationStateEngine::FallLeftState:
					case MechAnimationStateEngine::FallRightState:
							{
								m_CanStartGettingUp = true;
							}
							break;
					default:
							if (!IsDestroyed())
							{
								executionState->RequestState(ExecutionStateEngine::DrivingMotionState);
								tiltAngle = 0.0f;
								tiltRequest = 0.0f;
								currentSpeedMPS = 0.0f;
							}
							break;
				}
			}
			FindGroundAngles();
			
			//TiltMech(time_slice);
			ComputeFrictionSpeed (time_slice);
			if ((m_SlideTimer < gos_GetElapsedTime ()) || (Small_Enough (localSpaceVelocity.linearMotion.z) && m_CanStartGettingUp))
			{
				localSpaceVelocity.linearMotion = Vector3D::Identity;
				worldSpaceVelocity.linearMotion = Vector3D::Identity;
				if (!IsDestroyed())
				{
					queFallState = NoFallMode;
					animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
				}
				else
				{
					if (triggerDeath == NoDeathTrigger)
					{
						triggerDeath = FallDownDeathTrigger;
					}
				}
			}

			animStateEngine->RunStates(time_slice, Mech::NoBlend);
			Stuff::Vector3D temp = animationVelocity;
			animationVelocity = localSpaceVelocity.linearMotion;
			Min_Clamp (animationVelocity.x,temp.x);
			Min_Clamp (animationVelocity.y,temp.y);
			Min_Clamp (animationVelocity.z,temp.z);
			FallingMovementSimulation(time_slice, animationVelocity, instantaniousAngularVelocity);
			
			FootLockSimulation(time_slice);
			DampenMech(time_slice);
			RunSprings(time_slice);
			worldSpaceVelocity.linearMotion.Multiply(
				localSpaceVelocity.linearMotion,
				GetLocalToWorld ()
			);

		}
		break;
	}

	groundAngleDbg.yaw = 0.0f;
	groundAngleDbg.roll = localGroundRoll;
	groundAngleDbg.pitch = localGroundPitch;

	//
	//--------------------------------------------------------------------------
	// If this is the player vehicle, check to see if we are in the mission area
	//--------------------------------------------------------------------------
	//
	if (IsPlayerVehicle())
	{
		PRECOLLISION_LOGIC("Mech::MapBounds");
		Check_Object(Mission::GetInstance());
		ElementRenderer::Element *element = GetElement();
		Check_Object(element);
		Point3D where(element->GetNewLocalToParent());
		Mission::MissionArea area = Mission::GetInstance()->GetMissionArea(where);

		//
		//------------------------------------------------------------------------
		// If we aren't in the mission area, set up a fake collision if we haven't
		// already collided
		//------------------------------------------------------------------------
		//
		switch (area)
		{
			case Mission::InMissionArea:
			{
				break;
			}

			case Mission::OutOfMissionArea:
			{
				if ((vehicleInterface) &&
					(vehicleInterface->executionState) &&
					(vehicleInterface->executionState->GetState() == VehicleInterface::ExecutionStateEngine::AIRunningState))
				{
					break;
				}

				//
				//----------------------------------------------------------------
				// Now move the player back to where he was, except for the height
				//----------------------------------------------------------------
				//
				Check_Object(entityElement);
				LinearMatrix4D new_local_to_parent = element->GetNewLocalToParent();
				Point3D new_translation;
				new_translation = new_local_to_parent;
				Point3D old_translation;

				MWMission* mission = Cast_Object(MWMission*,Mission::GetInstance());
				if (mission->m_ConstraintTopLeft != Point3D::Identity)
				{
					old_translation = new_translation;

					Stuff::Scalar min_x = mission->m_ConstraintTopLeft.x;
					Stuff::Scalar max_x = mission->m_ConstraintBottomRight.x;

					if (min_x > max_x)
					{
						Scalar temp = min_x;
						min_x = max_x;
						max_x = temp;
					}

					Clamp(old_translation.x,min_x,max_x);

					Stuff::Scalar min_z = mission->m_ConstraintTopLeft.z;
					Stuff::Scalar max_z = mission->m_ConstraintBottomRight.z;

					if (min_z > max_z)
					{
						Scalar temp = min_z;
						min_z = max_z;
						max_z = temp;
					}

					Clamp(old_translation.z,min_z,max_z);

					Point3D delta;
					delta.Subtract(old_translation,new_translation);

					if (delta.GetLengthSquared() > 5.0f * 5.0f)
					{
						break;
					}
				}
				else
				{
					old_translation = (element->GetLocalToParent());
				}

				old_translation.y = new_translation.y;
				new_local_to_parent.BuildTranslation(old_translation);
				SetNewLocalToParent(new_local_to_parent);
				SyncMatrices(true);

				if (m_LastMissionWarning + mission_area_warning_frequency < (Stuff::Scalar)gos_GetElapsedTime())
				{
					if ((vehicleInterface) &&
						(vehicleInterface->GetBoundsWarningsEnabled() == true))
					{
						if ((g_nMR != 2) && MW4Shell::Instance->m_optionsObject->m_bettyOn)
						{
							AudioCommand *command = AudioCommand::Create(
								AudioRenderer::BettyType,
								"cmp_exit_mission_area.wav{handle}",
								1.0f,
								1.0f
							);
							Check_Object(command);
							command->Play();
						}
					}
					m_LastMissionWarning = (Stuff::Scalar)gos_GetElapsedTime();
				}

				break;
			}

			case Mission::InWarningArea:
			{
				if (m_LastMissionWarning + mission_area_warning_frequency < (Stuff::Scalar)gos_GetElapsedTime())
				{
					if ((vehicleInterface) &&
						(vehicleInterface->GetBoundsWarningsEnabled() == true))
					{
						if ((g_nMR != 2) && MW4Shell::Instance->m_optionsObject->m_bettyOn)
						{
							AudioCommand *command = AudioCommand::Create(
								AudioRenderer::BettyType,
								"cmp_approach_boundary.wav{handle}",
								1.0f,
								1.0f
							);
							Check_Object(command);
							command->Play();
						}
					}
					m_LastMissionWarning = (Stuff::Scalar)gos_GetElapsedTime();
				}

				break;
			}
		}
	}

	//WE are not a player Mech
	else
	{
		//Make sure to keep them atleast 15 meters from the edge of the map since then can
		//pass the warning and mission bounds
		Scalar min_x, min_z, max_x, max_z;
		Check_Object(Map::GetInstance());
		Map::GetInstance()->GetMapExtents(&min_z, &max_z, &min_x, &max_x);
		ElementRenderer::Element *element = GetElement();
		Check_Object(element);
		Point3D where(element->GetNewLocalToParent());

		Clamp(where.x, min_x + 15.0f, max_x - 15.0f);
		Clamp(where.z, min_z + 15.0f, max_z - 15.0f);

		LinearMatrix4D clamped_position = element->GetNewLocalToParent();
		clamped_position.BuildTranslation(where);

		SetNewLocalToParent(clamped_position);
		SyncMatrices(true);
	}
	
	{
	PRECOLLISION_LOGIC("Mech::LastBits");

	Check_Object(m_heatManager);
	//This should be set to the material heat, but for not it stays 1
	m_sensorDinstanceMultiplier = 1.0f;
	//WE then can add to it the effect stuff too
	MWMission *mw_mission = Cast_Object(MWMission *, MWMission::GetInstance());
	mw_mission->ProcessReactionSpheres(this);
	GetSensor()->m_maxRange *= m_sensorDinstanceMultiplier;

	m_heatManager->ApplyMovementHeat(currentSpeedMPS, GetMaxSpeed());
	m_heatManager->Execute();

	if ((armReNullTime != 0) &&
		((Stuff::Scalar)gos_GetElapsedTime() > armReNullTime))
	{
		if (armsNulled == true)
		{
			armsNulled = false;
			armBlanderizer.FadeToNewDampen(0.0f, 1.0f);
		}

		armReNullTime = 0;
	}

	if(GetTorso())
		GetTorso()->SetHeatMultiplier(m_heatManager->GetTorsoTwistMultiplier());

	if((vehicleShutDown) && (!m_alreadyShutDown))
	{
		//Check to see if we are shut down
		if(!animStateEngine->IsTransitioning() &&
			animStateEngine->GetState() == MechAnimationStateEngine::PowerDownState)
		{
			ReactToShutDown();
		}
		//Else check to see if we are gimped in which case we can't shutdown in the anim system
		else if(gimpState != NotGimpedMode)
		{
			ReactToShutDown();
		}
	}

	allowedToAnimateVelocity = true;

	}



	// SPECIAL CASE WORK AROUND FOR NETWORK BUG :JSE
	// Sometimes, for god knows what reason mechs spawn REALLY low under ground.
	// this detects and correct the problem.
	if (IsPlayerVehicle() && MWApplication::GetInstance()->networkingFlag)
	{
		Point3D position;
		position = GetElement()->GetNewLocalToParent();

		if (position.y < -2000.0f)
		{
			//damn mech is below ground...
			const LinearMatrix4D& local_to_world = GetElement()->GetNewLocalToParent();
			Stuff::Line3D line;
			line.m_length = 2000.0f;
			line.m_direction = Vector3D::Down;
			line.m_origin = local_to_world;
			line.m_origin.y = 1000.0f;
			Stuff::Normal3D normal;
			CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);
			Check_Object(CollisionGrid::Instance);
			
			CollisionGrid::Instance->ProjectLine(&query);
			Point3D tr;
			line.FindEnd(&tr);

			LinearMatrix4D new_local_to_world = local_to_world;

			new_local_to_world.BuildTranslation(tr);
			SetNewLocalToParent(new_local_to_world);

		}
	}


#if 0
	if (Connection::Local->GetID() == GetReplicatorID().connectionID && !MWApplication::GetInstance()->serverFlag)
	{
		Point3D position;
		position = GetElement()->GetNewLocalToParent();

		//SPEW(("jerryeds","PRE-MOVEMENT : %f %f %f", position.x, position.y, position.z));
	}
#endif

}

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

void
	Mech::FallDampingSimulation()
{
	PRECOLLISION_LOGIC("Mech::FallDampingSim");

	localSpaceVelocity.linearMotion.MultiplyByInverse(worldSpaceVelocity.linearMotion,GetLocalToWorld());

	Stuff::Scalar length(Fabs(localSpaceVelocity.linearMotion.z));

	Stuff::Point3D world_velocity;
	world_velocity.Subtract(m_FallDampingLocus,(Point3D)GetLocalToWorld());

	Stuff::Vector3D local_velocity(localSpaceVelocity.linearMotion);
	local_velocity.MultiplyByInverse(world_velocity,GetLocalToWorld());

	localSpaceVelocity.linearMotion.z = local_velocity.z;
	Clamp(localSpaceVelocity.linearMotion.z,-length,length);
	worldSpaceVelocity.linearMotion.Multiply(localSpaceVelocity.linearMotion,GetLocalToWorld());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mech::CollisionHandler(
		Stuff::LinearMatrix4D *new_position,
		Stuff::DynamicArrayOf<CollisionData> *collisions
	)
{



	Check_Object(this);
	Check_Object(collisions);
	Verify(GetInterestLevel() != DormantInterestLevel);
	Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));
	bool shoulddamage=true;

	//
	//----------------------------------------------------------
	// If we are destroyed, delete the collision list and return
	//----------------------------------------------------------
	//
	if (IsDestroyed())
	{
		Verify(!newCollisions);
		delete collisions;
		SetNewLocalToParent(GetLocalToParent()); // reset this since collision handler won't now
		return false;
	}

	//
	//--------------------------------
	// Ask the AI about the collision
	//--------------------------------
	//
	if (m_AI)
	{
		if (!m_AI->ReactToCollision(collisions,shoulddamage))			// ai will return false if collision should not occur
		{
			Verify(!newCollisions);
			delete collisions;
			return false;
		}
	}


	//
	//----------------------------------------
	// Turn off collision if we are going fast
	//----------------------------------------
	//
	#ifdef LAB_ONLY
		if (m_DebugFast)
		{
			Verify(!newCollisions);
			delete collisions;
			return false;
		}
	#endif



	//
	//-------------------------
	// Figure out our mech data
	//-------------------------
	//
	int step_class;
	Scalar mech_speed;
	Scalar building_speed;
	Scalar damage_given;
	Scalar slowdown;
	if (GetTonage() >= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_tonage))
	{
		step_class = HeavyCanWalkThruType;
		mech_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_mech_speed);
		building_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_building_speed);
		damage_given = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_damage);
		slowdown = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_slowdown);
	}
	else if (GetTonage() >= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_tonage))
	{
		step_class = MediumCanWalkThruType;
		mech_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_mech_speed);
		building_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_building_speed);
		damage_given = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_damage);
		slowdown = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_slowdown);
	}
	else
	{
		step_class = AnythingCanWalkThruType;
		mech_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_mech_speed);
		building_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_building_speed);
		damage_given = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_damage);
		slowdown = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_slowdown);
	}

	//
	//-----------------------
	// Iterate the collisions
	//-----------------------
	//
	Vector3D delta = Vector3D::Identity;
	bool just_bump = true;

	bool ignore_collision = true;
	

	for (int i=0; i<collisions->GetLength(); ++i)
	{
		CollisionData *data = &(*collisions)[i];
		Check_Pointer(data);

		//
		//---------------------------------------------------------------------
		// Look to see if we have run into a collider, and if so, calculate the
		// relative velocity
		//---------------------------------------------------------------------
		//
		Entity *other = data->m_otherEntity;
		if (other->IsACollider())
		{
			MWObject *mover = Cast_Object(MWObject*, other);
			Vector3D rel_vel;
			rel_vel.Subtract(mover->worldSpaceVelocity.linearMotion, worldSpaceVelocity.linearMotion);
			Scalar speed = rel_vel.GetLengthSquared();

			//
			//------------------------------------------------
			// If its a mech, figure out the tonnage constants
			//------------------------------------------------
			//
			if (other->GetClassID() == MechClassID)
			{
				if (other->IsDestroyed())
				{
					
					continue;					
				}
				
				ignore_collision = false;
				just_bump = false;
				Mech *mech = Cast_Object(Mech*, mover);
				Scalar damage_received;
				if (mech->GetTonage() >= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_tonage))
					damage_received = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_damage);
				else if (mech->GetTonage() >= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_tonage))
					damage_received = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_damage);
				else
					damage_received = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_damage);

				//
				//--------------------------
				// See if the hit will count
				//--------------------------
				//
				Time too_old = gos_GetElapsedTime() - 5.0;
				SortedChainIteratorOf<Mech*, Time> oldies(&m_lastHits);
				Mech *maybe_mech;
				while ((maybe_mech = oldies.GetCurrent()) != NULL)
				{
					if (oldies.GetValue() <= too_old)
						oldies.Remove();
					else if (maybe_mech == mech)
						break;
					else
						oldies.Next();
				}
				if (maybe_mech)
					shoulddamage = false;

				//
				//------------------------------------------------------------------------------------
				// See if we are going fast enough to get damaged, add ourselves to the last hit chain
				// to avoid further unpleasantness
				//------------------------------------------------------------------------------------
				//
				if (speed >= mech_speed)
				{
					if (shoulddamage)
					{
						m_lastHits.AddValue(mech, gos_GetElapsedTime());

						//
						//------------------------
						// Play the ramming effect
						//------------------------
						//
						Point3D target_local_to_world;
						target_local_to_world = data->m_otherVolume->m_worldSpaceBounds.localToParent;
						Point3D local_to_world;
						local_to_world = data->m_volume->m_worldSpaceBounds.localToParent;
						Point3D effect_offset;
						effect_offset.Subtract(target_local_to_world, local_to_world);
						effect_offset *= 0.5f;
						Point3D effect_translation;
						effect_translation.Add(local_to_world, effect_offset);
						const GameModel *model = GetGameModel();
						Check_Object(model);
						CreateEffect(model->m_mechRamEffect, effect_translation);
					}

					//
					//------------------------
					// Evaluate the DFA states
					//------------------------
					//
					speed = Sqrt(speed)*mover->GetTonage();
					Scalar min_dfa_vel = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_speed);
					Entity::ExecutionStateEngine *engine = executionState;
					bool our_dfa = worldSpaceVelocity.linearMotion.y <= -min_dfa_vel && engine->GetState() == ExecutionStateEngine::FlyingMotionState;
					engine = mech->executionState;
					bool their_dfa = mech->worldSpaceVelocity.linearMotion.y <= -min_dfa_vel && engine->GetState() == ExecutionStateEngine::FlyingMotionState;

					//
					//---------------------------------------
					// Use the appropriate collision modifier
					//---------------------------------------
					//
					if (our_dfa ^ their_dfa)
					{
						if (our_dfa)
							speed *= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_damage_taken);
						else
							speed *= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_damage_given);

						//
						//-------------------------------------------------------------
						// Figure out the direction that the mech needs to fall down in
						//-------------------------------------------------------------
						//
						Check_Object(m_gyro);
						Vector3D local_vel;
						local_vel.MultiplyByInverse(
							rel_vel,
							GetElement()->GetNewLocalToParent()
						);
						if (Fabs(local_vel.z) > Fabs(local_vel.x))
						{
							if (local_vel.z > 0)
								m_gyro->FallDown(FallForwardMode, 0.0f);
							else
								m_gyro->FallDown(FallBackMode, 0.0f);
						}
						else
						{
							if (local_vel.x > 0)
								m_gyro->FallDown(FallRightMode, 0.0f);
							else
								m_gyro->FallDown(FallLeftMode, 0.0f);
						}
					}
					else
					{
						speed *= damage_received;
						our_dfa = their_dfa = false;
					}

					//
					//------------------------------------
					// Figure out the direction of the hit
					//------------------------------------
					//
					char damage_type;
					if (our_dfa)
						damage_type = RammingDamageFromBelowType;
					else if (their_dfa)
						damage_type = RammingDamageFromAboveType;
					else
					{
						Vector3D local_vel;
						local_vel.MultiplyByInverse(
							rel_vel,
							GetElement()->GetNewLocalToParent()
						);
						if (Fabs(local_vel.z) > Fabs(local_vel.x))
						{
							if (local_vel.z > 0)
								damage_type = RammingDamageFromBehindType;
							else
								damage_type = RammingDamageFromAheadType;
						}
						else
						{
							if (local_vel.x > 0)
								damage_type = RammingDamageFromLeftType;
							else
								damage_type = RammingDamageFromRightType;
						}
					}

					if (vehicleInterface)
					{
						switch (damage_type)
						{
						case RammingDamageFromBelowType:
							vehicleInterface->PlayHitForce (Point3D (1.0f,0.0f,1.0f),2.0f);
							break;
						case RammingDamageFromAboveType:
							vehicleInterface->PlayHitForce (Point3D (1.0f,0.0f,1.0f),2.0f);
							break;
						case RammingDamageFromBehindType:
							vehicleInterface->PlayHitForce (Point3D (0.0f,0.0f,-1.0f),2.0f);
							break;
						case RammingDamageFromAheadType:
							vehicleInterface->PlayHitForce (Point3D (0.0f,0.0f,1.0f),2.0f);
							break;
						case RammingDamageFromLeftType:
							vehicleInterface->PlayHitForce (Point3D (-1.0f,0.0f,0.0f),2.0f);
							break;
						case RammingDamageFromRightType:
							vehicleInterface->PlayHitForce (Point3D (1.0f,0.0f,0.0f),2.0f);
							break;
						}
					}
					//
					//----------------------------------
					// Set the damage message to ourself
					//----------------------------------
					//
					if (shoulddamage)
					{

// MSL 5.02 Collision Smoke
						Point3D myloc;
						myloc = animationArray[torsoAboveJointIndex]->GetLocalToWorld();
//						Stuff::Point3D myloc(GetLocalToWorld());
//						myloc.y += 6.0f;

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

						TakeDamageMessage damage_message(
							GetReplicatorID(),
							other->GetReplicatorID(),
							speed,
							m_ArmorMode,
							damage_type,
							data->m_normal,
							myloc,
//							data->m_worldIntersectionPoint,
							0.0f,
							false,
							TakeDamageMessage::DefaultWeaponType
						);
						Receive(&damage_message);
					}
				}
			}

			//
			//-----------------------------------------------------
			// We didn't hit a mech, so see if we need to slow down
			//-----------------------------------------------------
			//
			else if ((step_class > other->GetWalkThruType()) || ((GetAlignment () == Player) && (other->GetAlignment () == Player)))
			{
				ignore_collision = false;
				just_bump = false;
			}
			else
				continue;
		}

		//
		//--------------------------------------------------------------
		// If we've run into a static object, see if we can just kill it
		//--------------------------------------------------------------
		//
		else
		{
			ignore_collision = false;

// MSL 5.03 Hit Glass Effect
			//
			// Currently the shield does not display a reasonable effect when a mech runs into it, so we'll special
			// case glass to play an effect.
			//
			if ((data->m_otherVolume->m_material & 0x1f) == GlassMaterial)
			{
				//
				//------------------------
				// Play the ramming effect
				//------------------------
				//
				Point3D local_to_world;
				local_to_world = data->m_volume->m_worldSpaceBounds.localToParent;

				//
				// In order to make this look at all right, I'll need to do two additional steps:
				//		Identify the closest point on the target volumes closest plane as the place to create the effect
				//		Send the normal along with the effect to have it played correctly.
				//

				//
				// Find the correct plane to use:
				//		
				//



				Point3D effect_offset;

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

				OBB::SeparatingAxis axis;
				Vector3D adj;
				axis = data->m_volume->m_worldSpaceBounds.CalculateSeparationVector(
					&adj,
					data->m_otherVolume->m_worldSpaceBounds);

			  // Need to compensate for the size of the collision volume.
			  Vector3D adjDirection;
			  Stuff::Scalar adjDirection_length = adj.GetLengthSquared();
			  if (!Small_Enough(adjDirection_length))
			  {

				//
				// Normalize
				//
				adjDirection_length = 1.0f / Sqrt(adjDirection_length);
				adjDirection.x = adj.x * adjDirection_length;
				adjDirection.y = adj.y * adjDirection_length;
				adjDirection.z = adj.z * adjDirection_length;

				adjDirection *= data->m_volume->m_worldSpaceBounds.axisExtents.z;


				effect_offset.Subtract(local_to_world, adjDirection);



				CreateEffect(model->m_mechGlassRamEffect, effect_offset, adj);
									
			  }

			} // if we hit glass

			if (step_class <= other->GetWalkThruType())
			{
//				if (shoulddamage)
				{
					TakeDamageMessage damage_message(
						other->GetReplicatorID(),
						GetReplicatorID(),
						100000.0f,
// MSL 5.05 Armor Mode
						0,
						RammingDamageFromAboveType,
						data->m_otherNormal,
						data->m_worldIntersectionPoint,
						0.0f,
						false,
						TakeDamageMessage::DefaultWeaponType
					);
					other->Receive(&damage_message);
					continue;
				}
			}

			//
			//-------------------------------------------------------------
			// Otherwise, check to see if we are going fast enough to apply
			// damage
			//-------------------------------------------------------------
			//
			Scalar min_dfa_vel = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_speed);
			Entity::ExecutionStateEngine *engine = executionState;

			//
			//---------------------------------------
			// Use the appropriate collision modifier
			//---------------------------------------
			//
			char damage_type;
			Scalar speed = worldSpaceVelocity.linearMotion.GetLengthSquared();
			Scalar damage;
			if (worldSpaceVelocity.linearMotion.y <= -min_dfa_vel && engine->GetState() == ExecutionStateEngine::FlyingMotionState)
			{
				damage_type = RammingDamageFromAboveType;
				damage = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_damage_given);
			}
			else
			{
				damage_type = RammingDamageFromAheadType;
				damage = damage_given;
			}

			//
			//-----------------------------------
			// If we can crush the thing, kill it
			//-----------------------------------
			//
// MSL 5.06 Building Collision Damage Applied
// Collision damage modifed based on armor mode
			MWApplication *m_App;
			m_App = MWApplication::GetInstance ();
			m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;

			just_bump = false;
			if (speed >= building_speed)
			{
				if (shoulddamage)
				{
					if (m_ArmorMode)
					{
						TakeDamageMessage damage_message(
							other->GetReplicatorID(),
							GetReplicatorID(),
							0.1f,
							m_ArmorMode,
							damage_type,
							data->m_otherNormal,
							data->m_worldIntersectionPoint,
							0.0f,
							false,
							TakeDamageMessage::DefaultWeaponType
						);
						other->Receive(&damage_message);
					}
					else
					{
						TakeDamageMessage damage_message(
							other->GetReplicatorID(),
							GetReplicatorID(),
							damage * Sqrt(speed) * GetTonage(),
							m_ArmorMode,
							damage_type,
							data->m_otherNormal,
							data->m_worldIntersectionPoint,
							0.0f,
							false,
							TakeDamageMessage::DefaultWeaponType
						);
						other->Receive(&damage_message);
					}
				}
			}
		}

		//
		//-------------------------------------------------------
		// Calculate how our mech needs to adapt to the collision
		//-------------------------------------------------------
		//
		OBB::SeparatingAxis axis;
		Vector3D adj;
		axis = data->m_volume->m_worldSpaceBounds.CalculateSeparationVector(
			&adj,
			data->m_otherVolume->m_worldSpaceBounds
		);

		//
		//-------------------------------------------------------------------------
		// If we are being pushed up, and this object is in our old collision list,
		// we could very well be stuck on top of the thing
		//-------------------------------------------------------------------------
		//
		if (oldCollisions)
		{
			for (unsigned j=0; j<oldCollisions->GetLength(); ++j)
			{
				if ((*oldCollisions)[j].m_otherVolume == data->m_otherVolume)
					break;
			}
			if (j<oldCollisions->GetLength())
			{
				UnitVector3D nudge(adj);
				if (nudge.y > 0.85f)
				{
					data->m_volume->m_worldSpaceBounds.CalculateSecondarySeparationVector(
						&adj,
						data->m_otherVolume->m_worldSpaceBounds,
						nudge
					);
				}
			}
		}

		delta += adj;
	}


	if (ignore_collision)
	{
		delete collisions;
		return false;
	}

	//
	//------------------------------------------------------------------------
	// If the mech is flying, make sure it isn't a bump before zeroing out the
	// mech's velocity against the normal it bounced on
	//------------------------------------------------------------------------
	//
	Entity::ExecutionStateEngine *engine = executionState;
	if (engine->GetState() == ExecutionStateEngine::FlyingMotionState)
	{
		Scalar dot = delta*worldSpaceVelocity.linearMotion;
		if (!just_bump && dot < -SMALL)
		{
			UnitVector3D direction(delta);
			dot = direction*worldSpaceVelocity.linearMotion;
			worldSpaceVelocity.linearMotion.AddScaled(
				worldSpaceVelocity.linearMotion,
				direction,
				-1.05f*dot
			);
			localSpaceVelocity.linearMotion.MultiplyByInverse(
				worldSpaceVelocity.linearMotion,
				GetLocalToWorld()
			);
			currentSpeedMPS = currentSpeedKPH = localSpaceVelocity.linearMotion.z * 3.6f;
		}
	}

	//
	//--------------------------------------------
	// If we are just bumping something, slow down
	//--------------------------------------------
	//
	else
	{
		const GameModel *model = GetGameModel();
		if (just_bump)
		{
			if (currentSpeedMPS-slowdown > model->minStandTransitionSpeed)
			{
				currentSpeedMPS -= slowdown;
				currentSpeedKPH = currentSpeedMPS * 3.6f;
				Verify(engine->GetState() != ExecutionStateEngine::NeverExecuteState);
				Verify(!newCollisions);
				delete collisions;
				return false;
			}
			if (currentSpeedMPS+slowdown < -model->minStandTransitionSpeed)
			{
				currentSpeedMPS += slowdown;
				currentSpeedKPH = currentSpeedMPS * 3.6f;
				Verify(engine->GetState() != ExecutionStateEngine::NeverExecuteState);
				Verify(!newCollisions);
				delete collisions;
				return false;
			}
		}

		//
		//------------------------------------------------------------------
		// We have come to a stop, so let the animation system handle things
		//------------------------------------------------------------------
		//
		allowedToAnimateVelocity = false;
		Max_Clamp(currentSpeedMPS, model->minStandTransitionSpeed);
		currentSpeedKPH = currentSpeedMPS * 3.6f;
		
		switch (animStateEngine->GetState())
		{
		case MechAnimationStateEngine::ForwardState:
		case MechAnimationStateEngine::BackwardState:
			animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
			break;
			
		case MechAnimationStateEngine::GimpForwardLeftState:
			animStateEngine->RequestState(MechAnimationStateEngine::GimpStandLeftState, Mech::NoBlend);
			break;

		case MechAnimationStateEngine::GimpForwardRightState:
			animStateEngine->RequestState(MechAnimationStateEngine::GimpStandRightState, Mech::NoBlend);
			break;
		}
	}




	//
	//--------------------------------------------------------------------
	// If the mech isn't executing, it can't move or retain its collisions
	//--------------------------------------------------------------------
	//
	if (engine->GetState() == ExecutionStateEngine::NeverExecuteState)
	{
		Verify(!newCollisions);
		delete collisions;
		return false;
	}

	//
	//----------------------------------------------------------------------
	// Adjust the physical position by evaluating the other OBB position and
	// moving away from it
	//----------------------------------------------------------------------
	//
	*new_position = GetElement()->GetNewLocalToParent();
	(*new_position)(3,0) += delta.x;
	(*new_position)(3,1) += delta.y;
	(*new_position)(3,2) += delta.z;
	engine = executionState;
	if (engine->GetState() == ExecutionStateEngine::NeverExecuteState)
	{
		Verify(!newCollisions);
		delete collisions;
		return false;
	}
	else
		newCollisions = collisions;
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::Eject (void)
{
	if (m_NeedEject == 0)
		m_NeedEject = 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::ProcessSelfDestruct()
{
	Check_Object(this);

	m_whoShotMeLast = GetReplicatorID();

	if(m_NeedEject == 0)
	{
		Eject();
		m_selfDestructTimer = gos_GetElapsedTime() + 0.3; // 2.0f;
	}

	if(gos_GetElapsedTime() >= m_selfDestructTimer)
		BaseClass::ProcessSelfDestruct();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if defined(LAB_ONLY)
	void Mech::SyncMatrices(bool update_matrix)
	{
		SYNC_LOGIC("Mech");
		BaseClass::SyncMatrices(update_matrix);
	}
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::PostCollisionExecute(Time till)
{
	Check_Object(this);
	POSTCOLLISION_LOGIC("Mech");


// MSL 5.03 Lava
	if (executionState->GetState() == ExecutionStateEngine::DrivingMotionState)
	{
		if (materialHit ==	OpenLavaMaterial)
		{
			NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();

			extern bool HeatOn(NetMissionParameters::MWNetMissionParameters& net_params); // found in HeatManager.cpp
			if (HeatOn(*params) == true)
			{
				if (gos_GetElapsedTime() - m_lastLavaTime > 0.3f)
				{
// MSL 5.06 Armor Mode
					MWApplication *m_App;
					m_App = MWApplication::GetInstance ();
					m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;

					TakeDamageMessage damage_message(
						GetReplicatorID(),
						GetReplicatorID(),
						1.0f, //damage
						m_ArmorMode,
						LavaDamageType,
						Normal3D::Up,
						Point3D::Identity,
						0.0f, //heat
						false,
						TakeDamageMessage::DefaultWeaponType);

					Receive (&damage_message);

// MSL 5.04 Lava Modified heat modifier from 1.0 to 0.5
					m_heatManager->AddHeat (0.85f);
					m_lastLavaTime = gos_GetElapsedTime();
				}
			}
		}
		else if (materialHit == CrackedLavaMaterial)
		{
			if (gos_GetElapsedTime() - m_lastLavaTime > 0.3f)
			{
// MSL 5.04 Lava Modified heat modifier from 1.0 to 0.5
				m_heatManager->AddHeat (0.85f);
				m_lastLavaTime = gos_GetElapsedTime();
			}
		}
	}

	m_eyePointManager->PostCollisionExecute(GetTimeSlice(till));

	if (m_NeedKillDropCradleEffect)
	{
		Verify (m_DropSite);
		m_NeedKillDropCradleEffect = false;
		const GameModel *model = GetGameModel();
		Effect *cradle_dead_effect;
		cradle_dead_effect = CreateEffect(model->cradleDeathEffect,m_DropSite,false);
		Check_Object(cradle_dead_effect);
		cradle_dead_effect->BecomeInteresting (true);
		cradle_dead_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
	}
	if (executionState->GetState() == ExecutionStateEngine::DroppingState)
	{
		if (m_DropCradle.GetCurrent () && m_DropSite)
		{
			LinearMatrix4D new_position;
			Verify (m_DropSite);
			new_position = m_DropSite->GetLocalToWorld();
			m_DropCradle.GetCurrent ()->SetNewLocalToParent(new_position);
			m_DropCradle.GetCurrent ()->SyncMatrices(true);
		}
		Point3D loc(GetLocalToWorld ());
		if ((m_CanStartDropJetEffect) && (leftJumpJetSite) && (!m_JumpEffect1.GetCurrent ()))
		{
			const GameModel *model = GetGameModel();
			Effect *jump_jet_effect;

			jump_jet_effect = CreateLoopingEffect(model->dropJumpEffect,leftJumpJetSite,true);
			Check_Object(jump_jet_effect);
			jump_jet_effect->BecomeInteresting (true);
			jump_jet_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
			m_JumpEffect1.Add(jump_jet_effect);
			
			jump_jet_effect = CreateLoopingEffect(model->dropJumpEffect,rightJumpJetSite,true);
			Check_Object(jump_jet_effect);
			jump_jet_effect->BecomeInteresting (true);
			jump_jet_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
			m_JumpEffect2.Add(jump_jet_effect);
		}
		else if ((m_CanStartDropJetEffect) && (!m_JumpEffect1.GetCurrent ()))
		{
			const GameModel *model = GetGameModel();
			Effect *jump_jet_effect;
			jump_jet_effect = CreateLoopingEffect(model->dropJumpEffect,m_JumpSite1,true);
			Check_Object(jump_jet_effect);
			jump_jet_effect->BecomeInteresting (true);
			jump_jet_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
			m_JumpEffect1.Add(jump_jet_effect);

			jump_jet_effect = CreateLoopingEffect(model->dropJumpEffect,m_JumpSite2,true);
			Check_Object(jump_jet_effect);
			jump_jet_effect->BecomeInteresting (true);
			jump_jet_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
			m_JumpEffect2.Add(jump_jet_effect);
			
			jump_jet_effect = CreateLoopingEffect(model->dropJumpEffect,m_JumpSite3,true);
			Check_Object(jump_jet_effect);
			jump_jet_effect->BecomeInteresting (true);
			jump_jet_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
			m_JumpEffect3.Add(jump_jet_effect);
			
			jump_jet_effect = CreateLoopingEffect(model->dropJumpEffect,m_JumpSite4,true);
			Check_Object(jump_jet_effect);
			jump_jet_effect->BecomeInteresting (true);
			jump_jet_effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
			m_JumpEffect4.Add(jump_jet_effect);
		}
	}


	if (m_NeedStartDrop)
		RealStartDropping ();


	if ((m_needSelfDestruct) )//&& (m_AI) && (m_AI->IsDerivedFrom (PlayerAI::DefaultData)))
		ProcessSelfDestruct();


	//SPEW(("jerryeds", "TEST--MECH  ---------------------------"));


	//Play Steps
	if(isLeftFootDown)
	{
		isLeftFootDown = false;
		CreateFootEffect(currentLeftFootFall, siteLeftFoot, leftFootNormal);
		if (vehicleInterface)
		{
			vehicleInterface->PlayForce (VehicleInterface::LeftFootForce);
		}
	}
	if(isRightFootDown)
	{
		isRightFootDown = false;
		CreateFootEffect(currentRightFootFall, siteRightFoot, rightFootNormal);
		if (vehicleInterface)
		{
			vehicleInterface->PlayForce (VehicleInterface::RightFootForce);
		}
	}
	const GameModel *model = GetGameModel();
	Check_Object(model);

	//Play Cage Effects if needed
	if(m_playLeftCageEffect)
	{
		if(!m_leftCageEffect.GetCurrent())
		{
			Effect *effect;
			effect = CreateCageDamageEffect(m_leftCageSite);
			if(effect)
				m_leftCageEffect.Add(effect);
		}
		m_playLeftCageEffect = false;
	}
	if(m_playRightCageEffect)
	{
		if(!m_rightCageEffect.GetCurrent())
		{
			Effect *effect;
			effect = CreateCageDamageEffect(m_rightCageSite);
			if(effect)
				m_rightCageEffect.Add(effect);
		}
		m_playRightCageEffect = false;
	}

	//Are we cooling
	if(m_heatManager->IsCooling())
	{
		if(!m_heatManager->coolantEffect.GetCurrent())
		{
			Check_Object(centerTorso);
			Effect *effect;
			effect = CreateEffect(model->coolantEffectResource, centerTorso, true);
			if(effect)
			{
				if (m_heatManager->coolantEffect.GetCurrent ())
					m_heatManager->coolantEffect.Remove ();
				m_heatManager->coolantEffect.Add(effect);
			}
		}
	}

	//Check if we are overheating
// MSL 5.02 Heat
	// Changed from .75 to .66
	if (m_heatManager->GetHeatPercentage() > 0.66)
	{
		if(!m_heatManager->overHeatEffect.GetCurrent())
		{
			Check_Object(centerTorso);
			Effect *effect;
			effect = CreateEffect(model->overHeatEffectResource, centerTorso, true);
			if(effect)
			{
				m_heatManager->overHeatEffect.Add(effect);
			}
		}
	}

// MSL 5.02 headshot	
	//This adds an overheat-like effect when a player takes a head-shot...
	//It cycles over 20 hard-coded values modified by a slight amount
	//g_HUDHeatAlpha is applied in hudcomp.cpp
	if (((Mech::dwDamageFlags & MECH_PERMANENT_OVERHEAT_FX) == MECH_PERMANENT_OVERHEAT_FX)
		&& (vehicleInterface)  ) // e.g. this 'Mech is the local 'Mech
	{
		static unsigned int HudDistortionCounter = 0;
		static int HudDistortionValues[20] = { 20,  56,  92, 125, 165, 
											  180, 160, 138, 165, 120, 
											  150, 160, 140, 120, 115,
											  120, 100,  60,  80,  50 };
		g_HUDHeatAlpha = (int) (HudDistortionValues[HudDistortionCounter++] + (Stuff::Random::GetFraction () * 100));
		if (HudDistortionCounter == 19)
			HudDistortionCounter = 0; //reset the counter
		Clamp (g_HUDHeatAlpha,0,180);
		if (!g_HUDHeatLevel) //The alpha is not applied if HUDHeatLevel is 0, and if its not 0 (meaning there is real heat) we do not want to set it to this small non-zero value
			g_HUDHeatLevel = (Scalar)0.01;
	}
	if (((Mech::dwDamageFlags & MECH_RETICULE_WASH) == MECH_RETICULE_WASH)
		&& (vehicleInterface)  ) // e.g. this 'Mech is the local 'Mech
	{
		if (!g_HUDPPCLevel)
			g_HUDPPCLevel = 10;
	}

//sanghoon
//extern bool sh_isdeathmode;
	//Are we ejecting?
	if (m_NeedEject)
	{
		Verify ((m_NeedEject == 1) || (m_NeedEject == 2) || (m_NeedEject == 3));
		if (m_NeedEject == 1)
		{
			if (!ejectEffect.GetCurrent ())
			{
				if (vehicleInterface != NULL)
					vehicleInterface->SetEjectMode();
// Changed Site location from site_eject to site_eject2
// MSL 5.00
				Adept::Site *ejectSite = FindSite("site_eject2");
				Check_Object(ejectSite);
				Effect *effect;
				effect = CreateEffect(model->ejectEffectResource, ejectSite, true);
				if(effect)
					ejectEffect.Add(effect);
			}
			m_NeedEject = 2;
			//sh_isdeathmode=true;
		}
		else if (m_NeedEject == 2)			// eject is done
		{
			if (!ejectEffect.GetCurrent ())
			{
				ReactToDestruction (InternalDamageObject::DestructionDamageMode,0);
				m_NeedEject = 3;
			}
		}
	}
	else
	{
		//sh_isdeathmode=false;
	}

	//We are moving in the water
	if(m_needWakeEffect && currentSpeedMPS)
	{
		if(!m_wakeEffect.GetCurrent())
		{
			Point3D effect_translation;
			effect_translation = GetLocalToWorld();
			Check_Object (Map::GetInstance());
			Check_Object (Map::GetInstance()->GetGameModel ());
			effect_translation.y = Map::GetInstance()->GetGameModel ()->m_waterLevel;
			Effect *effect = CreateEffect(model->m_wakeEffectResource, effect_translation);
			if(effect)
			{
				effect->BecomeInteresting (true);
				effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
				m_wakeEffect.Add(effect);
			}
		}
		else
		{
			LinearMatrix4D new_position = GetLocalToWorld();
			Check_Object (Map::GetInstance());
			Check_Object (Map::GetInstance()->GetGameModel ());
			new_position.entries[7] = Map::GetInstance()->GetGameModel ()->m_waterLevel;
			m_wakeEffect.GetCurrent()->SetNewLocalToParent(new_position);
			m_wakeEffect.GetCurrent()->SyncMatrices(true);
		}
	}
	else
	{
		if(m_wakeEffect.GetCurrent())
		{
			m_wakeEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
		}
	}
	if (triggerDeath == PowerDownDeathTrigger)
	{
		const GameModel *model = GetGameModel();
		Check_Object(model);
		

		Point3D location;
		location = animationArray[torsoAboveJointIndex]->GetLocalToWorld();
		CreateEffect(model->secondaryDestroyedEffectResource, location);

		SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);

		if (diedBySplash)
			DealSplashDamage();

		entityElement->SetAlwaysCullMode();
		//
		// Moved this to here so that we couldn't fall right through objects like
		// buildings during the death animation
		//
		SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);
		Entity *effect = CreateStaticHermitEntity(model->deathEntityResource);

		HandleSalvage();
		if(Compost::TerrainTextureLogistic::Instance)
		{
			const GameModel *model = GetGameModel();
			Check_Object(model);
			if(model->m_craterID >= 0)
			{
				Point3D local_to_world;
				local_to_world = GetLocalToWorld();
				Compost::TerrainTextureLogistic::Instance->AddFeature(
					model->m_craterID, local_to_world.x, local_to_world.z);
			}
		}

		if(GetSearchLight())
		{
	//
	// [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
	//
//			m_previousSearchLightState = GetSearchLight()->isLightOn;
//			if (IsPlayerVehicle())
//			{
//				Mission::GetInstance()->ResetMissionLights();
//			}
			GetSearchLight()->HideBeam();
			GetSearchLight()->DestroySubsystem();
		}

		if (effect != NULL)
			MWApplication::GetInstance()->AddReplicatedHermit(effect);


		// if the player isn't the local player
		//if (!IsPlayerVehicle() || GetReplicatorID().connectionID != Connection::Local->GetID())
		
		if (!IsPlayerVehicle() && !IsLanceMate())
		{	
			executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
			RemoveCollision();
		}

		// if it is not a player
		if (!IsPlayerVehicle() && !IsLanceMate())
		{
			AbstractEvent *event = m_pendingInterestMessage.GetCurrent();
			if (event)
			{
				Check_Object(event);
				delete event;
			}
			SetInterestLevel(DormantInterestLevel);
		}

		triggerDeath = DoneDeathTrigger;

		SyncMatrices(true);
		lastParameterization = till;
		initialLocalToParent = GetLocalToParent();

		if (lancemateIndex != -1 && MWApplication::GetInstance()->serverFlag)
		{
			MWApplication::GetInstance()->QueRespawnLancemate(lancemateIndex);
		}

	}
	else if (triggerDeath == FallDownDeathTrigger)
	{
		const GameModel *model = GetGameModel();
		Check_Object(model);
		
		
		Point3D location;
		location = animationArray[torsoAboveJointIndex]->GetLocalToWorld();
	//	CreateEffect(model->secondaryDestroyedEffectResource, centerTorso,true);							

		SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);

		if (diedBySplash)
			DealSplashDamage();

		entityElement->SetAlwaysCullMode();
		HandleSalvage ();

		Entity *effect = CreateStaticHermitEntity(model->secondaryDeathEntityResource);
		Point3D secondary_location;
		secondary_location = GetLocalToWorld();
		CreateEffect(model->secondaryDestroyedEffectResource, secondary_location);
		if(Compost::TerrainTextureLogistic::Instance)
		{
			const GameModel *model = GetGameModel();
			Check_Object(model);
			if(model->m_craterID >= 0)
			{
				Point3D local_to_world;
				local_to_world = GetLocalToWorld();
				Compost::TerrainTextureLogistic::Instance->AddFeature(
					model->m_craterID, local_to_world.x, local_to_world.z);
			}
		}

		if(GetSearchLight())
		{
//			if (IsPlayerVehicle())
//			{
//				Mission::GetInstance()->ResetMissionLights();
//			}
			GetSearchLight()->HideBeam();
			GetSearchLight()->DestroySubsystem();
		}

		if (effect != NULL)
			MWApplication::GetInstance()->AddReplicatedHermit(effect);

		//if (!IsPlayerVehicle() || GetReplicatorID().connectionID != Connection::Local->GetID())
		if (!IsPlayerVehicle() && !IsLanceMate())
		{
			
			executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
			RemoveCollision();

			//remove from execution will crash
		}

		// if it is not a player
		if (!IsPlayerVehicle() && !IsLanceMate())
		{
			AbstractEvent *event = m_pendingInterestMessage.GetCurrent();
			if (event)
			{
				Check_Object(event);
				delete event;
			}
			SetInterestLevel(DormantInterestLevel);
		}

		triggerDeath = DoneDeathTrigger;

		SyncMatrices(true);
		lastParameterization = till;
		initialLocalToParent = GetLocalToParent();

		if (lancemateIndex != -1 && MWApplication::GetInstance()->serverFlag)
		{
			MWApplication::GetInstance()->QueRespawnLancemate(lancemateIndex);
		}
	}
	else
	{
		lastParameterization = till;
		initialLocalToParent = GetLocalToParent();

		BaseClass::PostCollisionExecute(till);
	}


#if 0
	if (Connection::Local->GetID() == GetReplicatorID().connectionID && !MWApplication::GetInstance()->serverFlag)
	{
		Point3D position;
		position = GetElement()->GetNewLocalToParent();

		//SPEW(("jerryeds","POST-MOVEMENT : %f %f %f", position.x, position.y, position.z));
	}
#endif

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::FindGroundAngles(void)
{
	Check_Object(this);

	PRECOLLISION_LOGIC("Mech::FindGroundAngles-1");

	//
	//---------------------------------------------------
	// Look for the centerpoint of where our feet are now
	//---------------------------------------------------
	//
	const LinearMatrix4D& local_to_world = GetLocalToWorld();
	Stuff::Line3D line;
	line.m_length = 2000.0f;
	line.m_direction = Vector3D::Down;
	line.m_origin = local_to_world;
	line.m_origin.y += 1000.0f;
	Stuff::Normal3D normal;
	CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);
	Check_Object(CollisionGrid::Instance);
	
	Entity *entity_hit = CollisionGrid::Instance->ProjectLine(&query);
	m_footHitEntity = entity_hit;

	//if (!entity_hit)
	//	STOP(("Mech is off edge"));
	//else
	//{
	//	Verify(entity_hit->CanBeWalkedOn());
	//}

	materialHit = query.m_material;

	m_needWakeEffect = 0;

	Point3D tr;
	line.FindEnd(&tr);
	Check_Object (Map::GetInstance());
	Check_Object (Map::GetInstance()->GetGameModel ());
	m_WaterDelta = Map::GetInstance()->GetGameModel ()->m_waterLevel - tr.y;

	m_heatMaterialMultiplier = 1.0f;
	if ((m_WaterDelta >= ShallowWaterDepth) && (m_WaterDelta < MidWaterDepth))
	{
		materialHit = FakeShallowWaterMaterial;
		m_heatMaterialMultiplier = 1.50f;
		m_needWakeEffect = 1;
	}
	else if ((m_WaterDelta >= MidWaterDepth) && (m_WaterDelta < DeepWaterDepth))
	{
		materialHit = FakeMidWaterMaterial;
		m_heatMaterialMultiplier = 2.0f;
		m_needWakeEffect = 1;
	}
	else if (m_WaterDelta >= DeepWaterDepth)
	{
		materialHit = FakeOceanicWaterMaterial;
		m_heatMaterialMultiplier = 3.0f;
		m_needWakeEffect = 1;
	}

	if(m_needWakeEffect)
	{
		if(local_to_world.entries[7] > Map::GetInstance()->GetGameModel ()->m_waterLevel)
			m_needWakeEffect = 0;
	}

	//
	//----------------------------------------------------------------
	// Figure out the slope of the ground under the center of the mech
	//----------------------------------------------------------------
	//



	Stuff::Vector3D world_avg_normal(*query.m_normal);


	groundNormal = world_avg_normal;
	LinearMatrix4D world_to_local;
	world_to_local.Invert(local_to_world);
	m_LocalNormal.MultiplyByInverse(world_avg_normal, world_to_local);
	Stuff::Vector3D local_normal (m_LocalNormal);
	rawLocalGroundRoll = -Arctan(local_normal.x, local_normal.y);
	rawLocalGroundPitch = -Arctan(local_normal.z, local_normal.y);

	//
	//-----------------------------------------
	// Get the ground angle under the left foot
	//-----------------------------------------
	//
	Verify(siteLeftFoot != NULL);
	line.m_length = 2000.0f;
	line.m_direction = Vector3D::Down;
	line.m_origin = siteLeftFoot->GetLocalToWorld();
	line.m_origin.y += 1000.0f;

	CollisionGrid::Instance->ProjectLine(&query);
	//if (!CollisionGrid::Instance->ProjectLine(&query))
	//	STOP(("Mech foot is off edge"));
	
	


	//
	//--------------------------------------------------------
	// Store the left foot normal, height, and effect resource
	//--------------------------------------------------------
	//
	world_avg_normal += *query.m_normal;
	leftFootNormal = *query.m_normal;
	Stuff::Point3D end_point;
	line.FindEnd(&end_point);
	leftFootGround = end_point.y;
	const GameModel *model = GetGameModel();
	Check_Object(model);
	if (model->footFallEffectsTable != ResourceID::Null)
		Entity__GameModel::GetEffectResourceID(&currentLeftFootFall, model->footFallEffectsTable, materialHit);

	//
	//------------------------------------------
	// Get the ground angle under the right foot
	//------------------------------------------
	//
	Verify(siteRightFoot != NULL);
	line.m_length = 2000.0f;
	line.m_direction = Vector3D::Down;
	line.m_origin = siteRightFoot->GetLocalToWorld();
	line.m_origin.y += 1000.0f;

	CollisionGrid::Instance->ProjectLine(&query);
	//if (!CollisionGrid::Instance->ProjectLine(&query))
	//	STOP(("Mech foot is off edge"));

	

	//
	//--------------------------------------------------------
	// Store the right foot normal, height, and effect resource
	//--------------------------------------------------------
	//
	world_avg_normal += *query.m_normal;
	leftFootNormal = *query.m_normal;
	line.FindEnd(&end_point);
	leftFootGround = end_point.y;
	if (model->footFallEffectsTable != ResourceID::Null)
		Entity__GameModel::GetEffectResourceID(&currentRightFootFall, model->footFallEffectsTable, materialHit);

	//
	//--------------------------------------------------------------
	// take our normal sum and figure out the local pitch/roll angle
	//--------------------------------------------------------------
	//
	UnitVector3D temp_vec (world_avg_normal);
	m_RawGroundPitch = Arccos (temp_vec.y);				// world pitch
	m_WorldAvgNormal = temp_vec;

	local_normal.Multiply(world_avg_normal, world_to_local);
	float local_ground_roll = -Arctan(local_normal.x, local_normal.y);
	float local_ground_pitch = -Arctan(local_normal.z, local_normal.y);

	//
	//----------------------------------------------------------------------
	// clamp the values to something usable by the animation system, then
	// stick the numbers into the smoothers and set our resultant pitch/roll
	// variables from the frame smoothed averages
	//----------------------------------------------------------------------
	//
	Scalar max_value = Pi_Over_4 - Radians_Per_Degree;
	Clamp(local_ground_roll, -max_value, max_value);
	Clamp(local_ground_pitch, -max_value, max_value);
	pitchSmoother.Add(local_ground_pitch);
	rollSmoother.Add(local_ground_roll);
	localGroundPitch = pitchSmoother.CalculateAverage();
	localGroundRoll = rollSmoother.CalculateAverage();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::ComputeForwardSpeed(Stuff::Scalar time_slice)
{
	Check_Object(this);
	const GameModel *model = GetGameModel();
	Check_Object(model);
	Stuff::Scalar maxSpeedMod;
	Stuff::Scalar tonnage;
	bool slopecollide = false;

	PRECOLLISION_LOGIC("Mech::ComputeForwardSpeed");

	//
	//----------------------------------------------------
	// Set the demands to zero if the vehicle is shut down
	//----------------------------------------------------
	//
	if (vehicleShutDown)
	{
		speedDemand = 0.0f;
		speedDemandKPH = 0.0f;
	}

	maxSpeedMod = 1.0f;
	tonnage = GetTonage ();
	switch (materialHit)
	{
		case WaterMaterial:
		{
			maxSpeedMod = 0.75f;
			break;
		}
//			PAUSE (("mech walked on water or swamp material"));
		case SnowMaterial:
			maxSpeedMod = 0.95f;
			break;

		case FakeShallowWaterMaterial:
			maxSpeedMod = 0.75f;
			break;

		case FakeMidWaterMaterial:
			maxSpeedMod = 0.5f;
			break;
// MSL 5.03 Deep Water Fix
		case FakeOceanicWaterMaterial:
			maxSpeedMod = 0.25f;
			break;
	}
	switch (materialHit)
	{
		case FakeShallowWaterMaterial:
		case FakeMidWaterMaterial:
		case FakeOceanicWaterMaterial:
			if (vehicleInterface)
			{
				vehicleInterface->PlayForce (VehicleInterface::WaterMoveForce);
				vehicleInterface->ReactToEvent (VehicleInterface::STEP_WATER_START);
			}
			break;
		default:
			if (vehicleInterface)
			{
				vehicleInterface->StopForce (VehicleInterface::WaterMoveForce);
				vehicleInterface->ReactToEvent (VehicleInterface::STEP_WATER_STOP);
			}
			break;
	}
#ifdef LAB_ONLY
		if (m_DebugFast)
		{
			maxSpeedMod = 10.0f;
		}
#endif

	if (maxSpeedMod == 0.0f)				// tell the ai we had a collision based on material type
	{
		if (vehicleInterface)
			vehicleInterface->ReactToEvent (VehicleInterface::TERRAIN_BAD);
		if ((m_AI) && (m_AI->IsDerivedFrom (MoverAI::DefaultData)))
		{
			MoverAI *ai = Cast_Object(MoverAI*, m_AI);
			ai->SlopeCollide();
		}
	}
	//
	//------------------------------------------------------------------------
	// Figure out our desired speed.  If we are stopped, set the KPH variables
	// to zero and quit
	//------------------------------------------------------------------------
	//
	if (speedDemand >= 0.0f)
		speedDemandMPS = (speedDemand * GetMaxSpeed()*maxSpeedMod);
	else
		speedDemandMPS = -(speedDemand * model->maxReverseSpeed*maxSpeedMod);

	speedDemandMPS *= m_heatManager->GetSpeedMultiplier();


	if (speedDemandMPS == 0.0f && currentSpeedMPS == 0.0f)
	{
		localSpaceVelocity.linearMotion.z = 0.0f;
		speedDemandKPH = 0.0f;
		currentSpeedKPH = 0.0f;
		if ((m_LastSoundSpeedMPS != 0) && (vehicleInterface))
		{
			vehicleInterface->ReactToEvent (VehicleInterface::ENGINE_STOP);
		}
		m_LastSoundSpeedMPS = 0;
		return;
	}

	//
	//----------------------------------------------------------------------
	// Figure out the grade we are on.  If it is less than what the mech can
	// normally walk on, slow or speed up based on pitch if we are moving
	// forward.  Reverse is always at a constant speed.
	//----------------------------------------------------------------------
	//
	Scalar grade;
	Scalar cosang;
	UnitVector3D forward;
	if (speedDemandMPS < 0)
		GetLocalToWorld().GetLocalBackwardInWorld(&forward);
	else
		GetLocalToWorld().GetLocalForwardInWorld(&forward);

	cosang = (forward.x*m_WorldAvgNormal.x)+(forward.y*m_WorldAvgNormal.y)+(forward.z*m_WorldAvgNormal.z);

//	if (m_LocalNormal.z < 0)
	if (cosang < 0)				// going up the slope,	
	{
		grade = Abs (m_RawGroundPitch);
		m_RawGroundPitch = m_RawGroundPitch < 0 ? m_RawGroundPitch * -1.0f : m_RawGroundPitch;
	}
	else
	{
		grade = 0;
		m_RawGroundPitch = m_RawGroundPitch > 0 ? m_RawGroundPitch * -1.0f : m_RawGroundPitch;
	}

	Scalar decceleration = model->decceleration;
	if (m_WaterDelta > 0)
	{
		if (currentSpeedMPS > 0.0f)
		{
			Stuff::Scalar speed_effect = -0.4f;
			speed_effect *= m_WaterDelta/DeepWaterDepth;
			speedDemandMPS += speedDemandMPS * speed_effect;
		}
	}
#ifdef LAB_ONLY
	if (m_DebugFast)
	{
	}
	else
#endif
	if (grade <= startSlopeDeceleration)
	{
		if (currentSpeedMPS > 0.0f)
		{
			Stuff::Scalar speed_effect = (m_RawGroundPitch >= 0.0f) ? -0.4f : -0.3f;
			speed_effect *= m_RawGroundPitch/startSlopeDeceleration;
			speedDemandMPS += speedDemandMPS * speed_effect;
		}
	}

	//
	//-----------------------------------------------------------------------
	// The slope is higher than we can tolerate, so we will have to slow down
	// very quickly to zero
	//------------------------------------------------------------------------
	//
	else if (m_RawGroundPitch > 0.0f)
	{
		slopecollide = true;
		speedDemandMPS = 0.0f;

		//
		//------------------------------------------------
		// If the grade is high enough, treat it as a wall
		//------------------------------------------------
		//
		if (grade >= maxSlope)
		{
			if (vehicleInterface)
				vehicleInterface->ReactToEvent (VehicleInterface::HILL_TOO_STEEP);
			decceleration = model->slopeDecel3;
			if ((m_AI) && (m_AI->IsDerivedFrom (MoverAI::DefaultData)))
			{
				MoverAI *ai = Cast_Object(MoverAI*, m_AI);
				ai->SlopeCollide();
			}
		}

		//
		//----------------------------------------------------------
		// Pick the amount of deceleration to use based on the slope
		//----------------------------------------------------------
		//
		else
		{
			if ((m_AI) && (m_AI->IsDerivedFrom (MoverAI::DefaultData)))				// the models will quickly slow	to zero.  mech should not be going up this slope
			{
				MoverAI *ai = Cast_Object(MoverAI*, m_AI);
				ai->SlopeCollide();
			}
			Verify(startSlopeDeceleration <= (Pi_Over_4+Pi_Over_8));
			Scalar band_size = (maxSlope - startSlopeDeceleration)/3.0f;
			Scalar grade_band_one = startSlopeDeceleration + band_size;

			if (grade < grade_band_one)
				decceleration = model->slopeDecel1;
			else
			{
				Scalar grade_band_two = grade_band_one + band_size;
				decceleration =
					(grade < grade_band_two) ? model->slopeDecel2 : model->slopeDecel3;
			}
		}
	}

	//
	//--------------------------------------------
	// Anything can go down - ain't gravity great?
	//--------------------------------------------
	//
	else
	{
		Stuff::Scalar adjust_pitch = -localGroundPitch;
		Max_Clamp(adjust_pitch, Pi_Over_4);
		Stuff::Scalar speed_effect = 0.3f * adjust_pitch / Pi_Over_4;
		speedDemandMPS += speedDemandMPS * speed_effect;
	}

	//
	//----------------------------
	// If we are gimped, slow down
	//----------------------------
	//
	if (gimpState != NotGimpedMode)
	{
		Max_Clamp(speedDemandMPS, model->maxGimpSpeed);
		Min_Clamp(speedDemandMPS,0);
	}

	//
	//--------------------------------------------------------------------
	// If we are not going backwards, find out what speed we want after we
	// consider braking
	//--------------------------------------------------------------------
	//
	if (currentSpeedMPS >= 0.0f)
	{
		Stuff::Scalar decel_speed = currentSpeedMPS - (decceleration * time_slice);


		//
		//-----------------------------------------------------------------
		// If we want to move slower than our minimum speed and we want to
		// decelerate to a stand, set our current speed to be between those
		// two bounds
		//-----------------------------------------------------------------
		//
		if (m_ForceSpeed)
		{
			currentSpeedMPS = m_ForceSpeedValue;
			m_ForceSpeed = false;
		}
		else if ((currentSpeedMPS == 0) && (speedDemandMPS < 0))
		{
			currentSpeedMPS = model->minReverseSpeed;
		}
		else if ((currentSpeedMPS == 0) && (speedDemandMPS > 0))
		{
			currentSpeedMPS = model->minSpeed;
		}
		else if (speedDemandMPS <= model->minSpeed && decel_speed <= model->minStandTransitionSpeed)
			Clamp(currentSpeedMPS, model->minSpeed, model->minStandTransitionSpeed);

		//
		//--------------------------------------
		// Otherwise, adjust our speed as needed
		//--------------------------------------
		//
		else if (speedDemandMPS > currentSpeedMPS)
		{
#ifdef LAB_ONLY
			if (m_DebugFast)
				currentSpeedMPS = speedDemandMPS;
			else
#endif
			currentSpeedMPS += (model->acceleration * time_slice);
			Max_Clamp(currentSpeedMPS, speedDemandMPS);
		}
		else if (speedDemandMPS < currentSpeedMPS)
		{
#ifdef LAB_ONLY
			if (m_DebugFast)
				currentSpeedMPS = speedDemandMPS;
			else
#endif
			currentSpeedMPS -= (decceleration * time_slice);
			Min_Clamp(currentSpeedMPS, speedDemandMPS);
		}
	}

	//
	//--------------------------------------------------------------
	// We are backing up, so tell the AI if we had a grade collision
	//--------------------------------------------------------------
	//
	else
	{
		Stuff::Scalar decel_spped = currentSpeedMPS + (model->reverseDeccelerationMultiplier * time_slice);

		//
		//-------------------------------------------------------------
		// Deal with the stand transition if that is the case we are in
		//-------------------------------------------------------------
		//
		if (speedDemandMPS >= model->minReverseSpeed && decel_spped >= -model->minStandTransitionSpeed)
			Clamp(currentSpeedMPS, -model->minStandTransitionSpeed, model->minReverseSpeed);


		//
		//-------------------------------------
		// Otherwise adjust our speed as needed
		//-------------------------------------
		//
		else if (speedDemandMPS < currentSpeedMPS)
		{
			currentSpeedMPS -= (model->acceleration * model->reverseAccelerationMultiplier * time_slice);
			Min_Clamp(currentSpeedMPS, speedDemandMPS);
		}
		else if (speedDemandMPS > currentSpeedMPS)
		{
			currentSpeedMPS += (decceleration * model->reverseDeccelerationMultiplier * time_slice);
			Max_Clamp(currentSpeedMPS, speedDemandMPS);
		}
	}

	//
	//----------------------------------------------------
	// Now adjust all this to the limits in the model file
	//----------------------------------------------------
	//
	Clamp(currentSpeedMPS, model->maxReverseSpeed*maxSpeedMod, GetMaxSpeed()*maxSpeedMod);
	localSpaceVelocity.linearMotion.z = currentSpeedMPS;

	//
	//----------------------
	// Set the KPH variables
	//----------------------
	//
	currentSpeedKPH = currentSpeedMPS * 3.6f;
	speedDemandKPH = speedDemandMPS * 3.6f;
	if ((m_LastSoundSpeedMPS == 0) && (currentSpeedMPS != 0) && (vehicleInterface))
	{
		if (currentSpeedMPS < 0)
			vehicleInterface->ReactToEvent (VehicleInterface::ENGINE_REVERSE);
		else
			vehicleInterface->ReactToEvent (VehicleInterface::ENGINE_WALK);
	}
	else if ((m_LastSoundSpeedMPS > 0) && (currentSpeedMPS < 0) && (vehicleInterface))
	{
		vehicleInterface->ReactToEvent (VehicleInterface::ENGINE_REVERSE);
	}
	else if ((m_LastSoundSpeedMPS < WALK_SPEED_SOUND) && (currentSpeedMPS >= WALK_SPEED_SOUND) && (vehicleInterface))
	{
		vehicleInterface->ReactToEvent (VehicleInterface::ENGINE_RUN);
	}
	else if ((m_LastSoundSpeedMPS != 0) && (currentSpeedMPS == 0) && (vehicleInterface))
	{
		vehicleInterface->ReactToEvent (VehicleInterface::ENGINE_STOP);
	}
	m_LastSoundSpeedMPS = currentSpeedMPS;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::TiltMech(Stuff::Scalar time_slice)
{
	Check_Object(this);

	PRECOLLISION_LOGIC("Mech::TiltMech");


	//
	//----------------------------------------------
	// Figure out the area of mech motion we tilt in
	//----------------------------------------------
	//
	const GameModel *model = GetGameModel();
	tiltRequest = 0.0f;
	Scalar temp = GetTurnSpeed();
	Scalar tilt_tan = currentSpeedMPS * yawDemand * temp;
	tiltRequest = Arctan(tilt_tan, g_Gravity) * model->tiltDegree / Pi_Over_2;

	//
	//----------------------------------------
	// Smooth the motion of the tilt angle out
	//----------------------------------------
	//
	if (tiltAngle < tiltRequest)
	{
		tiltAngle += (model->tiltSpeed*time_slice);
		Max_Clamp(tiltAngle, tiltRequest);
	}
	else if (tiltAngle > tiltRequest)
	{
		tiltAngle -= (model->tiltSpeed*time_slice);
		Min_Clamp(tiltAngle, tiltRequest);
	}
	if (internalViewPoint)
		tiltAngle *= model->scaleInternalTiltDegree;

	//
	//------------------------------------------------------------------------
	// Apply the extra tilt to the ground to make the mech appear to lean over
	//------------------------------------------------------------------------
	//
	localGroundRoll += tiltAngle;

	//
	//-----------------------------------
	// Add any damage rotation from a hit
	//-----------------------------------
	//


	localGroundPitch += rootHit.GetCurrentPosition().pitch;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::MaintainWalkingAnimStates(bool run_minimal)
{
	PRECOLLISION_LOGIC("Mech::MaintainAnimStates");



	const GameModel *model = GetGameModel();

	if (!animStateEngine->IsTransitioning())
	{
		if (queFallState != NoFallMode)
		{
			switch(queFallState)
			{
			case FallBackMode:
				animStateEngine->RequestState(MechAnimationStateEngine::FallBackwardState, run_minimal);
				break;

			case FallRightMode:
				animStateEngine->RequestState(MechAnimationStateEngine::FallRightState, run_minimal);
				break;

			case FallLeftMode:
				animStateEngine->RequestState(MechAnimationStateEngine::FallLeftState, run_minimal);
				break;

			case FallForwardMode:
				animStateEngine->RequestState(MechAnimationStateEngine::FallForwardState, run_minimal);
				break;

				
			}	
			StartFall();
			fallDirection = queFallState;
//			queFallState = NoFallMode;
			return;
		}
		else if (gimpState == LeftGimpMode)
		{
			if (animStateEngine->GetState() == MechAnimationStateEngine::ForwardState)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::GimpForwardLeftState, run_minimal);
			}
			
		}
		else if (gimpState == RightGimpMode)
		{
			if (animStateEngine->GetState() == MechAnimationStateEngine::ForwardState)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::GimpForwardRightState, run_minimal);
			}
			
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::FallForwardState)
		{
			localSpaceVelocity.linearMotion = Vector3D::Identity;
			worldSpaceVelocity.linearMotion = Vector3D::Identity;
			if (!IsDestroyed())
			{
				animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::FallBackwardState)
		{
			localSpaceVelocity.linearMotion = Vector3D::Identity;
			worldSpaceVelocity.linearMotion = Vector3D::Identity;
			if (!IsDestroyed())
			{
				animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::FallLeftState)
		{
			localSpaceVelocity.linearMotion = Vector3D::Identity;
			worldSpaceVelocity.linearMotion = Vector3D::Identity;
			if (!IsDestroyed())
			{
				animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::FallRightState)
		{
			localSpaceVelocity.linearMotion = Vector3D::Identity;
			worldSpaceVelocity.linearMotion = Vector3D::Identity;
			if (!IsDestroyed())
			{
				animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
			}
		}
			
			

		
		if (animStateEngine->GetState() == MechAnimationStateEngine::FlyState)
		{
			if (executionState->GetState() == ExecutionStateEngine::DrivingMotionState)
			{
				if (currentSpeedMPS <= 0.0f)
					animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
				else
					animStateEngine->RequestState(MechAnimationStateEngine::ForwardState, run_minimal);
			}

		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::ForwardState)
		{

			m_eyePointManager->Stabalize(1.0f);

			if (currentSpeedMPS <= model->minStandTransitionSpeed && speedDemandMPS <= model->minSpeed)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
				lastSpeedMPS = currentSpeedMPS;
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::BackwardState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (currentSpeedMPS >= -model->minStandTransitionSpeed && speedDemandMPS >= model->minReverseSpeed)
			{
			
				animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
				lastSpeedMPS = currentSpeedMPS;			
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::StandState)
		{

			m_eyePointManager->Stabalize(1.0f);

			if (vehicleShutDown)
			{
// MSL 5.03 Cockpit Follow
				m_eyePointManager->Follow(0.0f);
				animStateEngine->RequestState(MechAnimationStateEngine::PowerDownState,run_minimal);
				if (vehicleInterface)
					vehicleInterface->EndEngineIdle ();
			}
			else if (speedDemandMPS < model->minReverseSpeed)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::BackwardState,run_minimal);
			}
			else if (speedDemandMPS > model->minSpeed)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::ForwardState,run_minimal);
			}
			else if (yawDemand < 0.0f && speedDemandMPS == 0.0f)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::TurnLeftState,run_minimal);
			}
			else if (yawDemand > 0.0f && speedDemandMPS == 0.0f)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::TurnRightState,run_minimal);
			}
			else
			{
				currentSpeedMPS = 0.0f;
			}

		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::GimpStandLeftState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (speedDemandMPS > model->minSpeed)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::GimpForwardLeftState,run_minimal);
			}
			else if (yawDemand < 0.0f && speedDemandMPS == 0.0f)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::LGimpTurnLeftState,run_minimal);
			}
			else if (yawDemand > 0.0f && speedDemandMPS == 0.0f)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::LGimpTurnRightState,run_minimal);
			}
			else
			{
				currentSpeedMPS = 0.0f;
			}
	
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::GimpStandRightState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (speedDemandMPS > model->minSpeed)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::GimpForwardRightState,run_minimal);
			}
			else if (yawDemand < 0.0 && speedDemandMPS == 0.0f)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::RGimpTurnLeftState,run_minimal);
			}
			else if (yawDemand > 0.0f && speedDemandMPS == 0.0f)
			{
				currentSpeedMPS = 0.0f;
				animStateEngine->RequestState(MechAnimationStateEngine::RGimpTurnRightState,run_minimal);
			}
			else
			{
				currentSpeedMPS = 0.0f;
			}
	
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::GimpForwardLeftState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (currentSpeedMPS <= model->minStandTransitionSpeed && speedDemandMPS <= model->minSpeed)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::GimpStandLeftState,run_minimal);
				lastSpeedMPS = currentSpeedMPS;

			}

		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::GimpForwardRightState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (currentSpeedMPS <= model->minStandTransitionSpeed && speedDemandMPS <= model->minSpeed)
			{
				animStateEngine->RequestState(MechAnimationStateEngine::GimpStandRightState,run_minimal);
				lastSpeedMPS = currentSpeedMPS;
				
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::TurnRightState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (animStateEngine->CurrentStateLoopedThisFrame())
			{
				if (yawDemand == 0.0f || speedDemand != 0.0f)
				{
					animStateEngine->RequestState(MechAnimationStateEngine::StandState,run_minimal);
				}
				else
				{
					animStateEngine->RequestState(MechAnimationStateEngine::TurnLeftState,run_minimal);
				}
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::TurnLeftState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (animStateEngine->CurrentStateLoopedThisFrame())
			{
				if (yawDemand == 0.0f || speedDemand != 0.0f)
				{
					animStateEngine->RequestState(MechAnimationStateEngine::StandState,run_minimal);
				}
				else
				{
					animStateEngine->RequestState(MechAnimationStateEngine::TurnRightState,run_minimal);
				}
			}
		}


		else if (animStateEngine->GetState() == MechAnimationStateEngine::LGimpTurnRightState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (animStateEngine->CurrentStateLoopedThisFrame())
			{
				if (yawDemand == 0.0f || speedDemand != 0.0f)
				{
					animStateEngine->RequestState(MechAnimationStateEngine::GimpStandLeftState,run_minimal);
				}
				else
				{
					animStateEngine->RequestState(MechAnimationStateEngine::LGimpTurnLeftState,run_minimal);
				}
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::LGimpTurnLeftState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (animStateEngine->CurrentStateLoopedThisFrame())
			{
				if (yawDemand == 0.0f || speedDemand != 0.0f)
				{
					animStateEngine->RequestState(MechAnimationStateEngine::GimpStandLeftState,run_minimal);
				}
				else
				{
					animStateEngine->RequestState(MechAnimationStateEngine::LGimpTurnRightState,run_minimal);
				}
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::RGimpTurnRightState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (animStateEngine->CurrentStateLoopedThisFrame())
			{
				if (yawDemand == 0.0f || speedDemand != 0.0f)
				{
					animStateEngine->RequestState(MechAnimationStateEngine::GimpStandRightState,run_minimal);
				}
				else
				{
					animStateEngine->RequestState(MechAnimationStateEngine::RGimpTurnLeftState,run_minimal);
				}
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::RGimpTurnLeftState)
		{
			m_eyePointManager->Stabalize(1.0f);

			if (animStateEngine->CurrentStateLoopedThisFrame())
			{
				if (yawDemand == 0.0f || speedDemand != 0.0f)
				{
					animStateEngine->RequestState(MechAnimationStateEngine::GimpStandRightState,run_minimal);
				}
				else
				{
					animStateEngine->RequestState(MechAnimationStateEngine::RGimpTurnRightState,run_minimal);
				}
			}
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::PowerDownState)
		{
			if (currentSpeedMPS != speedDemandMPS)
			{
				m_LastSoundSpeedMPS = speedDemandMPS;
				currentSpeedMPS = speedDemandMPS;
			}

			if (triggerDeath == NoDeathTrigger && IsDestroyed())
			{
				
				triggerDeath = PowerDownDeathTrigger;
			}
			else
			{
				if (!vehicleShutDown)
				{
					if (vehicleInterface)
						vehicleInterface->StartEngineIdle ();
					animStateEngine->RequestState(MechAnimationStateEngine::StandState, run_minimal);
				}
			}
		}

	}
	else
	{
		
		//we are in a transition...
		if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::ForwardState)
		{
			Min_Clamp(currentSpeedMPS, model->minSpeed);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::BackwardState)
		{
			Max_Clamp(currentSpeedMPS, model->minReverseSpeed);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::GimpForwardRightState)
		{
			Min_Clamp(currentSpeedMPS, model->minSpeed);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::GimpForwardLeftState)
		{
			Min_Clamp(currentSpeedMPS, model->minSpeed);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::FlyState)
		{
			//Min_Clamp(currentSpeedMPS, model->minSpeed);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::StandState)
		{
			//Min_Clamp(currentSpeedMPS, lastSpeedMPS);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::StandHalfState)
		{
			//Min_Clamp(currentSpeedMPS, lastSpeedMPS);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::GimpStandRightState)
		{
			//Min_Clamp(currentSpeedMPS, lastSpeedMPS);
		}
		else if (animStateEngine->GetTransitionState() == MechAnimationStateEngine::GimpStandLeftState)
		{
			//Min_Clamp(currentSpeedMPS, lastSpeedMPS);
		}

		// if we are falling add some slide
		// etc etc..
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::MovementSimulation(
		Scalar time_slice,
		Stuff::Vector3D &new_velocity,
		Stuff::Vector3D &instantanious_angular_velocity
	)
{
	Check_Object(this);	
	Verify(time_slice > 0.0f);
	
	PRECOLLISION_LOGIC("Mech::MovementSim");



	bool networking = MWApplication::GetInstance()->networkingFlag;
			

	//
	//-------------------------------------
	// Find the position we are standing on
	//-------------------------------------
	//
	const Stuff::LinearMatrix4D &mech_to_world = GetLocalToWorld();
	Stuff::LinearMatrix4D axis_to_world(Stuff::LinearMatrix4D::Identity);
	if (leftFootDown && !rightFootDown && !networking)
	{
		const LinearMatrix4D &matrix = siteLeftFoot->GetLocalToWorld();
		axis_to_world(3,0) = matrix(3,0);
		axis_to_world(3,1) = matrix(3,1);
		axis_to_world(3,2) = matrix(3,2);
	}
	else if (!leftFootDown && rightFootDown && !networking)
	{
		const LinearMatrix4D &matrix = siteRightFoot->GetLocalToWorld();
		axis_to_world(3,0) = matrix(3,0);
		axis_to_world(3,1) = matrix(3,1);
		axis_to_world(3,2) = matrix(3,2);
	}
	else
	{
		axis_to_world(3,0) = mech_to_world(3,0);
		axis_to_world(3,1) = mech_to_world(3,1);
		axis_to_world(3,2) = mech_to_world(3,2);
	}

	//
	//-----------------------------------------------------------------------
	// add in the yaw, pitch, and roll demands from the interface & animation
	//-----------------------------------------------------------------------
	//
	YawPitchRoll mech_rotation_local_to_world(mech_to_world);
	Scalar temp = GetTurnSpeed();
	temp *= time_slice;
	YawPitchRoll rotation_step;
	rotation_step.yaw   = yawDemand   * temp;
	rotation_step.pitch = pitchDemand * temp;
	rotation_step.roll  = rollDemand  * temp;

	//
	//-----------------------------------------------------------------------
	// if either foot is locked, accumulate the rotation for counter steering
	//-----------------------------------------------------------------------
	//
	if (rightFootState == FootLocked)
		rightFootTurnAccumulation += rotation_step.yaw;
	if (leftFootState == FootLocked)
		leftFootTurnAccumulation += rotation_step.yaw;

	//
	//-------------------------------------------------------------
	// Compute the acceleration on the mech and move it accordingly
	//-------------------------------------------------------------
	//
	Point3D mech_in_world(mech_to_world);
	JumpJet *jump_jet = GetJumpJet();
	if (!jump_jet || jump_jet->executionState->GetState() != JumpJet::ExecutionStateEngine::JumpingState)
		Max_Clamp(localSpaceVelocity.linearMotion.y, 0.0f);
	else
		Max_Clamp(localSpaceVelocity.linearMotion.y, 30.0f);
	new_velocity.y = localSpaceVelocity.linearMotion.y + 0.5f*localSpaceAcceleration.linearMotion.y*time_slice*Special_Mech_Gravity;
	Vector3D adj;
	adj.Multiply(new_velocity, mech_to_world);
	adj *= time_slice;
	mech_in_world += adj;
	localSpaceVelocity.linearMotion.y += localSpaceAcceleration.linearMotion.y*time_slice*Special_Mech_Gravity;

	//
	//------------------------------------------------
	// Find the correct axis to rotate the mech around
	//------------------------------------------------
	//
	Point3D mech_in_axis;
	mech_in_axis.MultiplyByInverse(mech_in_world, axis_to_world);
	LinearMatrix4D rotation_matrix(true);
	rotation_matrix.BuildRotation(rotation_step);
	Point3D mech_in_axle;
	mech_in_axle.Multiply(mech_in_axis, rotation_matrix);
	mech_in_world.Multiply(mech_in_axle, axis_to_world);
	if (m_ForceYaw)
	{
		mech_rotation_local_to_world.yaw = m_ForceYawValue;
		m_ForceYaw = false;
	}
	else
	{
		mech_rotation_local_to_world.yaw += rotation_step.yaw;
	}
	mech_rotation_local_to_world.pitch += rotation_step.pitch;
	mech_rotation_local_to_world.roll += rotation_step.roll;


	//------------------------------------
	// add in the network dead reckon adjustments...
	//------------------------------------

	YawPitchRoll correction_angle;
	Point3D correction_position;
	


	//GetNetworkAdjustment(time_slice, correction_position, correction_angle);
	//mech_rotation_local_to_world.yaw += correction_angle.yaw;
	//mech_in_world.Add(mech_in_world, correction_position);


	if (GetNetworkAdjustment(time_slice, correction_position, correction_angle))
	{

		mech_rotation_local_to_world = correction_angle;
		mech_in_world = correction_position;
	}



	//
	//----------------------
	// Test our new location
	//----------------------
	//
	
	Stuff::Line3D line;
	
	//regular...
	if ((GetReplicatorMode () == ClientMasterMode) || (GetReplicatorMode () == MasterMode))
	{
		line.m_length = (Ground_Mode==0) ? 40.0f : (m_groundRaycastHeight + 0.0001f);
	}
	else
	{
		line.m_length = 40.0f;
	}


	line.m_direction = Vector3D::Down;
	line.m_origin = mech_in_world;
	line.m_origin.y += m_groundRaycastHeight;
	Stuff::Normal3D normal;
	CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);
	Check_Object(CollisionGrid::Instance);

	//
	//----------------------------------------------------------------------
	// If we don't hit the ground, and neither foot is marked to hit the
	// ground, we will need to see where we will be after the jump transition
	// occurs
	//----------------------------------------------------------------------
	//

	LinearMatrix4D new_local_to_world;
	new_local_to_world.BuildRotation(mech_rotation_local_to_world);

	

	if (!CollisionGrid::Instance->ProjectLine(&query))
	{
		
		if ((GetReplicatorMode () == ClientMasterMode) || (GetReplicatorMode () == MasterMode))
		{
			if (Ground_Mode==2 && !(isLeftFootDown || isRightFootDown))
			{
				Point3D mech_in_world(mech_to_world);
				Scalar t = time_slice + 0.8f;
				Vector3D v(Vector3D::Identity);
				v.y = localSpaceVelocity.linearMotion.y + 0.5f*localSpaceAcceleration.linearMotion.y*t*Special_Mech_Gravity;
				Vector3D adj;
				adj.Multiply(v, mech_to_world);
				adj *= t;
				mech_in_world += adj;
				line.m_origin = mech_in_world;
				line.m_origin.y += m_groundRaycastHeight;
				line.m_length = m_groundRaycastHeight + 0.001f;

				//
				//-----------------------------------------------
				// If we still haven't hit anything, start flying
				//-----------------------------------------------
				//
				if (!CollisionGrid::Instance->ProjectLine(&query))
					executionState->RequestState(ExecutionStateEngine::FlyingMotionState);
			}
		}
		
		new_local_to_world.BuildTranslation(mech_in_world);


		worldSpaceVelocity.linearMotion.Multiply(
			localSpaceVelocity.linearMotion,
			new_local_to_world
		);

		//
		//-----------------------------------------------
		// Make sure we can't leave footprints in the air
		//-----------------------------------------------
		//
		isLeftFootDown = false;
		isRightFootDown = false;
	}

	//
	//--------------------------------------
	// Otherwise, just snap to that position
	//--------------------------------------
	//
	else
	{
		line.FindEnd(&mech_in_world);
		Vector3D linear_motion;
		Point3D old_position;
		old_position = mech_to_world;
		linear_motion.Subtract(mech_in_world, old_position);
		linear_motion.Divide(linear_motion, time_slice);
		if (!jump_jet || jump_jet->executionState->GetState() != JumpJet::ExecutionStateEngine::JumpingState)
			Max_Clamp(linear_motion.y, 0.0f);

		new_local_to_world.BuildTranslation(mech_in_world);
		
		worldSpaceVelocity.linearMotion = linear_motion;
		localSpaceVelocity.linearMotion.MultiplyByInverse(
			worldSpaceVelocity.linearMotion,
			new_local_to_world
		);
	}

	//
	//-----------------------------------------
	// Place the mech at the specified location
	//-----------------------------------------
	//
	SetNewLocalToParent(new_local_to_world);
}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::FallingMovementSimulation(Scalar time_slice, Stuff::Vector3D &new_velocity, Stuff::Vector3D &instantanious_angular_velocity)
{

	Check_Object(this);	
	Verify(time_slice > 0.0f);

	PRECOLLISION_LOGIC("Mech::FallingMovementSim");


	//instantanious_angular_velocity.Divide(instantanious_angular_velocity, time_slice);


	//
	// get the local to world matrix from the locator
	//
	const Stuff::LinearMatrix4D &local_to_world = GetLocalToWorld();

	//
	// make a vector of where we want to go
	//
	Vector3D point = Point3D::Identity;
	point.Multiply( new_velocity, time_slice );

	//
	// put it in local space
	//
	Vector3D adj;
	adj.Multiply(point, local_to_world);

	//
	// add the local adjustment to the current position
	//
	Point3D new_translation;
	new_translation = local_to_world;
	new_translation += adj;

	//
	// get the current yawpitchroll from the local to world matrix
	//
	YawPitchRoll new_rotation(YawPitchRoll::Identity);
	new_rotation = local_to_world;


	//
	// then add in the yaw, pitch, and roll demands from the animation
	//

	new_rotation.yaw += instantanious_angular_velocity.y * time_slice;
	new_rotation.pitch += instantanious_angular_velocity.x * time_slice;
	new_rotation.roll += instantanious_angular_velocity.z * time_slice;



	YawPitchRoll correction_angle;
	Point3D correction_position;
	
	//GetNetworkAdjustment(time_slice, correction_position, correction_angle);
	//new_rotation.yaw += correction_angle.yaw;
	//new_translation.Add(new_translation, correction_position);
	
	if (GetNetworkAdjustment(time_slice, correction_position, correction_angle))
	{

		new_rotation = correction_angle;
		new_translation = correction_position;
	}



	// Find the ground

	//
	// make a line...
	//
	Stuff::Line3D line;
	line.m_length = m_groundRaycastHeight;
	line.m_direction = Vector3D::Down;
	line.m_origin = new_translation;
	line.m_origin.y += 5.0f;  // pretty harsh hill!  =)

	//
	// Prepare query
	//	
	Stuff::Normal3D normal;
	CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);

	//
	// Cast ray
	//
	Adept::Entity *entity_hit;
	Check_Object(CollisionGrid::Instance);
	entity_hit = CollisionGrid::Instance->ProjectLine(&query);
	
	Stuff::Vector3D world_avg_normal(Stuff::Vector3D::Identity);




	if(entity_hit != NULL)
	{
		// if we hit ground, great!
		line.FindEnd(&new_translation);
		world_avg_normal = *query.m_normal;

	}
	else
	{
		// Damnit...then find the ground aggresivly!!!!
		line.m_length = 10000.0f;
		entity_hit = CollisionGrid::Instance->ProjectLine(&query);
		if (entity_hit != NULL)
		{
			line.FindEnd(&new_translation);
			world_avg_normal = *query.m_normal;
		}
		else // now try up!
		{
			line.m_direction = Vector3D(0.0f, 1.0f, 0.0f);
			entity_hit = CollisionGrid::Instance->ProjectLine(&query);
			if (entity_hit != NULL)
			{
				line.FindEnd(&new_translation);
				world_avg_normal = *query.m_normal;
			}
		}
		// ok stop we are way off the map
	}


	// figure out the ground angle...

	Stuff::Vector3D local_normal;
	local_normal.MultiplyByInverse(world_avg_normal, local_to_world);

	Stuff::Scalar local_ground_roll = 0.0f;
	Stuff::Scalar local_ground_pitch = 0.0f;

	if (local_normal.y != 0)
	{
		local_ground_roll = Arctan(local_normal.x, local_normal.y);
		local_ground_pitch = Arctan(local_normal.z, local_normal.y);
	}
	

	//
	// create a new matrix and build the translation and rotation
	//

	LinearMatrix4D new_local_to_world;
	new_local_to_world.BuildTranslation(new_translation);
	new_local_to_world.BuildRotation(new_rotation);


	//
	// set the local to parent to the new matrix created above
	//
	SetNewLocalToParent(new_local_to_world);


	if (animStateEngine->IsTransitioning())
	{
		switch (animStateEngine->GetState())
		{

			case MechAnimationStateEngine::FallForwardState:
			case MechAnimationStateEngine::FallBackwardState:
			case MechAnimationStateEngine::FallLeftState:
			case MechAnimationStateEngine::FallRightState:
			{
				if (fallTimer <= 0.0f)
				{
					// tilt the mech to adjust back..
					const GameModel *model = GetGameModel();

					YawPitchRoll rotation(YawPitchRoll::Identity);
					rotation.roll = -local_ground_roll;
					rotation.pitch = local_ground_pitch;
					UnitQuaternion ground_quaternion;
					ground_quaternion = rotation;

					if (getUpTimer > 0.0f)
					{
						// tilt the mech to adjust on the ground
						Stuff::Scalar slerp_value;
						
						// if the delay is gone...
						if (getUpTimer < model->getUpAdjustmentDelaySeconds)
						{
							slerp_value = getUpTimer / model->getUpAdjustmentSeconds;
						}
						else
						{
							slerp_value = 1.0f;
						}
						
						
						fallGround.Lerp(UnitQuaternion::Identity, ground_quaternion, slerp_value);

						getUpTimer -= time_slice;
					}
					else
					{
						fallGround = UnitQuaternion::Identity;
					}


					Point3D translation(Point3D::Identity);	
					LinearMatrix4D new_local_to_parent;
					new_local_to_parent.BuildRotation(fallGround);
					new_local_to_parent.BuildTranslation(translation);

					jointWorld->SetNewLocalToParent(new_local_to_parent);
				}
			}
			break;

			default:
			{
				const GameModel *model = GetGameModel();

				YawPitchRoll rotation(YawPitchRoll::Identity);
				rotation.roll = -local_ground_roll;
				rotation.pitch = local_ground_pitch;
				UnitQuaternion ground_quaternion;
				ground_quaternion = rotation;

				if (fallTimer > 0.0f)
				{
					// tilt the mech to adjust on the ground
					Stuff::Scalar slerp_value;
					
					// if the delay is gone...
					if (fallTimer < model->fallAdjustmentSeconds)
					{
						slerp_value = fallTimer / model->fallAdjustmentSeconds;
					}
					else
					{
						slerp_value = 1.0f;
					}
					
					
					fallGround.Lerp(ground_quaternion, initialPosition, slerp_value);
					fallGround.Normalize();

					fallTimer -= time_slice;
				}
				else
				{
					fallGround = rotation;
				}


				Point3D translation(Point3D::Identity);	
				LinearMatrix4D new_local_to_parent;
				new_local_to_parent.BuildRotation(fallGround);
				new_local_to_parent.BuildTranslation(translation);

				jointWorld->SetNewLocalToParent(new_local_to_parent);
			}
		}
	}
	

}



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

void
	Mech::StartFall(void)
{
	m_CanStartGettingUp = false;
	armsNulled = false;
	armReNullTime = 0;
	
	if (vehicleInterface)
	{
		vehicleInterface->PlayForce (VehicleInterface::FallDownForce);
	}
	GetTorso()->LookForward();
// MSL 5.03 Cockpit follow
	m_eyePointManager->Follow(0.0f);
	executionState->RequestState(ExecutionStateEngine::FallingMotionState);
	initialPosition = jointWorld->GetLocalToParent();
	initialPosition.Normalize();
	const GameModel *model = GetGameModel();
	fallTimer = model->fallAdjustmentSeconds + model->fallAdjustmentDelaySeconds;
	getUpTimer = model->getUpAdjustmentSeconds + model->getUpAdjustmentDelaySeconds;
	m_SlideTimer = gos_GetElapsedTime () + 3.0f;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::BallisticMovementSimulation(Stuff::Time till)
{
	Check_Object(this);

	PRECOLLISION_LOGIC("Mech::BallisticSim");



	//
	//----------------------------------------------------------
	// Put gravity into local space and compute our new position
	//----------------------------------------------------------
	//
	LinearDragMotionSimulation(till);
	currentSpeedMPS = localSpaceVelocity.linearMotion.z;



	Scalar time_slice = GetTimeSlice(till);

	YawPitchRoll mech_rotation(entityElement->GetNewLocalToParent());
	Scalar turn_rate = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::flying_turn_rate);
	if (turn_rate != 0.0f)
	{
		Scalar deflection = turn_rate * time_slice * yawDemand;
		SinCosPair rot(deflection);
		Scalar new_x = rot.cosine*worldSpaceVelocity.linearMotion.x + rot.sine*worldSpaceVelocity.linearMotion.z;
		Scalar new_z = rot.cosine*worldSpaceVelocity.linearMotion.z - rot.sine*worldSpaceVelocity.linearMotion.x;
		worldSpaceVelocity.linearMotion.x = new_x;
		worldSpaceVelocity.linearMotion.z = new_z;
		mech_rotation.yaw += deflection;
	}
	Point3D mech_position(entityElement->GetNewLocalToParent());

	//------------------------------------
	// add in the network dead reckon adjustments...
	//------------------------------------

	YawPitchRoll correction_angle;
	Point3D correction_position;
	
	//GetNetworkAdjustment(time_slice, correction_position, correction_angle);
	//mech_rotation.yaw += correction_angle.yaw;
	//mech_position.Add(mech_position, correction_position);
	
	if (GetNetworkAdjustment(time_slice, correction_position, correction_angle))
	{

		mech_rotation = correction_angle;
		mech_position = correction_position;
	}



	LinearMatrix4D lin_mat;
	lin_mat.BuildRotation(mech_rotation);
	lin_mat.BuildTranslation(mech_position);

	SetNewLocalToParent(lin_mat);

	//worldSpaceVelocity.linearMotion.Multiply(localSpaceVelocity.linearMotion, lin_mat);


	//
	//-------------------------------------
	// Grab the new position and cast a ray
	//-------------------------------------
	//
	LinearMatrix4D new_local_to_world = GetElement()->GetNewLocalToParent();
	Stuff::Line3D line;
	line.m_length = m_groundRaycastHeight + 0.001f;
	line.m_direction = Vector3D::Down;
	line.m_origin = new_local_to_world;
	line.m_origin.y += m_groundRaycastHeight;
	Stuff::Normal3D normal;
	CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);
	Adept::Entity *entity_hit;
	Check_Object(CollisionGrid::Instance);
	entity_hit = CollisionGrid::Instance->ProjectLine(&query);

	//
	//------------------------------------------------------------------------
	// If we have hit the ground, time to drive again, so put ourself where we
	// hit and zero out the vertical velocity
	//------------------------------------------------------------------------
	//
	if (entity_hit)
	{
		new_local_to_world(3,1) = line.m_origin.y - line.m_length;
		SetNewLocalToParent(new_local_to_world);
		localSpaceVelocity.linearMotion.y = 0.0f;
		worldSpaceVelocity.linearMotion.y = 0.0f;

		//
		//-------------------------------------
		// If we have jumpjets, tell it to stop
		//-------------------------------------
		//
		JumpJet *jump_jet = GetJumpJet();
		if (jump_jet)
		{
			Check_Object(jump_jet);
			jump_jet->RequestJumpJetsOff();
		}
		executionState->RequestState(ExecutionStateEngine::DrivingMotionState);

	}
}

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

void Mech::FindGroundAngle(const Stuff::LinearMatrix4D &local_to_world)
{
		PRECOLLISION_LOGIC("Mech::FingGroundAngle-2");

	// Get where we are...

	
	local_to_world.TestInstance();
	// put four lines into the world to collide with the ground

	Stuff::Point3D forward_point(Stuff::Point3D::Identity);

	
	// one would think I can just get the
	forward_point = local_to_world;


	Stuff::Vector3D world_avg_normal(Stuff::Vector3D::Identity);
	

	Stuff::Normal3D normal;
	Stuff::Line3D line;
	CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);

	//
	// Cast ray
	//
	Adept::Entity *entity_hit;
	Check_Object(CollisionGrid::Instance);
	
	line.m_length = 2000.0f;
	line.m_direction = Vector3D::Down;
	line.m_origin = forward_point;
	line.m_origin.y = 1000.0f;



	entity_hit = CollisionGrid::Instance->ProjectLine(&query);
	if(entity_hit != NULL)
	{
		// if we hit ground, great!
		world_avg_normal = *query.m_normal;
	}
	else
	{
		
		return;
	}



	Stuff::Vector3D local_normal;
	local_normal.MultiplyByInverse(world_avg_normal, local_to_world);

	float local_ground_roll = -Arctan(local_normal.x, local_normal.y);
	float local_ground_pitch = -Arctan(local_normal.z, local_normal.y);



		
	rawLocalGroundRoll = local_ground_roll;
	rawLocalGroundPitch = local_ground_pitch;




	Scalar max_value = Pi_Over_4 - 0.02f;
	Clamp(local_ground_roll, -max_value, max_value);
	Clamp(local_ground_pitch, -max_value, max_value);

	


	pitchSmoother.Add(local_ground_pitch);
	rollSmoother.Add(local_ground_roll);

	localGroundPitch = pitchSmoother.CalculateAverage();
	localGroundRoll = rollSmoother.CalculateAverage();


}



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

Stuff::Scalar Mech::FindMechFootPenetration(void)
{

	PRECOLLISION_LOGIC("Mech::FootPenetration");


	Verify(siteLeftFoot != NULL);
	Verify(siteRightFoot != NULL);

	Stuff::Point3D left_foot_point(Stuff::Point3D::Identity);
	Stuff::Point3D right_foot_point(Stuff::Point3D::Identity);
	
	left_foot_point = siteLeftFoot->GetLocalToWorld();
	right_foot_point = siteRightFoot->GetLocalToWorld();
	
	right_foot_point.y -= lastFramePushUp;
	left_foot_point.y -= lastFramePushUp;


	Stuff::Scalar push_up = 0.0f;


	if (leftFootGround > left_foot_point.y)
	{
		push_up = leftFootGround - left_foot_point.y;
	
	}

	if (rightFootGround >  right_foot_point.y)
	{
		if (rightFootGround - right_foot_point.y > push_up)
		{
			push_up = rightFootGround - right_foot_point.y;
		}
		
	}

	lastFramePushUp = push_up * 1.3f;

	if (debugPushupOff)
	{
		push_up = 0.0f;
	}

	return push_up;

}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::GetUpRequestRequest(void)
{
	if (animStateEngine->IsTransitioning())
	{
		return;
	}


	switch (animStateEngine->GetState())
	{
		case MechAnimationStateEngine::FallForwardState:
		case MechAnimationStateEngine::FallBackwardState:
		case MechAnimationStateEngine::FallLeftState:
		case MechAnimationStateEngine::FallRightState:
			animStateEngine->RequestState(MechAnimationStateEngine::StandState);
			break;
	}
}

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

bool Mech::ShutDownRequest(bool shutdown)
{
	if (shutdown)
	{
		if (GetAI() != 0)
		{
			GetAI()->NotifyShutdown();
		}

		vehicleShutDown = true;
		if(!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::StandState)
		{
			vehicleShutDown = true;
			return true;
		}
		else if (animStateEngine->GetState() == MechAnimationStateEngine::PowerDownState)
		{
			return true;
		}

		return true;
	}
	else
	{
		bool can_start = true;
		if (m_heatManager)
		{
			can_start = !m_heatManager->shutdown;
		}

		if(can_start)
		{
//			if(m_previousSearchLightState)
//			{
//				if (IsPlayerVehicle())
//				{
//					Mission::GetInstance()->SetSearchLightMissionLights();
//				}
//				searchLight->ShowBeam();
//			}

			if (!animStateEngine->IsTransitioning())
			{
				switch (animStateEngine->GetState())
				{
					case MechAnimationStateEngine::GimpStandRightState:
					case MechAnimationStateEngine::GimpStandLeftState:
					case MechAnimationStateEngine::PowerDownState:
					case MechAnimationStateEngine::CrouchState:
						vehicleShutDown = false;
						m_alreadyShutDown = false;
						return true;
				}
			}
			else if (animStateEngine->GetState() != MechAnimationStateEngine::PowerDownState)
			{
				return true;
			}

		
		}
	}
	return false;
}

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

void Mech::CrouchRequest(void)
{
	if(!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::StandState)
	{
		animStateEngine->RequestState(MechAnimationStateEngine::CrouchState, Mech::NoBlend);
// MSL 5.03 Cockpit Follow
		m_eyePointManager->Follow(0.0f);
	}
	else if (!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::CrouchState)
	{
		animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
	}
}

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

bool Mech::IsShutdown()
{
	return vehicleShutDown;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

bool Mech::IsCrouched()
{
	if (!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::CrouchState)
		return true;

	if (animStateEngine->IsTransitioning() && animStateEngine->GetTransitionState() == MechAnimationStateEngine::CrouchState)
		return true;

	return false;
}	

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

bool Mech::JumpRequest(void)
{
	//
	//--------------------------
	// No jumpjets == no jumping
	//--------------------------
	//
	JumpJet *jump_jet = GetJumpJet();
	if (!jump_jet)
		return false;

	//
	//-----------------------------------------------
	// Make sure the animation states are OK for this
	//-----------------------------------------------
	//

	
	switch (animStateEngine->GetState())
	{
//		case MechAnimationStateEngine::BackwardState:
		case MechAnimationStateEngine::FallForwardState:
		case MechAnimationStateEngine::FallBackwardState:
		case MechAnimationStateEngine::FallLeftState:
		case MechAnimationStateEngine::FallRightState:
		case MechAnimationStateEngine::FallCataclysmicState:
		case MechAnimationStateEngine::PowerDownState:
		case MechAnimationStateEngine::PowerDownCataclysmicState:
//		case MechAnimationStateEngine::CrouchState:
			return false;
	}

	if (executionState->GetState () == Vehicle__ExecutionStateEngine::DroppingState)
	{
		return false;
	}

	if (animStateEngine->IsTransitioning() && animStateEngine->GetTransitionState() != MechAnimationStateEngine::FlyState)
		return false;

	jump_jet->RequestJumpJetsOn();
	return true;
}	

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::EnableFallDamping(const Point3D& point)
{
	m_FallDampingLocus = point;
	m_FallDampingEnabled = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::DisableFallDamping()
{
	m_FallDampingEnabled = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::StopJumpRequest(void)
{
	JumpJet *jump_jet = GetJumpJet();
	if (jump_jet)
	{
		Check_Object(jump_jet);
		jump_jet->RequestJumpJetsOff();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::CreateJumpJetEffect()
{
	Check_Object(this);

	const GameModel *model = GetGameModel();
	Check_Object(model);
	
	if(model->dropJumpEffect != ResourceID::Null)
	{
		Resource jet_resource(model->jumpJetEffect);
		if(jet_resource.DoesResourceExist())
		{
			ClassID class_ID;
			class_ID = GetClassIDFromDataListID(model->jumpJetEffect);
			Verify(class_ID != NullClassID);

			if(leftJumpJetSite)
			{
				Check_Object(leftJumpJetSite);
				Effect::CreateMessage effect_create_message(
					sizeof(Effect::CreateMessage),
					DefaultEventPriority,
					CreateMessage::DefaultFlags,
					class_ID,
					Effect::DefaultFlags,
					model->jumpJetEffect,
					LinearMatrix4D::Identity,
					0.0f,
					ExecutionStateEngine::AlwaysExecuteState,
					NameTable::NullObjectID,
					Entity::DefaultAlignment
				);
				MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

				Entity *entity;
				ReplicatorID trail_id = Connection::Hermit->GetNextReplicatorID();
				entity = CreateEntity(&stream, &trail_id, false);
				Check_Object(entity);
				Check_Object(Map::GetInstance());
				Map::GetInstance()->AddChild(entity);
				leftJumpJetEffect = Cast_Object(Effect *, entity);
				leftJumpJetEffect->SetFollowEntity(leftJumpJetSite);
				leftJumpJetEffect->PlaceOnEntity();
				leftJumpJetEffect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
				entity->SyncMatrices(true);
			}
			if(rightJumpJetSite)
			{
				Check_Object(rightJumpJetSite);
				Effect::CreateMessage effect_create_message(
					sizeof(Effect::CreateMessage),
					DefaultEventPriority,
					CreateMessage::DefaultFlags,
					class_ID,
					Effect::DefaultFlags,
					model->jumpJetEffect,
					LinearMatrix4D::Identity,
					0.0f,
					ExecutionStateEngine::AlwaysExecuteState,
					NameTable::NullObjectID,
					Entity::DefaultAlignment
				);
				MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

				Entity *entity;
				ReplicatorID trail_id = Connection::Hermit->GetNextReplicatorID();
				entity = CreateEntity(&stream, &trail_id, false);
				Check_Object(entity);
				Check_Object(Map::GetInstance());
				Map::GetInstance()->AddChild(entity);
				rightJumpJetEffect = Cast_Object(Effect *, entity);
				rightJumpJetEffect->SetFollowEntity(rightJumpJetSite);
				leftJumpJetEffect->PlaceOnEntity();
				rightJumpJetEffect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
				entity->SyncMatrices(true);
			}
		}
	}
}

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

void
	Mech::LeftFootTriggerHandler(int trigger_value, void *pass_data)
{
	Mech *mech = Cast_Object(Mech *, pass_data);

	PRECOLLISION_LOGIC("Mech::LeftFootDown");

	


	if (trigger_value)
	{
		//SPEW(("jerryeds", "LEFT-DOWN"));

		mech->LockLeftFoot();
		mech->leftFootDown = true;
		//
		//---------------------------------------------
		//This is where we know that the foot came down
		//---------------------------------------------
		//
		mech->isLeftFootDown = true;
	}
	else
	{
		//SPEW(("jerryeds", "LEFT-UP"));

		mech->ReleaseLeftFoot();
		mech->leftFootDown = false;
	}
}

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

void
	Mech::RightFootTriggerHandler(int trigger_value, void *pass_data)
{
	Mech *mech = Cast_Object(Mech *, pass_data);

	PRECOLLISION_LOGIC("Mech::RightFootDown");

	if (trigger_value)
	{
		//SPEW(("jerryeds", "RIGHT-DOWN"));

		mech->LockRightFoot();
		mech->rightFootDown = true;
		//
		//---------------------------------------------
		//This is where we know that the foot came down
		//---------------------------------------------
		//
		mech->isRightFootDown = true;
	}
	else
	{
		//SPEW(("jerryeds", "RIGHT-UP"));

		mech->ReleaseRightFoot();
		mech->rightFootDown = false;
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::CreateFootEffect(const ResourceID& effect_id, Site *foot, const Normal3D& normal)
{
	Check_Object(this);
	Check_Object(foot);

	m_LastFootFallTime = (Stuff::Scalar)gos_GetElapsedTime();

	if(effect_id != ResourceID::Null)
	{
		Resource foot_resource(effect_id);
		if(foot_resource.DoesResourceExist())
		{
			ClassID class_ID;
			class_ID = GetClassIDFromDataListID(effect_id);
			Verify(class_ID != NullClassID);

			LinearMatrix4D effect_position = LinearMatrix4D::Identity;
			effect_position.AlignLocalAxisToWorldVector(normal, Y_Axis, X_Axis, Z_Axis);
			Point3D effect_translation;
			effect_translation = foot->GetLocalToWorld();
			effect_position.BuildTranslation(effect_translation);

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

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


			UnitVector3D mech_forward;
			GetLocalToWorld().GetLocalForwardInWorld(&mech_forward);

			effect_position.AlignLocalAxisToWorldVector(mech_forward, Z_Axis, Y_Axis, -1);

			MidLevelRenderer::MLRTexture *foot_texture = GetFootTexture(materialHit);
			if(foot_texture)
			{
				if((m_footHitEntity) && (m_footHitEntity->GetClassID() == MWMapClassID))
				{
					Check_Object(CollisionGrid::Instance);
					CollisionGrid::Instance->MakeFootStep(effect_position, 2.0f, foot_texture);
				}
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MidLevelRenderer::MLRTexture*
	Mech::GetFootTexture(int material)
{
	FootStepPlug *foot_plug = m_footSteps.Find(material);
	if(!foot_plug)
		foot_plug = m_defaultFootStep;

	if(foot_plug)
		return foot_plug->GetFootTexture();

	return NULL;
}

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

void Mech::LockLeftFoot(void)
{
	//SPEW(("jerryeds", "LOCK LEFT"));

	

	Verify(jointLeftAnkle != NULL);
	Verify(jointRightAnkle != NULL);

	if (gimpState == LeftGimpMode)
	{
		const GameModel *model = GetGameModel();
		leftFootReturnTimer = model->footReturnSeconds;
		leftFootLerpBackValue = leftFootTurnAccumulation;
		leftFootState = FootReturn;
		return;
	}


	leftFootState = FootLocked;
	leftFootTurnAccumulation = 0.0f;

}

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

void Mech::LockRightFoot(void)
{
	//SPEW(("jerryeds", "LOCK RIGHT"));


	Verify(jointLeftAnkle != NULL);
	Verify(jointRightAnkle != NULL);

	if (gimpState == RightGimpMode)
	{
		const GameModel *model = GetGameModel();
		rightFootReturnTimer = model->footReturnSeconds;
		rightFootLerpBackValue = rightFootTurnAccumulation;
		rightFootState = FootReturn;
		return;
	}


	rightFootState = FootLocked;
	rightFootTurnAccumulation = 0.0f;
}

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

void Mech::ReleaseLeftFoot(void)
{
	//SPEW(("jerryeds", "REL LEFT"));

	Verify(jointLeftAnkle != NULL);
	Verify(jointRightAnkle != NULL);
	leftFootState = FootReturn;


	const GameModel *model = GetGameModel();
	leftFootReturnTimer = model->footReturnSeconds;
	leftFootLerpBackValue = leftFootTurnAccumulation;

}

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

void Mech::ReleaseRightFoot(void)
{
	//SPEW(("jerryeds", "REL RIGHT"));

	Verify(jointLeftAnkle != NULL);
	Verify(jointRightAnkle != NULL);
	rightFootState = FootReturn;

	const GameModel *model = GetGameModel();
	rightFootReturnTimer = model->footReturnSeconds;
	rightFootLerpBackValue = rightFootTurnAccumulation;
}


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

void Mech::FootLockSimulation(Stuff::Scalar time_slice)
{
	Verify(jointLeftAnkle != NULL);
	Verify(jointRightAnkle != NULL);

	PRECOLLISION_LOGIC("Mech::FootLockSim");

	const GameModel *model = GetGameModel();

	if (rightFootState == FootLocked)
	{
		Point3D translation(Point3D::Identity);
		
		YawPitchRoll rotation(YawPitchRoll::Identity);
		rotation.yaw = -rightFootTurnAccumulation;


		//SPEW(("jerryeds", "TURN RIGHT %f ", -siteRightFootTurnAccumulation));

		LinearMatrix4D new_local_to_parent;
		new_local_to_parent.BuildRotation(rotation);
		new_local_to_parent.BuildTranslation(translation);

		jointRightAnkle->SetNewLocalToParent(new_local_to_parent);
	}
	else if (rightFootState == FootReturn)
	{
		

		Point3D translation(Point3D::Identity);
		YawPitchRoll rotation(YawPitchRoll::Identity);

		rotation.yaw.Lerp(0.0f, -rightFootLerpBackValue, rightFootReturnTimer/model->footReturnSeconds);

		//SPEW(("jerryeds", "RIGHT %f %f %f %f", 0.0f, -siteRightFootLerpBackValue,  siteRightFootReturnTimer/footReturnTime, rotation.yaw.angle));

		LinearMatrix4D new_local_to_parent;
		new_local_to_parent.BuildRotation(rotation);
		new_local_to_parent.BuildTranslation(translation);

		jointRightAnkle->SetNewLocalToParent(new_local_to_parent);

		rightFootReturnTimer -= (time_slice);
		if (rightFootReturnTimer <= 0.0f)
		{
			rightFootState = FootNormal;
		}
	}
	else
	{
		//SPEW(("jerryeds", "NORM RIGHT "));

		LinearMatrix4D new_local_to_parent(LinearMatrix4D::Identity);
		jointRightAnkle->SetNewLocalToParent(new_local_to_parent);
	}

	if (leftFootState == FootLocked)
	{
		
		
		Point3D translation(Point3D::Identity);
		YawPitchRoll rotation(YawPitchRoll::Identity);
		
		rotation.yaw = -leftFootTurnAccumulation;

		//SPEW(("jerryeds", "TURN LEFT %f ", -siteLeftFootTurnAccumulation));

		LinearMatrix4D new_local_to_parent;
		new_local_to_parent.BuildRotation(rotation);
		new_local_to_parent.BuildTranslation(translation);

		jointLeftAnkle->SetNewLocalToParent(new_local_to_parent);
	}
	else if (leftFootState == FootReturn)
	{
		
		Point3D translation(Point3D::Identity);
		YawPitchRoll rotation(YawPitchRoll::Identity);

		rotation.yaw.Lerp(0.0f, -leftFootLerpBackValue, leftFootReturnTimer/model->footReturnSeconds);

		//SPEW(("jerryeds", "LEFT %f %f %f %f", 0.0f, -siteLeftFootLerpBackValue, siteLeftFootReturnTimer/footReturnTime, rotation.yaw.angle));

		LinearMatrix4D new_local_to_parent;
		new_local_to_parent.BuildRotation(rotation);
		new_local_to_parent.BuildTranslation(translation);

		jointLeftAnkle->SetNewLocalToParent(new_local_to_parent);

		leftFootReturnTimer -= (time_slice);
		if (leftFootReturnTimer <= 0.0f)
		{
			leftFootState = FootNormal;
		}
	}
	else
	{
		//SPEW(("jerryeds", "NORM LEFT "));

		LinearMatrix4D new_local_to_parent(LinearMatrix4D::Identity);
		jointLeftAnkle->SetNewLocalToParent(new_local_to_parent);
	}


}

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

void Mech::FadeDampened()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	worldRotDampener.FadeToNewDampen(model->dampenWorldJoint, 1.0f);
	rootRotDampener.FadeToNewDampen(model->dampenRootJoint, 1.0f);
	rootTransDampener.FadeToNewDampen(model->dampenTranslationJoint, 1.0f);
	torsoRotDampener.FadeToNewDampen(model->dampenTorsoJoint, 1.0f);
	hipRotDampener.FadeToNewDampen(model->dampenHipJoint, 1.0f);
}

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

void Mech::FadeUndampened()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	worldRotDampener.FadeToNewDampen(model->undampenWorldJoint, 1.0f);
	rootRotDampener.FadeToNewDampen(model->undampenRootJoint, 1.0f);
	rootTransDampener.FadeToNewDampen(model->undampenTranslationJoint, 1.0f);
	torsoRotDampener.FadeToNewDampen(model->undampenTorsoJoint, 1.0f);
	hipRotDampener.FadeToNewDampen(model->undampenHipJoint, 1.0f);
}

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

void Mech::SetDampened()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	worldRotDampener.SetNewDampen(model->dampenWorldJoint);
	rootRotDampener.SetNewDampen(model->dampenRootJoint);
	rootTransDampener.SetNewDampen(model->dampenTranslationJoint);
	torsoRotDampener.SetNewDampen(model->dampenTorsoJoint);
	hipRotDampener.SetNewDampen(model->dampenHipJoint);
}

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

void Mech::SetUndampened()
{
	const GameModel *model = GetGameModel();
	Check_Object(model);

	worldRotDampener.SetNewDampen(model->undampenWorldJoint);
	rootRotDampener.SetNewDampen(model->undampenRootJoint);
	rootTransDampener.SetNewDampen(model->undampenTranslationJoint);
	torsoRotDampener.SetNewDampen(model->undampenTorsoJoint);
	hipRotDampener.SetNewDampen(model->undampenHipJoint);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::DampenMech(Stuff::Scalar time_slice)
{

	PRECOLLISION_LOGIC("Mech::DampenMech");

	worldRotDampener.AdvanceTime(time_slice);
	rootRotDampener.AdvanceTime(time_slice);
	rootTransDampener.AdvanceTime(time_slice);
	torsoRotDampener.AdvanceTime(time_slice);
	hipRotDampener.AdvanceTime(time_slice);


	if (internalViewPoint)
	{
		ElementRenderer::Element *element;
		Point3D old_position;
		Point3D new_position;
		UnitQuaternion joint_old_rot;
		UnitQuaternion joint_new_rot;
		LinearMatrix4D new_matrix;

		element = animationArray[worldJointIndex]->GetElement();
		Check_Object(element);
		joint_old_rot = element->GetNewLocalToParent();
		old_position = element->GetNewLocalToParent();
		
		joint_new_rot = worldRotDampener.DampenValue(initialPositions[worldJointIndex].angularPosition, joint_old_rot);
		new_matrix.BuildIdentity();
		new_matrix.BuildTranslation(old_position);
		new_matrix.BuildRotation(joint_new_rot);
		animationArray[worldJointIndex]->SetNewLocalToParent(new_matrix);

		element = animationArray[rootJointIndex]->GetElement();
		Check_Object(element);
		joint_old_rot = element->GetNewLocalToParent();
		old_position = element->GetNewLocalToParent();
		joint_new_rot = rootRotDampener.DampenValue(initialPositions[rootJointIndex].angularPosition, joint_old_rot);
		
		new_position = rootTransDampener.DampenValue(initialPositions[rootJointIndex].linearPosition, old_position);
		new_matrix.BuildIdentity();
		new_matrix.BuildTranslation(new_position);
		new_matrix.BuildRotation(joint_new_rot);
		animationArray[rootJointIndex]->SetNewLocalToParent(new_matrix);

		element = animationArray[hipJointIndex]->GetElement();
		Check_Object(element);
		joint_old_rot = element->GetNewLocalToParent();
		old_position = element->GetNewLocalToParent();
	
		joint_new_rot = hipRotDampener.DampenValue(initialPositions[hipJointIndex].angularPosition, joint_old_rot);
		new_matrix.BuildIdentity();
		new_matrix.BuildTranslation(old_position);
		new_matrix.BuildRotation(joint_new_rot);
		animationArray[hipJointIndex]->SetNewLocalToParent(new_matrix);

		element = animationArray[torsoJointIndex]->GetElement();
		Check_Object(element);
		joint_old_rot = element->GetNewLocalToParent();
		old_position = element->GetNewLocalToParent();
		
		joint_new_rot = torsoRotDampener.DampenValue(initialPositions[torsoJointIndex].angularPosition, joint_old_rot);
		new_matrix.BuildIdentity();
		new_matrix.BuildTranslation(old_position);
		new_matrix.BuildRotation(joint_new_rot);
		animationArray[torsoJointIndex]->SetNewLocalToParent(new_matrix);
	}
	

	ElementRenderer::Element *element;
	Point3D old_position;
	UnitQuaternion joint_old_rot;
	UnitQuaternion joint_new_rot;
	LinearMatrix4D new_matrix;


	if (!internalViewPoint)
	{

		Torso *torso = GetTorso();
		
		const Torso::GameModel *model = torso->GetGameModel();

		Scalar ratio;
		
		Verify(model->armRatioAngle > 0);
		ratio = Abs(torso->yawValue) / model->armRatioAngle;
		Max_Clamp(ratio, 1.0f);

		bool torso_stable = true;

		switch(animStateEngine->GetState())
		{
			case MechAnimationStateEngine::FallForwardState:
			case MechAnimationStateEngine::FallBackwardState:
			case MechAnimationStateEngine::FallLeftState:
			case MechAnimationStateEngine::FallRightState:
			case MechAnimationStateEngine::CrouchState:
			case MechAnimationStateEngine::PowerDownState:
				torso_stable = false;
				break;
		}
		if (animStateEngine->IsTransitioning())
		{
			switch(animStateEngine->GetTransitionState())
			{
				case MechAnimationStateEngine::FallForwardState:
				case MechAnimationStateEngine::FallBackwardState:
				case MechAnimationStateEngine::FallLeftState:
				case MechAnimationStateEngine::FallRightState:
				case MechAnimationStateEngine::CrouchState:
				case MechAnimationStateEngine::PowerDownState:
					torso_stable = false;
					break;
			}
		}

		if (torso_stable)
		{
			torsoBlanderizer.FadeToNewDampen(ratio, 0.1f);
		}
		else
		{
			torsoBlanderizer.FadeToNewDampen(0.0f, 0.2f);
		}


		if (!armsNulled)
		{
			armBlanderizer.FadeToNewDampen(ratio, 0.2f);
		}

		UnitQuaternion old_rotation;
		old_position = centerTorso->GetElement()->GetNewLocalToParent();	
		old_rotation = centerTorso->GetElement()->GetNewLocalToParent();

		LinearMatrix4D joint_to_world = centerTorso->GetElement()->GetLocalToWorld();	
		joint_to_world.AlignLocalAxisToWorldVector(Vector3D::Up,Y_Axis, Z_Axis, -1);
		
		LinearMatrix4D world_to_parent;
		world_to_parent.Invert(centerTorso->GetParentEntity()->GetElement()->GetLocalToWorld());

		LinearMatrix4D local_twist;
		local_twist.Multiply(joint_to_world, world_to_parent);

		UnitQuaternion stabalized_rotation;
		stabalized_rotation = local_twist;

		joint_new_rot = torsoBlanderizer.DampenValue(stabalized_rotation, old_rotation);
		
		new_matrix.BuildIdentity();
		new_matrix.BuildTranslation(old_position);
		new_matrix.BuildRotation(joint_new_rot);

		centerTorso->SetNewLocalToParent(new_matrix);
	
	}

	// nullify the arms
	armBlanderizer.AdvanceTime(time_slice);
	torsoBlanderizer.AdvanceTime(time_slice);

	element = animationArray[leftGunJointIndex]->GetElement();
	Check_Object(element);
	joint_old_rot = element->GetNewLocalToParent();
	old_position = element->GetNewLocalToParent();
		
	joint_new_rot = armBlanderizer.DampenValue(initialPositions[leftGunJointIndex].angularPosition, joint_old_rot);
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(old_position);
	new_matrix.BuildRotation(joint_new_rot);
	animationArray[leftGunJointIndex]->SetNewLocalToParent(new_matrix);


	element = animationArray[leftArmJointIndex]->GetElement();
	Check_Object(element);
	joint_old_rot = element->GetNewLocalToParent();
	old_position = element->GetNewLocalToParent();	
	joint_new_rot = armBlanderizer.DampenValue(initialPositions[leftArmJointIndex].angularPosition, joint_old_rot);
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(old_position);
	new_matrix.BuildRotation(joint_new_rot);
	animationArray[leftArmJointIndex]->SetNewLocalToParent(new_matrix);


	element = animationArray[rightGunJointIndex]->GetElement();
	Check_Object(element);
	joint_old_rot = element->GetNewLocalToParent();
	old_position = element->GetNewLocalToParent();	
	joint_new_rot = armBlanderizer.DampenValue(initialPositions[rightGunJointIndex].angularPosition, joint_old_rot);
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(old_position);
	new_matrix.BuildRotation(joint_new_rot);
	animationArray[rightGunJointIndex]->SetNewLocalToParent(new_matrix);


	element = animationArray[rightArmJointIndex]->GetElement();
	Check_Object(element);
	joint_old_rot = element->GetNewLocalToParent();
	old_position = element->GetNewLocalToParent();
	joint_new_rot = armBlanderizer.DampenValue(initialPositions[rightArmJointIndex].angularPosition, joint_old_rot);
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(old_position);
	new_matrix.BuildRotation(joint_new_rot);
	animationArray[rightArmJointIndex]->SetNewLocalToParent(new_matrix);

}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::RunSprings(Stuff::Scalar time_slice)
{
	PRECOLLISION_LOGIC("Mech::RunSprings");

	eyeSpringRotation.AdvanceTime(time_slice);

	LinearMatrix4D new_matrix;
	new_matrix = LinearMatrix4D::Identity;

	Point3D position = eyeSpringRotation.GetCurrentPosition();
	new_matrix.BuildRotation(YawPitchRoll(position.x*Stuff::Radians_Per_Degree, position.y*Stuff::Radians_Per_Degree, position.z*Stuff::Radians_Per_Degree));
	m_eyePointManager->SetSpringOffset(new_matrix);
	
	ElementRenderer::Element *element;
	UnitQuaternion rotation;
	new_matrix = LinearMatrix4D::Identity;
	YawPitchRoll ypr_rotation;

	if (executionState->GetState() != ExecutionStateEngine::FallingMotionState)
	{
		element = animationArray[worldJointIndex]->GetElement();
		Check_Object(element);
		position = element->GetNewLocalToParent();
		rootHit.AdvanceTime(time_slice);
		ypr_rotation = rootHit.GetCurrentPosition();
		ypr_rotation.roll = -tiltAngle;	
		rotation = ypr_rotation;
		new_matrix.BuildIdentity();
		new_matrix.BuildTranslation(position);
		new_matrix.BuildRotation(rotation);
		animationArray[worldJointIndex]->SetNewLocalToParent(new_matrix);
	}
	else
	{
		rootHit.Reset();
	}


	element = animationArray[torsoAboveJointIndex]->GetElement();
	Check_Object(element);
	position = element->GetNewLocalToParent();
	torsoHit.AdvanceTime(time_slice);
	rotation = torsoHit.GetCurrentPosition();
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(position);
	new_matrix.BuildRotation(rotation);
	animationArray[torsoAboveJointIndex]->SetNewLocalToParent(new_matrix);


	element = animationArray[hipAboveJointIndex]->GetElement();
	Check_Object(element);
	position = element->GetNewLocalToParent();
	hipHit.AdvanceTime(time_slice);
	rotation = hipHit.GetCurrentPosition();
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(position);
	new_matrix.BuildRotation(rotation);
	animationArray[hipAboveJointIndex]->SetNewLocalToParent(new_matrix);


#if 0
	element = animationArray[leftGunAboveJointIndex]->GetElement();
	Check_Object(element);
	position = element->GetNewLocalToParent();
	leftGunRecoil.AdvanceTime(time_slice);
	rotation = leftGunRecoil.GetCurrentPosition();
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(position);
	new_matrix.BuildRotation(rotation);
	animationArray[leftGunAboveJointIndex]->SetNewLocalToParent(new_matrix);



	element = animationArray[leftArmAboveJointIndex]->GetElement();
	Check_Object(element);
	position = element->GetNewLocalToParent();
	leftArmRecoil.AdvanceTime(time_slice);
	rotation = leftArmRecoil.GetCurrentPosition();
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(position);
	new_matrix.BuildRotation(rotation);
	animationArray[leftArmAboveJointIndex]->SetNewLocalToParent(new_matrix);



	element = animationArray[rightGunAboveJointIndex]->GetElement();
	Check_Object(element);
	UnitQuaternion quat;
	quat = element->GetNewLocalToParent();
	rightGunRecoil.AdvanceTime(time_slice);
	position = rightGunRecoil.GetCurrentPosition();
	new_matrix.BuildIdentity();
	new_matrix.BuildTranslation(position);
	new_matrix.BuildRotation(quat);	
	animationArray[rightGunAboveJointIndex]->SetNewLocalToParent(new_matrix);

#endif


}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mech::FriendlyFire(const TakeDamageMessage *message)
{
	MWApplication *app = MWApplication::GetInstance();

	if (app->serverFlag)
	{
		if (app->GetLocalNetParams()->m_friendlyFirePercentage != 100)
		{
			
			Connection *connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);
			if (connection != 0)
			{
				Check_Object(connection);

				
				Replicator* r = connection->FindReplicator(message->inflictingEntityID);
				if (r != NULL)
				{
					Entity *entity = Cast_Object(Entity*, r);
					if (entity->GetClassID() == MechClassID)
					{
						Mech *inflictor = Cast_Object(Mech*, entity);

						if (inflictor->teamNumber == teamNumber && teamNumber != MWApplication::No_Team)
						{
							//if high explosive then only damage ourselves not our friends.
							if(message->typeOfDamage == HighExplosiveDamageType)
							{
								if(inflictor == this)
									return false;
								else
									return true;
							}
							else
							{
								return true;						
							}
						}
					}
				}
			}
		}
	}

	return false;
}

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

	ChainOf<DamageObject *> effected_parts(NULL);

	PRECOLLISION_LOGIC("Mech::TakeDamage");

	switch(message->typeOfDamage)
	{
		case RammingDamageFromAboveType:
			{
                if (g_nMR != 2)
				{
					if (MWApplication::GetInstance()->networkingFlag == true)
					{
						MWMission *mission;
						Check_Object (MWMission::GetInstance());
						mission = Cast_Object (MWMission *,MWMission::GetInstance());
						mission->m_BucketManager->NotifyAction (CBucketManager::DFA,message->inflictingEntityID,1);
					}
                }

				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::HeadArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::LeftTorsoArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::RightTorsoArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::CenterTorsoArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				break;
			}
		case RammingDamageFromBelowType:
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::RightLegArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::LeftLegArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				break;
			}
		case RammingDamageFromLeftType:
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::LeftArmArmorZone);
				if(damage_object)
					effected_parts.Add(damage_object);
				else
				{
					damage_object = damageObjects.Find(DamageObject::LeftTorsoArmorZone);
					Check_Object(damage_object);
					effected_parts.Add(damage_object);
				}
				damage_object = damageObjects.Find(DamageObject::LeftLegArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				break;
			}
		case RammingDamageFromRightType:
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::RightArmArmorZone);
				if(damage_object)
					effected_parts.Add(damage_object);
				else
				{
					damage_object = damageObjects.Find(DamageObject::RightTorsoArmorZone);
					Check_Object(damage_object);
					effected_parts.Add(damage_object);
				}
				damage_object = damageObjects.Find(DamageObject::RightLegArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				break;
			}
		case RammingDamageFromAheadType:
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::CenterTorsoArmorZone);
				if(damage_object)
					effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::RightTorsoArmorZone);
				if(damage_object)
					effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::LeftTorsoArmorZone);
				if(damage_object)
					effected_parts.Add(damage_object);
				break;
			}
		case RammingDamageFromBehindType:
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::CenterRearTorsoArmorZone);
				if(damage_object)
					effected_parts.Add(damage_object);
				break;
			}
// MSL 5.03 Lava
		case LavaDamageType :
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::RightLegArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::LeftLegArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				break;
			}
// MSL 5.03 Ammo Bay Fire
		case AmmoFireDamageType :
			{
				DamageObject *damage_object;
				damage_object = damageObjects.Find(DamageObject::CenterTorsoArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::RightTorsoArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				damage_object = damageObjects.Find(DamageObject::LeftTorsoArmorZone);
				Check_Object(damage_object);
				effected_parts.Add(damage_object);
				break;
			}
	}

	DamageObject *special_zone_1 = damageObjects.Find(DamageObject::SpecialArmorZone1);
	DamageObject *special_zone_2 = damageObjects.Find(DamageObject::SpecialArmorZone2);
	DamageObject *rammed_part = NULL;
	ChainIteratorOf<DamageObject *> iterator(&effected_parts);
	if(effected_parts.GetSize() > 0)
	{
		Scalar damage_ammount = message->amountOfDamage / effected_parts.GetSize();
		TakeDamageMessage *damage_message = (TakeDamageMessage *)message;
		damage_message->amountOfDamage = damage_ammount;
		while((rammed_part = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(rammed_part);
			rammed_part->TakeDamage(damage_message, NULL);
			if(special_zone_1)
			{
				Check_Object(special_zone_1);
				if(special_zone_1->m_specialConnectedToZone == rammed_part->armorZone)
				{
					special_zone_1->TakeDamage(damage_message, NULL);
				}
			}
			if(special_zone_2)
			{
				Check_Object(special_zone_2);
				if(special_zone_2->m_specialConnectedToZone == rammed_part->armorZone)
				{
					special_zone_2->TakeDamage(damage_message, NULL);
				}
			}
		}
	}
}

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

	if (IsDestroyed())
		return;

    if (g_nMR == 2) {
    	BaseClass::ReactToHit(message,part_hit);
        return;
    }
	Replicator* r = NULL;
	Connection *connection = NULL;

	if (IsPlayerVehicle ())
	{
		Connection *mechconn = Network::GetInstance ()->GetConnection (GetReplicatorID ().connectionID);
		if (mechconn == Connection::Local)
		{
			connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);
	
			if (connection != NULL)
			{
				r = connection->FindReplicator(message->inflictingEntityID);
				if (r != 0)
				{
					Verify(r->IsDerivedFrom(Entity::DefaultData));
					Entity* e = Cast_Object(Entity*,r);
					MWGUIManager *gui = MWGUIManager::GetInstance ();
					GUIRadarManager *radar;
					radar = Cast_Object (GUIRadarManager *,gui->Component (MWGUIManager::HUD_RADAR));
					Verify (radar);
					radar->AddShot (e->objectID);
					HUDMap *map;
					map = Cast_Object (HUDMap *,gui->Component (MWGUIManager::HUD_MAP));
					map->AddShot (e->objectID);
				}
			}
		}
	}

	takenDamageThisFrame = true;
	lastDamageTaken = (Scalar)gos_GetElapsedTime();

#if !defined(NO_MR)
	if(MWApplication::GetInstance()->serverFlag && IsPlayerVehicle())
	{
		MWApplication *app = MWApplication::GetInstance();

		app->SetMissionReviewTakeDamage(GetReplicatorID().connectionID);
	}
#endif // !defined(NO_MR)


	BaseClass::ReactToHit(message,part_hit);
	if (vehicleInterface)
	{
		switch (message->weaponID)
		{
		case W_ClanERPPC:
		case W_ERPPC:
		case W_PPC:
			vehicleInterface->ReactToEvent (VehicleInterface::INTERNAL_PPC_WASH, message->weaponID);
			break;
		}
	}

	if(message->amountOfHeat > 0.0f)
	{
		Check_Object(m_heatManager);
		m_heatManager->AddHeat(message->amountOfHeat);
	}


	//------------ always play - only on local ----------------
	// spin the mech
	// spin the torso

	//------------ external play - everyone ----------------
	// hit the root joint
	// hit the torso joint
	// hit the hip joint

	//------------ internal play - only on local ----------------
	// hit the eye joint

	
	const GameModel *model = GetGameModel();
	Check_Object(model);
	
	Scalar internal_damage_scale = 1.0f;
	Scalar external_damage_scale = 1.0f;
	Scalar internal_spin_damage_scale = 1.0f;

	Scalar spin_force = 0.0f;
	switch(message->typeOfDamage)
	{
	case BeamDamageType:
		internal_damage_scale = model->internalHitScaleBeamDamage;
		external_damage_scale = model->externalHitScaleBeamDamage;
		internal_spin_damage_scale = model->internalSpinHitScaleBeamDamage;
		spin_force = model->spinForceBeamDamage;
		break;

	case MissileDamageType:
		internal_damage_scale = model->internalHitScaleMissileDamage;
		external_damage_scale = model->externalHitScaleMissileDamage;
		internal_spin_damage_scale = model->internalSpinHitScaleMissileDamage;
		spin_force = model->spinForceMissileDamage;
		break;

	case ProjectileDamageType:
		internal_damage_scale = model->internalHitScaleProjectileDamage;
		external_damage_scale = model->externalHitScaleProjectileDamage;
		internal_spin_damage_scale = model->internalSpinHitScaleProjectileDamage;
		spin_force = model->spinForceProjectileDamage;
		break;

	case SplashDamageType:
		internal_damage_scale = model->internalHitScaleSplashDamage;
		external_damage_scale = model->externalHitScaleSplashDamage;
		internal_spin_damage_scale = model->internalSpinHitScaleSplashDamage;
		spin_force = model->spinForceSplashDamage;
		break;

	case HeatDamageType:
		internal_damage_scale = model->internalHitScaleHeatDamage;
		external_damage_scale = model->externalHitScaleHeatDamage;
		internal_spin_damage_scale = model->internalSpinHitScaleHeatDamage;
		spin_force = model->spinForceHeatDamage;
		break;

	case AmmoFireDamageType:
		internal_damage_scale = model->internalHitScaleProjectileDamage;
		external_damage_scale = model->externalHitScaleProjectileDamage;
		internal_spin_damage_scale = model->internalSpinHitScaleProjectileDamage;
		spin_force = model->spinForceProjectileDamage;
		break;

	default:
		int i = 0;
		i = 0;
		break;

	}
	MWMission *mission;
	Check_Object (MWMission::GetInstance());
	mission = Cast_Object (MWMission *,MWMission::GetInstance());

	if ((MWApplication::GetInstance()->networkingFlag == true) &&
		(IsDestroyed() == false))
	{
		if (part_hit)
		{
			switch (part_hit->armorZone)
			{
				case Adept::DamageObject::LeftLegArmorZone:
				case Adept::DamageObject::RightLegArmorZone:
					mission->m_BucketManager->NotifyAction (CBucketManager::LEG_SHOTS,message->inflictingEntityID,1);
					break;
				case Adept::DamageObject::LeftArmArmorZone:
				case Adept::DamageObject::RightArmArmorZone:
					mission->m_BucketManager->NotifyAction (CBucketManager::ARM_SHOTS,message->inflictingEntityID,1);
					break;
				case Adept::DamageObject::RightTorsoArmorZone:
				case Adept::DamageObject::LeftTorsoArmorZone:
				case Adept::DamageObject::CenterTorsoArmorZone:
				case Adept::DamageObject::CenterRearTorsoArmorZone:
					mission->m_BucketManager->NotifyAction (CBucketManager::TORSO_SHOTS,message->inflictingEntityID,1);
					break;
				case Adept::DamageObject::HeadArmorZone:
					mission->m_BucketManager->NotifyAction (CBucketManager::HEAD_SHOTS,message->inflictingEntityID,1);
					break;
			}
		}
	}
	if (part_hit)
    {
        g_RSF.RecScore(CBucketManager::SHOTS_HIT, message->inflictingEntityID, GetReplicatorID(), message->weaponID, part_hit->armorZone, message->typeOfDamage); // jcem
		switch (part_hit->armorZone)
		{
			case Adept::DamageObject::CenterTorsoArmorZone:
				if (part_hit->GetCurrentDamageLevel() == Adept::DamageObject::Destroyed)
				{
					if(vehicleInterface)
						vehicleInterface->ReactToEvent (VehicleInterface::DAMAGE_CRITICAL);
				}
				break;
		}
	}


	Torso *torso = GetTorso();
	if(torso)
	{
		Check_Object(torso);
		
		Point3D hit_location;

		Connection	*connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);

		if (connection == NULL)
			return;

		Check_Object(connection);

		Replicator* rep = connection->FindReplicator(message->inflictingEntityID);

		if (rep == NULL)
			return;

		Entity *inflictor = Cast_Object(Entity *, rep);

		Point3D inflictor_location;
		inflictor_location = inflictor->GetLocalToWorld();

		hit_location.MultiplyByInverse(inflictor_location, torso->twistJoint->GetLocalToWorld());
		UnitVector3D normalized_location;
		if (Small_Enough(hit_location))
		{
			hit_location.z = 1.0f;
			hit_location.x = 1.0f;
			hit_location.y = 1.0f;
		}
		normalized_location.Normalize(hit_location);
		LinearMatrix4D torso_matrix = torso->GetTwistJointMatrix();
		Point3D torso_location;
		torso_location = torso_matrix;
		

		//figure out the quadrent



		if (Abs(normalized_location.z) > Abs(normalized_location.x))
		{

			if (normalized_location.z > 0.0f)
			{
				lastHitDirection = ForwardHitDirection;
			}
			else
			{
				lastHitDirection = RearHitDirection;
			}

		}
		else
		{
			if (normalized_location.x > 0.0f)
			{
				lastHitDirection = LeftHitDirection;
			}
			else
			{
				lastHitDirection = RightHitDirection;
			}
		}

		if (IsPlayerVehicle () && vehicleInterface)
		{
			MWGUIManager *gui = MWGUIManager::GetInstance ();
			HUDReticle *ret;
			ret = Cast_Object (HUDReticle *,gui->Component (MWGUIManager::HUD_RETICLE));
			Verify (ret);
			switch (lastHitDirection)
			{
				case ForwardHitDirection:
					ret->ForwardHit ();
				break;
			case RearHitDirection:
				ret->RearHit ();
				break;
			case LeftHitDirection:
				ret->LeftHit ();
				break;
			case RightHitDirection:
				ret->RightHit ();
				break;
			}
		}
		//Check to see if we want to play cage damage!
		if(IsPlayerVehicle() && internalViewPoint)
		{
			if(message->amountOfDamage >= model->damageNeededForCageEffect)
			{
				switch(lastHitDirection)
				{
				case LeftHitDirection:
					m_playLeftCageEffect = true;
					break;
				case RightHitDirection:
					m_playRightCageEffect = true;
					break;
				case ForwardHitDirection:
					m_playLeftCageEffect = true;
					m_playRightCageEffect = true;
					break;
				}
			}
		}
		
		if (message->amountOfDamage > model->minimumDamageForInternalHitAnimation)
		{
			Scalar scaled_damage = message->amountOfDamage - model->minimumDamageForInternalHitAnimation;
				
// MSL 5.02 headshot
// MSL 5.03 Gyro Hit
//			spin_force = scaled_damage * internal_spin_damage_scale * spin_force;
//			spin_force = scaled_damage * (internal_spin_damage_scale * ((m_HeadShotTorsoSpinDamageMod + m_AdvancedGyroTorsoSpinDamageMod)/2)) * spin_force;
			spin_force = scaled_damage * (internal_spin_damage_scale * m_HeadShotTorsoSpinDamageMod) * spin_force;
			if (vehicleInterface)
			{
				vehicleInterface->PlayHitForce (Point3D (normalized_location), spin_force);
			}

			Max_Clamp(spin_force, 1.5f);
			Min_Clamp(spin_force, 0.0f);

			if(message->hitOffset.y >= torso_location.y)
			{
				//spin the torso
				if (vehicleInterface)
				{
// MSL 5.02 Torso Spin / Mech Spin
					switch (part_hit->armorZone)
					{
						case Adept::DamageObject::LeftArmArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinTorsoYaw(spin_force*2);
							}
							else
							{
								vehicleInterface->SpinTorsoYaw(-spin_force*2);
							}
							break;
						case Adept::DamageObject::LeftTorsoArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinTorsoYaw(spin_force);
							}
							else
							{
								vehicleInterface->SpinTorsoYaw(-spin_force);
							}
							break;
						case Adept::DamageObject::RightArmArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinTorsoYaw(-spin_force*2);
							}
							else
							{
								vehicleInterface->SpinTorsoYaw(spin_force*2);
							}
							break;
						case Adept::DamageObject::RightTorsoArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinTorsoYaw(-spin_force);
							}
							else
							{
								vehicleInterface->SpinTorsoYaw(spin_force);
							}
							break;
						case Adept::DamageObject::CenterRearTorsoArmorZone:
							vehicleInterface->SpinTorsoPitch(spin_force*0.6f);
							break;
						case Adept::DamageObject::CenterTorsoArmorZone:
						case Adept::DamageObject::HeadArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinTorsoPitch(-spin_force*0.6f);
							}
							else
							{
								vehicleInterface->SpinTorsoPitch(spin_force*0.6f);
							}
							break;
					}
				}
			}
			else
			{
				//spin the legs
				if (vehicleInterface)
				{
					switch (part_hit->armorZone)
					{
						case Adept::DamageObject::LeftLegArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinMechYaw(spin_force);
							}
							else
							{
								vehicleInterface->SpinMechYaw(-spin_force);
							}
							break;
						case Adept::DamageObject::RightLegArmorZone:
							if (normalized_location.z >= 0.0f)
							{
								vehicleInterface->SpinMechYaw(-spin_force);
							}
							else
							{
								vehicleInterface->SpinMechYaw(spin_force);
							}
							break;
					}
				}
			}
		}
					
//					if (normalized_location.x >= 0.0f)
//					{
//						vehicleInterface->SpinTorsoYaw(-spin_force);
//					}
//					else
//					{
//						vehicleInterface->SpinTorsoYaw(spin_force);
//					}


//					if (normalized_location.z >= 0.0f)
//					{
//						vehicleInterface->SpinTorsoPitch(-spin_force*0.6f);
//					}
//					else
//					{
//						vehicleInterface->SpinTorsoPitch(spin_force*0.6f);
//					}
//				}
//			}

//					if (normalized_location.x >= 0.0f)
//					{
//						vehicleInterface->SpinMechYaw(-spin_force);
//					}
//					else
//					{
//						vehicleInterface->SpinMechYaw(spin_force);
//					}
//				}
//			}
//		}


		if (!usingEyeSpring)
		{
			// hit the root
			// hit the torso
			// hit the hip
// MSL 5.05 Armor Mode affect damage fall check
			float damage_hit_check = message->amountOfDamage;
			if (message->amountOfModifier)
			{
				damage_hit_check *= 2.0f;
			}
// MSL 5.05
//			if (message->amountOfDamage > model->minimumDamageForHitAnimation)
			if (damage_hit_check > model->minimumDamageForHitAnimation)
			{
				//
				//This should be the position local to us where we were hit.
				//i.e. if y is lower that some value then it hit our lower section
				//if z is > 0 then it hit us in the back.
				//
// MSL 5.05
//				Scalar pitch =  (message->amountOfDamage - model->minimumDamageForHitAnimation) / model->rootScaleTakeHit;
				Scalar pitch =  (damage_hit_check - model->minimumDamageForHitAnimation) / model->rootScaleTakeHit;
				if(normalized_location.z > 0)
					pitch = -pitch;
				
// MSL 5.05
//				Scalar yaw = (message->amountOfDamage - model->minimumDamageForHitAnimation) / model->torsoScaleTakeHit;
				Scalar yaw = (damage_hit_check - model->minimumDamageForHitAnimation) / model->torsoScaleTakeHit;
				if(normalized_location.x > 0)
					yaw = -yaw;
				if(normalized_location.z > 0)
					yaw = -yaw;
				
// MSL 5.02 headshot
// MSL 5.03 Gyro Hit
//				pitch *= external_damage_scale;
//				yaw *= external_damage_scale;
//				pitch *= (external_damage_scale * ((m_HeadShotTorsoRockDamageMod + m_AdvancedGyroTorsoRockDamageMod)/2));
//				yaw *= (external_damage_scale * ((m_HeadShotTorsoRockDamageMod + m_AdvancedGyroTorsoRockDamageMod)/2));
				pitch *= (external_damage_scale * m_HeadShotTorsoRockDamageMod);
				yaw *= (external_damage_scale * m_HeadShotTorsoRockDamageMod);
				
				rootHit.SetInitialSpeed(YawPitchRoll(0.0f, pitch, 0.0f));
				torsoHit.SetInitialSpeed(YawPitchRoll(yaw, 0.0f, 0.0f));

// MSL 5.05
//				pitch =  (message->amountOfDamage - model->minimumDamageForHitAnimation) / model->hipScaleTakeHit;
				pitch =  (damage_hit_check - model->minimumDamageForHitAnimation) / model->hipScaleTakeHit;
// MSL 5.02 headshot
// MSL 5.03 Gyro Hit
//				pitch *= external_damage_scale;
//				pitch *= (external_damage_scale * ((m_HeadShotTorsoRockDamageMod + m_AdvancedGyroTorsoRockDamageMod)/2));
				pitch *= (external_damage_scale * m_HeadShotTorsoRockDamageMod);
				hipHit.SetInitialSpeed(YawPitchRoll(0.0f, pitch, 0.0f));
			}

		}
		else
		{

			float damage_hit_check = message->amountOfDamage;

			if (message->amountOfModifier)
			{
				damage_hit_check *= 2.0f;
			}

// MSL 5.05
//			if (message->amountOfDamage > model->minimumDamageForInternalHitAnimation)
			if (damage_hit_check > model->minimumDamageForInternalHitAnimation)
			{

// MSL 5.05
//				Scalar scaled_damage = message->amountOfDamage - model->minimumDamageForInternalHitAnimation;
				Scalar scaled_damage = damage_hit_check - model->minimumDamageForInternalHitAnimation;
				
				scaled_damage *= internal_damage_scale;
//				SPEW(("johnyo", "Time = %2.3f, HitSpring(%2.3f, %2.3f, %2.3f)",(Stuff::Scalar)gos_GetElapsedTime(),
//												normalized_location.x * scaled_damage, normalized_location.z * scaled_damage, normalized_location.x * scaled_damage));

				eyeSpringRotation.HitSpring(Point3D( normalized_location.x * scaled_damage, normalized_location.z * scaled_damage, normalized_location.x * scaled_damage));
			}
		}
	}

	if ((m_AI) || (GetReplicatorMode () == ClientMasterMode) || (GetReplicatorMode () == MasterMode))
	{

		
		if (((Scalar)gos_GetElapsedTime() - m_lastFall) > (MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::min_fall_timer)))
		{

			
			if (message->typeOfDamage == SplashDamageType)
			{
				m_FallDamage += (MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::fall_splash_multiplier))*message->typeOfDamage;
			}
			else
			{
// MSL 5.05 Armor Mode affect damage fall check
				if(message->amountOfModifier)
				{
					m_FallDamage += ((message->amountOfDamage) * 2);
				}
				else
				{
					m_FallDamage += (message->amountOfDamage);
				}
			}


// Fall Factor callculated here (no changes)
// falldamage >= (AIConstant * tonnage) to cause a pilot check
// MSL 5.02 headshot
// MSL 5.03 Gyro Hit
//			if (m_FallDamage >= (MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::damage_amount)) * GetTonage ())
			if ( (m_FallDamage * ((m_HeadShotFallDamageMod + m_AdvancedGyroFallDamageMod)/2)) >= (MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::damage_amount)) * GetTonage ())
//			if ( (m_FallDamage * m_HeadShotFallDamageMod) >= (MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::damage_amount)) * GetTonage ())
			{
				bool fall=false;
				if (!m_AI)
// MSL 5.05 Pilot Checking
					fall = (Stuff::Random::GetFraction () > 0.66f); // 33% chance of failing pilot check
				else
					fall = !PilotSkillCheck (m_FallDamage,false);
				if (fall)
				{
					m_lastFall = (Scalar)gos_GetElapsedTime();
					m_FallDamage = 0;
					Check_Object(m_gyro);
					switch(lastHitDirection)
					{
					case ForwardHitDirection:
						m_gyro->FallDown(FallBackMode, 0.0f);
						break;

					case LeftHitDirection:
						m_gyro->FallDown(FallRightMode, 0.0f);
						break;

					case RightHitDirection:
						m_gyro->FallDown(FallLeftMode, 0.0f);
						break;

					case NoHitDirection:
					case RearHitDirection:
						m_gyro->FallDown(FallForwardMode, 0.0f);
						break;
					}
				}
			}
		}
	}
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::ReactToDamageTaken(Stuff::Scalar damage_taken, const Adept::ReplicatorID& inflicting_entity, int weaponID, int damageType)
{
	if (IsDestroyed() == true)
		return;
	MWApplication* app = MWApplication::GetInstance();
	if (app->networkingFlag == false)
	{
		if (!app->IsCampCOOP())
		return;
	}

/*
if (g_nMR != 2) {
	MWApplication* mwapplication = Cast_Object(MWApplication*,MWApplication::GetInstance());
	MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance());
	int damage((int)damage_taken);
	float mod_damage = damage_taken;

	Stuff::Scalar integer_damage((Stuff::Scalar)damage);

	m_SavedFractionalDamage += damage_taken - integer_damage;

	if (m_SavedFractionalDamage > 1)
	{
		int added_damage = (int)m_SavedFractionalDamage;

		m_SavedFractionalDamage -= (Stuff::Scalar)added_damage;

		damage += added_damage;
	}
*/


if (g_nMR != 2)
	{
		MWApplication* mwapplication = Cast_Object(MWApplication*,MWApplication::GetInstance());
		MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance());

//		int damage((int)damage_taken);
		float mod_damage_taken = damage_taken;
		int mod_damage((int)damage_taken);

//		Stuff::Scalar integer_damage((Stuff::Scalar)damage);

//		m_SavedFractionalDamage += damage_taken - integer_damage;

//		if (m_SavedFractionalDamage > 1)
//		{
//			int added_damage = (int)m_SavedFractionalDamage;
//			m_SavedFractionalDamage -= (Stuff::Scalar)added_damage;
//			damage += added_damage;
//		}

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

// MSL 5.06 Armor damage mode is bumped up x2 for scoring
		if (m_ArmorMode)
		{
			mod_damage_taken *= 2;
			mod_damage = (int)mod_damage_taken;
		}

		Stuff::Scalar integer_mod_damage((Stuff::Scalar)mod_damage);

		m_SavedFractionalModDamage += mod_damage_taken - integer_mod_damage;

		if (m_SavedFractionalModDamage > 1)
		{
			int added_mod_damage = (int)m_SavedFractionalModDamage;
			m_SavedFractionalModDamage -= (Stuff::Scalar)added_mod_damage;
//			mod_damage += added_mod_damage;
			mod_damage_taken += added_mod_damage;
		}

		mod_damage_taken = (int)mod_damage_taken;


		ReplicatorID inflicting = inflicting_entity;
		Connection *connection = Network::GetInstance()->GetConnection(inflicting.connectionID);

		if (connection != 0)
		{
			Check_Object(connection);
			Replicator* rep = connection->FindReplicator(inflicting);

			if (rep != 0)
			{
				Entity* ent = Cast_Object(Entity*,rep);

				if (ent->IsDerivedFrom(Mech::DefaultData) == true)
				{
					Mech* inflicting_mech = Cast_Object(Mech*,ent);

					if ((inflicting_mech->IsDestroyed() == true) &&	(inflicting_mech->m_whoShotMeLast != ReplicatorID::Null))
					{
						inflicting = inflicting_mech->m_whoShotMeLast;
					}
				}
			}
		}

#if 0
	// This doesnt allow for hurting self
		if((inflicting == GetReplicatorID()) || (inflicting == ReplicatorID::Null))
#else
	// Skip only if the Mech doesnt exist
		if(inflicting == ReplicatorID::Null)
#endif
		{
			return;
		}

//		mission->m_BucketManager->NotifyAction (CBucketManager::DAMAGE_RECEIVE,GetReplicatorID (),damage_taken);
//		mission->m_BucketManager->NotifyAction (CBucketManager::DAMAGE_INFLICT,inflicting,damage_taken);
		mission->m_BucketManager->NotifyAction (CBucketManager::DAMAGE_RECEIVE,GetReplicatorID (),mod_damage_taken);
		mission->m_BucketManager->NotifyAction (CBucketManager::DAMAGE_INFLICT,inflicting,mod_damage_taken);
		mission->m_BucketManager->NotifyAction (CBucketManager::SHOTS_HIT,inflicting,1);

		CBucketManager::Bucket_Type receive_type;
		CBucketManager::Bucket_Type inflict_type;

		if (mwapplication->TeamsAreFriendly(inflicting,GetReplicatorID()) == false)
		{
			receive_type = CBucketManager::ENEMY_DAMAGE_RECEIVE;
			inflict_type = CBucketManager::ENEMY_DAMAGE_INFLICT;
		}
		else
		{
			receive_type = CBucketManager::FRIENDLY_DAMAGE_RECEIVE;
			inflict_type = CBucketManager::FRIENDLY_DAMAGE_INFLICT;
// MSL 5.04 Friendly Fire Betty
// If is on team and is not you, then sound betty
			if((inflicting == GetReplicatorID()) || (inflicting == ReplicatorID::Null))
			{
			// do not sound the betty because we are hurting ourselves
			}
			else
			{
				if (m_FriendlyFireHit + 1.0f < gos_GetElapsedTime())
				{
					MWApplication* app = Cast_Object(MWApplication*,MWApplication::GetInstance());
					app->SendSound(inflicting, VehicleInterface::FRIENDLYFIREPENALTY);
				}
				m_FriendlyFireHit = (Stuff::Scalar)gos_GetElapsedTime();
			}
		}

//		mission->m_BucketManager->NotifyAction(receive_type,GetReplicatorID (),damage_taken);
//		mission->m_BucketManager->NotifyAction(inflict_type,inflicting,damage_taken,GetReplicatorID());
		mission->m_BucketManager->NotifyAction(receive_type,GetReplicatorID (),mod_damage_taken);
		mission->m_BucketManager->NotifyAction(inflict_type,inflicting,mod_damage_taken,GetReplicatorID());

		if (g_nMR == 1)
		{
//			extern void g_MRF_MechDamageTaken(ReplicatorID id1, ReplicatorID id2, Stuff::Scalar damage_taken, int weaponID, int damageType);
//			g_MRF_MechDamageTaken(GetReplicatorID(), inflicting_entity, damage_taken, weaponID, damageType);
			extern void g_MRF_MechDamageTaken(ReplicatorID id1, ReplicatorID id2, Stuff::Scalar mod_damage_taken, int weaponID, int damageType);
			g_MRF_MechDamageTaken(GetReplicatorID(), inflicting_entity, mod_damage_taken, weaponID, damageType);
		}
	}
	
	ReplicatorID inflicting = inflicting_entity;
	Connection *inflConn = Network::GetInstance()->GetConnection(inflicting.connectionID);
	if (inflConn != 0)
	{
		Check_Object(inflConn);
		Replicator* repInfl = inflConn->FindReplicator(inflicting);

		if (repInfl)
            Mech_CheckDamage(this, repInfl);
    }

	// ngLog addition
#if !defined(NO_LOG)
	MWApplication *app = MWApplication::GetInstance();

	if(app->serverFlag) {// && (IsPlayerVehicle() || IsLanceMate())
		Replicator *r = NULL;
		int i = inflicting.connectionID;
		int j = weaponID;
		int self;


		if(IsLanceMate()) {
			self = Maximum_Players + lancemateIndex;
		} else {
			self = GetReplicatorID().connectionID;
		}

		if(damageType >= RammingDamageFromAboveType || j < 0) {
			j = 200 + damageType;
		}

		// Check if inflictor is a lancemate
		if(i == Connection::Server->GetID()) {
			connection = Network::GetInstance()->GetConnection(inflicting.connectionID);
			if(connection != NULL) {
				r = connection->FindReplicator(inflicting);
				if(r && r->GetClassID() == MechClassID) {
					Mech *inflictor = Cast_Object(Mech *, r);

					if(inflictor->IsLanceMate()) {
						i = inflictor->lancemateIndex + Maximum_Players;
					}
				}
			}
		}

		// Keep track of only player-to-player damage
		if(i >= 0) {
			if(damageType < SplashDamageType || (j >= 200 && j != 200+SplashDamageType)) {
				if(i >= Maximum_Players) {
					app->lancemateConnectionData[i-Maximum_Players].wep_hits[j]++;
					// Just for sanity's sake
					if(j >= 200) {
						app->lancemateConnectionData[i-Maximum_Players].wep_atts[j]++;
					}
				} else {
					app->servedConnectionData[i].wep_hits[j]++;
					// Just for sanity's sake
					if(j >= 200) {
						app->servedConnectionData[i].wep_atts[j]++;
					}
				}
			}

/*
			if(i >= Maximum_Players) {
				app->lancemateConnectionData[i-Maximum_Players].dmg_given[j] += damage;
				app->lancemateConnectionData[i-Maximum_Players].pdmg_given[self] += damage;
				app->lancemateConnectionData[i-Maximum_Players].stats_update = 1;
			} else {
				app->servedConnectionData[i].dmg_given[j] += damage;
				app->servedConnectionData[i].pdmg_given[self] += damage;
				app->servedConnectionData[i].stats_update = 1;
			}

			if(self >= Maximum_Players) {
				app->lancemateConnectionData[self-Maximum_Players].pdmg_rcvd[i] += damage;
				app->lancemateConnectionData[self-Maximum_Players].stats_update = 1;
			} else {
				app->servedConnectionData[self].pdmg_rcvd[i] += damage;
				app->servedConnectionData[self].stats_update = 1;
			}

			// Move this out if we want ALL received damage collected
			if(self >= Maximum_Players) {
				app->lancemateConnectionData[self-Maximum_Players].dmg_rcvd[j] += damage;
				app->lancemateConnectionData[self-Maximum_Players].stats_update = 1;
			} else {
				app->servedConnectionData[self].dmg_rcvd[j] += damage;
				app->servedConnectionData[self].stats_update = 1;
			}
*/

			if(i >= Maximum_Players) {
				app->lancemateConnectionData[i-Maximum_Players].dmg_given[j] += mod_damage;
				app->lancemateConnectionData[i-Maximum_Players].pdmg_given[self] += mod_damage;
				app->lancemateConnectionData[i-Maximum_Players].stats_update = 1;
			} else {
				app->servedConnectionData[i].dmg_given[j] += mod_damage;
				app->servedConnectionData[i].pdmg_given[self] += mod_damage;
				app->servedConnectionData[i].stats_update = 1;
			}

			if(self >= Maximum_Players) {
				app->lancemateConnectionData[self-Maximum_Players].pdmg_rcvd[i] += mod_damage;
				app->lancemateConnectionData[self-Maximum_Players].stats_update = 1;
			} else {
				app->servedConnectionData[self].pdmg_rcvd[i] += mod_damage;
				app->servedConnectionData[self].stats_update = 1;
			}

			// Move this out if we want ALL received damage collected
			if(self >= Maximum_Players) {
				app->lancemateConnectionData[self-Maximum_Players].dmg_rcvd[j] += mod_damage;
				app->lancemateConnectionData[self-Maximum_Players].stats_update = 1;
			} else {
				app->servedConnectionData[self].dmg_rcvd[j] += mod_damage;
				app->servedConnectionData[self].stats_update = 1;
			}

		}
	}
#endif // !defined(NO_LOG)

}

// MSL 5.02 headshot
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::HeadShotInternal( ) //**^ 
{
	if ((dwDamageFlags & MECH_HEAD_SHOT_RCVD) == MECH_HEAD_SHOT_RCVD) 
	{
		return;
	}

	//set all flags for internal head damage
	dwDamageFlags |= MECH_HEAD_SHOT_FX;
	m_HeadShotFallDamageMod = MECH_HEAD_SHOT_FALL_MOD; //*= ? //fall-down chance increased... (see modifier at top of file : MECH_HEAD_SHOT_FALL_MOD) -- handled by setting the flags
	m_HeadShotTorsoRockDamageMod = MECH_HEAD_SHOT_TORSO_ROCK_MOD;
	m_HeadShotTorsoSpinDamageMod = MECH_HEAD_SHOT_TORSO_SPIN_MOD;
	if (vehicleInterface) //if we are the player getting hit --possibly need to add IsPlayerVehicle() check if needed
	{
		vehicleInterface->hudZoomDestroyed = true; //Zoom is destroyed
		vehicleInterface->HideZoom();  //zoom -- if in zoom, take out of zoom 

		//play sound "component destroyed"
		vehicleInterface->ReactToEvent (VehicleInterface::COMPONENT_DESTROYED);
	}


	//BAP/ECM destroyed -- iterate over the mech's subsystems and remove BAP/ECM if they exist
	if ((DoesHaveECM()) /*|| (DoesHaveBeagle())*/)
	{
		for (int j=0;(j<10); j++)
		{
			MWInternalDamageObject* damage_obj = internalDamageObjects.Find (j);
			if (damage_obj != NULL)
			{
				ChainIteratorOf<Subsystem*> subsys_iter(&damage_obj->subsystemChain);
				Subsystem* subsys;
				while ((subsys = subsys_iter.ReadAndNext()) != NULL)
				{
					if(subsys->IsDerivedFrom(ECM::DefaultData) /*|| subsys->IsDerivedFrom(Beagle::DefaultData)*/)
					{
						subsys->TakeCriticalHit();
						damage_obj->destroyedSubsystemChain.Add(subsys); // So we can later completely remove the subsystem //** 
						damage_obj->subsystemChain.Remove(subsys);
						subsys_iter.First();
					}
				}
			}
		}
	}
}

// MSL 5.03 Gyro Hit
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::GyroHitInternal( ) //**^ 
{
// MSL 5.05 Advance Mode
	MWApplication *m_App;
	m_App = MWApplication::GetInstance ();
	m_AdvanceMode = m_App->GetLocalNetParams()->m_advancemodeOn;

	if (!m_AdvanceMode)
	{
		return;
	}

	if ((dwGyroDamageFlags & MECH_GYRO_HIT_RCVD) == MECH_GYRO_HIT_RCVD) 
	{
		return;
	}

	if (Stuff::Random::GetFraction () > 0.0625f) // 1 in 16 chance of gyro hit
	{
		return;
	}

	//set all flags for internal damage
	dwGyroDamageFlags |= MECH_GYRO_HIT_RCVD;
	m_AdvancedGyroFallDamageMod = ADVANCED_GYRO_FALL_MOD; //*= ? //fall-down chance increased... (see modifier at top of file : MECH_HEAD_SHOT_FALL_MOD) -- handled by setting the flags

	//Advanced Gyro destroyed -- iterate over the mech's subsystems and remove if exist
	if (DoesHaveAdvancedGyro())
	{
		for (int j=0;(j<10); j++)
		{
			MWInternalDamageObject* damage_obj = internalDamageObjects.Find (j);
			if (damage_obj != NULL)
			{
				ChainIteratorOf<Subsystem*> subsys_iter(&damage_obj->subsystemChain);
				Subsystem* subsys;
				while ((subsys = subsys_iter.ReadAndNext()) != NULL)
				{
					if(subsys->IsDerivedFrom(AdvancedGyro::DefaultData))
					{
						subsys->TakeCriticalHit();
						damage_obj->destroyedSubsystemChain.Add(subsys); // So we can later completely remove the subsystem //** 
						damage_obj->subsystemChain.Remove(subsys);
						subsys_iter.First();
					}
				}
			}
		}
	}

	if (vehicleInterface) //if we are the player getting hit --possibly need to add IsPlayerVehicle() check if needed
	{
		//play sound "component destroyed"
		vehicleInterface->ReactToEvent (VehicleInterface::COMPDESTROYED);
		//reset cameramode
		vehicleInterface->SetCameraMode(0);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mech::HandleSalvage (void)
{
	MWGame *game;

	if (GetAlignment() != Entity::Enemy)
		return;
	game = MWGame::GetInstance ();
	if (!game)
		return;
		
	Scalar value = MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::chance_salvage);
	Scalar chance = Stuff::Random::GetFraction ();
	if (chance > (value*0.01f))
		return;

	m_markedForSalvage = true;
	game->AddMechInstance(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	pick a random sound for the crowd noises in a coliseum game
static void ColiseumDeathNoise()
{
	if (VehicleInterface::GetInstance())
	{
		// if a coliseum game
		MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance());
		Check_Object (mission);
		int theType = mission->GetMissionType();
		if (theType == MWMission::MISSIONTYPE_COLISEUM)
		{
//			VehicleInterface::GetInstance()->ReactToEvent(VehicleInterface::COLISEUM_HORN);

			// 80% of the time
			if (Stuff::Random::GetLessThan(100) < 80)
			{
				// play a random crowd noise
				const numSounds = 9;
				VehicleInterface::SOUND_TRIGGER soundList[numSounds] = {
					VehicleInterface::COLISEUM_CHEER1,
					VehicleInterface::COLISEUM_CHEER2,
					VehicleInterface::COLISEUM_AHH,
					VehicleInterface::COLISEUM_BOO2,
					VehicleInterface::COLISEUM_CHEER9,
					VehicleInterface::COLISEUM_CHEER8,
					VehicleInterface::COLISEUM_CHEER5,
					VehicleInterface::COLISEUM_AWW,
					VehicleInterface::COLISEUM_ROAR,
				};
				VehicleInterface::GetInstance()->ReactToEvent( soundList[Stuff::Random::GetLessThan(numSounds)] );
			}
		}
	}
}

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

void
	Mech::ReactToDestruction(int damage_mode, int damage_type)
{
	
	PRECOLLISION_LOGIC("Mech::ReactToDestruction");

	if (damage_mode != InternalDamageObject::HeadShotDamageMode)
		damage_mode = InternalDamageObject::DestructionDamageMode;
	
	switch(damage_mode)
	{
	case InternalDamageObject::HeadShotDamageMode:
		{
			if(!IsDestroyed())
			{
				// coliseum games have a reaction to 'Mech death
				ColiseumDeathNoise();

				if (vehicleInterface)
				{
					vehicleInterface->ReactToEvent (VehicleInterface::NO_HEAT);
					vehicleInterface->ReactToEvent (VehicleInterface::COOLANT_FLUSH_STOP);
					vehicleInterface->ReactToEvent (VehicleInterface::NARC_SIGNAL_STOP);
					vehicleInterface->ReactToEvent (VehicleInterface::STEP_WATER_STOP);
				}

				// ngLog addition
#if !defined(NO_LOG)
				if(MWApplication::GetInstance()->serverFlag && MWApplication::GetInstance()->networkingFlag)
				{
					int self  = 0;
					int enemy = 0;
					int t_delta = 0;
					Replicator *r = NULL;
					Connection *conn = Network::GetInstance()->GetConnection(m_whoShotMeLast.connectionID);


					if(IsLanceMate())
					{
						self = lancemateIndex + Maximum_Players;
					}
					else
					{
						self = GetReplicatorID().connectionID;
					}

					enemy = m_whoShotMeLast.connectionID;
					if(conn)
					{
						r = conn->FindReplicator(m_whoShotMeLast);
						if(r && r->GetClassID() == MechClassID)
						{
							Mech *inflictor = Cast_Object(Mech *, r);

							if(inflictor->IsLanceMate())
							{
								enemy = inflictor->lancemateIndex + Maximum_Players;
							}

							if(enemy > 0)
							{
								t_delta = (int)GetTonage() - (int)inflictor->GetTonage();
								if(t_delta < 0)
								{
									t_delta = 0;
								}
							}
						}
					}

					if(m_weaponShotMeLast == -50)
					{
						MW4log_generic(MW4P_KILL, va("Player_Suicide\t%d", self));
					}
					else
					{
						int i = m_weaponShotMeLast;

						if(i < 0)
						{
							i = 200 + damage_type;
						}

						MW4log_generic(MW4P_KILL, va("Player_Kill\t%d\t%d\t%d\t%d", enemy, self, i, t_delta));
					}
				}
#endif // !defined(NO_LOG)

				Check_Object(Mission::GetInstance());
// MSL 5.02 headshot
				Mission::GetInstance()->ScoringReactToMechDeath(m_whoShotMeLast, GetReplicatorID(), damage_mode); //need to somehow learn if the death was caused by a headshot, cuz right now its in destructiondamagemode and that will just not do

				Flag::RemoveAllFlagsFrom(*this);

// MSL 5.02 headshot
				// also remove our head-shot flags
				dwDamageFlags = 0; //reset the flags -- heal the mech after destruction //** reset the flags -- still need to do this
				if (vehicleInterface) 
				{
					vehicleInterface->hudZoomDestroyed = false; 
				}

				if (vehicleInterface != NULL)
				{
					vehicleInterface->SetDeathMode();
				}

// MSL 5.03 Gyro Hit
				dwGyroDamageFlags = 0;
				
// MSL 5.05 Server/Client issues with ejeect effect for headshot
				if (!ejectEffect.GetCurrent ())
				{
					const GameModel *model = GetGameModel();
					Check_Object(model);
					Adept::Site *ejectSite = FindSite("site_eject2");
					Check_Object(ejectSite);
					Effect *effect;
					effect = CreateEffect(model->ejectEffectResource, ejectSite, true);
					if(effect)
						ejectEffect.Add(effect);
				}

				// if we are standing
#if 0
				if(!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::StandState)
				{
					vehicleShutDown = true;
				}
				// if we are powering down
				else if (animStateEngine->IsTransitioning() && animStateEngine->GetTransitionState() == MechAnimationStateEngine::PowerDownState)
				{
					vehicleShutDown = true;
				}
				// if we are powered down
				else if (!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::PowerDownState)
				{
					vehicleShutDown = true;
				}
				else
#endif
				{
					// fall the opposite way you got hit
					Check_Object(m_gyro);
					switch(lastHitDirection)
					{
					case ForwardHitDirection:
						m_gyro->FallDown(FallBackMode, 0.0f);
						break;

					case LeftHitDirection:
						m_gyro->FallDown(FallRightMode, 0.0f);
						break;

					case RightHitDirection:
						m_gyro->FallDown(FallLeftMode, 0.0f);
						break;

					case NoHitDirection:
					case RearHitDirection:
						m_gyro->FallDown(FallForwardMode, 0.0f);
						break;

						
					}
				}


				Check_Object(executionState);
				if(m_AI)
				{
					Check_Object(m_AI);
					m_AI->Die();
				}
				
				const GameModel *model = GetGameModel();
				Check_Object(model);
				
				CreateEffect(model->destroyedEffectResource, FindChildMover("joint_centertorsofront"), true);
				
//				SetDestroyedFlag(damage_mode);
				DestroyChildren(damage_mode);

				if (damage_type == SplashDamageType)
					diedBySplash = true;
				else
// MSL 5.04 Disable Splash for Ejecting (Disabled)
//					if (!m_needSelfDestruct)
						DealSplashDamage();

				break;
				}
			}
	case InternalDamageObject::DestructionDamageMode:
		{

			if(!IsDestroyed())
			{
				// coliseum games have a reaction to 'Mech death
				ColiseumDeathNoise();

				if (vehicleInterface)
				{
					vehicleInterface->ReactToEvent (VehicleInterface::NO_HEAT);
					vehicleInterface->ReactToEvent (VehicleInterface::COOLANT_FLUSH_STOP);
					vehicleInterface->ReactToEvent (VehicleInterface::NARC_SIGNAL_STOP);
					vehicleInterface->ReactToEvent (VehicleInterface::STEP_WATER_STOP);
				}

				// ngLog addition
#if !defined(NO_LOG)
				if(MWApplication::GetInstance()->serverFlag && MWApplication::GetInstance()->networkingFlag) {
					int self  = 0;
					int enemy = 0;
					int t_delta = 0;
					Replicator *r = NULL;
					Connection *conn = Network::GetInstance()->GetConnection(m_whoShotMeLast.connectionID);


					if(IsLanceMate()) {
						self = lancemateIndex + Maximum_Players;
					} else {
						self = GetReplicatorID().connectionID;
					}

					enemy = m_whoShotMeLast.connectionID;
					if(conn) {
						r = conn->FindReplicator(m_whoShotMeLast);
						if(r && r->GetClassID() == MechClassID) {
							Mech *inflictor = Cast_Object(Mech *, r);

							if(inflictor->IsLanceMate()) {
								enemy = inflictor->lancemateIndex + Maximum_Players;
							}

							if(enemy > 0) {
								t_delta = (int)GetTonage() - (int)inflictor->GetTonage();
								if(t_delta < 0) {
									t_delta = 0;
								}
							}
						}
					}

					if(m_weaponShotMeLast == -50) {
						MW4log_generic(MW4P_KILL, va("Player_Suicide\t%d", self));
					} else {
						int i = m_weaponShotMeLast;

						if(i < 0) {
							i = 200 + damage_type;
						}

						MW4log_generic(MW4P_KILL, va("Player_Kill\t%d\t%d\t%d\t%d", enemy, self, i, t_delta));
					}
				}
#endif // !defined(NO_LOG)



				Check_Object(Mission::GetInstance());
// MSL 5.02 headshot
				Mission::GetInstance()->ScoringReactToMechDeath(m_whoShotMeLast, GetReplicatorID(), damage_mode); //need to somehow learn if the death was caused by a headshot, cuz right now its in destructiondamagemode and that will just not do

				Flag::RemoveAllFlagsFrom(*this);

// MSL 5.02 headshot
				// also remove our head-shot flags
				dwDamageFlags = 0; //reset the flags -- heal the mech after destruction //** reset the flags -- still need to do this
				if (vehicleInterface) 
				{
					vehicleInterface->hudZoomDestroyed = false; 
				}

				if (vehicleInterface != NULL)
				{
					vehicleInterface->SetDeathMode();
				}

// MSL 5.03 Gyro Hit
				dwGyroDamageFlags = 0;
				
//MSL 5.00
//	- Added eject Effect Code here

			if (!ejectEffect.GetCurrent ())
			{
				const GameModel *model = GetGameModel();
				Check_Object(model);
				Adept::Site *ejectSite = FindSite("site_eject2");
				Check_Object(ejectSite);
				Effect *effect;
				effect = CreateEffect(model->ejectEffectResource, ejectSite, true);
				if(effect)
					ejectEffect.Add(effect);
			}

				// if we are standing
#if 0
				if(!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::StandState)
				{
					vehicleShutDown = true;
				}
				// if we are powering down
				else if (animStateEngine->IsTransitioning() && animStateEngine->GetTransitionState() == MechAnimationStateEngine::PowerDownState)
				{
					vehicleShutDown = true;
				}
				// if we are powered down
				else if (!animStateEngine->IsTransitioning() && animStateEngine->GetState() == MechAnimationStateEngine::PowerDownState)
				{
					vehicleShutDown = true;
				}
				else
#endif
				{
					// fall the opposite way you got hit
					Check_Object(m_gyro);
					switch(lastHitDirection)
					{
					case ForwardHitDirection:
						m_gyro->FallDown(FallBackMode, 0.0f);
						break;

					case LeftHitDirection:
						m_gyro->FallDown(FallRightMode, 0.0f);
						break;

					case RightHitDirection:
						m_gyro->FallDown(FallLeftMode, 0.0f);
						break;

					case NoHitDirection:
					case RearHitDirection:
						m_gyro->FallDown(FallForwardMode, 0.0f);
						break;

						
					}
				}


				Check_Object(executionState);
				if(m_AI)
				{
					Check_Object(m_AI);
					m_AI->Die();
				}
				
				const GameModel *model = GetGameModel();
				Check_Object(model);
				
				CreateEffect(model->destroyedEffectResource, FindChildMover("joint_centertorsofront"), true);
				
//				SetDestroyedFlag(damage_mode);
				DestroyChildren(damage_mode);

				if (damage_type == SplashDamageType)
					diedBySplash = true;
				else
// MSL 5.04 Disable Splash for Ejecting (Disabled)
//					if (!m_needSelfDestruct)
						DealSplashDamage();

				break;
			}
		}
	}

	SetDead ();
	if (vehicleInterface)
	{
		vehicleInterface->EndEngineIdle ();
	}
//	m_previousSearchLightState = GetSearchLight()->isLightOn;
//	if (IsPlayerVehicle())
//	{
//		Mission::GetInstance()->ResetMissionLights();
//	}
//	GetSearchLight()->HideBeam();

	Entity::ReactToDestruction(damage_mode, damage_type);

	#ifdef LAB_ONLY
	if (MW4AI::Statistics::Enabled() == true)
	{
		MW4AI::Statistics::NotifyDestroyed(objectID);
	}
	#endif
}
	
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Fix Bug #3100 
// Damage Object are now refreshed when a mech sustains internal damage
void
	Mech::ReactToInternalDamage(int damage_mode)
{
	Check_Object(this);

	for (int i = 0; i < 11; i++)
	{
		DamageObject *damage_object = damageObjects.Find(i);
		if(damage_object)
		{
			damage_object->RefreshCurrentDamageLevel();
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyLeftArmSpecialZones()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *special = internalDamageObjects.Find(InternalDamageObject::SpecialZone1);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::LeftArmZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone1);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}

	special = internalDamageObjects.Find(InternalDamageObject::SpecialZone2);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::LeftArmZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone2);
			Check_Object(damage_object);
	
			damage_object->SetCurrentDamageLevel(2);
		}
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyRightArmSpecialZones()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *special = internalDamageObjects.Find(InternalDamageObject::SpecialZone1);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::RightArmZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone1);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}

	special = internalDamageObjects.Find(InternalDamageObject::SpecialZone2);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::RightArmZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone2);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyLeftTorsoSpecialZones()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *special = internalDamageObjects.Find(InternalDamageObject::SpecialZone1);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::LeftTorsoZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone1);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}

	special = internalDamageObjects.Find(InternalDamageObject::SpecialZone2);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::LeftTorsoZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone2);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}
return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyRightTorsoSpecialZones()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *special = internalDamageObjects.Find(InternalDamageObject::SpecialZone1);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::RightTorsoZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone1);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}

	special = internalDamageObjects.Find(InternalDamageObject::SpecialZone2);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::RightTorsoZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone2);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}
return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyLeftLegSpecialZones()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *special = internalDamageObjects.Find(InternalDamageObject::SpecialZone1);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::LeftLegZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone1);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}

	special = internalDamageObjects.Find(InternalDamageObject::SpecialZone2);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::LeftLegZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone2);
			Check_Object(damage_object);
	
			damage_object->SetCurrentDamageLevel(2);
		}
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyRightLegSpecialZones()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *special = internalDamageObjects.Find(InternalDamageObject::SpecialZone1);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::RightLegZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone1);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}

	special = internalDamageObjects.Find(InternalDamageObject::SpecialZone2);
	if (special)
	{
		Check_Object(special);

		if(special->m_specialConnectedTo == InternalDamageObject::RightLegZone)
		{
			special->SetCurrentDamageLevel(2);
			special->KillAllContainedSubsystems();

			DamageObject *damage_object;
			damage_object = damageObjects.Find(DamageObject::SpecialArmorZone2);
			Check_Object(damage_object);

			damage_object->SetCurrentDamageLevel(2);
		}
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyLeftArm()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *arm = internalDamageObjects.Find(InternalDamageObject::LeftArmZone);
	if (arm)
	{
		Check_Object(arm);

		arm->SetCurrentDamageLevel(2);
		arm->KillAllContainedSubsystems();

		DamageObject *damage_object;
		damage_object = damageObjects.Find(DamageObject::LeftArmArmorZone);
		Check_Object(damage_object);

		damage_object->SetCurrentDamageLevel(2);
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.05 Torso
void
	Mech::DestroyRightArm()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	MWInternalDamageObject *arm = internalDamageObjects.Find(InternalDamageObject::RightArmZone);
	if (arm)
	{
		Check_Object(arm);

		arm->SetCurrentDamageLevel(2);
		arm->KillAllContainedSubsystems();

		DamageObject *damage_object;
		damage_object = damageObjects.Find(DamageObject::RightArmArmorZone);
		Check_Object(damage_object);

		damage_object->SetCurrentDamageLevel(2);
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::SetRightGimp()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	if (gimpState == LeftGimpMode)
	{
		ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		return;
	}
	if (gimpState == NotGimpedMode)
	{
		gimpState = RightGimpMode;
        if(vehicleInterface) {
            MWEntityManager::GetInstance()->m_uPostDeathFlags |= 1;
			//vehicleInterface->ReactToEvent(VehicleInterface::CRITICAL_HIT_GIMP);
        }
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::SetLeftGimp()
{
	Check_Object(this);

	if(IsDestroyed())
		return;

	if (gimpState == RightGimpMode)
	{
		ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		return;
	}
	if (gimpState == NotGimpedMode)
	{
		gimpState = LeftGimpMode;
        if(vehicleInterface) {
            MWEntityManager::GetInstance()->m_uPostDeathFlags |= 1;
			//vehicleInterface->ReactToEvent(VehicleInterface::CRITICAL_HIT_GIMP);
        }
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::SetSearchLightIntensity(Scalar intensity)
{
	Check_Object(this);
	if(searchLightEffect)
	{
		Check_Object(searchLightEffect);
		searchLightEffect->lightIntensity = intensity;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::SetCooling(int new_int)
{
	Check_Object(this);
	Check_Object(m_heatManager);

	m_heatManager->SetCooling(new_int);
}

Scalar Mech::AverageDamage (void) const			// 0-1 for average damage of mech  center torso has a higher weight
{
	int i;
	Scalar toret;
	Scalar count;

	count = 0;
	toret = 0;
	for (i=0;i<11;i++)
	{
		if (damageArray[i] != -1)
		{
			if (i==6)
			{
				toret += (damageArray[i]*5.0f);
				count+=5.0f;
			}
			else
			{
				toret += damageArray[i];
				count++;
			}
		}
	}
	if (count)
	{
		toret /= count;
	}
	return toret;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::InitializeDamageArray()
{
	Check_Object(this);

	memset(damageArray, -1, sizeof(int) * 11);
	for(int i=0; i<11; i++)
	{
		DamageObject *damage_object = damageObjects.Find(i);
		if(damage_object)
		{
			damageArray[i] = damage_object->damageLevel;
			damage_object->SetDamageArrayEntry(&damageArray[i]);
		}
		else
		{
			damageArray[i] = -1;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
	Mech::FriendlyFireDamageMultiplier() const
{
	NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
	return (Scalar)params->m_friendlyFirePercentage * 0.01f;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::DestroySearchLight()
{
	Check_Object(this);

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

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

void
	Mech::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_ArmActivation()
{
	//arms activate - deactive
	if (!armsNulled)
	{
		armsNulled = true;
		armBlanderizer.FadeToNewDampen(1.0f, 0.2f);
	}
	else
	{
		armsNulled = false;
		armBlanderizer.FadeToNewDampen(0.0f, 1.0f);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mech::Test_GetArmActivation() const
{
	return (armsNulled);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_PushupOff()
{
	debugPushupOff = !debugPushupOff;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mech::Test_GetPushupOff() const
{
	return (!debugPushupOff);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_LeftArmRecoil()
{
//	leftArmRecoil.SetInitialSpeed(YawPitchRoll(0.0f, 8.0f, 0.0f));
//	leftGunRecoil.SetInitialSpeed(YawPitchRoll(0.0f, -8.0f, 0.0f));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_RightGunRecoil()
{
//	rightGunRecoil.SetInitialSpeed(Point3D(0.0f, 0.0f, -8.0f));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_Hit1()
{

	//eyeSpringPosition.HitSpring(Point3D(10.0f,20.0f,0.0f));
	
	vehicleInterface->SpinTorsoYaw(0.5f);
	vehicleInterface->SpinTorsoPitch(0.5f);
				
	if (usingEyeSpring)
	{
		eyeSpringRotation.HitSpring(
			Point3D(30.0f, 0.0f, -20.0f)	
		);
	}
	else
	{
		rootHit.SetInitialSpeed(YawPitchRoll(0.0f, 0.5f, 0.0f));
		torsoHit.SetInitialSpeed(YawPitchRoll(0.5f, 0.0f, 0.0f));
		hipHit.SetInitialSpeed(YawPitchRoll(0.0f, 0.5f, 0.0f));
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_Hit2()
{

	vehicleInterface->SpinTorsoYaw(-0.5f);
	vehicleInterface->SpinTorsoPitch(-0.5f);

	//eyeSpringPosition.HitSpring(Point3D(-10.0f,10.0f,0.0f));
	
	if (usingEyeSpring)
	{
		eyeSpringRotation.HitSpring(
			Point3D(-30.0f, 0.0f, 20.0f)
		);
	}
	else
	{
		rootHit.SetInitialSpeed(YawPitchRoll(0.0f, 1.0f, 0.0f));
		torsoHit.SetInitialSpeed(YawPitchRoll(1.0f, 0.0f, 0.0f));
		hipHit.SetInitialSpeed(YawPitchRoll(0.0f, 1.0f, 0.0f));
	}


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_Hit3()
{

	
	vehicleInterface->SpinMechYaw(-0.5f);

	if (usingEyeSpring)
	{
		eyeSpringRotation.HitSpring(
			Point3D( 0.0f, 30.0f,10.0f)
		);
	}
	else
	{
		rootHit.SetInitialSpeed(YawPitchRoll(0.0f, -0.5f, 0.0f));
		torsoHit.SetInitialSpeed(YawPitchRoll(-0.5f, 0.0f, 0.0f));
		hipHit.SetInitialSpeed(YawPitchRoll(0.0f, -0.5f, 0.0f));
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_Hit4()
{

	vehicleInterface->SpinMechYaw(0.5f);

	if (usingEyeSpring)
	{
		eyeSpringRotation.HitSpring(
			Point3D( 0.0f, -30.0f,-10.0f)
		);
	}
	else
	{
		rootHit.SetInitialSpeed(YawPitchRoll(0.0f, -1.0f, 0.0f));
		torsoHit.SetInitialSpeed(YawPitchRoll(-1.0f, 0.0f, 0.0f));
		hipHit.SetInitialSpeed(YawPitchRoll(0.0f, -1.0f, 0.0f));
	}


}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_Reset()
{
	lastSpeedMPS = 0.0f;
	speedDemand = 0.0f;
	speedDemandMPS = 0.0f;
	currentSpeedMPS = 0.0f;
	currentSpeedKPH = 0.0;
	speedDemandKPH = 0.0;
	gimpState = NotGimpedMode;
	queFallState = NoFallMode;
	fallDirection = NoFallMode;

	animStateEngine->Reset();
	animStateEngine->RequestState(MechAnimationStateEngine::StandState, Mech::NoBlend);
	executionState->RequestState(ExecutionStateEngine::DrivingMotionState);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_LeftGimp()
{
	if (gimpState == LeftGimpMode)
	{
		gimpState = NotGimpedMode;
	}
	else
	{
		gimpState = LeftGimpMode;
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mech::Test_GetLeftGimp() const
{
	return (gimpState == LeftGimpMode);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::Test_RightGimp()
{
	if (gimpState == RightGimpMode)
	{
		gimpState = NotGimpedMode;
	}
	else
	{
		gimpState = RightGimpMode;
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mech::Test_GetRightGimp() const
{
	return (gimpState == RightGimpMode);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//		
void
	Mech::Test_FallForward()
{
	Check_Object(m_gyro);
	m_gyro->FallDown(FallForwardMode, 0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	
void
	Mech::Test_FallBackward()
{
	Check_Object(m_gyro);
	m_gyro->FallDown(FallBackMode, 0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	
void
	Mech::Test_FallRight()
{
	Check_Object(m_gyro);
	m_gyro->FallDown(FallRightMode, 0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	
void
	Mech::Test_FallLeft()
{
	Check_Object(m_gyro);
	m_gyro->FallDown(FallLeftMode, 0.0f);
}

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

	BaseClass::BecomeInteresting(render_me);
  //
  // Need to destroy these each time we cross a zone
  //
	Check_Pointer(Mission::GetInstance());

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

	if(!Mission::GetInstance()->DoesAllowSearchLights())
	{
		DestroySearchLight();
		if(GetSearchLight())
		{
//			if (IsPlayerVehicle())
//			{
//				Mission::GetInstance()->ResetMissionLights();
//			}
			GetSearchLight()->HideBeam();
			GetSearchLight()->DestroySubsystem();
		}
	}


}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::SeedHeatManager()
{
	Check_Object(this);

	Subsystem *subsystem;
	Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
	while((subsystem = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(subsystem);
		subsystem->ConnectHeatManager(m_heatManager);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::ReactToShutDown()
{
	Check_Object(this);

	//
	//--------------------------------
	//Check to see if we are in an MFB
	//--------------------------------
	//
	MFB::IsWithinMFB(this);
#if 0
		Check_Object(MFB::Instance);
		if(IsWithin(MFB::Instance, 2.0f))
		{
			MFB::Instance->StartNewMech(this);
		}
	}		
#endif
	m_alreadyShutDown = true;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
	Mech::GetLastFootFallTime() const
{
	return (m_LastFootFallTime);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::GetLineOfSight(Stuff::LinearMatrix4D& line_of_sight)
{
	if ((eyeSitePointer.GetCurrent() != 0) &&
		(GetTorso() != 0) &&
		(GetTorso()->twistJoint != 0))
	{
		line_of_sight = GetTorso()->twistJoint->GetLocalToWorld();

		Stuff::Point3D middle(line_of_sight);
		middle += (Stuff::Point3D)eyeSitePointer.GetCurrent()->GetLocalToWorld();
		middle *= 0.5f;

		line_of_sight.BuildTranslation(middle);
	}
	else
	{
		Vehicle::GetLineOfSight(line_of_sight);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Mech::GetMaxFlagsCarried() const
{
	if (m_MaxFlagsCarried == -1)
	{
		MWMission* mwmission = Cast_Object(MWMission*,MWMission::GetInstance());
		return (mwmission->GetMaxFlagsCarried());
	}

	return (m_MaxFlagsCarried);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mech::ToggleLightAmpLoad()
{
	Check_Object(this);

	if(DoesHaveLightAmp())
	{
		m_doesHaveLightAmp = false;
		SubtractTonage(1.0f);
	}
	else
	{
		if(DoesHaveAvailableTonage(1.0f))
		{
			m_doesHaveLightAmp = true;
			AddTonage(1.0f);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
	Mech::CreateCageDamageEffect(Site *site)
{
	Check_Object(this);

	Effect *effect = NULL;
	const GameModel *model = GetGameModel();
	Check_Object(model);

	if((site) && (model->m_cageDamageEffect != ResourceID::Null))
	{
		effect = CreateEffect(model->m_cageDamageEffect, site, true);
	}

	return effect;
}





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

void Mech::GetNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation)
{
	current_position = GetLocalToWorld();
	current_rotation = GetLocalToWorld();
}


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

void Mech::GetDeadReckonedNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation)
{

	current_position = correctionPosition;
	current_rotation = correctionAngle;

}

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

void Mech::ClearNetworkPosition()
{


	if (deadReckonCurve != NULL)
	{
		delete deadReckonCurve;
		deadReckonCurve = NULL;
	}
	deadReckonScale = 0.0f;
	deadReckonCurveTime = 0.0f;
	correctingPosition = false;

}

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

void Mech::SetNetworkCorretionPosition(Stuff::Point3D new_position, Stuff::YawPitchRoll new_rotation, Point3D velocity, Scalar vel_request, Scalar latency, Scalar rate)
{
	
	// p1 is our position
	// p2 is our position over the latency
	// p3 is the network position plus the latency
	// p4 is the network position plus the latency and the lerp time

	correctionAngle = new_rotation;
	correctionPosition = new_position;



	if (deadReckonCurve != NULL)
	{
		delete deadReckonCurve;
		deadReckonCurve = NULL;
	}
	deadReckonScale = 0.0f;
	deadReckonCurveTime = 0.0f;
	correctingPosition = false;


	
	Point3D p1,p2,p3,p4;
	p1 = GetLocalToWorld();


	Point3D distance_point;
	distance_point.Subtract(new_position,p1);

	Scalar distance = 0.0f;

	if (!Small_Enough(distance_point))
	{
		distance = distance_point.GetLengthSquared();
	}

	
	if (distance < 1600.0f)
	{

		
		startRotation = GetLocalToWorld();
		endRotation = new_rotation;

		startRotation.pitch = 0.0f;
		startRotation.roll = 0.0f;
		endRotation.pitch = 0.0f;
		endRotation.roll = 0.0f;

		//if (Close_Enough(p1, p2))
		//{
		//	SPEWALWAYS(("jerryeds", "NO MOVE-------------"));
		//	// we are in the same place, no correction needed.
		//	return;
		//}



		//Point3D local_vel(0.0f, 0.0f, currentSpeedMPS * (latency+rate));
		//p2.Multiply(local_vel, GetLocalToWorld());

		LinearMatrix4D network_update_position;
		network_update_position.BuildTranslation(new_position);
		network_update_position.BuildRotation(new_rotation);


		//Point3D net_update_vel(0.0f, 0.0f, speed * latency);
		//Point3D net_update_vel(0.0f, 0.0f, speed);
		//p3.Multiply(net_update_vel, network_update_position);

		//SPEWALWAYS(("jerryeds", "LATENCY : %f", latency));

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

		if (velocity.z >= 0.0f)
		{
			if (vel_request > currentSpeedMPS)
			{
				velocity.z += (model->acceleration * (latency+rate));
				Max_Clamp(velocity.z, vel_request);
			}
			else if (vel_request < currentSpeedMPS)
			{
				velocity.z -= (model->decceleration * (latency+rate));
				Min_Clamp(velocity.z, vel_request);
			}
		}
		else
		{
			if (vel_request < currentSpeedMPS)
			{
				velocity.z -= (model->acceleration * model->reverseAccelerationMultiplier * (latency+rate));
				Min_Clamp(velocity.z, vel_request);
			}
			else if (vel_request > currentSpeedMPS)
			{
				velocity.z += (model->decceleration * model->reverseDeccelerationMultiplier * (latency+rate));
				Max_Clamp(velocity.z, vel_request);
			}
		}



		Point3D net_update_vel;
		net_update_vel.Multiply(velocity, (latency+rate));
		p4.Multiply(net_update_vel, network_update_position);
		
		//p4 = new_position;
		
		p2.Lerp(p1,p4, 0.33f);
		p3.Lerp(p1,p4, 0.66f);


		deadReckonCurve = new CubicCurve(p1, p2, p3, p4);

		deadReckonCurveTime = 0.0f;
		deadReckonScale = (latency+rate);
		Min_Clamp(deadReckonScale,0.001f);

		//SPEWALWAYS(("jerryeds", "SET CURVE-------------"));
		//SPEWALWAYS(("jerryeds", "length : %f", deadReckonScale));
		//SPEWALWAYS(("jerryeds", "p1 : < %f : %f : %f > ", p1.x, p1.y, p1.z));
		//SPEWALWAYS(("jerryeds", "p2 : < %f : %f : %f > ", p2.x, p2.y, p2.z));
		//SPEWALWAYS(("jerryeds", "p3 : < %f : %f : %f > ", p3.x, p3.y, p3.z));
		//SPEWALWAYS(("jerryeds", "p4 : < %f : %f : %f > ", p4.x, p4.y, p4.z));
		//SPEWALWAYS(("jerryeds", "nt : < %f : %f : %f > \n", new_position.x, new_position.y, new_position.z));

	}
	else
	{
		//SPEWALWAYS(("jerryeds", "SET SNAP-------------"));
		correctingPosition = true;
		
	}
	

}

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

bool Mech::GetNetworkAdjustment(Stuff::Scalar time_slice, Point3D &adjustment_position, Stuff::YawPitchRoll &adjustment_rotation)
{
	
	adjustment_position = Point3D::Identity;
	adjustment_rotation = YawPitchRoll::Identity;


	if (correctingPosition)
	{
		correctingPosition = false;
		adjustment_position = correctionPosition;
		adjustment_rotation = correctionAngle;
		//SPEWALWAYS(("jerryeds", "SNAP : %f : < %f : %f : %f > \n", deadReckonCurveTime, adjustment_position.x, adjustment_position.y, adjustment_position.z));
	
		return true;
	}


	if (deadReckonCurve == NULL)
	{
		//SPEWALWAYS(("jerryeds", "NO RECKON"));
		return false;
	}


	//SPEWALWAYS(("jerryeds", "CURVE RECKON"));

	deadReckonCurveTime += (time_slice / deadReckonScale);
	Max_Clamp(deadReckonCurveTime, 1.0f);

	Vector3D velocity;
	deadReckonCurve->Evaluate(deadReckonCurveTime, &adjustment_position, &velocity);
	
	
	//if (Close_Enough(second_position, adjustment_position))
	//{
		//twice as fast...
		Scalar rot_time = deadReckonCurveTime * 2.0f;
		Max_Clamp(rot_time, 1.0f);
		adjustment_rotation.yaw.Lerp(startRotation.yaw, endRotation.yaw, rot_time);
	//}
	//else
	//{
	//	YawPitchRange ypr;
	//	ypr = velocity;
	//	adjustment_rotation.yaw = ypr.yaw;
	//}

	//SPEWALWAYS(("jerryeds", "v :  < %f : %f : %f >", velocity.x, velocity.y, velocity.z));
	//SPEWALWAYS(("jerryeds", "r :  < %f : %f : %f >", ypr.yaw.angle*Degrees_Per_Radian, ypr.pitch.angle*Degrees_Per_Radian, ypr.range));
	//SPEWALWAYS(("jerryeds", "r :  < %f : %f : %f >", adjustment_rotation.yaw.angle*Degrees_Per_Radian, adjustment_rotation.pitch.angle*Degrees_Per_Radian, adjustment_rotation.roll*Degrees_Per_Radian));
	

	if (deadReckonCurveTime == 1.0f)
	{
		ClearNetworkPosition();
	}

	

	
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Mech::GetHeatEffic()
{
	Check_Object(this);
	Check_Object(m_heatManager);
// MSL 5.04 0.08 changed to 0.04 due to Head Sink Eff change
//	Scalar heat_dissapation = (m_numHeatSinks + 10) * 0.08f;
//	Scalar heat_dissapation = (m_numHeatSinks + 10) * 0.04f;
	Scalar heat_dissapation = ((m_numHeatSinks + 10) * 2) * 0.04f;
	Scalar heat_add = 0.0f;
	Subsystem *subsystem;
	ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
	while((subsystem = iterator.ReadAndNext()) != NULL)
	{
		if(subsystem->IsDerivedFrom(Weapon::DefaultData))
		{
			Weapon *weapon = Cast_Object(Weapon *, subsystem);
			Check_Object(weapon);
			const Weapon::GameModel *weapon_model = weapon->GetGameModel();
			Check_Object(weapon_model);
//			heat_add += (weapon_model->heat * 2) * (10 / (weapon_model->reloadTime + 1.0f));
			heat_add += (weapon_model->heat * 2);
		}
	}
	
	heat_dissapation *= 20;
// MSL 5.04 Modified Heat Effic bar
	int value = 100;
	if(!Small_Enough(heat_add))
		value = (int)(((100.0 + (((heat_dissapation - heat_add)/heat_add) * 100.0)) / 240.0) * 100.0);
//	int value = 100;
//	if(!Small_Enough(heat_add))
//		value = (int)(100 + (((heat_dissapation - heat_add)/heat_add) * 100));
//	int value = (int)(heat_dissapation - heat_add);
//	value *= 10;
	Clamp(value, 0, 100);
	return value;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Mech::GetAlignment() const
{
	if ((m_AI != 0) &&
		(isPlayerVehicle == false))
	{
		int align(0);
		if (m_AI->GetLeaderAlignment(align) == true)
		{
			return (align);
		}
	}

	if (teamNumber < MWApplication::No_Team)
	{
		if (MWApplication::GetInstance()->teams[teamNumber] != 0)
		{
			Team* team = MWApplication::GetInstance()->teams[teamNumber]->GetCurrent();
			if (team != 0)
			{
				return (team->GetTeamAlignment() + Team1);
			}
		}

		return (teamNumber + Team1);
	}

	if (MWApplication::GetAlignmentSchema() == MWApplication::MP_NON_TEAMPLAY)
	{
		if ((m_AI != 0) &&
			(isPlayerVehicle == false))
		{
			return (objectID + 100);
		}

		return (teamNumber + MWApplication::No_Team + replicatorID.connectionID);
	}

	return (MWObject::GetAlignment());
}

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

void Mech::NullArms()
{
	if (armsNulled == false)
	{
		armsNulled = true;
		armBlanderizer.FadeToNewDampen(1.0f, 0.2f);
		armReNullTime = (Stuff::Scalar)gos_GetElapsedTime() + arm_re_null_time;
	}
	else
	{
		if (armReNullTime != 0)
		{
			armReNullTime = (Stuff::Scalar)gos_GetElapsedTime() + arm_re_null_time;
		}
	}
}

void
	Mech::NotifyFired(const Adept::Entity::CollisionQuery& query)
{
	NullArms();

	Vehicle::NotifyFired(query);
}



void MechWarrior4::MechSecurityCheckStop()
{
	_asm
	{
		nop
	}	
}

int Mech::GetJumpJetState() const
{
    JumpJet *jump_jet = ((Mech*)this)->GetJumpJet();

	if (jump_jet) {
        if (jump_jet->IsDestroyed())
            return 0; // destroyed
        else
		    return +1; // not destroyed & attached
	} else {
		return -1; // no jump jet
	}
}

void Mech::ClearInterestings()
{
    for(int i = 0; i < sizeof(m_Others) / sizeof(m_Others[0]); i++)
    {
        m_Others[i].Clear();
    }
}

Mech::CMechOther::CMechOther()
    : m_fTimeStart(0.0f), m_fTimeLast(0.0f)
{
}

void Mech::CMechOther::Clear()
{
	while (GetCurrent() != NULL)
	{
        Remove();
    }
    m_fTimeStart = m_fTimeLast = GetMissionTime();
}

Stuff::Scalar Mech::CMechOther::GetMissionTime()
{
    if (MWMission::GetInstance()) {
        // to check the case of MechLab...Mech::CommonCreation...Clear
        MWMission* mission = Cast_Object(MWMission*, MWMission::GetInstance());
        if (mission) {
            return mission->GetMissionTime();
        }
    }

    return 0.0f;
}

Mech* Mech::CMechOther::Get(Stuff::Scalar& fTime/* = *(Stuff::Scalar*)NULL*/)
{
    if (&fTime) {
        fTime = GetMissionTime() - m_fTimeLast;
    }

    return GetCurrent();
}

void Mech::CMechOther::Set(Entity* pMech)
{
    Check_Object(pMech);

    if (pMech->IsDerivedFrom(Mech::DefaultData)) {
        m_fTimeLast = GetMissionTime();

        Mech* pOld = GetCurrent();
        if (pOld != pMech) {
	        while (GetCurrent() != NULL)
	        {
                Remove();
            }
            Add(Cast_Pointer(Mech*, pMech));
            m_fTimeStart = m_fTimeLast;
        }
    } else {
        //Clear();
    }
}

void Mech_CheckDamage(Replicator* pVictim, Replicator* pInflictor, bool bDeath/* = false*/)
{
    if (pVictim && pInflictor) {
        if (pVictim->IsDerivedFrom(Mech::DefaultData) && pInflictor->IsDerivedFrom(Mech::DefaultData)) {
            Mech* pMechVictim = Cast_Pointer(Mech*, pVictim);
            Mech* pMechInflictor = Cast_Pointer(Mech*, pInflictor);
            if (bDeath) {
                pMechVictim->m_Others[1].Set(pMechInflictor);
            } else if (pMechVictim != pMechInflictor) {
                if (!pMechVictim->IsDestroyed() && !pMechInflictor->IsDestroyed()) {
                    pMechInflictor->m_Others[0].Set(pMechVictim);
                }
            }
        }
    }
}

void Mech::RepairForCOOP()
{
    RepairGimp();
    RepairWeapons();
    ReloadAmmoAll();
    ReloadCoolant();
}

void Mech::RepairGimp()
{
  if (IsGimped()) {
	SetNoGimp();

	animStateEngine->Reset();
	animStateEngine->RequestState(MechAnimationStateEngine::PowerDownState, Mech::NoBlend);

	//We also must make the legs have atleast one internal structure point
	MWInternalDamageObject *leg = internalDamageObjects.Find(InternalDamageObject::LeftLegZone);
	Check_Object(leg);
	Min_Clamp(leg->currentInternalDamage, 1.0f);
	leg = internalDamageObjects.Find(InternalDamageObject::RightLegZone);
	Check_Object(leg);
	Min_Clamp(leg->currentInternalDamage, 1.0f);
  }
}

void Mech::RepairWeapons()
{
#if 0
    ChainIteratorOf<Weapon*> weaponIterator(&weaponChain);

	Weapon *weapon;
	while((weapon = weaponIterator.ReadAndNext()) != NULL)
	{
		Check_Object(weapon);
		if(weapon->IsDestroyed())
		{
		}
	}
#endif
}

void Mech::ReloadAmmoAll()
{
    ChainIteratorOf<Weapon*> weaponIterator(&weaponChain);

	Weapon *weapon;
	while((weapon = weaponIterator.ReadAndNext()) != NULL)
	{
		Check_Object(weapon);
		if(weapon->HasFiredAmmo())
		{
			weapon->Reload();
		}
	}
}

void Mech::ReloadCoolant()
{
	if(m_heatManager->GetCoolant() < m_heatManager->GetMaxCoolant())
	{
		m_heatManager->AddCoolant(m_heatManager->GetMaxCoolant());
    }
}

