/* =====================================================================
* 파    일 :	SkillObject.h , SkillObject.cpp
* 목    적 :	사용중인 스킬 객체 , 상속을 받아 사용한다.
* 작 성 자 :	이법석
* 작 성 일 :    2007년 7월 13일
*
* 추가내용 :
*		추가날짜    작업자	  추가내용
* 
* 주의사항 :	.
* =======================================================================*/
#pragma once
#include "BaseObject_Common.h"
#include "DramaturgyInfo.h"

struct sTargetDamage;
struct sTargetHeal;

enum eAPPLYDRAMA_TYPE;

class cDynamicSceneNode;
class cEffectSceneNode;
class cSoundSceneNode;
struct sTrailInfo;


class cBaseObject;
class cBulletObj;

struct sApplyDrama
{
	sObject mTargetObj;
	cDramaturgyInfo* mpInfo;
};

///
class cDramaturgyObject 
{
public:
	virtual ~cDramaturgyObject();

	virtual void Process( float time ) = 0;

	/// TODO:
	/// 대상에게 객체를 링크 하면서
	/// 제거 하는 루틴을 넣어야 한다.
	/// Thread에 걸면서 추가 처리도 한다.

	/// TODO : 
	/// 연출 상태 변경 함수
	inline eDRAMASTATE GetDramaState() { return mCurrentState; }
	inline void SetDramaState( eDRAMASTATE state ) { mCurrentState = state; }

	inline unsigned long	GetManagedKey() { return mManagedKey; }
	inline unsigned long	GetSkillIdx() { return mSkillIdx; }

	void	Removed() { mRemoved = true; }
	bool	IsRemoved() { return mRemoved; }

protected:
	virtual void UpdateDramaObject( sDramaActionBase* pBase, bool bTarget = false, const NiPoint3& dir = -NiPoint3::UNIT_Y );
	virtual void UpdateTrailObject( sDramaActionBase* pBase );
	virtual void AddLoopEffect( cEffectSceneNode* pNode );
	virtual void AddLoopSound( cSoundSceneNode* pNode );
	virtual void AddLoopTrail( sTrailInfo* pInfo );

	void ChangeDramaState( eDRAMASTATE state );

protected:
	cDramaturgyObject();

	/// 연출 상태 제어 구조체
	struct sDramaStateController
	{
		sDramaStateController()
			: pAct(0), startTime(FLT_MAX)
		{
			mLoopEffect.Reserve(10);
			mLoopSound.Reserve(10);
			mLoopTrail.Reserve(10);
			animationIdx = UINT_MAX;
		}
		sDramaActionBase*	pAct;
		unsigned int		animationIdx;


		float	startTime;

		tPointerArray<void*>	mLoopEffect;
		tPointerArray<void*>	mLoopSound;
		tPointerArray<void*>	mLoopTrail;
	};

	/// 객체 보관소에 대한 참조 정보
	unsigned long			mManagedKey;

	/// 스킬 정보
	unsigned long			mSkillIdx;

	/// 연출 정보
	eDRAMASTATE				mCurrentState;
	cDramaturgyInfo*		mpDramaInfo;

	/// 적용자
	cDynamicSceneNode*		mViewNode;

	/// 타겟 정보
//	sObject					mTargetObj;

	/// 적용 연출 정보
	sDramaStateController	mApplyController;

	bool			mRemoved;

};

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


///
class cSkillObject : public cDramaturgyObject
{
public:
	cSkillObject();
	virtual ~cSkillObject();

	void*			operator new( size_t n ); 
	void			operator delete( void* ptr );

	enum eVERIFY
	{
		eVerify_Faile = 0,
		eVerify_Wait,
		eVerify_Success,
	};

	virtual bool Init( unsigned long skillIdx, float speedFactor );

	virtual void Process( float time );

	void			SetManagedKey( unsigned long key, bool isDummy ) { mManagedKey = key; mIsDummy = isDummy; }
	bool			IsDummySkill() { return mIsDummy; }

	void			WaitCancel();

	///
//	void			AddDamageTargetInfo( sTargetDamage* dInfo );
//	void			AddHealTargetInfo( sTargetHeal* dInfo );
//	void			AddTargetInfo( sObject* dInfo );

	void			EndCast();

protected:
	/// 캐스팅 처리
	void			ProcessCasting( float time );
	/// 발동 처리
	void			ProcessActivity( float time );
	/// 적용 처리
	void			ProcessApply( float time );

