#include "stdafx.h"
#include "monster.h"

#include "SceneManager.h"
#include "MonsterSceneNode.h"

#include "GameResourceManager.h"

#include "Application.h"
#include "WorldManager.h"

#include "GameFile.h"
#include "ObjectManager.h"
#include "Hero.h"

#include "Skill_Common.h"
#include "SkillManager.h"
#include "MonsterScript.h"

#include "RangeCheck.h"
#include "ChatManager.h"
#include "DamagePrintManager.h"
#include "DramaturgyManager.h"

#include "EffectSceneNode.h"
#include "SoundSceneNode.h"
#include "mode.h"


cMonster::cMonster( unsigned char type )
: cBaseObject( type )
, mMoveOverTime( 0 )
{
	mGotoX = 0.0f;
	mGotoY = 0.0f;

	mDesiredDir = -NiPoint3::UNIT_Y;

	mPathIndex = 0;
	mPathCount = 0;

	mHP = 0;
	mMP = 0;
	mMaxHP = 0;
	mMaxMP = 0;

	mState = eOBJECT_STATE_IDLE;

	mMonsterDieTime = 0;

	mLastGotoX = 0;
	mLastGotoY = 0;

	mMoveStopRange = 0.0f;

	mDelay = 0;
	mAngle = 0.0f;
	mAccumAngle = 0.0f;
	mAxis = NiPoint3::UNIT_Z;

	mDamageAfterAnim = M_ANITYPE_IDLE1;
}

cMonster::~cMonster()
{
}

bool cMonster::Create( sMonsterData* baseInfo, NiPoint3 pos, NiMatrix3 rotate )
{
	assert(baseInfo);

	/// 몬스터 스크립트 파일에서 정보를 읽어온다.
	sMonsterScript* pMonsterInfo;
	pMonsterInfo = MONSTERSCRIPT->GetMonsterListInfo( baseInfo->mMonsterClassIdx );
	if( pMonsterInfo == NULL )
	{
		MessageBox(NULL,_T("sMonsterScript ERROR"),_T("ERROR"),MB_OK);
		assert(NULL);
		return false;
	}

	mMonsterIdx = baseInfo->mMonsterIdx;

	//	mPos.X = sPos.x;
	//	mPos.Y = sPos.y;

	/// 몬스터 스크립트에서 읽어온 몬스터 정보 저장
	mpMonsterInfo = pMonsterInfo;

	///// 몬스터 기본 설정값
	mMaxHP = baseInfo->mMaxHP;
	mMaxMP = baseInfo->mMaxMP;
	mHP = baseInfo->mHP;
	mMP = baseInfo->mMP;
	mMoveSpeed = baseInfo->mMoveSpeed;

	float scale = 1.0f;
	if( mpMonsterInfo->mMonsterScale > 0.0f )
	{
		scale = mpMonsterInfo->mMonsterScale;
	}
	else
	{
		assert(0);
	}

	mFixedObjectSize = mpMonsterInfo->mMonsterFixSize * scale; 


	const char* strFile = GAMERESOURCEMAN->GetModelFileName( pMonsterInfo->mKfmIdx );
	assert( strFile );

	cMonsterSceneNodeParam param;
	param.mpObject = this;
	param.mTranslate = pos;
	param.mRotate = rotate;
	param.mScale = scale;
	param.mHeadHeight = (float)mpMonsterInfo->mNameHeight;

	cString pathName;
	pathName.Format( "./Data/Monster/%s", strFile );
	param.mPathName = pathName;

	cMonsterSceneNode* pSceneNode = SCENEMAN->CreateMonster( param );

	if( !pSceneNode )
	{
		assert(0);
		return false;
	}
	mpObjectSceneNode = pSceneNode;
	/// 수정요!
	mpObjectSceneNode->SetTargetAnimation( 1 );

	NiPoint3 sFoot = mpObjectSceneNode->GetObjectFoot();
	NiPoint3 sHead = mpObjectSceneNode->GetObjectHead();
	mStatureValue = (sHead.z - sFoot.z) / mpObjectSceneNode->GetWorldScale();

	mpObjectSceneNode->ShowNameGauge( true );
	mpObjectSceneNode->UpdateNameCardTextValue();
	mpObjectSceneNode->UpdateNameCardGaugeValue();

	mDesiredDir = rotate*mDesiredDir;
	mDesiredDir.Unitize();

	mDelay = 0;
	mAngle = 0.0f;
	mAccumAngle = 0.0f;
	mAxis = NiPoint3::UNIT_Z;

	return true;
}

