/* ====================================================================
* 파    일 :	
* 목    적 :	
* 작 성 자 :	정성대
* 작 성 일 :	2006.08.29
*
* 추가내용 :
*		추가날짜	작업자	추가내용
*		2006.08.29	정성대	생성
* 
* 주의사항 :	
* =================================================================== */
#pragma once

#include "Player.h"
#include "Skill_Common.h"
#include "Sphere.h"
//#include "PlayerSceneNode.h"

class cSkillExecuter;
class cLookAtCamera;
class cSkillObject;
///
class cRibbonGeometry;

// 방어구 세트 조합
#define ARMOR_SETS_NONE					0x0000
#define ARMOR_SETS_ROBES				0x001F
#define ARMOR_SETS_LIGHT_ARMOR			0x03E0
#define ARMOR_SETS_HEAVY_ARMOR			0x7C00

#define ROBES_HAT						0x0001
#define ROBES_UPPER						0x0002
#define ROBES_LOWER						0x0004
#define ROBES_ONEPIECE					0x0006
#define ROBES_HANDS						0x0008
#define ROBES_FEET						0x0010

#define LIGHT_ARMOR_HAT					0x0020
#define LIGHT_ARMOR_UPPER				0x0040
#define LIGHT_ARMOR_LOWER				0x0080
#define LIGHT_ARMOR_ONEPIECE			0x00C0
#define LIGHT_ARMOR_HANDS				0x0100
#define LIGHT_ARMOR_FEET				0x0200

#define HEAVY_ARMOR_HAT					0x0400
#define HEAVY_ARMOR_UPPER				0x0800
#define HEAVY_ARMOR_LOWER				0x1000
#define HEAVY_ARMOR_ONEPIECE			0x1800
#define HEAVY_ARMOR_HANDS				0x2000
#define HEAVY_ARMOR_FEET				0x4000

enum eAfterAction
{
	eAfterAction_None = 0,

	/// 이동후
	eAfterAction_Attack,
	eAfterAction_ItemPick,
	eAfterAction_UseTargetSkill,
	eAfterAction_UseFieldSkill,
	eAfterAction_NpcTalk,

	eAfterAction_UseTarotStore,
	//eAfterAction_OpenStore,

	eAfterAction_UseStall,	/// 노점상이용
	eAfterAction_MapChange,

	eAfterAction_GatheringPick,

	/// 공격후
	eAfterAction_Move,
};

enum eStateInfo_Type
{
	eSTATE_NORMAL,	/// 보통 상태
	eSTATE_PLUS,	/// 증가효과
	eSTATE_MINUS,	/// 감소효과
	eSTATE_OVERLAPPLUS, /// 증가 중첩효과 
	eSTATE_OVERLAPMINUS, /// 감소 중첩효과 
};

struct sAfterAction
{
	eAfterAction	mActionType;
	NiPoint3		mDestPos;
	float			mRange;

	sObject			mTarget;

	/// type에 따라 저장 정보를 달리한다..
	unsigned long	mExData1;
	unsigned long	mExData2;
};

class cNpc;

class cHero : public cPlayer
{
	friend	class cSkillExecuter;

public:
	cHero( unsigned char type = eOBJECTTYPE_HERO );
	virtual ~cHero();

	/// 객체 생성
	virtual bool	Create( sPlayerInfo* pBaseInfo, sPlayerWearInfo* pWearInfo, sPlayerWeaponInfo* pWeaponInfo, sPlayerExrInfo* pExrInfo,
		NiPoint3 sPos, NiMatrix3 sRot = NiMatrix3::IDENTITY, float fScale = 1.0f );

	/// TODO : 객체 재생성
	virtual void	ReCreate( char race, char gender );

	/// 진입 시점에 등록
	bool			GameIn( unsigned long channelNum );

	///
	void			SetHeroInfoNet( MSGROOT* pInfo );

	virtual void	SetState( unsigned int state , bool bShowAni = true );

	void ToggleIdleFlag();
	void ToggleSitDown();

	/// 081209 PKH 앉은 상태 회복2배 설정
	virtual	void	SitDownUpdate();
	bool			IsSitDownCalc();

	/// 신규 경로 탐색..
	bool			ResetMovePath( float destX, float destY );
	bool			ResetActionMovePath( float destX, float destY, float range );

	/// 처리부
	void			Update( unsigned long deltaTime, unsigned long accumTime );
	void			AttackUpdate( unsigned long deltaTime, unsigned long accumTime ); 
	virtual void	MoveUpdate( unsigned long deltaTime );
	virtual void	IdleUpdate( unsigned long deltaTime );

