//===========================================================================//
// File:	bridge.cpp										
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/12/2000  AHF  Inital base class 
//===========================================================================//

#include "MW4Headers.hpp"

#include "cultural.hpp"
#include <adept\EntityManager.hpp>
#include "obstacle.hpp"
#include <adept\effect.hpp>
#include <adept\map.hpp>
#include <adept\damageobject.hpp>
#include "MWDamageObject.hpp"
#include <adept\application.hpp>
//#############################################################################
//###############################    Cultural      ############################
//#############################################################################

extern int g_nMR;

Cultural::ClassData* Cultural::DefaultData = NULL;

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

DWORD Cultural_Count = 0;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Cultural::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			CulturalClassID,
			"MechWarrior4::Cultural",
			Entity::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
		);
	Register_Object(DefaultData);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Cultural__GameModel,
		DeathEntityResource,
		deathEntityResource,
		ResourceID
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Cultural__GameModel,
		DestroyedEffectResource,
		destroyedEffectResource,
		ResourceID
	);
	DIRECT_GAME_MODEL_ATTRIBUTE(
		Cultural__GameModel,
		RammingDestroyedEffectResource,
		rammingDestroyedEffectResource,
		ResourceID
	);

	Cultural_Count = 0;
	AddStatistic("Culturals", "culturals", gos_DWORD, &Cultural_Count, 0);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Cultural* Cultural::Make(CreateMessage *message,ReplicatorID *base_id)
{
	Cultural *new_entity = new Cultural(DefaultData, message, base_id, NULL);
	Check_Object(new_entity);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Cultural::Cultural(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element):
  Entity(class_data, message, base_id, element)
{
	Check_Pointer(this);
	Check_Object(message);
	Set_Statistic(Cultural_Count, Cultural_Count+1);

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

	//remove when content fixed
	destroyableFlag = true;

	lastHitType = RammingDamageFromAheadType;


	delete executionState;
	executionState = NULL;


	if (Application::GetInstance()->applicationMode != Application::EditorMode)
	{

		NameTable *table = NameTable::GetInstance();

		ObjectID id = table->FindID(instanceName);

		table->SetName(id, NULL);


		instanceName = NULL;

	}

}


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

	--Cultural_Count; 
}

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



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

	Entity::Respawn(message);
	destroyableFlag = true;
	lastHitType = RammingDamageFromAheadType;
}

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

	if (IsDestroyed())
		return;

    if (g_nMR == 2)
        return;
  //
  //  Save off the direction we were hit from as we have to initiate some destruction phases (trees) with knowledge of where
  // we either were hit from, or run into from.
  //
  //
  //
  last_hit_normal = message->normal;

	lastHitType = message->typeOfDamage;
}


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


	if(!IsDestroyed())
	{

    SetDestroyedFlag(damage_mode);


		MW4AI::g_Rect4DHash->RemovePermRect (this);
		const GameModel *model = GetGameModel();
		Check_Object(model);
				
	//
	// Due to the network not being able to specify how something died, the trees need to do their differing 
	// reactions by whether they received a reactotohit message.
	//
    //
    // Here we need to kick off the destruction effect with a normal from the direction of the damage
    //
    switch (lastHitType)
    { 
    case BeamDamageType: 
    case MissileDamageType:  
    case ProjectileDamageType:
    case SplashDamageType:   
    case HeatDamageType:
			//
			// don't use default here or it will always play the hit effect which we only want
			// when shot.
			//
 //   default:
			CreateEffect(model->destroyedEffectResource, (Point3D)GetLocalToWorld(), last_hit_normal);
      break;
		/*
    case RammingDamageFromAboveType:
    case RammingDamageFromBelowType:
    case RammingDamageFromLeftType: 
    case RammingDamageFromRightType:
    case RammingDamageFromAheadType:
    case RammingDamageFromBehindType:
	case LavaDamageType;
	case AmmoFireDamageType:
    */
    }		

		CreateEffect(model->rammingDestroyedEffectResource, (Point3D)GetLocalToWorld(), last_hit_normal);
		Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
		if((death_entity) && (!m_deathEntity.GetCurrent()))
		{
			m_deathEntity.Remove();
			m_deathEntity.Add(death_entity);
		}
		

    RemoveFromExecution();

	}

	Entity::ReactToDestruction(damage_mode, damage_type);
}


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

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

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



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

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


	
	entity->SyncMatrices(true);

	return entity;
	
}


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

Entity *
	Cultural::CreateStaticHermitEntity(const Adept::ResourceID& entity_id)
{

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


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

	unsigned flags = HermitMode;

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

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



	return entity;

}

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

	//executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
	entityElement->SetAlwaysCullMode();
	EntityManager::GetInstance()->RemovePostCollisionExecution(this);
	RemoveCollision();

	SyncMatrices(true);

	
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Cultural::ReactToInternalDamage(int damage_mode)
{
  _asm nop;
}

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

	if (IsDestroyable() && !IsDestroyed())
	{
		ReactToHit(message,NULL);
        if (g_nMR != 2)
		ReactToDestruction( InternalDamageObject::DestructionDamageMode, message->typeOfDamage);
	}
}



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

bool
	Cultural::IsNeverExecuteState()
{
	return true;
}