#include <windows.h>
#include "sprite.h"

#define ATTACH_POINT_TOP				"p_top"
#define ATTACH_POINT_DOWN				"p_down"
#define ATTACH_POINT_HIT01				"p_hit_point01"
#define ATTACH_POINT_HIT02				"p_hit_point02"
#define ATTACH_POINT_BACK_STAFF			"p_back_staff"
#define ATTACH_POINT_BACK_SHIELD		"p_back_shield"
#define ATTACH_POINT_BACK_SWORD			"p_back_sword"
#define ATTACH_POINT_BACK_BOW			"p_back_bow"
#define ATTACH_POINT_BACK_GUN			"p_back_gun"
#define ATTACH_POINT_NAME_TITLE			"p_name_title"
#define ATTACH_POINT_HAND_SHIELD		"p_hand_shield"
#define ATTACH_POINT_LEFT_HAND			"p_left_hand"
#define ATTACH_POINT_RIGHT_HAND			"p_right_hand"
#define ATTACH_POINT_LEFT_FOOT			"p_left_foot"
#define ATTACH_POINT_RIGHT_FOOT			"p_right_foot"
#define ATTACH_POINT_LEFT_WEAPON		"p_left_weapon"
#define ATTACH_POINT_RIGHT_WEAPON		"p_right_weapon"
#define ATTACH_POINT_SHOOT				"p_shoot"
#define ATTACH_POINT_RIDE_01			"p_mount01"
#define ATTACH_POINT_RIDE_02			"p_mount02"
#define ATTACH_POINT_FREEZE_DOWN		"freeze_down"
#define ATTACH_POINT_FREEZE_HIT			"freeze_hit"

#define MOTION_STAND				"stand_idle01"
#define MOTION_IDLE01				"idle02"
#define MOTION_IDLE02				"idle03"
#define MOTION_IDLE03				"idle04"
#define MOTION_STAND_UP				"stand_up"
#define MOTION_RUN_FORWARD			"run_forward"
#define MOTION_RUN_BACK				"run_back"
#define MOTION_WALK_FORWARD			"walk_forward"
#define MOTION_WALK_BACK			"walk_back"
#define MOTION_SHUFFLE_LEFT			"shuffle_left"
#define MOTION_SHUFFLE_RIGHT		"shuffle_right"
#define MOTION_JUMP_UP				"jump_up"
#define MOTION_JUMP_LOOP			"jump_loop"
#define MOTION_JUMP_DOWN			"jump_down"
#define MOTION_JUMP_LENDRUN			"jump_lendrun"
#define MOTION_SWIM_IDLE			"swim_idle"
#define MOTION_SWIM_FORWARD			"swim_forward"
#define MOTION_SWIM_BACK			"swim_back"
#define MOTION_SWIM_LEFT			"swim_left"
#define MOTION_SWIM_RIGHT			"swim_right"
#define MOTION_DROWN				"drown"
#define MOTION_DEATH_DROWNED		"death_drowned"
#define MOTION_DEAD_WATER			"dead_water"
#define MOTION_UNARMED_IDLE			"unarmed_idle"
#define MOTION_UNARMED_ATTACK01		"unarmed_attack01"
#define MOTION_UNARMED_ATTACK02		"unarmed_attack02"
#define MOTION_UNARMED_ATTACK03		"unarmed_attack03"
#define MOTION_UNARMED_PARRY		"unarmed_parry"
#define MOTION_1H_IDLE				"1h_idle"
#define MOTION_1H_ATTACK01			"1h_attack01"
#define MOTION_1H_ATTACK02			"1h_attack02"
#define MOTION_1H_ATTACK03			"1h_attack03"
#define MOTION_1H_PIERCE01			"1h_pierce01"
#define MOTION_OH_PIERCE01			"oh_pierce01"
#define MOTION_OH_ATTACK01			"oh_attack01"
#define MOTION_1H_PARRY				"1h_parry"
#define MOTION_2H_IDLE				"2h_idle"
#define MOTION_2H_ATTACK01			"2h_attack01"
#define MOTION_2H_ATTACK02			"2h_attack02"
#define MOTION_2H_ATTACK03			"2h_attack03"
#define MOTION_2H_PARRY				"2h_parry"
#define MOTION_POLEARM_IDLE			"polearm_idle"
#define MOTION_POLEARM_ATTACK01		"polearm_attack01"
#define MOTION_POLEARM_ATTACK02		"polearm_attack02"
#define MOTION_POLEARM_ATTACK03		"polearm_attack03"
#define MOTION_POLEARM_PARRY		"polearm_parry"
#define MOTION_BOW_IDLE				"bow_idle"
#define MOTION_BOW_READY			"bow_ready"
#define MOTION_BOW_CHANNEL			"bow_channel"
#define MOTION_BOW_RELEASE			"bow_release"
#define MOTION_BOW_PARRY			"bow_parry"
#define MOTION_GUN_IDLE				"gun_idle"
#define MOTION_GUN_READY			"gun_ready"
#define MOTION_GUN_CHANNEL			"gun_channel"
#define MOTION_GUN_RELEASE			"gun_release"
#define MOTION_GUN_PARRY			"gun_parry"
#define MOTION_SHIELD_BLOCK			"shield_block"
#define MOTION_SHIELD_BASH			"shield_bash"
#define MOTION_CASTING_DELAY		"casting_delay"
#define MOTION_CAST01				"cast01"
#define MOTION_CAST02				"cast02"
#define MOTION_CONTINUOUS_CAST		"continuous_cast"
#define MOTION_1H_HOLSTER			"1h_weapon_holster"
#define MOTION_1H_UNHOLSTER			"1h_weapon_unholster"
#define MOTION_2H_HOLSTER			"2h_weapon_holster"
#define MOTION_2H_UNHOLSTER			"2h_weapon_unholster"
#define MOTION_DODGE				"dodge"
#define MOTION_HURT					"hurt"
#define MOTION_DEATH				"death"
#define MOTION_DEAD					"dead"
#define MOTION_REVIVE				"revive"
#define MOTION_DAZED				"dazed"
#define MOTION_SLUMBER				"slumber"
#define MOTION_KNOCKDOWN_START		"knockdown_start"
#define MOTION_KNOCKDOWN_IDLE		"knockdown_idle"
#define MOTION_KNOCKDOWN_END		"knockdown_end"
#define MOTION_KNOCKDOWN_RECOVER	"knockdown_recover"
#define MOTION_SIT					"sit"
#define MOTION_SIT_IDLE				"sit_idle"
#define MOTION_SLEEP_DOWN			"sleep_down"
#define MOTION_SLEEP_IDLE			"sleep_idle"
#define MOTION_SLEEP_UP				"sleep_up"
#define MOTION_CROUCH_DOWN			"croush_down"
#define MOTION_CROUCH_IDLE			"croush_idle"
#define MOTION_CROUCH_UP			"croush_up"
#define MOTION_DRINK				"drink"
#define MOTION_EAT					"eat"
#define MOTION_USE_ITEM				"use_item"
#define MOTION_SPEAK01				"emote_speak01"
#define MOTION_SPEAK02				"emote_speak02"
#define MOTION_HEAD_NOD				"emote_head_nod"
#define MOTION_HEAD_SHAKE			"emote_head_shake"
#define MOTION_LAUGH				"emote_laugh"
#define MOTION_ANGRY				"emote_angry"
#define MOTION_CRY					"emote_cry"
#define MOTION_APPROVAL				"emote_approval"
#define MOTION_VICTORY				"emote_victory"
#define MOTION_APPLAUSE				"emote_applause"
#define MOTION_SALUTE				"emote_salute"
#define MOTION_WAVE					"emote_wave"
#define MOTION_POINT				"emote_point"
#define MOTION_PROVOKE				"emote_provoke"
#define MOTION_BEG					"emote_beg"
#define MOTION_DANCE				"emote_dance"
#define MOTION_SURRENDER			"emote_surrender"
#define MOTION_SIGNATURE			"emote_signature"
#define MOTION_THREATEN				"emote_threaten"
#define MOTION_FISHING_CAST			"fishing_cast"
#define MOTION_FISHING_IDLE			"fishing_idle"
#define MOTION_FISHING_REEL			"fishing_reel"
#define MOTION_GATHERING_START		"gathering_start"
#define MOTION_GATHERING_IDLE		"gathering_idle"
#define MOTION_GATHERING_END		"gathering_end"
#define MOTION_MINING_START			"mining_start"
#define MOTION_MINING_IDLE			"mining_idle"
#define MOTION_MINING_END			"mining_end"
#define MOTION_CRAFTING_START		"crafting_start"
#define MOTION_CRAFTING_IDLE		"crafting_idle"
#define MOTION_CRAFTING_END			"crafting_end"
#define MOTION_EFFECT_APPEAR		"appear"
#define MOTION_EFFECT_IDLE			"idle"
#define MOTION_EFFECT_DISAPPEAR		"disappear"
#define MOTION_EFFECT_EXPLODE		"explode"