	/// 리스너를 부착
	void			AttachListener();

	NiPoint3			GetDirection() const;
	const NiMatrix3&	GetRotate() const;

	/// 경계 구
	const cSphere& GetBoundSphere() const;
	const NiPoint3& GetCenter() const;

	virtual void	SetTargetObject( unsigned char type, unsigned long idx );

	inline sHeroInfo*		GetHeroInfo() { return &mHeroInfo; }
	inline sPlayerExrInfo*	GetHeroExrInfo() { return &mPlayerExrInfo; }

	/// 스텟
	const sStatus1*		GetStatus1()	{ return &mStatus1; }
	void				SetStatus1( ePLAYER_STATUS statusBase, float value );
	const sStatus1*		GetStatus1Plus()	{ return &mStatus1Plus; }
	void				SetStatus1Plus( ePLAYER_STATUS statusBasePlus, float value );
	const sStatus2*		GetStatus2()	{ return &mStatus2; }
	void				SetStatus2( ePLAYER_STATUS_EXT extStatus, float value );
	const sStatusEtc*	GetStatusEtc()	{ return &mStatusEtc; }
	void				SetStatusEtc( ePLAYER_STATUS_EXT_ADD statusAdd, float value  );
	
	float				CalcStatusSkillRange( float skillRange, eRANGETYPE mRangeType, bool itemPlus );

	void			SetSkillLevel( unsigned char skillLevel ) { mHeroInfo.SkillLevel = skillLevel; }
	unsigned char	GetSkillLevel() { return mHeroInfo.SkillLevel; }
	void			SetSkillPointRemain( unsigned short sp, unsigned short total )	{ mHeroInfo.SkillPointRemain = sp; mHeroInfo.SkillPointTotal = total; }
	unsigned long	GetSkillPointRemain(){ return mHeroInfo.SkillPointRemain;}
	unsigned long	GetSkillPointTotal() { return mHeroInfo.SkillPointTotal; }
	unsigned long	GetUsedSkillPoint() { return mHeroInfo.SkillPointTotal - mHeroInfo.SkillPointRemain; }

	void			SetJobUsedSkillPoint( unsigned int count, unsigned short* values );
	unsigned short	GetJobUsedSkillPoint( unsigned int jobLevel );

	/// 070508 PKH 스텟 증감(색상) 타입
	void			InitStatusInfoType();
	void			SetBaseStatusInfoType( ePLAYER_STATUS pos, eStateInfo_Type type ) { mStatusBaseInfoType[pos] = static_cast<unsigned char>(type); }
	eStateInfo_Type	GetBaseStatusInfoType( ePLAYER_STATUS pos ) { return static_cast<eStateInfo_Type>(mStatusBaseInfoType[pos]); }
	void			SetExtStatusInfoType( ePLAYER_STATUS_EXT pos, eStateInfo_Type type ) { mStatusExtInfoType[pos] = static_cast<unsigned char>(type); }
	eStateInfo_Type	GetExtStatusInfoType( ePLAYER_STATUS_EXT pos ) { return static_cast<eStateInfo_Type>(mStatusExtInfoType[pos]); }


	void			SetExp( unsigned long exp )	{ mHeroInfo.Exp = exp; }
	void			SetSxp( unsigned long exp )	{ mHeroInfo.SkillExp = exp; }

	inline unsigned long	GetMapNum() { return mMapNum; }
	inline void				SetMapNum( unsigned long mapNum ) { mMapNum = mapNum; }

	inline unsigned long	GetChannelNum() { return mChannelNum; }

	inline unsigned long	GetAreaNameIdx() { return mAreaNameIdx; }
	void					SetAreaNameIdx( unsigned long idx );

	/// hero는 max값을 받아 처리할 필요 없다.
	virtual void	HPChange( sTargetDamageHP* damage, cBaseObject* attacker = 0 );
	void			HPChange( unsigned long objectHP, unsigned long objectMaxHP, bool die );
	void			MPChange( unsigned long objectMP, unsigned long objectMaxMP );

	/// hero에서 아무 처리 하지 않는다.
	virtual void PlayerAttack( unsigned long, unsigned long, cBaseObject*, float ) {}
	virtual void PlayerUseSkill( unsigned long /*uIdx*/, unsigned long /*skillIdx*/, cBaseObject* /*pTarget*/ ) {}
	virtual void PlayerUseSkill( unsigned long /*uIdx*/, unsigned long /*skillIdx*/, NiPoint3 /*fieldPos*/ ) {}
	virtual void PlayerMapChangeSkill( unsigned long /*uIdx*/, unsigned long /*skillIdx*/ ) {}
	virtual void PlayerVehicleSkill( unsigned long /*uIdx*/, unsigned long /*skillIdx*/ ) {}

