#include "stdafx.h"
#include "SkillObject.h"

#include "SceneManager.h"
#include "DynamicSceneNode.h"

#include "SkillManager.h"
#include "DramaturgyManager.h"

#include "EffectSceneNode.h"
#include "SoundSceneNode.h"
#include "SkillScript.h"
#include "BulletObj.h"

#include "Application.h"

#include "ModelView.h"
#include "CharacterForm.h"
#include "MonsterForm.h"

//////////////////////////////////////////////////////////////////////////
cDramaturgyObject::cDramaturgyObject()
: mpDramaInfo(0), mManagedKey(0)
{
	mCurrentState = eDRAMASTATE_NONE;

	mRemoved = false;
}

cDramaturgyObject::~cDramaturgyObject()
{
}

void cDramaturgyObject::UpdateDramaObject( sDramaActionBase* pBase, bool bTarget, const NiPoint3& dir )
{
	if( pBase == 0 ) 
		return;
	if( pBase->actionType != eDRAMA_ACTION )
		return;

	sDramaAction* pAct = (sDramaAction*)pBase;
	sDramaObj* pobj = mpDramaInfo->GetDramaObj( pAct->objIdx );
	if( pobj == 0 )
		return;

	switch( pobj->kind )
	{
	case eDRAMAOBJ_EFFECT:
		{
			NiTransform trans;
			trans.m_Translate = pAct->var;
			trans.m_fScale = pobj->scale;
			trans.m_Rotate = pobj->rot;

			if( pAct->bFollow == false )
			{
				NiMatrix3 mat = mViewNode->GetRotate();
				trans.m_Rotate = pobj->rot*mat;
			}

			if( dir != -NiPoint3::UNIT_Y )
			{
				/// user -> target 방향으로 회전해야 하는 객체에 대한 회전
				/// 회전 Matrix 산출
				NiPoint3 userDir = -NiPoint3::UNIT_Y;
				NiMatrix3 matA, matB, matRot;
				matA.SetCol( 0, userDir );
				matA.SetCol( 1, -NiPoint3::UNIT_Z );
				matA.SetCol( 2, userDir.UnitCross( -NiPoint3::UNIT_Z ) );

				matB.SetCol( 0, dir );
				matB.SetCol( 1, -NiPoint3::UNIT_Z );
				matB.SetCol( 2, dir.UnitCross( -NiPoint3::UNIT_Z ) );
				matRot = matB * matA.Transpose();

				trans.m_Rotate = pobj->rot * matRot;
			}


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

			cEffectSceneNode* pNode = 0;
			if( mViewNode->GetType() == cSceneNode::eMONSTER )
			{
				if( pAct->linkPos >= eDRAMA_LINK_RWEAPON )
				{
					assert(0);
					return;
				}
				unsigned int linkPos = pAct->linkPos;
				if( bTarget == true )
				{
					linkPos = UINT_MAX;
				}
				pNode = mViewNode->LinkEffect( linkPos, pathName, &trans, pAct->bLoop, pAct->bFollow );
			}
			else
			{
				unsigned int linkPos = ePART_MAX + pAct->linkPos;
				if( bTarget == true )
				{
					linkPos = UINT_MAX;
				}

				pNode = mViewNode->LinkEffect( linkPos, pathName, &trans, pAct->bLoop, pAct->bFollow );
			}

			if( pNode && pAct->bLoop == true )
				AddLoopEffect( pNode );
		}
		break;
	default:
		break;
	case eDRAMAOBJ_SOUND:
		{
			/// 사운드 적용
			cSoundSceneNode* pNode = 0;
			pNode = mViewNode->LinkSound( pobj->soundListIndex, pAct->bLoop );

			if( pNode && pAct->bLoop )
				AddLoopSound( pNode );
		}
		break;
	}
}

void cDramaturgyObject::UpdateTrailObject( sDramaActionBase* pBase )
{
	if( pBase == 0 ) 
		return;
	if( pBase->actionType != eDRAMA_TRAIL )
		return;

	sTrailAction* pAct = (sTrailAction*)pBase;

	sDramaObj* pobj = mpDramaInfo->GetDramaObj( pAct->texIdx );
	if( pobj == 0 )
		return;
	if( pobj->kind != eDRAMAOBJ_TRAILTEX )
	{
		assert(0);
		return;
	}

	cString str;
	str.Format( "./Data/2DData/%s", pobj->file.Cstr() );
	sTrailInfo* pInfo = mViewNode->LinkTrailEffect( str, pAct->lifeTime, pAct->linkStart, pAct->linkEnd, pAct->lengthPer, pAct->speedFactor );
	if( pInfo )
	{
		if( pAct->lifeTime != 0 )
		{
			/// loop 

		}
	}
}