//-----------------------------------------------------------------------------
map<string, int>				g_motionMap;

//-----------------------------------------------------------------------------
CRuGlobalEventManager*			g_pRuGlobalEventManager = NULL;

set<IBaseSprite*>				IBaseSprite::s_containers;				// 
CRuFontType*					IBaseSprite::s_pFontType;				// 字型資料
CRuOptimalTerrain*				IBaseSprite::s_pRuTerrain;				// 地表資訊
CRuFusion_Mime_Template*		IBaseSprite::s_pRuMimeTemplate;
CRuFusion_Mime_Template*		IBaseSprite::s_pRuMimeTemplate_Deprecated;
//CRuGlobalEventManager*			IBaseSprite::s_pRuEventListener;		// 動作事件
int								IBaseSprite::s_mainPlayerId;

//-----------------------------------------------------------------------------
CRuGlobalEventManager::CRuGlobalEventManager()
{
	m_controllerFrame = ruNEW CRuEntity_Container_Impl();

	g_pRuGlobalEventManager = this;
}

//-----------------------------------------------------------------------------
CRuGlobalEventManager::~CRuGlobalEventManager()
{
	ruSAFE_RELEASE(m_controllerFrame);

	g_pRuGlobalEventManager = NULL;
}

//-----------------------------------------------------------------------------
void CRuGlobalEventManager::Update(REAL elapsedTime)
{
	// Chain update call to the controller container
	m_controllerFrame->Update( elapsedTime );
}

//-----------------------------------------------------------------------------
void CRuGlobalEventManager::AddEntity( CRuEntity* pRuEntity )
{
	m_controllerFrame->AddEntity( pRuEntity );
}

//-----------------------------------------------------------------------------
BOOL CRuGlobalEventManager::HandleEvent(CRuEntity *entity, INT32 eventID, INT32 eventParameter0, INT32 eventParameter1, const char *eventString, REAL eventDuration, void *userData)
{
	IBaseSprite* pSprite = (CRoleSprite*)userData;
	switch(eventID)
	{
	case ruENTITYEVENT_HIT:
		pSprite->MotionEvent( eventID );
		return TRUE;

	case ruENTITYEVENT_FOOTSTEP:
		{
			// Build a particle system or some such
			CRuController_ParticleSystem *psTest = ruNEW CRuController_ParticleSystem();
			psTest->SetParticleSystem(g_ruResourceManager->LoadEntity("model\\fx\\fx_fire.ros"));
			psTest->SetStartTime(0.1f);
			psTest->SetDuration(eventDuration);
			psTest->SetLoopTime(0.0f);
			psTest->SetTarget(entity);
			psTest->Update(0.0f);
			psTest->SetSelfDestructTimer(eventDuration + 2.0f);

			// Add controller to the container frame
			m_controllerFrame->AddEntity(psTest);
		}
		return TRUE;

	case ruENTITYEVENT_GHOSTTRAIL:
		{
			CRuController_GhostTrail *gtController = ruNEW CRuController_GhostTrail();
			gtController->SetInterval(0.001f);
			gtController->SetMaxAge(eventDuration);
			gtController->SetFadeCoefficients(0.0f, 0.0f, 1.0f);
			gtController->SetMaxSegments(128);
			gtController->SetTrailAnchors("effect01", "effect02");
			gtController->SetTrailTextureName("texture\\fx\\weapon_trail\\blade_flash");
			gtController->SetTarget(entity);

			gtController->SetActiveDuration(eventDuration);
			gtController->SetFadeOutDuration(0.5f);

			gtController->SetStartTime(0.0f);
			gtController->SetDuration(eventDuration + 0.5f);
			gtController->SetLoopTime(0.0f);
			gtController->SetSelfDestructTimer(eventDuration + 2.0f);

			// Add controller to the container frame
			m_controllerFrame->AddEntity(gtController);
		}
		return TRUE;

	case ruENTITYEVENT_HOLSTER:
		pSprite->MotionEvent( eventID );
		return TRUE;

	case ruENTITYEVENT_UNHOLSTER:
		pSprite->MotionEvent( eventID );
		return TRUE;
	}

	return FALSE;
}