	inline void SetWaitMoveFlag( bool flag ) { mWaitMove = flag; }

	virtual bool EquipWeaponItem( sPlayerWeaponInfo* info );

	virtual void ChangeWeaponState( eWEAPON_STATE state );

	/// 후처리
	void AfterAttack( cBaseObject* pTarget );
	void AfterItemPick( unsigned long idx, float destX, float destY );
	void AfterUseSkill( cBaseObject* pTarget );
	void AfterUseSkill( NiPoint3 fieldPos );

	void AfterNpcTalk( unsigned long npcIdx );
	void AfterNpcTalk( cNpc* pNpc );

	void AfterUseTarotStore( cPlayer* pPlayer );
	void AfterMapChange( unsigned long scriptIdx );
	void AfterUseStall( cPlayer* pPlayer );
	void AfterGatheringPick( unsigned long idx, unsigned long classIdx, float destX, float destY );

	inline sAfterAction* GetCurrentAfterAction() { return &mAfterAction; }
	bool IsProcessAfterAction();

	void SetLevel( unsigned char level );

	inline void CalcStatus() { mIsCalcStatus = true; }
	void		NowCalcStatus();
	inline void UpdateHeroInfo() { mIsUdateHeroInfo = true; }

	/// 주의 :  target지정 - 공격후 스킬 발동
	///			target지정 안함 - 스킬 장착
	inline unsigned long	GetWaitSkillIdx() { return mWaitSkillIdx; }
	void					SetWaitSkillIdx( unsigned long skillIdx );

	void					WaitWeaponSwitch() { mWaitWeaponSwitch = true; }

	bool					IsWeaponChanging() { return mSwitchWeaponFlag; }
	void					SetWeaponChangeFlag( bool val );

	inline bool				CheckSwichDelay() { return (mSwitchWeaponTime != 0); }

	virtual void SetReadyUseSkill( bool used ) 
	{
		if( mReadyUseSkill != used )
		{
			mReadyUseSkill = used; 
		}
	}

	virtual bool IsPossibleSitDown();

	virtual void AddBuff( unsigned long uniqueIdx, cInfluenceObject* p );
	virtual void DelBuff( unsigned long uniqueIdx );

	virtual void AddDeBuff( unsigned long uniqueIdx, cInfluenceObject* p );
	virtual void DelDeBuff( unsigned long uniqueIdx );

	virtual void BlinkBuffIcon( unsigned long uniqueIdx, unsigned long influenceIdx );
	virtual void BlinkDeBuffIcon( unsigned long uniqueIdx, unsigned long influenceIdx );

	inline unsigned long GetMoney() { return mMoney; }
	void SetMoney( unsigned long money ) { mMoney = money; }

	inline unsigned long GetDeposit() { return mDeposit; }
	void SetDeposit( unsigned long money ) { mDeposit = money; }

	inline unsigned long GetTarotPoint() { return mHeroInfo.TarotPoint; }
	void SetTarotPoint( unsigned long point ) { mHeroInfo.TarotPoint = point; }

	inline unsigned long GetPVPPoint() { return mHeroInfo.mPvPPoint; }
	void SetPVPPoint( unsigned long point ) { mHeroInfo.mPvPPoint = point; }

	unsigned long		GetMaxWeight()				{ return FloatToInt( mStatus2.mMaxWeight ); }

	/// 착용 아이템 세트 갱신
	void ResetArmorSets();
	unsigned short  GetArmorSets() { return mArmorSets; }

	virtual void ApplyDamageDrama( unsigned int damage, unsigned int damageType, cBaseObject* pAttacker = 0 );

	unsigned long		GetNpcIdx()	{ return mNpcIdx; }
	void				StartNpcTalk( unsigned long npcIdx );
	void				EndNpcTalk();
	void				SendEndNpcTalk();

	virtual void	SetFixedObjectSizeScale( unsigned short size );

	void ActiveQuestText( LPCTSTR msg, unsigned long color );
	void ActiveNoticeText( LPCTSTR msg, unsigned long color );

	/// 결투 신청/포기
	void			DuelRequest( unsigned long playerIdx = 0 );
	void			DuelGiveUp();