void cMonster::Update( unsigned long deltaTime, unsigned long accumTime )
{
	if( mAngle )
	{
		float angle = (float)deltaTime/(float)mDelay *mAngle;
		if( mAccumAngle + angle >= mAngle )
		{
			angle = mAngle - mAccumAngle;

			mAngle = 0;
			mAccumAngle = 0;
		}
		else
			mAccumAngle += angle;

		NiMatrix3 mat;
		if( mAxis.z < 0.0f )
			mat.FromEulerAnglesXYZ( 0.0f, 0.0f, -angle );
		else
			mat.FromEulerAnglesXYZ( 0.0f, 0.0f, angle );

		mpObjectSceneNode->SetRotate( mpObjectSceneNode->GetRotate()*mat );

		mDesiredDir = mat * mDesiredDir;
		mDesiredDir.z = 0.0f;
		mDesiredDir.Unitize();
	}

	switch( mState )
	{
	case eOBJECT_STATE_IDLE:
		{
			mIdleTime += deltaTime;
			if( mIdleTime >= 10000 )
			{
				mIdleTime = 0;
				mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE2 );
			}		
		}
		break;
	case eOBJECT_STATE_MOVE:
		{
			if( mPathCount == 0 )
				return;

			/// 이동중이면
			NiPoint3 pos = mpObjectSceneNode->GetWorldTranslate();

			/// 몬스터 이동 속도
			float speed = (float)mMoveSpeed;

			/// 방향 설정
			NiPoint2 dir1;
			dir1.x = mGotoX - pos.x;
			dir1.y = mGotoY - pos.y;
			dir1.Unitize();

			const unsigned long limitOverTime = 10;
			unsigned long plusTime;

			/// 목적지점 넘어서 저장된 시간을 이동시 +
			if( mMoveOverTime > limitOverTime )
				plusTime = limitOverTime;
			else
				plusTime = mMoveOverTime;

			mMoveOverTime = mMoveOverTime - plusTime;

			/// 속도 * 경과시간 만큼의 예상 이동 위치 계산
			pos.x += dir1.x * speed * ((deltaTime + plusTime) *0.001f);
			pos.y += dir1.y * speed * ((deltaTime + plusTime) *0.001f);
			pos.z = 0.0f;

			/// 목적지 좌표와 예상 이동 위치를 비교
			NiPoint2 dir2;
			dir2.x = mGotoX - pos.x;
			dir2.y = mGotoY - pos.y;
			dir2.Unitize();

			if( dir2.Dot(dir1) <= 0.0f )
			{
				NiPoint2 overPoint( pos.x, pos.y );
				NiPoint2 nextPos( mGotoX, mGotoY );

				/// 길찾기 경로 목적 지점을 넘어선 경우 넘은 거리만큼 시간 보관
				float overLength = ( overPoint - nextPos ).Length();
				mMoveOverTime = mMoveOverTime + (unsigned long)((overLength/speed)*1000.0f);

				pos.x = mGotoX;
				pos.y = mGotoY;
				if( mPathIndex < mPathCount-1 )
				{
					NiPoint2& nextPos = mPathArray[++mPathIndex];
					Move( nextPos.x, nextPos.y );
				}
				else
				{
					mPathCount = 0;
					mMoveOverTime = 0;
					SetState( eOBJECT_STATE_IDLE );
				}
			}

			/// 몬스터가 목적지에서 근처(일정범위)까지 도달하면 정지하는 모듈
			if( mMoveStopRange != 0.0f )
			{
				/// 몬스터가 가려고하는 경로의 최종 목적지
				NiPoint3 targetPos;
				NiPoint3 monsterGuessPos( pos.x, pos.y, 0.0f );
				/// 높이값 계산
				if( WORLDMAN->CalcHeight( &monsterGuessPos.z, monsterGuessPos.x, monsterGuessPos.y ) == false )
					assert(NULL);
				
				cBaseObject* pBaseObject = GetTargetObject();
				if( pBaseObject == NULL || pBaseObject->GetState() == eOBJECT_STATE_DIE )
				{
					targetPos.x = mLastGotoX;
					targetPos.y = mLastGotoY;
					if( WORLDMAN->CalcHeight( &targetPos.z, targetPos.x, targetPos.y ) == false )
						assert(NULL);
				}
				else
				{
					targetPos.x = pBaseObject->GetXPos();
					targetPos.y = pBaseObject->GetYPos();
					targetPos.z = pBaseObject->GetZPos();
				}

				float moveStopRangeFix = OBJECTMANAGER->ObjectSizeRange( this, pBaseObject, mMoveStopRange );

				/// 최종 목적지주변에 일정 범위에서 서야할 사이즈
				cRangeCheck rangecheck( moveStopRangeFix );

				/// 최종 목적지와 현재 위치의 거리를 비교
				if( rangecheck.IsRange( monsterGuessPos, targetPos ) )
				{
					/// 좌표 보정
					NiPoint3 p;

					NiPoint3 d = GetPos() - targetPos;
					d.Unitize();

					p.x = targetPos.x + ((moveStopRangeFix-1.0f)*d.x);
					p.y = targetPos.y + ((moveStopRangeFix-1.0f)*d.y);

					if( WORLDMAN->CalcHeight( &p.z, p.x, p.y ) )
					{
						SetPos(p);
						mLastGotoX =  p.x;
						mLastGotoY =  p.y;
					}
					else
					{
						assert(0);
					}

					mMoveStopRange = 0.0f;
					SetState( eOBJECT_STATE_IDLE );

					return;
				}
			}

			/// 높이값 계산
			if( WORLDMAN->CalcHeight( &pos.z, pos.x, pos.y ) )
			{
				SetPos( pos );
			}
			else
			{
				assert( 0 );
				SetState( eOBJECT_STATE_IDLE );
			}

		}break;
		/// 몬스터 상태 죽음
	case eOBJECT_STATE_DIE:
		{
			/// 몬스터가 죽은후 3초후에 몬스터 삭제리스트에 포함해 객체 제거함
			if( mMonsterDieTime+3000 < accumTime && mMonsterDieTime != 0 )
			{
				if( HERO->GetTargetObject() == this )
					HERO->SetTargetObject( eOBJECTTYPE_NONE, 0 );

				OBJECTMAN->AddMonsterDie( GetObjectID() );
			}
			/// 몬스터가 죽은후 2초후에 알파 블랜딩 시작
			else if( mMonsterDieTime+2000 < accumTime && mMonsterDieTime != 0 )
			{
				mpObjectSceneNode->SetAlphaBlended( 0.01f );
			}
		}
		break;
	default:
		break;
	}
	/// 애니메이션 연결에 대한 처리
	Interpret( accumTime );
}