//-----------------------------------------------------------------------------
void IBaseSprite::Initialize()
{
	s_containers.clear();	
	//s_pRuEventListener = new CRuGlobalEventManager;

	// 設定傀儡控制物件
	s_pRuMimeTemplate	= ruNEW CRuFusion_Mime_Template();
	s_pRuMimeTemplate_Deprecated = ruNEW CRuFusion_Mime_Template();
	if ( s_pRuMimeTemplate_Deprecated ) 
	{
		s_pRuMimeTemplate_Deprecated->InitializeDeprecatedBoneScalers();
	}

	s_pFontType = NULL;
	s_pRuTerrain = NULL;
	s_mainPlayerId = 0;

	g_motionMap.clear();
	g_motionMap.insert(make_pair(MOTION_STAND,				eMotion_Stand));
	g_motionMap.insert(make_pair(MOTION_IDLE01,				eMotion_Stand_Idle01));	
	g_motionMap.insert(make_pair(MOTION_IDLE02,				eMotion_Stand_Idle02));
	g_motionMap.insert(make_pair(MOTION_IDLE03,				eMotion_Stand_Idle03));
	g_motionMap.insert(make_pair(MOTION_STAND_UP,			eMotion_Stand_Up));
	g_motionMap.insert(make_pair(MOTION_RUN_FORWARD,		eMotion_Run_Forward));
	g_motionMap.insert(make_pair(MOTION_RUN_BACK,			eMotion_Run_Back));
	g_motionMap.insert(make_pair(MOTION_WALK_FORWARD,		eMotion_Walk_Forward));
	g_motionMap.insert(make_pair(MOTION_WALK_BACK,			eMotion_Walk_Back));
	g_motionMap.insert(make_pair(MOTION_SHUFFLE_LEFT,		eMotion_Shuffle_Left));
	g_motionMap.insert(make_pair(MOTION_SHUFFLE_RIGHT,		eMotion_Shuffle_Right));
	g_motionMap.insert(make_pair(MOTION_SWIM_IDLE,			eMotion_Swim_Idle));
	g_motionMap.insert(make_pair(MOTION_SWIM_FORWARD,		eMotion_Swim_Forward));
	g_motionMap.insert(make_pair(MOTION_SWIM_BACK,			eMotion_Swim_Back));
	g_motionMap.insert(make_pair(MOTION_SWIM_LEFT,			eMotion_Swim_Left));
	g_motionMap.insert(make_pair(MOTION_SWIM_RIGHT,			eMotion_Swim_Right));
	g_motionMap.insert(make_pair(MOTION_DROWN,				eMotion_Drown));
	g_motionMap.insert(make_pair(MOTION_DEATH_DROWNED,		eMotion_Death_Drowned));
	g_motionMap.insert(make_pair(MOTION_DEAD_WATER,			eMotion_Dead_Water));
	g_motionMap.insert(make_pair(MOTION_JUMP_UP,			eMotion_Jump_Up));
	g_motionMap.insert(make_pair(MOTION_JUMP_LOOP,			eMotion_Jump_Loop));
	g_motionMap.insert(make_pair(MOTION_JUMP_DOWN,			eMotion_Jump_Down));
	g_motionMap.insert(make_pair(MOTION_JUMP_LENDRUN,		eMotion_Jump_Lendrun));
	g_motionMap.insert(make_pair(MOTION_UNARMED_IDLE,		eMotion_Unarmed_Idle));
	g_motionMap.insert(make_pair(MOTION_UNARMED_ATTACK01,	eMotion_Unarmed_Attack01));
	g_motionMap.insert(make_pair(MOTION_UNARMED_ATTACK02,	eMotion_Unarmed_Attack02));
	g_motionMap.insert(make_pair(MOTION_UNARMED_ATTACK03,	eMotion_Unarmed_Attack03));
	g_motionMap.insert(make_pair(MOTION_UNARMED_PARRY,		eMotion_Unarmed_Parry));
	g_motionMap.insert(make_pair(MOTION_1H_IDLE,			eMotion_1H_Idle));
	g_motionMap.insert(make_pair(MOTION_1H_ATTACK01,		eMotion_1H_Attack01));
	g_motionMap.insert(make_pair(MOTION_1H_ATTACK02,		eMotion_1H_Attack02));
	g_motionMap.insert(make_pair(MOTION_1H_ATTACK03,		eMotion_1H_Attack03));
	g_motionMap.insert(make_pair(MOTION_1H_PIERCE01,		eMotion_1H_Pierce01));
	g_motionMap.insert(make_pair(MOTION_OH_PIERCE01,		eMotion_OH_Pierce01));
	g_motionMap.insert(make_pair(MOTION_OH_ATTACK01,		eMotion_OH_Attack01));
	g_motionMap.insert(make_pair(MOTION_1H_PARRY,			eMotion_1H_Parry));
	g_motionMap.insert(make_pair(MOTION_2H_IDLE,			eMotion_2H_Idle));
	g_motionMap.insert(make_pair(MOTION_2H_ATTACK01,		eMotion_2H_Attack01));
	g_motionMap.insert(make_pair(MOTION_2H_ATTACK02,		eMotion_2H_Attack02));
	g_motionMap.insert(make_pair(MOTION_2H_ATTACK03,		eMotion_2H_Attack03));
	g_motionMap.insert(make_pair(MOTION_2H_PARRY,			eMotion_2H_Parry));	
	g_motionMap.insert(make_pair(MOTION_POLEARM_IDLE,		eMotion_Polearm_Idle));
	g_motionMap.insert(make_pair(MOTION_POLEARM_ATTACK01,	eMotion_Polearm_Attack01));
	g_motionMap.insert(make_pair(MOTION_POLEARM_ATTACK02,	eMotion_Polearm_Attack02));
	g_motionMap.insert(make_pair(MOTION_POLEARM_ATTACK03,	eMotion_Polearm_Attack03));
	g_motionMap.insert(make_pair(MOTION_POLEARM_PARRY,		eMotion_Polearm_Parry));
	g_motionMap.insert(make_pair(MOTION_BOW_IDLE,			eMotion_Bow_Idle));
	g_motionMap.insert(make_pair(MOTION_BOW_READY,			eMotion_Bow_Ready));
	g_motionMap.insert(make_pair(MOTION_BOW_CHANNEL,		eMotion_Bow_Channel));
	g_motionMap.insert(make_pair(MOTION_BOW_RELEASE,		eMotion_Bow_Release));
	g_motionMap.insert(make_pair(MOTION_BOW_PARRY,			eMotion_Bow_Parry));
	g_motionMap.insert(make_pair(MOTION_GUN_IDLE,			eMotion_Gun_Idle));
	g_motionMap.insert(make_pair(MOTION_GUN_READY,			eMotion_Gun_Ready));
	g_motionMap.insert(make_pair(MOTION_GUN_CHANNEL,		eMotion_Gun_Channel));
	g_motionMap.insert(make_pair(MOTION_GUN_RELEASE,		eMotion_Gun_Release));
	g_motionMap.insert(make_pair(MOTION_GUN_PARRY,			eMotion_Gun_Parry));
	g_motionMap.insert(make_pair(MOTION_SHIELD_BLOCK,		eMotion_Shield_Block));
	g_motionMap.insert(make_pair(MOTION_SHIELD_BASH,		eMotion_Shield_Bash));
	g_motionMap.insert(make_pair(MOTION_CASTING_DELAY,		eMotion_Casting_Delay));
	g_motionMap.insert(make_pair(MOTION_CAST01,				eMotion_Cast_01));
	g_motionMap.insert(make_pair(MOTION_CAST02,				eMotion_Cast_02));
	g_motionMap.insert(make_pair(MOTION_CONTINUOUS_CAST,	eMotion_Continuous_Cast));
	g_motionMap.insert(make_pair(MOTION_1H_HOLSTER,			eMotion_1H_Holster));
	g_motionMap.insert(make_pair(MOTION_1H_UNHOLSTER,		eMotion_1H_Unholster));
	g_motionMap.insert(make_pair(MOTION_2H_HOLSTER,			eMotion_2H_Holster));
	g_motionMap.insert(make_pair(MOTION_2H_UNHOLSTER,		eMotion_2H_Unholster));
	g_motionMap.insert(make_pair(MOTION_DODGE,				eMotion_Dodge));
	g_motionMap.insert(make_pair(MOTION_HURT,				eMotion_Hurt));
	g_motionMap.insert(make_pair(MOTION_DEATH,				eMotion_Death));
	g_motionMap.insert(make_pair(MOTION_DEAD,				eMotion_Dead));
	g_motionMap.insert(make_pair(MOTION_REVIVE,				eMotion_Revive));
	g_motionMap.insert(make_pair(MOTION_DAZED,				eMotion_Dazed));
	g_motionMap.insert(make_pair(MOTION_SLUMBER,			eMotion_Slumber));
	g_motionMap.insert(make_pair(MOTION_KNOCKDOWN_START,	eMotion_Knockdown_Start));
	g_motionMap.insert(make_pair(MOTION_KNOCKDOWN_IDLE,		eMotion_Knockdown_Idle));
	g_motionMap.insert(make_pair(MOTION_KNOCKDOWN_END,		eMotion_Knockdown_End));
	g_motionMap.insert(make_pair(MOTION_KNOCKDOWN_RECOVER,	eMotion_Knockdown_Recover));
	g_motionMap.insert(make_pair(MOTION_SIT,				eMotion_Sit));
	g_motionMap.insert(make_pair(MOTION_SIT_IDLE,			eMotion_Sit_Idle));
	g_motionMap.insert(make_pair(MOTION_SLEEP_DOWN,			eMotion_Sleep_Down));
	g_motionMap.insert(make_pair(MOTION_SLEEP_IDLE,			eMotion_Sleep_Idle));
	g_motionMap.insert(make_pair(MOTION_SLEEP_UP,			eMotion_Sleep_Up));
	g_motionMap.insert(make_pair(MOTION_CROUCH_DOWN,		eMotion_Crouch_Down));
	g_motionMap.insert(make_pair(MOTION_CROUCH_IDLE,		eMotion_Crouch_Idle));
	g_motionMap.insert(make_pair(MOTION_CROUCH_UP,			eMotion_Crouch_Up));
	g_motionMap.insert(make_pair(MOTION_DRINK,				eMotion_Drink));
	g_motionMap.insert(make_pair(MOTION_EAT,				eMotion_Eat));
	g_motionMap.insert(make_pair(MOTION_USE_ITEM,			eMotion_Use_Item));
	g_motionMap.insert(make_pair(MOTION_SPEAK01,			eMotion_Speak01));
	g_motionMap.insert(make_pair(MOTION_SPEAK02,			eMotion_Speak02));
	g_motionMap.insert(make_pair(MOTION_HEAD_NOD,			eMotion_Head_Nod));
	g_motionMap.insert(make_pair(MOTION_HEAD_SHAKE,			eMotion_Head_Shake));
	g_motionMap.insert(make_pair(MOTION_LAUGH,				eMotion_Laugh));
	g_motionMap.insert(make_pair(MOTION_ANGRY,				eMotion_Angry));
	g_motionMap.insert(make_pair(MOTION_CRY,				eMotion_Cry));
	g_motionMap.insert(make_pair(MOTION_APPROVAL,			eMotion_Approval));
	g_motionMap.insert(make_pair(MOTION_VICTORY,			eMotion_Victory));
	g_motionMap.insert(make_pair(MOTION_APPLAUSE,			eMotion_Applause));
	g_motionMap.insert(make_pair(MOTION_SALUTE,				eMotion_Salute));
	g_motionMap.insert(make_pair(MOTION_WAVE,				eMotion_Wave));
	g_motionMap.insert(make_pair(MOTION_POINT,				eMotion_Point));
	g_motionMap.insert(make_pair(MOTION_PROVOKE,			eMotion_Provoke));
	g_motionMap.insert(make_pair(MOTION_BEG,				eMotion_Beg));
	g_motionMap.insert(make_pair(MOTION_DANCE,				eMotion_Dance));
	g_motionMap.insert(make_pair(MOTION_SURRENDER,			eMotion_Surrender));
	g_motionMap.insert(make_pair(MOTION_SIGNATURE,			eMotion_Signature));
	g_motionMap.insert(make_pair(MOTION_THREATEN,			eMotion_Threaten));
	g_motionMap.insert(make_pair(MOTION_EFFECT_APPEAR,		eMotion_Effect_Appear));
	g_motionMap.insert(make_pair(MOTION_EFFECT_IDLE,		eMotion_Effect_Idle));
	g_motionMap.insert(make_pair(MOTION_EFFECT_DISAPPEAR,	eMotion_Effect_Disappear));
	g_motionMap.insert(make_pair(MOTION_EFFECT_EXPLODE,		eMotion_Effect_Explode));
}