void cDramaturgyObject::AddLoopEffect( cEffectSceneNode* pNode )
{
	mApplyController.mLoopEffect.PushBack( pNode );
}

void cDramaturgyObject::AddLoopSound( cSoundSceneNode* pNode )
{
	mApplyController.mLoopSound.PushBack( pNode );
}

void cDramaturgyObject::AddLoopTrail( sTrailInfo* pInfo )
{
	mApplyController.mLoopTrail.PushBack( pInfo );
}

//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
cSkillObject::cSkillObject()
: mIsDummy(true)
{
	mCurrentState = eDRAMASTATE_CASTING;
	mSpeedFactor = 1.0f;

	mUsedAnimation = false;

	mPrintType = ePRINT_DAMAGE;

	mCastTime = 0.0f;
}

cSkillObject::~cSkillObject()
{
	FadeOutAllLoopEffect();
	FadeOutAllSoundEffect();
	RemoveAllTrail();

	for( unsigned int i = 0, iend = mTargetObjArray.GetSize(); i < iend; ++i )
	{
		delete (sDamageInfo*)mTargetObjArray[i];
	}
	mTargetObjArray.Clear();


	/// 발사체 제거
	tPointerList<void*>::cIterator k = mBulletList.Begin();
	tPointerList<void*>::cIterator kend = mBulletList.End();
	for( ; k != kend; ++k )
	{
		cBulletObj* pObj = (cBulletObj*)(*k);
		SAFE_DELETE(pObj);
	}
	mBulletList.Clear();
	mDelBulletArray.Clear();
}

void* cSkillObject::operator new(size_t n)
{ 
	n;
	return SKILLMAN->AllocSkillObject();
} 

void cSkillObject::operator delete(void* ptr)
{
	SKILLMAN->FreeSkillObject( (cSkillObject*)ptr );
}

void cSkillObject::FadeOutAllLoopEffect()
{
	/// casting loop effect fadeout
	if( mCastingController.mLoopEffect.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mCastingController.mLoopEffect.Begin();
		tPointerArray<void*>::cIterator end = mCastingController.mLoopEffect.End();
		for( ; b != end; ++b )
		{
			cEffectSceneNode* pNode = (cEffectSceneNode*)(*b);
			if( mViewNode->IsLinkedEffect( pNode ) == true )
				pNode->FadeOut();
		}
		mCastingController.mLoopEffect.Clear();
	}

	/// activity loop effect fadeout
	if( mActivityController.mLoopEffect.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mActivityController.mLoopEffect.Begin();
		tPointerArray<void*>::cIterator end = mActivityController.mLoopEffect.End();
		for( ; b != end; ++b )
		{
			cEffectSceneNode* pNode = (cEffectSceneNode*)(*b);
			if( mViewNode->IsLinkedEffect( pNode ) == true )
				pNode->FadeOut();
		}
		mActivityController.mLoopEffect.Clear();
	}

	/// apply loop effect fadeout
	if( mApplyController.mLoopEffect.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mApplyController.mLoopEffect.Begin();
		tPointerArray<void*>::cIterator end = mApplyController.mLoopEffect.End();

		for( ; b != end; ++b )
		{
			cEffectSceneNode* pNode = (cEffectSceneNode*)(*b);
			if( mViewNode->IsLinkedEffect( pNode ) == true )
				pNode->FadeOut();
		}
		mApplyController.mLoopEffect.Clear();
	}
}

void cSkillObject::FadeOutAllSoundEffect()
{
	/// casting loop sound fadeout
	if( mCastingController.mLoopSound.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mCastingController.mLoopSound.Begin();
		tPointerArray<void*>::cIterator end = mCastingController.mLoopSound.End();
		for( ; b != end; ++b )
		{
			cSoundSceneNode* pNode = (cSoundSceneNode*)(*b);
			if( mViewNode->IsLinkedSound( pNode ) == true )
				pNode->FadeOut();
		}
		mCastingController.mLoopSound.Clear();
	}

	/// activity loop sound fadeout
	if( mActivityController.mLoopSound.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mActivityController.mLoopSound.Begin();
		tPointerArray<void*>::cIterator end = mActivityController.mLoopSound.End();
		for( ; b != end; ++b )
		{
			cSoundSceneNode* pNode = (cSoundSceneNode*)(*b);
			if( mViewNode->IsLinkedSound( pNode ) == true )
				pNode->FadeOut();
		}
		mActivityController.mLoopSound.Clear();
	}

	/// apply loop sound fadeout
	if( mApplyController.mLoopSound.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mApplyController.mLoopSound.Begin();
		tPointerArray<void*>::cIterator end = mApplyController.mLoopSound.End();
		for( ; b != end; ++b )
		{
			cSoundSceneNode* pNode = (cSoundSceneNode*)(*b);
			if( mViewNode->IsLinkedSound( pNode ) == true )
				pNode->FadeOut();
		}
		mApplyController.mLoopSound.Clear();
	}
}