bool cMonster::Move( float x, float y )
{
	/// 추가: 부드러운 방향 전환을 넣도록 한다.

	NiPoint3 kWorldTranslate = NiPoint3(x, y, 0.0f);
	NiPoint3 kCurTranslate = mpObjectSceneNode->GetWorldTranslate();
	kCurTranslate.z = 0.0f;

	NiPoint3 kAt = kCurTranslate - kWorldTranslate;

	if( kAt == NiPoint3::ZERO )
		return false;

	if( kAt.SqrLength() < 0.001f )
	{
		return false;
	}

	kAt.Unitize();

	float fDot = mDesiredDir.Dot(-kAt);

	if( fDot < 1.0f - FLT_EPSILON )//0.999999f)
	{
		float fAngle = NiACos(fDot);
		if(mDesiredDir.Cross(-kAt).z > 0)
			fAngle = -fAngle;

		mDesiredDir = -kAt;

		NiMatrix3 kZRot;
		kZRot.MakeZRotation(fAngle);
		mpObjectSceneNode->SetRotate( mpObjectSceneNode->GetRotate()*kZRot );
	}

	// Animation Setting - Run
	SetState( eOBJECT_STATE_MOVE );

	/// 목적지 설정
	mGotoX = x;
	mGotoY = y;

	return true;
}