	/// 결투 수락/거부 창 출력
	void			ViewMsgDuelReq( unsigned long duelReqPlayerIdx );
	/// 수락거절 메세지 처리
	void			DuelNoStartMsg( int errorCode );		/// 결투불가 메세지 처리

	void			SetCantMove( bool cantMove )	{ mCantMove = cantMove; }
	void			SetCantSkill( bool cantSkill )	{ mCantSkill = cantSkill; }
	bool			IsCantSkill( unsigned long skillIdx );//	{ return mCantSkill == true || mIsSleep == true || mIsStun == true; }
	bool			IsCantMove()	{ return mCantMove == true || mIsSleep == true || mIsStun == true; }

	void			SetSleep( bool sleep )	{ mIsSleep = sleep; }
	void			SetStun( bool stun )	{ mIsStun = stun; }

	void			SetStaticFaceReq( unsigned long faceIdx );

	void			CheckTabTargetObject();
	void			CheckTabPartyObject();
	void			ClearTabTargetList();

	/// 알파
	void SetAlphaBlended( float alpha );

	virtual bool TransformMonster( unsigned long monsterClassIdx );
	virtual void RestoreMonster();

	void			SetForceType( unsigned char forceType );
	void			SetFirePoint( unsigned long firePoint );
	void			SetFireFriendly( unsigned long fireFriendly );
	void			SetWaterPoint( unsigned long waterPoint );
	void			SetWaterFriendly( unsigned long waterFriendly );
	void			SetWindPoint( unsigned long windPoint );
	void			SetWindFriendly( unsigned long windFriendly );
	void			SetEarthPoint( unsigned long earthPoint );
	void			SetEarthFriendly( unsigned long earthFriendly );

	unsigned long	GetFirePoint() { return mHeroInfo.mFirePoint; }
	unsigned long	GetWaterPoint() { return mHeroInfo.mWaterPoint; }
	unsigned long	GetWindPoint() { return mHeroInfo.mWindPoint; }
	unsigned long	GetEarthPoint() { return mHeroInfo.mEarthPoint; }

	void SetFieldEffRadius( float r );
	void UpdateFieldTargetEffect( NiPoint3 center );

	/// 전직 
	void SetJob( ePLAYER_JOB job );

	/// 파티 세팅
	void SetPartyIndex( unsigned long partyIndex );

	/// 길드 세팅
	void SetGuild( unsigned long guildIndex, LPCTSTR guildName, unsigned char guildPosition, unsigned long markIndex );

	void UseMapChangeSkill( unsigned long skillIdx, unsigned int slotIdx );
	void UseVehicleSkill( unsigned long skillIdx, unsigned int slotIdx );

	bool GatheringStart( unsigned long gaderIdx, unsigned long gatherClassIdx, NiPoint3 targetPos );
	void GatheringEnd();

	bool GatheringCancel();

	bool CheckGatheringEnable( unsigned long gaderClassIdx );

	/// 
	bool ItemMixCancel();
	bool ItemEnhanceCancel();

	/// 탈것 처리
	virtual void RideVehicle( unsigned long vehicleIdx );
	virtual void AlightVehicle();

	/// 오늘의 한마디 미리보기
	void PreviewTodayWord( LPCTSTR word, unsigned long color );
	
	/// 길드마크 미리보기
	void PreviewGuildMark( NiTexture* tex );

	/// 길드마크 기존정보로 갱신
	void UpdateGuildMark();

	/// 조합 직업 체크
	bool CheckHeroMakeSkill( unsigned long makeSkillIdx );

	/// 조합습득 스킬 저장
	void SetMixSkillFirst( unsigned char skill1 );
	void SetMixSkillSecond( unsigned char skill2 );

protected:
	/// 애니메이션 관계 처리
	virtual void Interpret( unsigned long time );

	/// 이동
	virtual bool	Move( float x, float y );
	virtual	bool	ActionMove( float x, float y, float range );

	void StopAfterAction();

	/// 실제 기본 공격 시작 (네트워크 패킷 발송)
	bool			StartAttack( unsigned long attackIdx, cBaseObject* pTarget );

	/// 실제 스킬 시작 (네트워크 패킷 발송)
	void			UseTargetSkill( unsigned long skillIdx, cBaseObject* pTarget );
	void			UseFieldSkill( unsigned long skillIdx, NiPoint3 fieldPos );

	void			AutoActionClear();

	void			ProcessAfterAction( NiPoint3& heroPos );

	/// player에서만 사용하고 혹시 모르는 hero에서의 사용을 막는다.
	virtual void	SetActionMove( float, float, float ) {}

	virtual cDynamicSceneNode* CreateSceneNode( cPlayerSceneNodeParam* param );