void cSkillObject::RemoveAllTrail()
{
	/// casting loop sound fadeout
	if( mCastingController.mLoopTrail.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mCastingController.mLoopTrail.Begin();
		tPointerArray<void*>::cIterator end = mCastingController.mLoopTrail.End();
		for( ; b != end; ++b )
		{
			sTrailInfo* pInfo = (sTrailInfo*)(*b);
			mViewNode->UnLinkTrailEffect( pInfo );
		}
		mCastingController.mLoopTrail.Clear();
	}

	/// activity loop sound fadeout
	if( mActivityController.mLoopTrail.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mActivityController.mLoopTrail.Begin();
		tPointerArray<void*>::cIterator end = mActivityController.mLoopTrail.End();
		for( ; b != end; ++b )
		{
			sTrailInfo* pInfo = (sTrailInfo*)(*b);
			mViewNode->UnLinkTrailEffect( pInfo );
		}
		mActivityController.mLoopTrail.Clear();
	}

	/// apply loop sound fadeout
	if( mApplyController.mLoopTrail.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mApplyController.mLoopTrail.Begin();
		tPointerArray<void*>::cIterator end = mApplyController.mLoopTrail.End();
		for( ; b != end; ++b )
		{
			sTrailInfo* pInfo = (sTrailInfo*)(*b);
			mViewNode->UnLinkTrailEffect( pInfo );
		}
		mApplyController.mLoopTrail.Clear();
	}
}

bool cSkillObject::Init( unsigned long skillIdx, float speedFactor )
{
	mSpeedFactor = speedFactor;
	if( mSpeedFactor <= 0.0f || mSpeedFactor > 2.0f )
	{
		assert(0);
		mSpeedFactor = 1.0f;
	}

	mSkillIdx = skillIdx;
	mRemoved = false;

	mVerifyState = eVerify_Wait;

	mUserWeapon = 0;

	mViewNode = SCENEMAN->GetCurrentSceneNode();

	if( mViewNode->GetType() == cSceneNode::ePLAYER )
	{
		mUserWeapon = CHARACTERFORM->GetCurrentWeaponState();

		unsigned char state = CHARACTERFORM->GetCurrentWeaponState();
		if( skillIdx < NORMAL_ATTACK_SKILL_MAX )
		{
			state = (unsigned char)((skillIdx%10) - 1);
		}

		/// 연출 정보 획득
		mpDramaInfo = DRAMATURGYMAN->GetPlayerDramaturgyInfo( skillIdx, state, 
										CHARACTERFORM->GetCurrentRace(), CHARACTERFORM->GetCurrentGender() );
		if( mpDramaInfo == 0 )
		{
			assert(0);
			return false;
		}

		sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( mSkillIdx );
		if( pInfo == 0 )
			return false;

		if( pInfo->mType == eSKILLTYPE_NONACTIVE )
		{
			/// 효과 생성
			unsigned long infIdx = pInfo->mpSetpInfoArray[0].mInfulenceIdx;
			cInfluenceObject* pInfluence = SKILLMAN->CreateInfluenceObject( 0, infIdx );
			if( pInfluence )
				pInfluence->StartProcess(10);
		}

		mCastTime = pInfo->mpSetpInfoArray[0].mCastingTime;
	}
	else
	{
		unsigned long classId = MONSTERFORM->GetCurrentMonsterIdx();
		mpDramaInfo = DRAMATURGYMAN->GetMonsterDramaturgyInfo( classId, (eMONSTERATTACK_TYPE)skillIdx );
		if( mpDramaInfo == 0 )
		{
			assert(0);
			return false;
		}

		sMonsterSkillScript* pSkillInfo = SKILLSCRIPT->GetMonsterSkillInfo( classId, (eMONSTERATTACK_TYPE)skillIdx );
		if( pSkillInfo == 0 )
			return false;

		if( pSkillInfo->mType == eSKILLTYPE_NONACTIVE )
		{
			/// 효과 생성
			unsigned long infIdx = pSkillInfo->mInfulenceIdx;
			cInfluenceObject* pInfluence = SKILLMAN->CreateInfluenceObject( 0, infIdx );
			if( pInfluence )
				pInfluence->StartProcess(10);
		}

		mCastTime = pSkillInfo->mCastingTime*0.001f;
	}

	/// 연출을 위한 정보를 참조
	mCastingController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_CASTING );
	mCastingController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_CASTING );
	mCastingController.startTime = FLT_MAX;

	mActivityController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_ACTIVITY );
	mActivityController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_ACTIVITY );
	mActivityController.startTime = FLT_MAX;

	mApplyController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_APPLY );
	mApplyController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_APPLY );
	mApplyController.startTime = FLT_MAX;

	/// 예외 체크
	assert(mActivityController.pAct);
	if( mCastingController.pAct == 0 )
	{
		ChangeDramaState( eDRAMASTATE_ACTIVITY );
	}

	return true;
}