void cMonster::Interpret( unsigned long time )
{
	cActorManagerForPartition*	pActor = mpObjectSceneNode->GetActorManager();
	if( !pActor ) return;

	unsigned int id = mpObjectSceneNode->GetTargetAnimation();

	/// 현재 애니메이션 종료 시점 획득
	float endTime = pActor->GetNextEventTime( cActorManagerForPartition::TEXT_KEY_EVENT, id, "end" );
	if( endTime == NI_INFINITY )
		return;
	if( endTime == cActorManagerForPartition::INVALID_TIME )
	{
		endTime = mpObjectSceneNode->GetTargetAnimationScaleEndTime() * 0.001f;
	}

	float checkTime = (float)mpObjectSceneNode->GetScaleAccumTime() * 0.001f;
	if( endTime > 0 && endTime <= checkTime )
	{
		if( M_ANITYPE_IDLE1 == id )
		{
			return;
		}
		else if( M_ANITYPE_IDLE2 == id )
		{
			mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE1 );
		}
		else if( M_ANITYPE_ATTACK1 <= id && id <= M_ANITYPE_ATTACK3 )
		{
			SetState( eOBJECT_STATE_IDLE );
		}
		else if( M_ANITYPE_SKILL1 <= id && id <= M_ANITYPE_SKILL2 )
		{
			SetState( eOBJECT_STATE_IDLE );
		}
		else if( id == M_ANITYPE_DAMAGE1 || id == M_ANITYPE_DAMAGE2 )
		{
			/// 공격받는 애니메이션이 끝나면 기본 애니메이션으로 바꾼다.
			if( mDamageAfterAnim == M_ANITYPE_CASTING )
			{
				UpdateSkillAnimation( M_ANITYPE_CASTING );
			}
			else
				SetState( eOBJECT_STATE_IDLE );
		}
		else
		{
			NiControllerSequence* seq = pActor->GetSequence( id );
			if( seq )
			{
				if( seq->GetCycleType() != NiTimeController::LOOP )
					SetState( eOBJECT_STATE_IDLE );
			}
			else
			{
				assert(0);
				SetState( eOBJECT_STATE_IDLE );
			}
		}
	}
	else if( endTime == cActorManagerForPartition::INVALID_TIME )
	{
		/// INVALID_TIME에 대한 보정
	}
}

unsigned int cMonster::SetLinkdObject( unsigned int num, char* nif )
{
	/// 객체 링크를 활성화한다.
	return mpObjectSceneNode->LinkObject( num, nif );
}



void cMonster::UnLinkdObject( unsigned int num )
{
	/// 객체 링크를 비활성화한다.
	mpObjectSceneNode->UnLinkObject( num );
}



bool cMonster::SetDesiredDir( NiPoint3 CurrentPos, NiPoint3 TargetPos, unsigned long delay )
{
	if( GetState() == eOBJECT_STATE_DIE )
		return true;

	CurrentPos.z = 0;
	TargetPos.z = 0;

	/// 현재 캐릭터의 방향
	NiPoint3 charDir = mDesiredDir;

	/// 바라봐야할 방향
	NiPoint3 viewDir = TargetPos - CurrentPos;
	if( viewDir.SqrLength() < 0.001f )	
	{
//		assert(0);
		return false;
	}
	viewDir.Unitize();

	if( mDesiredDir == viewDir )
	{
		mDelay = 0;
		mAngle = 0;
		mAccumAngle = 0;

		return true;
	}

	/// 회전 Matrix 산출
	NiMatrix3 matA, matB, matRot;
	matA.SetCol( 0, charDir );
	matA.SetCol( 1, -NiPoint3::UNIT_Z );
	matA.SetCol( 2, charDir.UnitCross( -NiPoint3::UNIT_Z ) );

	matB.SetCol( 0, viewDir );
	matB.SetCol( 1, -NiPoint3::UNIT_Z );
	matB.SetCol( 2, viewDir.UnitCross( -NiPoint3::UNIT_Z ) );

	matRot = matB * matA.Transpose();

	if( delay == 0 )
	{
		mpObjectSceneNode->SetRotate( mpObjectSceneNode->GetRotate()*matRot );
		mDesiredDir = viewDir;

		mDelay = 0;
		mAngle = 0;
		mAccumAngle = 0;
	}
	else
	{
		mDelay = delay;
		mAccumAngle = 0;
		matRot.ExtractAngleAndAxis(mAngle, mAxis.x, mAxis.y, mAxis.z);

		if( mAngle > 360.0f )
			mAngle -= 360.0f;
		else if( mAngle < 0.0f )
			mAngle += 360.0f;
	}

	return true;
}