	virtual void ClearAllBuff();
	virtual void ClearAllDeBuff();

	virtual void ClearDieBuff();

	void ProcessDelayFlag( unsigned long deltaTime );


	/// monster transform process
	virtual void Update_TransMon( unsigned long deltaTime, unsigned long accumTime );
//	virtual void SetState_TransMon( unsigned int state , bool bShowAni );
	virtual void Interpret_TransMon( unsigned long time );
	virtual void ApplyDamageDrama_TransMon( unsigned int damage, unsigned int damageType, cBaseObject* pAttacker );
	bool StartAttack_Mon( unsigned long attackIdx, cBaseObject* pTarget );
	void UseTargetSkill_TransMon( unsigned long skillIdx, cBaseObject* pTarget );
	void UseFieldSkill_TransMon( unsigned long skillIdx, NiPoint3 fieldPos );
    
protected:
	cLookAtCamera*	mpCamera;
	float			mDefaultCameraOffset;
	float			mCameraOffset;

	sHeroInfo		mHeroInfo;
	tArray<unsigned short>	mJobUsedSkillPoint;

	/// hero info window update 필요여부.
	bool			mIsUdateHeroInfo;

	/// status 재계산 필요여부.
	bool			mIsCalcStatus;

	/// 소속 map번호..
	unsigned long	mMapNum;

	/// 
	unsigned long	mChannelNum;

	///
	unsigned long	mAreaNameIdx;

	/// 스텟1 기본값
	sStatus1		mStatus1;
	/// 스텟1 +값
	sStatus1		mStatus1Plus;
	/// 스텟2 최종값
	sStatus2		mStatus2;

	/// 스텟외 스텟
	sStatusEtc		mStatusEtc;

	/// 데미지 계산용 순간효과 변수
	sDamageCalc		mDamageCalc;

	/// 070508 PKH 스텟 증감(색상) 타입
	unsigned char	mStatusBaseInfoType[ePLAYER_STATUS_LEVEL];
	unsigned char	mStatusExtInfoType[ePLAYER_STATUS_EXT_MAX];

	/// 착용한 아이템 세트
	unsigned short  mArmorSets;

	/// 돈 정보
	unsigned long	mMoney;

	/// 창고 보관액 정보
	unsigned long	mDeposit;

	/// 이동 후 처리
	sAfterAction	mAfterAction;

	/// 무기 교체 대기
	bool			mWaitWeaponSwitch;

	/// 대기 스킬
	unsigned long	mWaitSkillIdx;

	/// 공격중 이동 대기 - 주의 : Attack상태에서만 유효하다
	bool			mWaitMove;
	NiPoint2		mWaitMovePos;

	/// 직업군이 magic/shaman계열인지 체크
	bool			mMageJobType;

	/// 스킬 사용 시작 시간 + 재사용 대기시간
	unsigned long	mWaitUseSkillTime;

	/// 대화중인 npc 인덱스
	unsigned long	mNpcIdx;

	/// 이동 불가
	bool			mCantMove;
	/// 스킬 사용 불가
	bool			mCantSkill;
	/// 수면
	bool			mIsSleep;
	/// 스턴
	bool			mIsStun;

	/// 081209 PKH 자연회복 2배
	unsigned long	mSitDownStartTime;
	bool			mSitDownStatusCalc;

	/// 길찾기
	static const unsigned int MAX_PATH_COUNT = 2048;
	static const unsigned int MAX_PATH_DIST = 30000;
	NiPoint2 mPathArray[MAX_PATH_COUNT];
	unsigned int mPathIndex;
	unsigned int mPathCount;

	unsigned long	mDuelReqPlayerIdx;

	/// 평화 toggle
	unsigned long	mPeaceToggleTime;
	bool			mPeaceToggleFlag;

	unsigned long	mSwitchWeaponTime;
	bool			mSwitchWeaponFlag;

//	typedef tPointerList<void*> cMoveTargetEffect;
//	cMoveTargetEffect mMoveTargetList;
	unsigned long mMoveTargetEffectIdx;
	cEffectSceneNode* mMoveTargetEffect;

	/// 몬스터 탭타겟을 위한 설정
	NiTPointerList<sObject*> mTabTargetList;

};

inline
void cHero::SetWaitSkillIdx( unsigned long skillIdx )
{
	mWaitSkillIdx = skillIdx;
	mWaitMove = false;
}

inline
bool cHero::IsProcessAfterAction()
{
	return (mAfterAction.mActionType != eAfterAction_None);
}