void cSkillObject::AddLoopEffect( cEffectSceneNode* pNode )
{
	switch( mCurrentState )
	{
	case eDRAMASTATE_CASTING:
		mCastingController.mLoopEffect.PushBack( pNode );
		break;
	case eDRAMASTATE_ACTIVITY:
		mActivityController.mLoopEffect.PushBack( pNode );
		break;
	case eDRAMASTATE_APPLY:
		mApplyController.mLoopEffect.PushBack( pNode );
		break;
	default:
		assert(0);
		return;
	}
}

void cSkillObject::AddLoopSound( cSoundSceneNode* pNode )
{
	switch( mCurrentState )
	{
	case eDRAMASTATE_CASTING:
		mCastingController.mLoopSound.PushBack( pNode );
		break;
	case eDRAMASTATE_ACTIVITY:
		mActivityController.mLoopSound.PushBack( pNode );
		break;
	case eDRAMASTATE_APPLY:
		mApplyController.mLoopSound.PushBack( pNode );
		break;
	default:
		assert(0);
		return;
	}
}

void cSkillObject::AddLoopTrail( sTrailInfo* pInfo )
{
	switch( mCurrentState )
	{
	case eDRAMASTATE_CASTING:
		mCastingController.mLoopTrail.PushBack( pInfo );
		break;
	case eDRAMASTATE_ACTIVITY:
		mActivityController.mLoopTrail.PushBack( pInfo );
		break;
	case eDRAMASTATE_APPLY:
		mApplyController.mLoopTrail.PushBack( pInfo );
		break;
	default:
		assert(0);
		return;
	}

}

void cSkillObject::ChangeDramaState( eDRAMASTATE state )
{
	if( state == eDRAMASTATE_ACTIVITY || state == eDRAMASTATE_CANCEL_WAIT )
	{
		/// casting loop effect clear
		if( mCastingController.mLoopEffect.IsEmpty() == false )
		{
			tPointerArray<void*>::cIterator b = mCastingController.mLoopEffect.Begin();
			tPointerArray<void*>::cIterator end = mCastingController.mLoopEffect.End();
			for( ; b != end; ++b )
			{
				cEffectSceneNode* pNode = (cEffectSceneNode*)(*b);
				if( mViewNode->IsLinkedEffect( pNode ) == true )
					pNode->FadeOut();
			}
			mCastingController.mLoopEffect.Clear();
		}

		/// casting loop sound clear
		if( mCastingController.mLoopSound.IsEmpty() == false )
		{
			tPointerArray<void*>::cIterator b = mCastingController.mLoopSound.Begin();
			tPointerArray<void*>::cIterator end = mCastingController.mLoopSound.End();
			for( ; b != end; ++b )
			{
				cSoundSceneNode* pNode = (cSoundSceneNode*)(*b);
				if( mViewNode->IsLinkedSound( pNode) == true )
					pNode->FadeOut();
			}
			mCastingController.mLoopSound.Clear();
		}

		if( mCastingController.mLoopTrail.IsEmpty() == false )
		{
			tPointerArray<void*>::cIterator b = mCastingController.mLoopTrail.Begin();
			tPointerArray<void*>::cIterator end = mCastingController.mLoopTrail.End();
			for( ; b != end; ++b )
			{
				sTrailInfo* pInfo = (sTrailInfo*)(*b);
				mViewNode->UnLinkTrailEffect( pInfo );
			}
			mCastingController.mLoopTrail.Clear();
		}
	}
	mCurrentState = state;
}
void cSkillObject::WaitCancel()
{
	ChangeDramaState( eDRAMASTATE_CANCEL_WAIT );
}

void cSkillObject::AddBulletObject( sDramaActionBase* pBase )
{
	if( pBase == 0 )
		return;
	if( pBase->actionType != eDRAMA_BULLET )
		return;

	cBulletObj* pObj = new cBulletObj;
	if( pObj->Init( mpDramaInfo, (sBulletAction*)pBase, mViewNode ) == false )
	{
		delete pObj;
		return;
	}
	mBulletList.PushBack( pObj );
}