void cMonster::SetPathArray( NiPoint2* moveArray, unsigned int count )
{
	assert( moveArray );

	count = (count < MAX_PATH_COUNT) ? count : MAX_PATH_COUNT;

	for( unsigned int i = 0; i < count; ++i )
	{
		mPathArray[i].x = moveArray[i].x;
		mPathArray[i].y = moveArray[i].y;
	}

	mPathIndex = 0;
	mPathCount = count;

	if( mPathCount )
	{
		Move( mPathArray[0].x, mPathArray[0].y );
		SetLastGoto( mPathArray[count-1].x, mPathArray[count-1].y );
	}
}



void cMonster::SetState( unsigned int state, bool bShowAni ) 
{ 
	mIdleTime = 0;

	if( mState ==eOBJECT_STATE_DIE )
		return;

	mState = (eOBJECTSTATE)state;

	if( mState != eOBJECT_STATE_ATTACK )
	{
		/// 기본 속도 보정
		if( mpObjectSceneNode )
			mpObjectSceneNode->UpdateAniScaleFactor( 1.0f );
	}

	switch( mState )
	{
	case eOBJECT_STATE_DIE:
		{
			/// 
			if( bShowAni )
				mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DIE1 );
			/// 죽은 시간 기록 - 죽은 시간으로 2초 후부터 알파, 3초후 소멸
			mMonsterDieTime = THEAPP->GetWorldAccumTime();
		}
		break;
	case eOBJECT_STATE_IDLE:
	case eOBJECT_STATE_STOP:
		{
			/// idle1 or idle2
			if( bShowAni )
				mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE1 );
		}
		break;
	case eOBJECT_STATE_MOVE:
		{
			switch( mMoveSpeedType )
			{
			case eMOVESPEED_WALK: mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_WORK ); break;
			case eMOVESPEED_RUN: mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_RUN ); break;
			}
		}
		break;
	}
}

void cMonster::HPChange( unsigned long objectHP, unsigned long objectMaxHP, bool die )
{
	if( die ) 
	{
		assert(objectHP == 0);

		if( GetState() != eOBJECT_STATE_DIE )
		{
			SetState( eOBJECT_STATE_DIE );
			SKILLMAN->CreateApplyObject( 0, this, 0, eAPPLYDRAMA_DIE1 );

			/// 사망시 보유 효과 제거..
			ClearAllBuff();
			ClearAllDeBuff();
		}
		else
		{
			assert(0);
		}
	}

	mHP = objectHP;
	mMaxHP = objectMaxHP;
	mpObjectSceneNode->UpdateNameCardGaugeValue();
}

void cMonster::HPChange( sTargetDamageHP* damage, cBaseObject* attacker )
{
	if( damage == 0 )
	{
		assert(0);
		return;
	}


	if( damage->mDie )
	{
		assert(damage->mObjectHP == 0);

		if( GetState() != eOBJECT_STATE_DIE )
		{
			if( attacker )
				SetDesiredDir( GetPos(), attacker->GetPos() );

			SetState( eOBJECT_STATE_DIE );
			if( damage->mDamageKind == eDAMAGE_CRITICAL )
			{
				mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DIE2 );
				SKILLMAN->CreateApplyObject( attacker, this, 0, eAPPLYDRAMA_DIE2 );
			}
			else
			{
				SKILLMAN->CreateApplyObject( attacker, this, 0, eAPPLYDRAMA_DIE1 );
			}

			/// 사망시 보유 효과 제거..
			ClearAllBuff();
			ClearAllDeBuff();
		}
		else
		{
			assert(0);
		}
	}
	mHP = damage->mObjectHP;
	mMaxHP = damage->mObjectMaxHP;
	mpObjectSceneNode->UpdateNameCardGaugeValue();
}