//-----------------------------------------------------------------------------
void IBaseSprite::Shutdown()
{
	set<IBaseSprite*>::iterator iter;
	while ( (iter = s_containers.begin()) != s_containers.end() )
		delete *iter;

	/*
	if ( s_pRuEventListener )
	{
		delete s_pRuEventListener;
		s_pRuEventListener = NULL;
	}
	*/

	s_pFontType = NULL;
	s_pRuTerrain = NULL;
	s_mainPlayerId = 0;
}

//-----------------------------------------------------------------------------
void IBaseSprite::UpdateAll( float elapsedTime )
{
	//elapsedTime *= 2.0f;

	//s_pRuEventListener->Update( elapsedTime );

	set<IBaseSprite*>::iterator iter = s_containers.begin();
	while ( iter != s_containers.end() )
	{
		set<IBaseSprite*>::iterator next_iter = iter;
		next_iter++;

		if ( (*iter)->IsDestruct() && (*iter)->GetDestructTime() < elapsedTime )
			delete *iter;
		else
		{
			if ( (*iter)->GetPauseTime() < 0.000001f )
				(*iter)->Update( elapsedTime );
			else
				(*iter)->SetPauseTime( (*iter)->GetPauseTime() - elapsedTime );
		}

		iter = next_iter;
	}
}