void cSkillObject::BulletProcess( float time )
{
	tPointerList<void*>::cIterator i = mBulletList.Begin();
	tPointerList<void*>::cIterator end = mBulletList.End();
	for( ; i != end; ++i )
	{
		cBulletObj* pObj = (cBulletObj*)(*i);
		if( pObj->Update( time ) == false )
		{
			/// 삭제 등록
			mDelBulletArray.PushBack( pObj );
		}
	}

	/// 삭제 처리
	if( mDelBulletArray.IsEmpty() )
		return;

	for( unsigned int i=0; i<mDelBulletArray.GetSize(); ++i )
	{
		cBulletObj* pObj = (cBulletObj*)mDelBulletArray[i];

		delete pObj;
		mBulletList.Remove( pObj );
	}

	mDelBulletArray.Clear();
}

void cSkillObject::Process( float time )
{
	/// TODO: skill 정보에 따라서 상태 변경

	/// 발사체 Process
	BulletProcess( time );

	/// 상태에 따른 연출 처리
	switch( mCurrentState )
	{
	case eDRAMASTATE_CASTING:
		ProcessCasting( time );
		break;
	case eDRAMASTATE_ACTIVITY:
		ProcessActivity( time );
		break;
	case eDRAMASTATE_APPLY:
		ProcessApply( time );
		/// apply처리
		break;
	case eDRAMASTATE_CANCEL_WAIT:
		break;
	default:
		assert(0);
	}

	if( mActivityController.pAct == 0 && mApplyController.pAct == 0 )
	{
		/// 만약 발사체 처리가 끝나지 않았다면..
		/// 발사체 속도를 증가시켜서 빠르게 종료 시킬것..
		if( mBulletList.IsEmpty() == false )
		{
			tPointerList<void*>::cIterator i = mBulletList.Begin();
			tPointerList<void*>::cIterator end = mBulletList.End();
			for( ; i != end; ++i )
			{
				cBulletObj* pObj = (cBulletObj*)(*i);
				pObj->SpeedUp( 20.0f );
			}
			return;
		}

		/// 스킬 객체 제거
		SKILLMAN->DeleteSkillObject( this );
	}
}

void cSkillObject::ProcessCasting( float time )
{
	if( mVerifyState == eVerify_Faile )
		return;

	sDramaActionBase* pAct = mCastingController.pAct;
	if( pAct == 0 ) 
	{
		if( mCastingController.startTime == FLT_MAX )
		{
			EndCast();
		}
		else
		{
			if( mCastTime <= time - mCastingController.startTime )
			{
				EndCast();
			}
		}
		return;
	}

	/// 초기 설정
	if( mCastingController.startTime == FLT_MAX )
	{
		mCastingController.startTime = time;

		/// 애니메이션 적용
		if( mActivityController.animationIdx != UINT_MAX )
		{
			mViewNode->UpdateTargetAnimation( mCastingController.animationIdx );
			mUsedAnimation = true;
		}
	}

	float delta = time - mCastingController.startTime;
	while( pAct )
	{
		float checkTime = pAct->time;
		if( delta >= checkTime )
		{
			mCastingController.pAct = pAct->pNext;
			if( pAct->actionType == eDRAMA_TRAIL )
				UpdateTrailObject( pAct );
			else
			{
				UpdateDramaObject( pAct );
			}
		}
		else
			break;

		pAct = mCastingController.pAct;
	}
}

void cSkillObject::ProcessActivity( float time )
{
	sDramaActionBase* pAct = mActivityController.pAct;

	/// 초기 설정
	if( mActivityController.startTime == FLT_MAX )
	{
		mActivityController.startTime = time;

		/// 애니메이션 적용
		if( mActivityController.animationIdx != UINT_MAX )
		{
			mViewNode->UpdateTargetAnimation( mActivityController.animationIdx );
			mUsedAnimation = true;
		}
	}

	float delta = (time - mActivityController.startTime) * mSpeedFactor;
	while( pAct )
	{
		float checkTime = pAct->time;
		if( delta >= checkTime )
		{
			mActivityController.pAct = pAct->pNext;

			/// 처리부
			if( pAct->actionType == eDRAMA_TRAIL )
			{
				UpdateTrailObject( pAct );
			}
			else if( pAct->actionType == eDRAMA_ACTIVE )
			{
				ChangeDramaState( eDRAMASTATE_APPLY );
				break;
			}
			else if( pAct->actionType == eDRAMA_BULLET )
			{
				AddBulletObject( pAct );
				ChangeDramaState( eDRAMASTATE_APPLY );
				break;
			}
			else
			{
				UpdateDramaObject( pAct );
			}
			///

			/// 예외 처리
			if( mActivityController.pAct == 0 )
			{
				/// 발동 -> 적용으로 못넘아 갔다면 체크 하시오.
				assert(0);
				break;
			}
		}
		else
			break;

		pAct = mActivityController.pAct;
	}
}