void cMonster::MPChange( unsigned long objectMP, unsigned long objectMaxMP )
{
	if( GetState() == eOBJECT_STATE_DIE )
	{
		assert(objectMP == 0);
	}

	mMP = objectMP;
	mMaxMP = objectMaxMP;

	mpObjectSceneNode->UpdateNameCardGaugeValue();
}


void cMonster::SetMoveSpeed( unsigned int moveSpeed, eMOVE_SPEED_TYPE moveSpeedType )
{ 
	mMoveSpeed = moveSpeed; 

	/// 기존값 유지
	if( eMOVESPEED_STOP != moveSpeedType )
		mMoveSpeedType = moveSpeedType; 
}


void cMonster::MoveStop( float x, float y )
{ 
	mGotoX = x;
	mGotoY = y;

	mPathIndex = 0;
	mPathCount = 0;

	if( mState == eOBJECT_STATE_MOVE )
		SetState( eOBJECT_STATE_IDLE );

	FixPos( x, y );
}


void cMonster::MonsterAttack( unsigned long uIdx, unsigned long skillIdx, cBaseObject* pTarget, float attackSpeedFactor )
{
	if( GetState() == eOBJECT_STATE_DIE )
		return;

	if( pTarget )
		SetDesiredDir( GetPos(), pTarget->GetPos() );

	SKILLMAN->CreateSkillObject( uIdx, skillIdx, this, pTarget, attackSpeedFactor );

	SetState( eOBJECT_STATE_ATTACK );
}

void cMonster::ApplyDamageDrama( unsigned int damage, unsigned int damageType, cBaseObject* pAttacker )
{
	cBaseObject::ApplyDamageDrama( damage, damageType, pAttacker );

	if( GetState() == eOBJECT_STATE_DIE )
		return;

	unsigned int ani = mpObjectSceneNode->GetTargetAnimation();

	mDamageAfterAnim = UINT_MAX;
//	mDamageAfterAnim = M_ANITYPE_IDLE1;

	switch( ani )
	{
	case M_ANITYPE_WORK:
	case M_ANITYPE_RUN:
	case M_ANITYPE_SKILL1:
	case M_ANITYPE_SKILL2:
	case M_ANITYPE_DAMAGE1:
	case M_ANITYPE_DAMAGE2:
	case M_ANITYPE_DIE1:
	case M_ANITYPE_DIE2:
		return;
	}

	if( ani >= M_ANITYPE_MODEANI )
		return;

	if( M_ANITYPE_ATTACK1 <= ani && ani <= M_ANITYPE_ATTACK3 )
	{
		if( GetTargetObject() != pAttacker )
			return;

		unsigned long time = mpObjectSceneNode->GetTargetAnimationEndTime() - 200;
		if( THEAPP->GetWorldAccumTime() < time )
			return;
	}

	if( ani == M_ANITYPE_CASTING )
		mDamageAfterAnim = M_ANITYPE_CASTING;

	/// damage동작 적용
	if( damageType < eDAMAGEPRINT_HEAL_OUR )
	{
		mIdleTime = 0;

		if( damageType == eDAMAGEPRINT_CRITICAL_ENEMY || damageType == eDAMAGEPRINT_CRITICAL_OUR )
			mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DAMAGE2 );
		else
			mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DAMAGE1 );

		if( mpObjectSceneNode->GetTargetAnimation() == M_ANITYPE_IDLE1 || 
			mpObjectSceneNode->GetTargetAnimation() == M_ANITYPE_IDLE2 )
		{
			if( pAttacker )
				SetDesiredDir( GetPos(), pAttacker->GetPos() );//, 10 );
		}
	}
}

void cMonster::PlayIdle2Ani()
{
	if( GetState() != eOBJECT_STATE_IDLE )
		return;

	mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE2 );
}