//-----------------------------------------------------------------------------
void IBaseSprite::RenderAll()
{
	for ( set<IBaseSprite*>::iterator iter = s_containers.begin(); iter != s_containers.end(); iter++ )
	{
		if ( (*iter)->GetPauseTime() < 0.000001f && (*iter)->IsVisible() )
			(*iter)->Render();
	}
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetFontType( CRuFontType* pFontType )
{
	s_pFontType = pFontType;
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetRuTerrain( CRuOptimalTerrain* pRuTerrain )
{
	s_pRuTerrain = pRuTerrain;
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetMainPlayerId( int id )
{
	s_mainPlayerId = id;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::CheckedSpriteIsLife( IBaseSprite* pBaseSprite )
{
	return ( s_containers.find( pBaseSprite ) != s_containers.end() );
}

//-----------------------------------------------------------------------------
const char* IBaseSprite::GetAttachPointName( int point )
{
	switch ( point )
	{
	case eAttach_Top:
		return ATTACH_POINT_TOP;

	case eAttach_Down:
		return ATTACH_POINT_DOWN;

	case eAttach_Hit_Point1:
		return ATTACH_POINT_HIT01;

	case eAttach_Hit_Point2:
		return ATTACH_POINT_HIT02;

	case eAttach_Back_Polearm:
		return ATTACH_POINT_BACK_STAFF;

	case eAttach_Back_Shield:
		return ATTACH_POINT_BACK_SHIELD;

	case eAttach_Back_Sword:
		return ATTACH_POINT_BACK_SWORD;

	case eAttach_Name_Title:
		return ATTACH_POINT_NAME_TITLE;

	case eAttach_Hand_Shield:
		return ATTACH_POINT_HAND_SHIELD;

	case eAttach_Left_Hand:
		return ATTACH_POINT_LEFT_HAND;

	case eAttach_Right_Hand:
		return ATTACH_POINT_RIGHT_HAND;

	case eAttach_Left_Foot:
		return ATTACH_POINT_LEFT_FOOT;

	case eAttach_Right_Foot:
		return ATTACH_POINT_RIGHT_FOOT;

	case eAttach_Left_Weapon:
		return ATTACH_POINT_LEFT_WEAPON;

	case eAttach_Right_Weapon:
		return ATTACH_POINT_RIGHT_WEAPON;

	case eAttach_Shoot:
		return ATTACH_POINT_SHOOT;

	case eAttach_Ride_01:
		return ATTACH_POINT_RIDE_01;

	case eAttach_Ride_02:
		return ATTACH_POINT_RIDE_02;

	case eAttach_Freeze_Down:
		return ATTACH_POINT_FREEZE_DOWN;
	}
	return "";
}

//-----------------------------------------------------------------------------
int	IBaseSprite::GetAttachPointEnum( const char* point )
{
	if ( point == NULL || strlen(point) < 1 )
		return eAttach_Null;

	if ( strcmp(point, ATTACH_POINT_TOP) == 0 )
		return eAttach_Top;
	else if ( strcmp(point, ATTACH_POINT_DOWN) == 0 )
		return eAttach_Down;
	else if ( strcmp(point, ATTACH_POINT_HIT01) == 0 )
		return eAttach_Hit_Point1;
	else if ( strcmp(point, ATTACH_POINT_HIT02) == 0 )
		return eAttach_Hit_Point2;
	else if ( strcmp(point, ATTACH_POINT_BACK_STAFF) == 0 )
		return eAttach_Back_Polearm;
	else if ( strcmp(point, ATTACH_POINT_BACK_SHIELD) == 0 )
		return eAttach_Back_Shield;
	else if ( strcmp(point, ATTACH_POINT_BACK_SWORD) == 0 )
		return eAttach_Back_Sword;
	else if ( strcmp(point, ATTACH_POINT_NAME_TITLE) == 0 )
		return eAttach_Name_Title;
	else if ( strcmp(point, ATTACH_POINT_HAND_SHIELD) == 0 )
		return eAttach_Hand_Shield;
	else if ( strcmp(point, ATTACH_POINT_LEFT_HAND) == 0 )
		return eAttach_Left_Hand;
	else if ( strcmp(point, ATTACH_POINT_RIGHT_HAND) == 0 )
		return eAttach_Right_Hand;
	else if ( strcmp(point, ATTACH_POINT_LEFT_FOOT) == 0 )
		return eAttach_Left_Foot;
	else if ( strcmp(point, ATTACH_POINT_RIGHT_FOOT) == 0 )
		return eAttach_Right_Foot;
	else if ( strcmp(point, ATTACH_POINT_LEFT_WEAPON) == 0 )
		return eAttach_Left_Weapon;
	else if ( strcmp(point, ATTACH_POINT_RIGHT_WEAPON) == 0 )
		return eAttach_Right_Weapon;
	else if ( strcmp(point, ATTACH_POINT_FREEZE_DOWN) == 0 )
		return eAttach_Freeze_Down;
	else if ( strcmp(point, ATTACH_POINT_RIDE_01) == 0)
		return eAttach_Ride_01;
	else if ( strcmp(point, ATTACH_POINT_RIDE_02) == 0)
		return eAttach_Ride_02;

	return eAttach_Null;
}

//-----------------------------------------------------------------------------
const char* IBaseSprite::GetMotionName( int motion )
{
	switch ( motion )
	{
	case eMotion_Stand:
		return MOTION_STAND;

	case eMotion_Stand_Idle01:
		return MOTION_IDLE01;

	case eMotion_Stand_Idle02:
		return MOTION_IDLE02;

	case eMotion_Stand_Idle03:
		return MOTION_IDLE03;	

	case eMotion_Run_Forward:
		return MOTION_RUN_FORWARD;

	case eMotion_Run_Back:
		return MOTION_RUN_BACK;

	case eMotion_Walk_Forward:
		return MOTION_WALK_FORWARD;

	case eMotion_Walk_Back:
		return MOTION_WALK_BACK;

	case eMotion_Swim_Idle:
		return MOTION_SWIM_IDLE;

	case eMotion_Swim_Forward:
		return MOTION_SWIM_FORWARD;

	case eMotion_Swim_Back:
		return MOTION_SWIM_BACK;

	case eMotion_Swim_Left:
		return MOTION_SWIM_LEFT;

	case eMotion_Swim_Right:
		return MOTION_SWIM_RIGHT;

	case eMotion_Drown:
		return MOTION_DROWN;

	case eMotion_Death_Drowned:
		return MOTION_DEATH_DROWNED;

	case eMotion_Dead_Water:
		return MOTION_DEAD_WATER;

	case eMotion_Jump_Up:
		return MOTION_JUMP_UP;

	case eMotion_Jump_Loop:
		return MOTION_JUMP_LOOP;

	case eMotion_Jump_Down:
		return MOTION_JUMP_DOWN;

	case eMotion_Jump_Lendrun:
		return MOTION_JUMP_LENDRUN;

	case eMotion_Unarmed_Idle:
		return MOTION_UNARMED_IDLE;

	case eMotion_Unarmed_Attack01:		
		return MOTION_UNARMED_ATTACK01;

	case eMotion_Unarmed_Attack02:
		return MOTION_UNARMED_ATTACK02;

	case eMotion_Unarmed_Attack03:
		return MOTION_UNARMED_ATTACK03;

	case eMotion_Unarmed_Parry:
		return MOTION_UNARMED_PARRY;

	case eMotion_1H_Idle:
		return MOTION_1H_IDLE;

	case eMotion_1H_Attack01:
		return MOTION_1H_ATTACK01;

	case eMotion_1H_Attack02:
		return MOTION_1H_ATTACK02;

	case eMotion_1H_Attack03:
		return MOTION_1H_ATTACK03;

	case eMotion_1H_Pierce01:
		return MOTION_1H_PIERCE01;

	case eMotion_OH_Attack01:
		return MOTION_OH_ATTACK01;

	case eMotion_OH_Pierce01:
		return MOTION_OH_PIERCE01;

	case eMotion_1H_Parry:
		return MOTION_1H_PARRY;

	case eMotion_2H_Idle:
		return MOTION_2H_IDLE;

	case eMotion_2H_Attack01:
		return MOTION_2H_ATTACK01;

	case eMotion_2H_Attack02:
		return MOTION_2H_ATTACK02;

	case eMotion_2H_Attack03:
		return MOTION_2H_ATTACK03;

	case eMotion_2H_Parry:
		return MOTION_2H_PARRY;

	case eMotion_Polearm_Idle:
		return MOTION_POLEARM_IDLE;

	case eMotion_Polearm_Attack01:
		return MOTION_POLEARM_ATTACK01;

	case eMotion_Polearm_Attack02:
		return MOTION_POLEARM_ATTACK02;

	case eMotion_Polearm_Attack03:
		return MOTION_POLEARM_ATTACK03;

	case eMotion_Polearm_Parry:
		return MOTION_POLEARM_PARRY;

	case eMotion_Bow_Idle:
		return MOTION_BOW_IDLE;

	case eMotion_Bow_Ready:
		return MOTION_BOW_READY;

	case eMotion_Bow_Channel:
		return MOTION_BOW_CHANNEL;

	case eMotion_Bow_Release:
		return MOTION_BOW_RELEASE;

	case eMotion_Bow_Parry:
		return MOTION_BOW_PARRY;

	case eMotion_Gun_Idle:
		return MOTION_GUN_IDLE;

	case eMotion_Gun_Ready:
		return MOTION_GUN_READY;

	case eMotion_Gun_Channel:
		return MOTION_GUN_CHANNEL;

	case eMotion_Gun_Release:
		return MOTION_GUN_RELEASE;

	case eMotion_Gun_Parry:
		return MOTION_GUN_PARRY;

	case eMotion_Shield_Block:
		return MOTION_SHIELD_BLOCK;

	case eMotion_Shield_Bash:
		return MOTION_SHIELD_BASH;

	case eMotion_Casting_Delay:
		return MOTION_CASTING_DELAY;

	case eMotion_Cast_01:
		return MOTION_CAST01;

	case eMotion_Cast_02:
		return MOTION_CAST02;

	case eMotion_Continuous_Cast:
		return MOTION_CONTINUOUS_CAST;

	case eMotion_1H_Holster:
		return MOTION_1H_HOLSTER;

	case eMotion_1H_Unholster:
		return MOTION_1H_UNHOLSTER;

	case eMotion_2H_Holster:
		return MOTION_2H_HOLSTER;

	case eMotion_2H_Unholster:
		return MOTION_2H_UNHOLSTER;

	case eMotion_Dodge:
		return MOTION_DODGE;

	case eMotion_Hurt:
		return MOTION_HURT;

	case eMotion_Death:
		return MOTION_DEATH;

	case eMotion_Dead:
		return MOTION_DEAD;

	case eMotion_Revive:
		return MOTION_REVIVE;

	case eMotion_Dazed:
		return MOTION_DAZED;

	case eMotion_Slumber:
		return MOTION_SLUMBER;

	case eMotion_Knockdown_Start:
		return MOTION_KNOCKDOWN_START;

	case eMotion_Knockdown_Idle:
		return MOTION_KNOCKDOWN_IDLE;

	case eMotion_Knockdown_End:
		return MOTION_KNOCKDOWN_END;

	case eMotion_Knockdown_Recover:
		return MOTION_KNOCKDOWN_RECOVER;

	case eMotion_Fishing_Cast:
		return MOTION_FISHING_CAST;

	case eMotion_Fishing_Idle:
		return MOTION_FISHING_IDLE;

	case eMotion_Fishing_Reel:
		return MOTION_FISHING_REEL;

	case eMotion_Gathering_Start:
		return MOTION_GATHERING_START;

	case eMotion_Gathering_Idle:
		return MOTION_GATHERING_IDLE;

	case eMotion_Gathering_End:
		return MOTION_GATHERING_END;

	case eMotion_Mining_Start:
		return MOTION_MINING_START;

	case eMotion_Mining_Idle:
		return MOTION_MINING_IDLE;

	case eMotion_Mining_End:
		return MOTION_MINING_END;

	case eMotion_Crafting_Start:
		return MOTION_CRAFTING_START;

	case eMotion_Crafting_Idle:
		return MOTION_CRAFTING_IDLE;

	case eMotion_Crafting_End:
		return MOTION_CRAFTING_END;

	case eMotion_Sit:
		return MOTION_SIT;

	case eMotion_Sit_Idle:
		return MOTION_SIT_IDLE;

	case eMotion_Stand_Up:
		return MOTION_STAND_UP;

	case eMotion_Sleep_Down:
		return MOTION_SLEEP_DOWN;

	case eMotion_Sleep_Idle:
		return MOTION_SLEEP_IDLE;

	case eMotion_Sleep_Up:
		return MOTION_SLEEP_UP;

	case eMotion_Crouch_Down:
		return MOTION_CROUCH_DOWN;

	case eMotion_Crouch_Idle:
		return MOTION_CROUCH_IDLE;

	case eMotion_Crouch_Up:
		return MOTION_CROUCH_UP;

	case eMotion_Drink:
		return MOTION_DRINK;

	case eMotion_Eat:
		return MOTION_EAT;

	case eMotion_Use_Item:
		return MOTION_USE_ITEM;

	case eMotion_Speak01:
		return MOTION_SPEAK01;

	case eMotion_Speak02:
		return MOTION_SPEAK02;

	case eMotion_Head_Nod:
		return MOTION_HEAD_NOD;

	case eMotion_Head_Shake:
		return MOTION_HEAD_SHAKE;

	case eMotion_Laugh:
		return MOTION_LAUGH;

	case eMotion_Angry:
		return MOTION_ANGRY;

	case eMotion_Cry:
		return MOTION_CRY;

	case eMotion_Approval:
		return MOTION_APPROVAL;

	case eMotion_Victory:
		return MOTION_VICTORY;

	case eMotion_Applause:
		return MOTION_APPLAUSE;

	case eMotion_Salute:
		return MOTION_SALUTE;

	case eMotion_Wave:
		return MOTION_WAVE;

	case eMotion_Point:
		return MOTION_POINT;

	case eMotion_Provoke:
		return MOTION_PROVOKE;

	case eMotion_Beg:
		return MOTION_BEG;

	case eMotion_Dance:
		return MOTION_DANCE;

	case eMotion_Surrender:
		return MOTION_SURRENDER;

	case eMotion_Signature:
		return MOTION_SIGNATURE;

	case eMotion_Threaten:
		return MOTION_THREATEN;

	case eMotion_Effect_Appear:
		return MOTION_EFFECT_APPEAR;

	case eMotion_Effect_Idle:
		return MOTION_EFFECT_IDLE;

	case eMotion_Effect_Disappear:
		return MOTION_EFFECT_DISAPPEAR;

	case eMotion_Effect_Explode:
		return MOTION_EFFECT_EXPLODE;
	}
	return "";
}

//-----------------------------------------------------------------------------
int IBaseSprite::GetMotionEnum( const char* motion )
{
	map<string, int>::iterator iter = g_motionMap.find(motion);
	if ( iter != g_motionMap.end() )
	{
		return iter->second;
	}
	return eMotion_Null;
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetRuEntityDirection( CRuEntity* pRuEntity, CRuVector3& dir )
{
	// 讓 Entity 在正確的方向
	if ( pRuEntity )
		RuEntity_Orient( pRuEntity, CRuVector3( 0.0f, 0.0f, -1.0f), dir, 1.0 );
}

//-----------------------------------------------------------------------------
bool IBaseSprite::TerrainTest( CRuVector3& dir, CRuVector3& pos, CRuVector3 *newPos )
{
	/*
	assert( s_pRuTerrain );
	
	CRuCollisionQuery_Ray rayQuery;

	rayQuery.m_colRay.Origin().Set(pos.m_x, pos.m_y, pos.m_z);

	dir.Normalize();

	rayQuery.m_colRay.Direction().Set(dir.m_x, dir.m_y, dir.m_z);

	// Ray-cast into terrain
	s_pRuTerrain->QueryCollision(&rayQuery);

	if(rayQuery.m_colPoints->Count() > 0)
	{
		// Sort the results using insertion sort
		g_ruInsertionSort.Sort(rayQuery.m_colDistances->GetArray(), rayQuery.m_colDistances->Count());
		UINT32 *sortedIndices = g_ruInsertionSort.GetSortedIndices();

		// Store new y position
		if ( newPos )
			*newPos = rayQuery.m_colPoints->Get(sortedIndices[0]);

		return true;
	}
*/
	return false;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::TerrainTestHight( bool isDown, CRuVector3& pos, float& y )
{
	/*
	if ( s_pRuTerrain == NULL )
		return false;

	CRuCollisionQuery_Ray rayQuery;

	rayQuery.m_colRay.Origin().Set(pos.m_x, pos.m_y, pos.m_z);
	if ( isDown )
		rayQuery.m_colRay.Direction().Set(0.0f, -1.0f, 0.0f);
	else
		rayQuery.m_colRay.Direction().Set(0.0f, 1.0f, 0.0f);

	// Ray-cast into terrain
	s_pRuTerrain->QueryCollision(&rayQuery);

	if(rayQuery.m_colPoints->Count() > 0)
	{
		// Sort the results using insertion sort
		g_ruInsertionSort.Sort(rayQuery.m_colDistances->GetArray(), rayQuery.m_colDistances->Count());
		UINT32 *sortedIndices = g_ruInsertionSort.GetSortedIndices();

		// Store new y position
		y = rayQuery.m_colPoints->Get(sortedIndices[0]).y;

		return true;
	}
*/
	return false;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::ModifyPosOnTerrain( CRuVector3& pos )
{	
	CRuVector3 curPos = pos;
	float h = 2.0f;

	for ( int i = 0; i < 5; i++ )
	{
		float y;

		curPos.m_y += h;
		if ( TerrainTestHight( true, curPos, y ) )
		{
			pos.m_y = y;
			return true;
		}

		h *= 4.0f;
	}
	return false;
}

//-----------------------------------------------------------------------------
void IBaseSprite::Insert( IBaseSprite* pSprite )
{
	s_containers.insert( pSprite );
}

//-----------------------------------------------------------------------------
void IBaseSprite::Erase( IBaseSprite* pSprite )
{
	s_containers.erase( pSprite );

	if ( s_mainPlayerId == pSprite->GetIdentify() )
		s_mainPlayerId = 0;

	for ( set<IBaseSprite*>::iterator iter = s_containers.begin(); iter != s_containers.end(); iter++ )
        (*iter)->ReceiveDestruct( pSprite );
}

//-----------------------------------------------------------------------------
IBaseSprite::IBaseSprite()
{
	m_classType			= eSpriteClass_Base;	

	m_pRuEntity			= NULL;	
	m_objectType		= eSpriteObject_Unknown;

	m_isVisible			= true;
	m_id				= 0;

	m_scale				= 1.0f;
	m_nowPos.m_x		= 0.0f;
	m_nowPos.m_y		= 0.0f;
	m_nowPos.m_z		= 0.0f;
	m_lastPos.m_x		= 0.0f;
	m_lastPos.m_y		= 0.0f;
	m_lastPos.m_z		= 0.0f;
	m_direction.m_x		= 0.0f;
	m_direction.m_y		= 0.0f;
	m_direction.m_z		= 0.0f;
	m_moveSpeed			= 1.0f;	

	m_firstMotion		= eMotion_Null;
	m_secondMotion		= eMotion_Null;	

	m_isDestruct		= false;
	m_destructTime		= 0.0f;
	m_pauseTime			= 0.0f;

	m_event.clear();

	Insert( this );
}

//-----------------------------------------------------------------------------
IBaseSprite::~IBaseSprite()
{
	Erase( this );

	ReleaseEntity();

	m_event.clear();
}

//-----------------------------------------------------------------------------
void IBaseSprite::Update( float elapsedTime )
{
	if ( m_isDestruct )
		m_destructTime -= elapsedTime;	

	// 檢查待處理事件
	multimap<int, SpriteEventInfo>::iterator iter = m_event.begin();
	while ( iter != m_event.end() )
	{
		multimap<int, SpriteEventInfo>::iterator next_iter = iter;
		next_iter++;
		
		if ( (iter->second).func( elapsedTime, this, &(iter->second) ) )
			m_event.erase( iter );

		iter = next_iter;
	}

	if ( m_pRuEntity )
		m_pRuEntity->Update( elapsedTime * 1.0f );
}

//-----------------------------------------------------------------------------
void IBaseSprite::Render()
{
	if ( m_pRuEntity )
		g_ruDefaultRenderContext->Submit( m_pRuEntity );
}

//-----------------------------------------------------------------------------
bool IBaseSprite::SetObject( const char* act )
{
	ReleaseEntity();

	if ( m_pRuEntity = g_ruResourceManager->LoadEntity( act ) )
	{
		SetDirection( CRuVector3(0.0f, 0.0f, -1.0f) );
        m_pRuEntity->SetTranslation( m_nowPos );
		return true;
	}	
	
	return false;
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetPos( CRuVector3 &pos )
{
	m_nowPos = pos;
	if ( m_pRuEntity )
		m_pRuEntity->SetTranslation( pos );
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetDirection( CRuVector3 direction )
{
	if ( IsSame(direction.m_x, 0.0f) && IsSame(direction.m_z, 0.0f) )
		return;

	m_direction = direction.Normalize();
	SetRuEntityDirection( m_pRuEntity, m_direction );
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetDirection( float angle )
{
	// 以X軸為基準
	SetDirection( CRuVector3( cos( angle ), 0.0f, -sin( angle ) ) );
}

//-----------------------------------------------------------------------------
// 設定縮放大小 1.0 基本值
void IBaseSprite::SetScale(float scale)
{
	CRuVector3 destScale(scale, scale, scale);
	if (m_pRuEntity )
	{
		CRuVector3 srcScale, shear, rotation, position;
		CRuMatrix4x4 matrix = m_pRuEntity->GetLocalTransform();
		matrix.GetDecomposition(srcScale, shear, rotation, position);

		if ( destScale != srcScale )
		{
			m_pRuEntity->ResetLocalTransform();
			m_pRuEntity->Scale(destScale);
		}
	}
}

//-----------------------------------------------------------------------------
void IBaseSprite::ClearDestruct()
{
	m_isDestruct = false;
	m_destructTime = 0.0f;
}

//-----------------------------------------------------------------------------
void IBaseSprite::SetDestructTime( float time )
{
	m_isDestruct = true;
	m_destructTime = time;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::PushEvent( int eventId, SpriteEventInfo& eventInfo )
{	
	if ( m_event.size() > 50 )
		return false;

	m_event.insert( make_pair(eventId, eventInfo) );
	return true;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::FindEvent( int eventId )
{
	return m_event.find( eventId ) != m_event.end();
}

//-----------------------------------------------------------------------------
CRuEntity* IBaseSprite::FindLinkEntity( int point )
{
	if ( m_pRuEntity && point != eAttach_Null )
		return RuEntity_FindLinkFrame( m_pRuEntity, GetAttachPointName(point) );
	return NULL;	
}

//-----------------------------------------------------------------------------
bool IBaseSprite::GetAttachPos( int point, CRuVector3& pos )
{
	CRuEntity* pRuEntity = FindLinkEntity( point );
	if ( pRuEntity )
	{
		pos.Set( 0.0f, 0.0f, 0.0f );
		pRuEntity->GetWorldTransform().TransformPoint( pos );
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
void IBaseSprite::ReleaseEntity()
{
	if ( m_pRuEntity )
	{
		m_pRuEntity->Release();
		m_pRuEntity = NULL;
	}

	m_firstMotion = eMotion_Null;
	m_secondMotion = eMotion_Null;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::PlayMotion( int id, int channel, float blendTime, bool forceReset )
{	
	if ( m_pRuEntity == NULL )
		return false;

	const char* motionStr = GetMotionName(id);

	if ( RuACT_HasMotion(m_pRuEntity, motionStr) ==false )
		return false;

	switch ( channel )
	{
	case 2:
		m_secondMotion = id;
		if ( !RuACT_PlayMotionEx( m_pRuEntity, 0x02, motionStr, blendTime, forceReset ) )
			return false;
		break;

	case 4:
		m_firstMotion = id;
		if ( !RuACT_PlayMotionEx( m_pRuEntity, 0x04, motionStr, blendTime, forceReset ) )
			return false;		
		break;

	case 0xFFFFFFFF:
		m_firstMotion	= id;
		m_secondMotion	= id;
		if ( !RuACT_PlayMotionEx( m_pRuEntity, 0xFFFFFFFF, motionStr, blendTime, forceReset ) )
			return false;
		break;
	}

	return true;
}

//-----------------------------------------------------------------------------
bool IBaseSprite::IsMotionComplete()
{
	if ( m_pRuEntity == NULL )
		return true;

	return ( RuACT_IsMotionComplete( m_pRuEntity ) ) ? true : false;
}

//-----------------------------------------------------------------------------
void IBaseSprite::AddOnEntity( bool isAttach, CRuEntity* pRuEntity, SpriteAttachPoint point )
{
	if ( m_pRuEntity == NULL || pRuEntity == NULL )	
		return;

	if ( isAttach )
		RuEntity_Attach( m_pRuEntity, pRuEntity, GetAttachPointName(point) );
	else
		RuEntity_Detach( m_pRuEntity, pRuEntity, GetAttachPointName(point) );
}

//-----------------------------------------------------------------------------
SpriteMoveDirection IBaseSprite::ComputeDirection( CRuVector3 forward )
{
	if ( IsSame(forward.m_x, 0.0f) && IsSame(forward.m_z, 0.0f) )
		return eMove_NULL;

	forward.m_y = 0.0f;
	forward.Normalize();
	float theta = forward.Dot( m_direction );

	// 大於157.5度 , 後退
	if ( theta < -0.92388 )
		return eMove_Back;
	// 介於 112.5 ~ 157.5 度 , 斜後退
	else if ( theta < -0.38268 )			
	{
		if ( TripleProduct_Scalar( m_direction, forward, CRuVector3(0.0f, 1.0f, 0.0f) ) > 0.0f )
			return eMove_Back_Left;
		else
			return eMove_Back_Right;
	}
	// 介於 67.5 ~ 112.5 度 , 側移
	else if ( theta < 0.38268 )
	{
		if ( TripleProduct_Scalar( m_direction, forward, CRuVector3(0.0f, 1.0f, 0.0f) ) > 0.0f )
			return eMove_Side_Right;
		else
			return eMove_Side_Left;
	}
	// 介於 22.5 ~ 67.5 度 , 斜前進
	else if ( theta < 0.92388 )
	{
		if ( TripleProduct_Scalar( m_direction, forward, CRuVector3(0.0f, 1.0f, 0.0f) ) > 0.0f )
			return eMove_Forward_Right;
		else
			return eMove_Forward_Left;
	}
	// 小於 22.5 , 前進
	else
		return eMove_Forward;
}