/// 시전자와 적용자의 처리를 동시에 진행
void cSkillObject::ProcessApply( float time )
{
	//////////////////////////////////////////////////////////////////////////
	/// 시전자 행동 처리
	sDramaActionBase* pAct = mActivityController.pAct;
	if( pAct )
	{
		if( mActivityController.startTime == FLT_MAX )
		{
			mActivityController.startTime = time;

			/// 애니메이션 적용
			if( mActivityController.animationIdx != UINT_MAX )
			{
				mViewNode->UpdateTargetAnimation( mActivityController.animationIdx );
				mUsedAnimation = true;
			}
		}

		float delta = (time - mActivityController.startTime) * mSpeedFactor;
		while( pAct )
		{
			float checkTime = pAct->time;
			if( delta >= checkTime )
			{
				mActivityController.pAct = pAct->pNext;

				/// 처리부 
				if( pAct->actionType == eDRAMA_TRAIL )
					UpdateTrailObject( pAct );
				else if( pAct->actionType == eDRAMA_ACTION )
				{
					UpdateDramaObject( pAct );
				}
			}
			else
				break;

			pAct = mActivityController.pAct;
		}
	}

	pAct = mApplyController.pAct;
	if( pAct )
	{
		if( mApplyController.startTime == FLT_MAX )
		{
			mApplyController.startTime = time;
		}

		float delta = (time - mApplyController.startTime) * mSpeedFactor;
		while( pAct )
		{
			float checkTime = pAct->time;
			if( delta >= checkTime )
			{
				mApplyController.pAct = pAct->pNext;

				/// 처리부 
				if( pAct->actionType == eDRAMA_DAMAGE )
				{
					/// print type에 따라 별도의 처리가 필요..
					if( mPrintType == ePRINT_DAMAGE )
					{
						ApplyDamage( pAct );
					}
					else if( mPrintType == ePRINT_HEAL )
					{
						ApplyHeal( pAct );
					}
					else
					{
						/// 별도의 처리가 필요하다면 체크하자..
					}
				}
				else
				{
					if( pAct->actionType == eDRAMA_TRAIL )
						UpdateTrailObject( pAct );
					else
					{
						UpdateDramaObject( pAct, true );
					}
				}
				///
			}
			else
				break;

			pAct = mApplyController.pAct;
		}
	}
}

void cSkillObject::ApplyDamage( const sDramaActionBase* pAct )
{
	if( pAct == 0 )
		return;

	SKILLMAN->CreateApplyObject( mUserWeapon, eAPPLYDRAMA_DAMAGE );

	if( mViewNode->GetType() == cSceneNode::ePLAYER )
	{
		sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( mSkillIdx );
		if( pInfo == 0 )
			return;

		unsigned long infIdx = pInfo->mpSetpInfoArray[0].mInfulenceIdx;
		cInfluenceObject* pInfluence = SKILLMAN->CreateInfluenceObject( 0, infIdx );
		if( pInfluence )
			pInfluence->StartProcess(5);
	}
	else
	{
		unsigned long classId = MONSTERFORM->GetCurrentMonsterIdx();
		sMonsterSkillScript* pSkillInfo = SKILLSCRIPT->GetMonsterSkillInfo( classId, (eMONSTERATTACK_TYPE)mSkillIdx );
		if( pSkillInfo == 0 )
			return;

		unsigned long infIdx = pSkillInfo->mInfulenceIdx;
		cInfluenceObject* pInfluence = SKILLMAN->CreateInfluenceObject( 0, infIdx );
		if( pInfluence )
			pInfluence->StartProcess(5);
	}
}

void cSkillObject::ApplyHeal( const sDramaActionBase* pAct )
{
	if( pAct == 0 )
		return;
}

void cSkillObject::EndCast()
{
	if( mCurrentState != eDRAMASTATE_CASTING && mCurrentState != eDRAMASTATE_CANCEL_WAIT )
	{
		assert(0);
		return;
	}

	mViewNode->ClearAllEffect();
	ChangeDramaState( eDRAMASTATE_ACTIVITY );
}

//////////////////////////////////////////////////////////////////////////
cInfluenceObject::cInfluenceObject()
{
	mCurrentState = eDRAMASTATE_APPLY;

	mCheckBlink = false;
	mBlinkTime = 0;

	mStartTimeCheck = false;

	mIsHeroInfluce = false;
	mOnlyShowLoopEffect = false;

	mTickInit = false;
	mTickInfluence = false;
}