void cMonster::ActiveChatBubble( sTextItem* text )
{
	mpObjectSceneNode->ActiveChatBubble( text );
}

bool cMonster::IsPrecedeAttack() 
{
	if( mpMonsterInfo == 0 )
		return false;
	return mpMonsterInfo->mIsPrecedeAttack;
}

void cMonster::ChangeMonsterMode( long modeIdx )
{
	/// 기존 모드 정보 제거
	if( mModeLoopEffectList.IsEmpty() == false )
	{
		cModeLoopList::cIterator i = mModeLoopEffectList.Begin();
		cModeLoopList::cIterator end = mModeLoopEffectList.End();
		for( ; i != end; ++i )
		{
			unsigned long idx = (unsigned long)*i;
			cEffectSceneNode* n = SCENEMAN->GetEffectSceneNode( idx );
			if( n )
				n->SetLoopFlag( false );
		}
		mModeLoopEffectList.Clear();
	}

	if( mModeLoopSoundList.IsEmpty() == false )
	{
		cModeLoopList::cIterator i = mModeLoopSoundList.Begin();
		cModeLoopList::cIterator end = mModeLoopSoundList.End();
		for( ; i != end; ++i )
		{
			unsigned long idx = (unsigned long)*i;
			cSoundSceneNode* n = SCENEMAN->GetSoundSceneNode( idx );
			if( n )
				n->FadeOut();
		}
		mModeLoopSoundList.Clear();
	}

	if( modeIdx < 0 )
		return;
	if( GetState() == eOBJECT_STATE_DIE )
		return;

	/// 신규 모드 Init정보 처리
	cModeAgent* pAgent = MONSTERSCRIPT->GetMonsterModeAgent( GetMonsterClassIdx() );
	if( pAgent == 0 )
		return;

	cMode* pMode = pAgent->GetMode( modeIdx );
	if( pMode == 0 )
		return;

	cModeInfoArr* arr = pMode->GetInitModeInfoArr();
	for( unsigned int i=0; i<arr->GetSize(); i++ )
	{
		sModeInfoBase* p = (sModeInfoBase*)((*arr)[i]);
		switch( p->type )
		{
		case eMODEINFO_MODESTATE:
			{
				/// Animation
				sModeState* modeData = (sModeState*)p;

				if( mpObjectSceneNode )
					mpObjectSceneNode->SetTargetAnimation( modeData->mAnimationIdx );
			}
			break;
		case eMODEINFO_APPLYRESOURCE:
			{
				sModeResource* modeData = (sModeResource*)p;

				bool blinkData = true;
				if( modeData->mLoop == false )
					blinkData = false;

				if( blinkData == true )
				{
					sModeObj* pobj = pAgent->GetModeObject( modeData->mModeObjIdx );
					if( pobj == 0 )
						break;

					switch( pobj->kind )
					{
					case eMODEOBJ_EFFECT:
						{
							NiTransform trans;
							trans.m_Translate = modeData->mVar;
							trans.m_fScale = pobj->scale;
							trans.m_Rotate = pobj->rot;

							if( modeData->mFollow == false )
							{
								NiMatrix3 mat = GetModelRot();
								trans.m_Rotate = pobj->rot*mat;
							}

							char pathName[256] = {0,};
							::sprintf( pathName, "./Data/Effect/%s", pobj->file.Cstr() );

							cEffectSceneNode* pNode = SetLinkdEffect( modeData->mLinkPos, pathName, &trans, modeData->mLoop, modeData->mFollow );
							if( pNode && modeData->mLoop )
								mModeLoopEffectList.PushBack( pNode->GetIndexByManger() );
						}
						break;
					case eMODEOBJ_SOUND:
						{
							/// 사운드 적용
							cSoundSceneNode* pNode = SetLinkdSound( pobj->soundListIndex, modeData->mLoop );
							if( pNode && modeData->mLoop )
								mModeLoopSoundList.PushBack( pNode->GetIndexByManger() );
						}
						break;
					default: 
						{
							assert(0);
						}
						break;
					}
				}
			}
			break;
		default:
			break;
		}
	}
}