	void			ApplyDamage( const sDramaActionBase* pAct );
	void			ApplyHeal( const sDramaActionBase* pAct );

	virtual void	AddLoopEffect( cEffectSceneNode* pNode );
	virtual void	AddLoopSound( cSoundSceneNode* pNode );
	virtual void	AddLoopTrail( sTrailInfo* pInfo );

	void FadeOutAllLoopEffect();
	void FadeOutAllSoundEffect();
	void RemoveAllTrail();

	void			ChangeDramaState( eDRAMASTATE state );

	/// 발사체
	void AddBulletObject( sDramaActionBase* pBase );

	void BulletProcess( float time );

protected:
	struct sDamageInfo
	{
		unsigned long damageValue;
		unsigned char damageType;
		sObject obj;
	};

	enum
	{
		ePRINT_NONE =0,
		ePRINT_DAMAGE,
		ePRINT_HEAL,
	};

	/// 인증 여부
	bool					mIsDummy;

	eVERIFY					mVerifyState;

	/// 캐스팅 연출 정보
	sDramaStateController	mCastingController;
	float					mCastTime;

	/// 발동 연출 정보
	sDramaStateController	mActivityController;

	/// 시전자 정보
//	sObject					mUserObj;
	unsigned char			mUserWeapon;

	/// damage 적용 타겟
	unsigned char			mPrintType;
	tArray<void*>			mTargetObjArray;

	/// 발사체 관리
	tPointerList<void*>		mBulletList;
	tArray<void*>			mDelBulletArray;

	/// Apply Drama 관리
	tPointerList<void*>		mApplyDramaList;

	/// 동작 speed 변수
	float	mSpeedFactor;

	bool	mUsedAnimation;
};

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

///
class cInfluenceObject : public cDramaturgyObject
{
public:
	cInfluenceObject();
	virtual ~cInfluenceObject();

	void*			operator new( size_t n ); 
	void			operator delete( void* ptr );

	virtual bool Init( unsigned long uniqueIdx, unsigned long influenceIdx, bool isbuff );

	/// 적용에 대한 처리만 존재
	virtual void Process( float time );

	/// 실제로 process시작하는 타이밍 제어용
	void StartProcess( float restTime = FLT_MAX, bool onlyLoopEffect = false );

	enum
	{
		eTick_HP,
		eTick_MP,
	};

	void SetTickInfo( unsigned char tickType, long value );

	inline float GetRestTime() { return mRestTime; }

	/// hero 효과인 경우 처리를 위해서
	inline bool IsHeroInfluence() { return mIsHeroInfluce; }

protected:
	void ApplyHP( sDramaActionBase* pAct );
	void ApplyMP( sDramaActionBase* pAct );

protected:
	bool			mIsBuff;
	bool			mRemoved;

	bool			mCheckBlink;
	bool			mIsHeroInfluce;
	bool			mOnlyShowLoopEffect;
	unsigned long	mBlinkTime;

	float	mStartTime;
	float	mLifeTime;

	float	mRestTime;

	bool			mStartTimeCheck;

	unsigned char	mInfluenceType;

	/// tick효과 에서 사용한다.
	bool			mTickInit; /// 최초연출에선 제외시키기위한..
	bool			mTickInfluence;
	unsigned char	mTickType;
	float			mTickValue;
};

class cApplyObject : public cDramaturgyObject
{
public:
	cApplyObject();
	virtual ~cApplyObject();

	void*			operator new( size_t n ); 
	void			operator delete( void* ptr );

	/// apply drama에서 정보를 획득한다.
	virtual bool Init( unsigned long managedKey, unsigned char weaponType, eAPPLYDRAMA_TYPE type );

	/// 효과번호로 Apply만을 가져온다.(item 효과 적용등에 사용)
	virtual bool Init( unsigned long managedKey, unsigned long influenceIdx );

	virtual void Process( float time );

private:

	enum
	{
		eINDEX_DRAMA,
		eINDEX_INFLUENCE,
	};

//	sObject				mUserObj;
	unsigned char		mUserWeapon;

	/// drama or influence
	unsigned char		mIndexType;
	///
	unsigned long		mApplyIndex;

//	eAPPLYDRAMA_TYPE	mApplyType;
//	unsigned long		mInfluenceIdx;
};