cInfluenceObject::~cInfluenceObject()
{
	/// Apply loop effect clear
	if( mApplyController.mLoopEffect.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mApplyController.mLoopEffect.Begin();
		tPointerArray<void*>::cIterator end = mApplyController.mLoopEffect.End();
		for( ; b != end; ++b )
		{
			cEffectSceneNode* pNode = (cEffectSceneNode*)(*b);
			if( mViewNode->IsLinkedEffect( pNode ) == true )
				pNode->FadeOut();
		}
		mApplyController.mLoopEffect.Clear();
	}

	/// Apply loop sound clear
	if( mApplyController.mLoopSound.IsEmpty() == false )
	{
		tPointerArray<void*>::cIterator b = mApplyController.mLoopSound.Begin();
		tPointerArray<void*>::cIterator end = mApplyController.mLoopSound.End();
		for( ; b != end; ++b )
		{
			cSoundSceneNode* pNode = (cSoundSceneNode*)(*b);
			if( mViewNode->IsLinkedSound( pNode ) == true )
				pNode->FadeOut();
		}
		mApplyController.mLoopSound.Clear();
	}

}

void* cInfluenceObject::operator new(size_t n)
{ 
	n;
	return SKILLMAN->AllocInfluenceObject();
} 

void cInfluenceObject::operator delete(void* ptr)
{
	SKILLMAN->FreeInfluenceObject( (cInfluenceObject*)ptr );
}

bool cInfluenceObject::Init( unsigned long uniqueIdx, unsigned long influenceIdx, bool isbuff )
{
	mManagedKey = uniqueIdx;
	mSkillIdx = influenceIdx;
	mIsBuff = isbuff;
	sInfluenceScript* p = SKILLSCRIPT->GetInfluenceInfo( influenceIdx );
	if( p == 0 )
	{
		assert(0);
		return false;
	}

	/// 효과 타입을 저장한다.
	mInfluenceType = p->mTypeDetail;

	mRestTime = p->mContinuanceTime;
	mLifeTime = p->mContinuanceTime;

	mRemoved = false;

	mViewNode = SCENEMAN->GetCurrentSceneNode();

	/// 연출 획득
	mpDramaInfo =DRAMATURGYMAN->GetInfluenceDramaturgyInfo( influenceIdx );
	if( mpDramaInfo == 0 )
	{
		assert(0);
		return false;
	}

	/// 연출 정보 셋팅
	mApplyController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_APPLY );
	mApplyController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_APPLY );
	mApplyController.startTime = FLT_MAX;

	return true;
}

void cInfluenceObject::StartProcess( float restTime, bool onlyLoopEffect )
{
	mOnlyShowLoopEffect = onlyLoopEffect;

	if( mStartTimeCheck == true )
		return;

	mStartTimeCheck = true;

	mStartTime =  THEAPP->GetAccumTime();

	if( restTime > 0 && restTime != FLT_MAX )
	{
		mRestTime = restTime;
		mLifeTime = restTime;
	}

	mApplyController.startTime = THEAPP->GetAccumTime();

	/// hero 의 타겟팅 대상과 동일하면 적용.

}

void cInfluenceObject::SetTickInfo( unsigned char tickType, long value )
{
	mTickType = tickType;
	mTickValue = (float)value;
	mTickInfluence = true;

	/// 
	if( mpDramaInfo == 0 )
	{
		assert(0);
		return;
	}

	mApplyController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_APPLY );
	mApplyController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_APPLY );
	mApplyController.startTime = FLT_MAX;
}

void cInfluenceObject::Process( float time )
{
	if( mStartTimeCheck == false )
		return;

	sDramaActionBase* pAct = mApplyController.pAct;
	if( pAct )
	{
		if( mApplyController.startTime == FLT_MAX )
		{
			mApplyController.startTime = time;
		}

		float delta = time - mApplyController.startTime;
		while( pAct )
		{
			if( delta >= pAct->time )
			{
				mApplyController.pAct = pAct->pNext;

				if( pAct->actionType == eDRAMA_DAMAGE )
				{
					if( mTickInit )
					{
						/// heal or damage 처리
						if( mTickType == eTick_HP )
						{
							ApplyHP( pAct );
						}
						else if( mTickType == eTick_MP )
						{
							ApplyMP( pAct );
						}
						else
							assert(0);
					}
				}
				else if( pAct->actionType == eDRAMA_TRAIL )
				{
					UpdateTrailObject( pAct );
				}
				else if( pAct->actionType == eDRAMA_ACTION )
				{
					sDramaAction* p = (sDramaAction*)pAct;
					if( mOnlyShowLoopEffect == true)
					{
						/// 진행형을 등록하는 경우는 반복효과만 연출한다.
						if( p->bLoop == true )
							UpdateDramaObject( pAct, true );
					}
					else
					{
						UpdateDramaObject( pAct, true );
					}
				}
			}
			else
				break;

			pAct = mApplyController.pAct;
			if( pAct == 0 )
			{
				mTickInit = true;
			}
		}
	}

	if( mInfluenceType != eINFLUENCETYPEDETAIL_AURA )
	{
		/// 효과 객체의 삭제 주기를 계산한다.
		if( mLifeTime < (time - mStartTime) )
			mRestTime = 0;
		else
			mRestTime = mLifeTime - (time - mStartTime);

		if( mTickInfluence == false )
		{
			if( mRestTime <= 0 )
			{
				mRestTime = 0;
				/// 스킬 객체 제거
				SKILLMAN->DeleteInfluenceObject( this );
			}
		}
		else
		{
			if( time - mStartTime > 5000 * mLifeTime )
				assert(0);
		}
	}
}

void cInfluenceObject::ApplyHP( sDramaActionBase* pAct )
{
	if( pAct == 0 )
		return;
}

void cInfluenceObject::ApplyMP( sDramaActionBase* pAct )
{
	if( pAct == 0 )
		return;
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////

cApplyObject::cApplyObject()
{
	mCurrentState = eDRAMASTATE_APPLY;
	mUserWeapon = 0;
}

cApplyObject::~cApplyObject()
{

}

void* cApplyObject::operator new( size_t n )
{
	n;
	return SKILLMAN->AllocApplyObject();
}

void cApplyObject::operator delete( void* ptr )
{
	SKILLMAN->FreeApplyObject( (cApplyObject*)ptr );
}

bool cApplyObject::Init( unsigned long managedKey, unsigned char weaponType, eAPPLYDRAMA_TYPE type )
{
	if( type >= eAPPLYDRAMA_MAX )
		return false;

	mIndexType = eINDEX_DRAMA;
	mApplyIndex = type;

	mRemoved = false;
	mManagedKey = managedKey;

	mUserWeapon = weaponType;

	mViewNode = SCENEMAN->GetCurrentSceneNode();

	if( VIEW->GetCurStage() == CModelView::eSTAGE_CHARACTER )
	{
		mpDramaInfo = DRAMATURGYMAN->GetPlayerApplyDramaInfo( CHARACTERFORM->GetCurrentRace(), CHARACTERFORM->GetCurrentGender(), type );
		if( mpDramaInfo == 0 )
		{
			assert(0);
			return false;
		}
	}
	else
	{
		mpDramaInfo = DRAMATURGYMAN->GetMonsterApplyDramaInfo( MONSTERFORM->GetCurrentMonsterIdx(), type );
		if( mpDramaInfo == 0 )
		{
			assert(0);
			return false;
		}
	}

	/// 연출을 위한 정보를 참조
	mApplyController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_APPLY );
	mApplyController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_APPLY );
	mApplyController.startTime = FLT_MAX;

	return true;
}

bool cApplyObject::Init( unsigned long managedKey, unsigned long influenceIdx )
{
	mManagedKey = managedKey;

	mIndexType = eINDEX_INFLUENCE;
	mApplyIndex = influenceIdx;

	mRemoved = false;

	mViewNode = SCENEMAN->GetCurrentSceneNode();

	/// 연출 획득
	mpDramaInfo =DRAMATURGYMAN->GetInfluenceDramaturgyInfo( influenceIdx );
	if( mpDramaInfo == 0 )
	{
		assert(0);
		return false;
	}

	/// 연출 정보 셋팅
	mApplyController.pAct = mpDramaInfo->GetStartAction( eDRAMASTATE_APPLY );
	mApplyController.animationIdx = mpDramaInfo->GetAnimation( eDRAMASTATE_APPLY );
	mApplyController.startTime = FLT_MAX;

	return true;
}
void cApplyObject::Process( float time )
{
	sDramaActionBase* pAct = mApplyController.pAct;
	if( pAct )
	{
		if( mApplyController.startTime == FLT_MAX )
		{
			mApplyController.startTime = time;
		}

		float delta = time - mApplyController.startTime;
		while( pAct )
		{
			float checkTime = pAct->time;
			if( delta >= checkTime )
			{
				mApplyController.pAct = pAct->pNext;

				if( pAct->actionType == eDRAMA_TRAIL )
					UpdateTrailObject( pAct );
				else
				{
					if( ((sDramaAction*)pAct)->weaponType == mUserWeapon )
						UpdateDramaObject( pAct, true );
				}
				///
			}
			else
				break;

			pAct = mApplyController.pAct;
		}
	}

	if( mApplyController.pAct == 0 )
	{
		/// 스킬 객체 제거
		SKILLMAN->DeleteApplyObject( this );
	}
}

//////////////////////////////////////////////////////////////////////////