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

#include "GameSrvDefines.h"

#include "BaseObject.h"
#include "Player_Common.h"
#include "Npc_Common.h"
#include "Stage_Common.h"
#include "Tarot_Common.h"
#include "Quest_Common.h"
#include "Chat_Common.h"
#include "RangeCheck.h"

#include "ItemCountPool.h"
#include "CooltimePool.h"
#include "SQLGameStmt.h"

/// 추적 퍼짐위치 최대값/중심값
const int FOLLOW_POS_MAX = 9;
const int FOLLOW_POS_CENTER = 4;

/// 스킬 포인트 증가 수치
const unsigned char SKILL_LEVELUP_POINT = 2;

/// 일정시간 일괄저장 시간
const unsigned long BATCH_SAVE_TIME = 10 * MINUTE;

struct MAKESKILL_SELECT;
struct MAKESKILL_INSERT;

enum eREQUEST_REJECTION
{
	eREQREJCT_NONE,			/// 요청 거절 상태 없음(요청수락)
	eREQREJCT_GAMEFINISH,	/// 게임 종료 상태
	eREQREJCT_REQWAIT,		/// 요청 대기 상태
	eREQREJCT_DUEL,			/// 결투 상태
	eREQREJCT_PARTY,		/// 파티 상태
	eREQREJCT_GUILD,		/// 길드 상태
};

enum ePLAYER_PARTYSTATE
{
	ePARTY_NONE,		/// 파티 없음
	ePARTY_COMPLETE,	/// 파티중
	ePARTY_SENDJOIN,	/// 파티원 초대중
	ePARTY_RECVJOIN,	/// 파티초대 받는중
};

enum XCOPY_INVENTORY_OPT
{
	XCOPY_INVENTORY_ALL = 0,
	XCOPY_INVENTORY_COUNT,
	XCOPY_INVENTORY_SWAP,
};

// 방어구 세트 조합
#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

/*-- 판매노점 등록 아이템
*/

// 판매아이템 구조체
struct StallSellItem
{
	eStallSellItemStatus status;	// 상태
	TB_INVENTORY*        inventory;	// 인벤토리 참조
	unsigned long        price;		// 가격(개당)
};

struct sGameOption
{
	union
	{
		struct
		{
			bool showGauge				: 1;	// 
			bool showBubble				: 1;	//
			bool showHeroNameCard		: 1;	//
			bool showHeroTotal			: 1;	//
			bool showPlayerNameCard		: 1;	//
			bool showPlayerTotal		: 1;	//
			bool showNPCNameCard		: 1;	//
			bool showMonsterNameCard	: 1;	//
			bool showHelmet				: 1;	//
			bool showTip				: 1;	//

			bool rejectionTrade			: 1;	//
			bool rejectionDuel			: 1;	//
			bool rejectionWhisper		: 1;	//
			bool rejectionParty			: 1;	//
			bool rejectionFriend		: 1;	//
			bool rejectionNote			: 1;	//
		} option1;
		long optionData1;
	};
};
/// default 0x1111 1111 1100 0000 0000 0000 0000 0000

class cPlayer : public cBaseObject
{
public:
	cPlayer();
	~cPlayer();

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

	/// 각종 데이터 초기화
	bool				Init             ( unsigned long connectionIdx, unsigned long playerIdx, unsigned long money, unsigned long deposit );

	/// 플레이어 업데이트 프로세스
	void				Update           ( unsigned long elapsedTime, unsigned long accumTime );

	/// inline functions
	unsigned long		GetConnectionIdx ( ) { return mConnectionIdx; }

	sPlayerInfo*		GetPlayerInfo    ( ) { return &mPlayerInfo;        }
	sPlayerExrInfo*		GetExrInfo       ( ) { return &mPlayerExrInfo;     }
	sHeroInfo*			GetHeroInfo      ( ) { return &mHeroInfo;          }

	wchar_t*			GetUserID        ( ) { return NULL; }

	wchar_t*			GetName          ( ) { return mPlayerInfo.strName; }
	char				GetRace          ( ) { return mPlayerInfo.Race;    }
	char				GetGender        ( ) { return mPlayerInfo.Gender;  }

	eWEAPON_STATE		GetWeaponState   ( ) { return mPlayerWeaponState; }

	void				SetName          ( wchar_t* name );
	void				SetRace          ( char race );
	void				SetGender        ( char gender );

	void				SetStaticFaceIndex( unsigned long faceIdx );

	/// 070607 PKH 플레이어 생존 유무 셋팅
	bool				GetStateDie( )	{ return mPlayerExrInfo.mState == eOBJECT_STATE_DIE; }

	/// 070115 PKH 플레이어 레벨
	unsigned char		GetLevel( ) { return mPlayerInfo.Level; }
	void				LevelUp( unsigned char upLevel ); 
	/// 070115 PKH 직업
	ePLAYER_JOB			GetJob() { return mPlayerInfo.Job; }
	void				SetJob(ePLAYER_JOB job, unsigned long* skillList, unsigned char skillListCnt );

	/// 070528 PKH 스킬 레벨
	unsigned char		GetSkillLevel() { return mHeroInfo.SkillLevel; }
	void				SkillLevelUp( unsigned char upLevel );
	/// 스킬 초기화
	unsigned char		SkillReset( unsigned short itemSlotNum );

	/// exp/sxp 습득
	void				AddExpSxp( unsigned long exp, unsigned long sxp );
	void				AddExpSxpNoPer( unsigned long exp, unsigned long sxp );

	/// 070807 PKH HP초기 셋팅
	void				InitHP( unsigned long HP );
	void				InitMP( unsigned long MP );

	/// 070807 PKH HP/MP값을 알려줌
	unsigned long		GetHP()	{ return mPlayerExrInfo.RestHP; }
	unsigned long		GetMP()	{ return mPlayerExrInfo.RestMP; }

	/// 070807 PKH HP감소
	unsigned long		HPDamage( unsigned long damage, bool *die, bool msgSend, bool cri = false );
	/// 070807 PKH 순식간에 HP증가
	void				HPHeal( unsigned long hp, bool msgSend, unsigned long healerIdx, long distressPoint, eTAKEDAMAGE_TYPE type );
	bool                SendHPHeal( );
	void				SendMaxHP();

	/// 070807 PKH mp처리
	void				MPDamage( unsigned long mp, bool msgSend );
	void				MPHeal( unsigned long mp, bool msgSend );
	bool                SendMPHeal( );
	void				SendMaxMP();

	inline unsigned int	GetRaceGender(){return (mPlayerInfo.Race*eGENDER_MAX + mPlayerInfo.Gender);}

	/// 061208 PKH 플레이어 이동 목적지 설정
	void				SetMoveTargetPos( float x, float y );
	float				GetMoveTargetPosX( ) { return mGotoX; }
	float				GetMoveTargetPosY( ) { return mGotoY; }

	bool				IsMovePossible( NiPoint2 startPos, NiPoint2 goalPos );

	void				SetRangeTarget( float tPosX, float tPosY, sObject& tInfo, float range );
	void				InitRangeTarget()	{ mRange = 0.0f; }

	/// 오브젝트의 거리 체크 수정 거리 - 적용 범위
	float				GetFixedObjectSize()	{ return mFixedObjectSize; }
	void				SetFixedObjectSizePer( short sizePer );
	unsigned short		GetFixedObjectSizePer()	{ return mPlayerExrInfo.mFixedObjectSizePer; }

	/// 몬스터 외형 변신
	unsigned long		GetChgMonsterIdx()	{ return mPlayerExrInfo.mChgMonsterIdx; }
	void				SetChgMonster( unsigned long infObjectIdx, unsigned long monsterIdx );
	void				EndChgMonster();

	/// 세력 친밀도/포인트
	void				SetForceType( unsigned char forceType, bool msgSend = true );
	unsigned char		GetForceType()	{ return mPlayerExrInfo.mForceType; }
	void				FirePointPlus( unsigned long firePoint, bool msgSend = true );
	void				FireFriendlyPlus( unsigned long fireFriendly, bool msgSend = true );
	void				WaterPointPlus( unsigned long waterPoint, bool msgSend = true );
	void				WaterFriendlyPlus( unsigned long waterFriendly, bool msgSend = true );
	void				WindPointPlus( unsigned long windPoint, bool msgSend = true );
	void				WindFriendlyPlus( unsigned long windFriendly, bool msgSend = true );
	void				EarthPointPlus( unsigned long earthPoint, bool msgSend = true );
	void				EarthFriendlyPlus( unsigned long earthFriendly, bool msgSend = true );

	unsigned long		GetGuildIndex() { return mPlayerExrInfo.mGuildIndex; }
	unsigned char		GetGuildPosition() { return mPlayerExrInfo.mGuildPosition; }

public:

	/// 스텟
	void				InitStatus2()	{ memset( &mStatus2, 0 , sizeof(mStatus2) ); }
	const sStatus1*		GetStatus1()	{ return &mStatus1; }
	void				SetStatus1( ePLAYER_STATUS statusBase, float value );
	const sStatus1*		GetStatus1Plus()	{ return &mStatus1Plus; }
	void				SetStatus1Plus( ePLAYER_STATUS statusBasePlus, float value );
	float*				GetPointerStatus2Plus()	{ return mStatus2Plus; }
	float*				GetPointerStatus2Per()	{ return mStatus2Per; }
	float				GetStatus2Plus( ePLAYER_STATUS_EXT extStatus );
	float				GetStatus2Per( ePLAYER_STATUS_EXT extStatus );
	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 );

	const sDamageCalc*	GetDamagecalc()	{ return &mDamageCalc; }
	void				SetDamageCalc( ePLAYER_STATUS_DAMAGE statusDamage, unsigned long value );

	unsigned long		DamageCalc( sObject target, unsigned long skillIdx, unsigned long aType, unsigned long rType );
	bool				AttackSuccess( sObject target, unsigned long skillIdx, unsigned long aType, unsigned short accuracyValue );
	bool				CriticalSuccess( sObject target, unsigned long skillIdx, unsigned long aType, unsigned short criticalValue );
	/// 순간 쓰고 사라지는 스킬효과(데미지) 계산 
	void				CalcInstantSkill( unsigned long statusType1, unsigned long value1, unsigned long statusType2, unsigned long value2 );

	unsigned long		GetMaxHP()	{ return FloatToInt( mStatus2.mMaxHP ); }
	unsigned long		GetMaxMP()	{ return FloatToInt( mStatus2.mMaxMP ); }

	long				GetMoveSpeed( );

	float				CalcStatusSkillRange( float skillRange, eRANGETYPE mRangeType, bool itemPlus );

	/// 070215 PKH 장비 입출력
	sPlayerWeaponInfo*	GetWeaponInfo( ) { return &mPlayerWeaponInfo; }
	sPlayerWearInfo*	GetWearInfo  ( ) { return &mPlayerWearInfo;   }

	/// 070216 PKH 지연시간 기록
	void				SetLoseTime( unsigned long loseTime );

	/// Player의 상태 정보
	unsigned int		GetState() { return mPlayerExrInfo.mState; }
	bool				IsChangeState( unsigned int newState, bool resurrection = false );
	bool				ChangeState( unsigned int newState, bool resurrection = false );

	/// 파티 상태
	void				SetPartyState( ePLAYER_PARTYSTATE state ) { mPartyState = state; }
	ePLAYER_PARTYSTATE	GetPartyState() { return mPartyState; }

	/// 평화/전투 상태
	void				SetStateIdle( unsigned char stateIdle )	{ mPlayerExrInfo.mStateIdle = stateIdle; }
	void				SetStateStop( unsigned char stateStop )	{ mPlayerExrInfo.mStateStop = stateStop; }

	unsigned char		GetStateStop() { return mPlayerExrInfo.mStateStop; }

	/// 070628 PKH 현재 대화중인 npcidx
	unsigned long		GetNpcIdx() { return mNpcIdx; }
	void				SetNpcIdx( unsigned long npcIdx ) { mNpcIdx = npcIdx; }

	/// 070702 PKH 플레이어 부활
	void				Resurrection( unsigned long resurrectionType );
	bool				SkillResurrection();	/// 스킬 부활 
	void				PvPResurrection( bool timeCheck = true );

	/// 적대 리스트에 포함한 몬스터
	void				AddTargetingMonster( unsigned long monsterIdx );
	void				DelTargetingMonster( unsigned long monsterIdx );
	void				ClearTargetingMonster();
	void				DietargetingMonster();
	/// 플레이어가 힐을 받은 경우 몬스터에 공격 포인트 등록
	void				HealAttackToMonster( unsigned long healerIdx, unsigned long heal, long distressPoint, eTAKEDAMAGE_TYPE type );


	/// 효과 
	bool				AddInfluence( unsigned long uniqueIdx, unsigned long influenceIdx );
	tHashSet<unsigned long>* GetInfluenceSet() { return &mInfluenceSet; }
	void				DeleteInfluence( unsigned long influenceIdx );
	void				ReleaseInfluenceSet(); 
	void				DieDeleteInfluence(); 
	void				InfluenceProcessStart();
	void				InfluenceProcessStop();

	bool				IsParentEqual( unsigned long parentUniqueIdx );

	void				SkillResurrectionHP( unsigned long HP );
	void				SkillResurrectionMP( unsigned long MP );

	/// SkillPoint
	unsigned short		GetSkillPoint()	{ return mHeroInfo.SkillPointRemain; }
	unsigned short		GetJobUsedSkillPoint( unsigned char jobstep );
	bool				SkillPointMinus( unsigned short minusSP );
	bool				SkillPointMinusRestore( unsigned short minusSP );
	bool				SkillPointPlus( unsigned short plusSP );
	void				SetSkillReset( unsigned short skillPoint, TB_CHARACTER_SKILL* pSkill, long cnt );
	void				SendSkillPoint();

	/// 080619 KCJ 맵이동 요청.
	bool                IsMapChange ( ) { return mMapChange; }
	void                MapChange ( bool boolean ) { mMapChange = boolean; }
	bool				MapChange( unsigned long posIdx );
	bool				CheatMapChange( unsigned short mapNumber, float x, float y );
	bool				PvPMapChange( unsigned short mapNumber, unsigned short mapDataNumber, unsigned char teamType, float x, float y );
	bool				IsItemMapChange( unsigned long posIdx );
	bool				ItemMapChange( unsigned long posIdx );
	unsigned short		GetPvPMapDataNumber()	{ return mPvPMapDataNumber; }


	///
	/// 071025 PKH 맵이동 위치.
	void                SetMapTargetPos( sTargetPos targetPos ) { mMapTargetPos = targetPos; }
	void                ApplyMapTargetPos( );

	/// 몬스터가 추적하는 비중 합
	bool				MonsterImportancePlus( unsigned char importance );
	void				MonsterImportanceMinus( unsigned char importance );

	void				MoveStop()	{ mGotoX = GetXPos(); mGotoY = GetYPos(); mRange = 0.0f; }

	/// 스텟 변경값 클라이언트에 전송
	void				SendMoveSpeed();		/// 이동 속도
	void				SendAttackSpeed();		/// 공격 속도
	void				SendPlayerSize();		/// 캐릭터 크기
//	void				SendSynStatus();		/// 전체

	void				SetGameIn();
	void				SetGameOut()	{ mGameIn = false; }
	bool				GetGameIn()     { return mGameIn; }

	bool                IsGameFinish();		/// updatecomplete에서 정상 종료 최종 체크

	void				CalcNatureRecovery();

	/// 캐릭터 처음 접속시 스텟 계산이후에 적용할 hp mp값
	void				SetInitRestHP();
	void				SetInitRestMP();
	void				ApplyInitRest();

	/// 생활 스킬
	void				SetCommunitySkill( unsigned long communitySkillIdx);

	/// 몬스터가 플레이어를 추적하는 위치
	unsigned char		SelectFollowPos( unsigned char followPos );
	void				UnSelectFollowPos( unsigned char followPos );

	/// 수락 답변 메세지 대기
	bool				IsRequestRejection()	{ return mIsRequestRejection != eREQREJCT_NONE; }
	unsigned long		GetRequestRejection()	{ return mIsRequestRejection; }
	void				StartRequestRejection( eREQUEST_REJECTION IsRequestRejection );
	void				EndRequestRejection( eREQUEST_REJECTION IsRequestRejection );

	/// 경험치 하락
	unsigned long		ExpDown( unsigned long minimum, unsigned long maximum );	

	/// 플레이어 정보 DB 저장
	void				DBUpdate( bool updateComplete = true );

	/// 순간이동
	void				SetBlink( float x, float y )	{ mBlinkPos.x = x; mBlinkPos.y = y; }
	void				Blink(); 

	/// 몬스터 변신시 쿨타임 처리
	bool				IsChgMonCoolTimeEnd( eMONSTERATTACK_TYPE type );
	void				UpdateChgMonCoolTime( eMONSTERATTACK_TYPE type );
	void				SendCoolTimeChgMon();

	/*--------------- 결투 ---------------*/
	/// 결투 고유번호
	unsigned long		GetDuelIdx()	{ return mDuelIdx; }
	void				SetDuelIdx( unsigned long duelIdx );

	/// 결투 대상자 기록
	void				SetDuelPlayerIdx( unsigned long playerIdx, bool IsAttacker )	{ mDuelPlayerIdx = playerIdx; mIsDuelRequester = IsAttacker; }
	unsigned long		GetDuelPlayerIdx()	{ return mDuelPlayerIdx; }

	/// 본인이 나간경우 대상자와 결투 관련 처리
	void				DuelEnd();

	/// 연승 기록
	void				SetDuelWin()	{ ++mDuelStraightWin; }
	void				ClearDuelWin()	{ mDuelStraightWin = 0; }
	unsigned long		GetDuelWin()	{ return mDuelStraightWin; }

	/// 결투 종료후 결투에 사용된 디버프 제거
	void				DuelEndDebuffClear( unsigned long enemyIdx );

	/// pvp 입장
	bool				IsPvPJoin()	{ return mPlayerExrInfo.mIsPvPJoin; }
	bool				CheckPvPJoin();
	void				PvPOut();
	void				AutoPvPOut();
	unsigned short		GetPvPJoinBeforeMapIdx()	{ return mPvPJoinBeforeMapIdx; }
	NiPoint2			GetPvPJoinBeforePos()	{ return mPvPJoinBeforPos; }
	unsigned long		GetPvPDMIdx()	{ return mPvPDMIdx; }
	unsigned long		GetPvPDMTeam()	{ return mPlayerExrInfo.mPvPDMTeamType; }
	bool				SendPvPTeamChat( char* msg, int length );
	void				PvPScorePlus( unsigned long plusScore )	{ mHeroInfo.mPvPPoint = mHeroInfo.mPvPPoint + plusScore; }

	/// 받은 데미지로 pvp 스코어 계산
	void				AddTakeDamage( sObject attacker, unsigned long damage, long distressPoint, eTAKEDAMAGE_TYPE type );

	/*--------------- 상태 이상 ---------------*/
	void				StateOddity( long* pOddity );
	void				SendOddity( eODDITYTYPE pos, bool apply );
	unsigned long		GetStateOddity( eODDITYTYPE oddityType )	{ return mODDITY[oddityType]; }

	bool				IsCantSkill()	{ return mODDITY[eODDITYTYPE_CANTSKILL] != 0 || mODDITY[eODDITYTYPE_SLEEP] != 0 || mODDITY[eODDITYTYPE_STUN] != 0; }
	bool				IsCantMove()	{ return mODDITY[eODDITYTYPE_CANTMOVE] != 0 || mODDITY[eODDITYTYPE_SLEEP] != 0 || mODDITY[eODDITYTYPE_STUN] != 0; }

	/// 타겟 해제
//	void				DeleteTarget( sObject target, unsigned long range );
	void				MonsterInTargeting( tArray<sMultiTarget>* targetAry, float range );

	/// 각 직업당 사용한 SP 저장
	void				UpdateJobUsedSP();

	void				StatusCalc();

	unsigned long		GetGatheringIdx()	{ return mGatheringIdx; }
	void				SetGatheringIdx( unsigned long gatheringIdx )	{ mGatheringIdx = gatheringIdx; }
	bool				CancelGathering( unsigned long gatheringIdx );

	/// 제조스킬
	unsigned char		AddMakeSkill( unsigned short itemSlotNum );
	void				SetMakeSkill( MAKESKILL_INSERT* pInsert );

	unsigned char		ReqDelMakeSkill( unsigned char makeSkill );
	void				DelMakeSkill( unsigned char makeSkillIdx );

	unsigned char		AddRecipe( unsigned short itemSlotNum );
	void				SetRecipe( unsigned char makeSkill, unsigned long recipeIdx );
	void				SetRecipeGroup( sRecipeGroupInfo* groupInfo, unsigned long cnt );

	bool				InitMakeSkill( MAKESKILL_SELECT* pMakeSkill );
	void				SendMsgRecipeList();
	bool				IsMakeSkill( unsigned char makeSkillIdx );

	int					ItemMixReq( unsigned char makeSkill, unsigned long mixRecipeIdx );	/// 클라이언트에서 조합 요청 - 프로세스 진행여부 체크
	int					ItemMixEnd();		/// 아이템 조합
	void				ItemMixCoolTime();	/// 조합후 관련 정보 변경
	void				ItemMixCancel();	/// 조합 취소
	bool				SaveRecipeCoolTime( RECIPE_COOLTIME* skillCoolTime );

	/// 탈것
	void				SetVehicle( unsigned long infObjectIdx, unsigned long vehicleIdx );
	void				SendEndVehicle();
	bool				IsVehicle()	{ return mPlayerExrInfo.mVehicleIdx != 0 ? true : false; }
	/// 클라이언트에서 탈것 종료 요청온 처리
	void				EndVehicleClient( bool sendSync );
	void				SendEndVehicleExcept();
	/// 탈것 관련 아이템 상태 변경시 탈것 종료 처리
	void				EndVehicleItem( unsigned long skillClassIdx );

protected:
	sPlayerInfo			mPlayerInfo;
	sPlayerExrInfo		mPlayerExrInfo;
    
	sPlayerWeaponInfo	mPlayerWeaponInfo;
	sPlayerWearInfo		mPlayerWearInfo;

	sHeroInfo			mHeroInfo;

	bool				mIsSleep;
	bool				mIsStun;

	typedef tArray<void*> cAry;

	/// 스텟1 기본값
	sStatus1			mStatus1;
	/// 스텟1 +값
	sStatus1			mStatus1Plus;
	/// 스텟2 +값
	float				mStatus2Plus[ePLAYER_STATUS_EXT_MAX];
	/// 스텟2 %값
	float				mStatus2Per[ePLAYER_STATUS_EXT_MAX];
	/// 스텟2 최종값
	sStatus2			mStatus2;

	/// 스텟외 스텟
	sStatusEtc			mStatusEtc;

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

	/// 스텟 계산후 다음 스텟계산시 수치 변동이 있는지 체크를 위한 저장값
	unsigned long		mLastMaxHP;
	unsigned long		mLastMaxMP;

	/// 071016 PKH 회복(힐) 버프 추가 수치 - 기본수치는 가지고 있지않고 스크립트에서 입력된다.
	float				mHealBuffPlus;
	float				mHealBuffPer;

	eWEAPON_STATE		mPlayerWeaponState;

	unsigned long		mConnectionIdx;	

	/// 061208 PKH 이동시 목적지 좌표
	float				mGotoX;
	float				mGotoY;

	///
	float				mRange;
	NiPoint2			mRangeTargetPos;
	sObject				mRangeTarget;

	ePLAYER_PARTYSTATE	mPartyState;
	bool				mIsGuildAddReq;		// 길드 초대를 하고 있는지 여부

	/// 070216 PKH 지연시간
	unsigned int		mLoseTime;

	/// 070628 PKH 현재 대화중인 npcidx
	unsigned long		mNpcIdx;

	typedef tHashSet<unsigned long> cSkillInfluenceSet;
	cSkillInfluenceSet	mInfluenceSet;

	typedef tArray<unsigned short> cJobUsedSpArr;
	cJobUsedSpArr	mJobUsedSpArr;

	typedef tHashSet<unsigned long> cTargetingMonsterSet;
	cTargetingMonsterSet mTargetingMonsterSet;

	/// 부활
	bool				mIsSkillResurrection;
	unsigned long		mSkillResurrectionHP;
	unsigned long		mSkillResurrectionMP;

	/// 080619 KCJ 맵이동 요청.
	bool                mMapChange;

	/// 071025 PKH 맵이동 위치.
	sTargetPos          mMapTargetPos;

	/// 오브젝트의 거리 체크 수정 거리 - 적용 범위
	float				mFixedObjectSize;

	/// 플레이어를 쫓아오는 몬스터의 비중 합계
	long				mMonsterImportance;

	/// 게임 안에 들어 갔는지 기록
	bool				mGameIn;

	/// 자연 회복 다음 적용 시간
	unsigned long		mNextNatureRecoveryTime;

	/// 081209 PKH 자연회복 2배 계산 시점
	unsigned long		mSitDownStartTime;
	bool				mSitDownStatusCalc;

	/// 캐릭터 처음 접속시 스텟 계산이후에 적용할 hp mp값
	unsigned long		mInitRestHP;
	unsigned long		mInitRestMP;

	/// 생활 스킬 종료시간
	float				mCommunitySkillEndTime;

	/// 방향값
	float				mDirection;

	/// 추적 퍼짐위치 자리 선정값
	bool				mFollowPos[FOLLOW_POS_MAX];

	cRangeCheck			mRangeCheck;

	/// 요청을 받을수 없는 상태
	eREQUEST_REJECTION	mIsRequestRejection;

	/// 결투 
	unsigned long		mDuelIdx;			/// 고유번호
	unsigned long		mDuelPlayerIdx;		/// 결투 대상자
	bool				mIsDuelRequester;	/// 본인이 결투 요청자인지 구분
	unsigned long		mDuelStraightWin;	/// 결투 연승 카운트

	unsigned long		mBatchSaveTime;

	NiPoint2			mBlinkPos;			/// 순간이동 목적지 좌표


	long				mODDITY[eODDITYTYPE_MAX];

	eCHEAT_SPEEDUP		mCheatSpeedUp;

	unsigned long		mChgMonCoolTime[eMONSTERATTACK_MAX];

	unsigned long		mPvPDMIdx;
	unsigned short		mPvPJoinBeforeMapIdx;
	NiPoint2			mPvPJoinBeforPos;
	unsigned long		mPvPDieTime;
	unsigned short		mPvPMapDataNumber;

	unsigned long		mGatheringIdx;

	/// 제조 스킬 & 하위 레시피
	typedef tHashMap<unsigned long, unsigned long> cRecipeGroup;
	cRecipeGroup		mRecipeGroup1;		/// 제조스킬의 레시피그룹 보유목록
	cRecipeGroup		mRecipeGroup2;		

	/// 사용 중인 조합 기술
	unsigned long		mItemMixEndTime;	/// 조합 완료 시간
	unsigned char		mMixMakeSkill;
	unsigned long		mMixRecipeIdx;

	unsigned long		mChgMonsterInfIdx;	/// 몬스터 변신 효과 고유 번호
	unsigned long		mVehicleInfIdx;		/// 탈것 효과 고유번호

	// 소지금액 & 예치금액 관련 변수정의.
private:
	unsigned long       mMoney;
	unsigned long       mDeposit;

	// 소지금액 & 예치금액  관련 메소드.
public:
	unsigned long       GetMoney                 ( ) { return mMoney; }
	bool                IsAddMoney               ( long money );
	long                AddMoney                 ( sObject object, long money, bool save=true );
	bool                SaveMoney                ( sObject object, unsigned long befor, unsigned long after, long money );
	bool                SendMoney                ( sObject object, long addMoney=0 );

	unsigned long       GetDeposit               ( ) { return mDeposit; }
	long                AddDeposit               ( sObject object, long deposit );
	bool                SaveDeposit              ( sObject object, unsigned long befor, unsigned long after, long deposit );
	bool                SendDeposit              ( sObject object, long addDeposit=0 );

	void                NpcDeposit               ( MSG_REQ_NPC_DEPOSIT* msg );
	void                NpcWithdraw              ( MSG_REQ_NPC_WITHDRAW* msg );

	// 포인트 관련 메소드.
public:
	unsigned long       GetTarotPoint            ( ) { return mHeroInfo.TarotPoint; }
	long                AddTarotPoint            ( long point );
	bool                SaveTarotPoint           ( long point );
	bool                SendTarotPoint           ( long point );

	unsigned long       GetPvPPoint              ( ) { return mHeroInfo.mPvPPoint; }
	long                AddPvPPoint              ( long point );
	bool                SavePvPPoint             ( long point );
	bool                SendPvPPoint             ( long point );

	// 아이템 & 인벤토리 관련 변수정의.
private:
	TB_INVENTORY        mInventory[ MAX_INVENTORY ];

	eItemActiveWeapon   mItemActiveWeapon;

	unsigned short      mItemWeight;
	sEquipAbility       mEquipAbility;
	unsigned short      mArmorSets;

	DWORD               mItemEnhancedSeed;
	DWORD               mItemChangeSeed;

	ItemCountRoot       mItemCountRoot;
	CooltimeRoot        mCooltimeRoot;

	// 아이템 & 인벤토리 관련 메소드.
public:
	bool                IsInventory              ( TB_INVENTORY* inventory );
	bool                IsInventoryRange         ( unsigned short number );
	bool                IsInventoryEquip         ( unsigned short number );
	bool                IsInventoryQuest         ( unsigned short number );
	bool                IsInventoryMall          ( unsigned short number );
	bool                IsInventoryWarehouse     ( unsigned short number );
	bool                IsInventoryMove          ( unsigned short number1, unsigned short number2, unsigned short& except, int& depth );
	bool                IsInventoryMerge         ( unsigned short number1, unsigned short number2 );
	bool                IsInventoryDivide        ( unsigned short number1, unsigned short number2, unsigned short divide );

	short               GetEmptyBagNumber        ( short number=INVENTORY_BAG_BEGIN );
	short               GetEmptyQuestNumber      ( short number=INVENTORY_QUEST_BEGIN );

	void                InventorySwap            ( unsigned short number1, unsigned short number2 );
	void                InventoryMove            ( unsigned short number1, unsigned short number2 );
	void                InventoryExcept          ( unsigned short number1, unsigned short number2 );

	short               GetItemCount             ( long itemDefineIndex );

	bool                IsItem                   ( long itemDefineIndex );
	bool                IsItemUse                ( long itemDefineIndex, unsigned short count=1 );
	bool                ItemUse                  ( long itemDefineIndex, unsigned short count=1 );
	long                IsItemMapChange          ( short number, long itemDefineIndex, long itemAbilityInfluence );
	long                IsItemVehicle            ( short number, long itemDefineIndex, long itemAbilityInfluence );
	bool                ItemUseMapChange         ( long inventoryIdx );
	bool                SendItemUse              ( TB_INVENTORY* inventory );

	unsigned int        IsItemReward             ( long inventoryIdx, eDisjointItem* items, int maxCount );
	unsigned int        IsItemReward             ( sQuestItem* items, int maxCount );
	unsigned int        IsItemTake               ( sQuestItem* items, int maxCount );
	unsigned int		GetQuestItemCount		 ( long itemDefineIndex, int maxCount );

	void                SetActiveWeapon          ( eItemActiveWeapon activeWeapone ) { mItemActiveWeapon = activeWeapone; }
	eItemActiveWeapon   GetActiveWeapon          ( ) { return mItemActiveWeapon; }

	void                EquipItems               ( );
	void                CalcItemWeight           ( );
	unsigned short      GetItemWeight            ( ) { return mItemWeight; }

	void                AddEquipAbility          ( short opt, short value );
	void                AddEquipAbility          ( TB_ITEM_ABILITY* itemAbility );
	void                AddEquipEnhanced         ( TB_ITEM_ENHANCED* itemEnhanced, BYTE enhanced );
	void                AddEquipCards            ( TB_INVENTORY* inventory );
	sEquipAbility*      GetEquipAbility          ( ) { return &mEquipAbility; }

	void                ResetArmorSets           ( );
	unsigned short      GetArmorSets             ( ) { return mArmorSets; }

	ItemCountRoot*      GetItemCountRoot         ( ) { return &mItemCountRoot; }

	CooltimeRoot*       GetCooltimeRoot          ( ) { return &mCooltimeRoot; }
	void                AddCooltime              ( TB_INVENTORY_COOLTIME* table );

	bool                CheckInventory           ( long itemDefineIndex, int itemCount );

	TB_INVENTORY*       XCopyInventory           ( TB_INVENTORY* destination, TB_INVENTORY* source, XCOPY_INVENTORY_OPT opt=XCOPY_INVENTORY_ALL );
	TB_INVENTORY*       XCopyInventory           ( TB_INVENTORY* inventory, XCOPY_INVENTORY_OPT opt=XCOPY_INVENTORY_ALL );

	TB_INVENTORY*		SelectInventory          ( short number=MIN_INVENTORY );
	TB_INVENTORY*		SelectInventoryIdx       ( long idx );
	TB_INVENTORY*       CreateInventory          ( TB_ITEM_DEFINE* itemDefine, short number, short count, short* pcbValue );
	TB_INVENTORY*       CreateInventory          ( long itemDefineIndex, short number, short count, short* pcbValue );
	short               UpdateInventory          ( TB_INVENTORY* inventory, short count );
	short               UpdateInventory          ( short number, short count );
	bool                RemoveInventory          ( TB_INVENTORY* inventory );
	bool                RemoveInventory          ( short number );

	void                ItemUseInventory         ( ULONG_PTR socketContext, MSG_REQ_ITEM_USE_INVENTORY* msg );
	void                ItemDelInventory         ( ULONG_PTR socketContext, MSG_REQ_ITEM_DEL_INVENTORY* msg );
	void                ItemSwiInventory         ( ULONG_PTR socketContext, MSG_REQ_ITEM_SWI_INVENTORY* msg );
	void                ItemDivideInventory      ( ULONG_PTR socketContext, MSG_REQ_ITEM_DIVIDE_INVENTORY* msg );
	void                ItemMov2Inventory        ( ULONG_PTR socketContext, MSG_REQ_NPC_ITEM_MOV2_INVENTORY* msg );
	void                ItemEnhancedInventory    ( ULONG_PTR socketContext, MSG_REQ_ITEM_ENHANCED_END* msg );
	void                ItemDisjointInventory    ( ULONG_PTR socketContext, MSG_REQ_ITEM_DISJOINT_INVENTORY* msg );
	void                ItemPutCardInventory     ( ULONG_PTR socketContext, MSG_REQ_ITEM_PUT_CARD_INVENTORY* msg );
	void                ItemChangeInventory      ( ULONG_PTR socketContext, MSG_REQ_ITEM_CHANGE_INVENTORY* msg );

	void                ItemSell                 ( ULONG_PTR socketContext, MSG_REQ_NPC_ITEM_SELL* msg );
	void                ItemBuy                  ( ULONG_PTR socketContext, MSG_REQ_NPC_ITEM_BUY* msg );
	void                ItemCollect              ( ULONG_PTR socketContext, MSG_REQ_ITEM_COLLECT* msg );

	bool                SendInventory            ( ULONG_PTR socketContext );
	bool                SendInventoryCooltime    ( ULONG_PTR socketContext );

	bool				SetWearInfoWithSendMsg   ( eWEAR_TYPE type, unsigned long itemDefineIndex );
	void				SetWeaponInfoWithSendMsg ( TB_INVENTORY* left, TB_INVENTORY* right );

	// 아이템줍기 관련 변수정의.
private:
	bool                mItemGetOpen;
	unsigned long       mItemGetIdx;

	int  				mItemGetCount;
	sItemData			mItemGetData[ MAX_ITEMS ];

	// 아이템줍기 관련 메소드.
public:
	void                ItemGetOpen              ( MSG_REQ_ITEM_GET_OPEN* msg );
	void                ItemGetClose             ( MSG_REQ_ITEM_GET_CLOSE* msg );
	void                ItemGetClose             ( );
	void                ItemGet                  ( MSG_REQ_ITEM_GET* msg );

	unsigned short      ItemGetAutoPush          ( unsigned long itemDefineIndex, unsigned short count );
	bool				ItemGetAutoEnd           ( bool apply );

	bool                ItemGetQuest             ( unsigned long itemDefineIndex, unsigned short count );

	// 아이템줍기 관련 메소드.
private:
	bool                SendItemGetOpen          ( cBaseObject* baseObject );
	bool                SendItemGetClose         ( );
	bool                SendItemGetLeave         ( cBaseObject* baseObject );
	bool                SendItemGatheringOpen    ( cBaseObject* baseObject );

	// 거래 관련 변수정의.
private:
	eItemExchangeStatus mExchangeStatus;
	sObject             mExchangeTarget;
	unsigned long       mExchangeItems;
	unsigned long       mExchangeMoney;

	// 거래 관련 메소드.
public:
	eItemExchangeStatus GetExchangeStatus        ( ) { return mExchangeStatus; }
	long                GetExchangeMoney         ( ) { return mExchangeMoney; }

	void                ExchangeDie              ( );
	void                ExchangeShutdown         ( bool shutdown=false );

	void                ExchangeAsk              ( MSG_REQ_ITEM_EXCHANGE_ASK* msg );
	void                ExchangeAsk              ( sObject object );
	void                ExchangeReply            ( MSG_REQ_ITEM_EXCHANGE_REP* msg );
	void                ExchangeReply            ( BYTE type );

	void                ExchangeAdd              ( MSG_REQ_ITEM_EXCHANGE_ADD* msg );
	void                ExchangeAdd              ( TB_INVENTORY* inventory );
	void                ExchangeAdd              ( unsigned long money );
	void                ExchangeDel              ( MSG_REQ_ITEM_EXCHANGE_DEL* msg );
	void                ExchangeDel              ( TB_INVENTORY* inventory );

	void                ExchangeOk               ( MSG_REQ_ITEM_EXCHANGE_OK* msg );
	void                ExchangeRetry            ( MSG_REQ_ITEM_EXCHANGE_RETRY* msg );
	void                ExchangeRetry            ( );
	void                ExchangeCancel           ( MSG_REQ_ITEM_EXCHANGE_CANCEL* msg );
	void                ExchangeCancel           ( );

	void                ExchangeEnd              ( MSG_REQ_ITEM_EXCHANGE_END* msg );
	void                ExchangeEnd              ( TB_INVENTORY* table, unsigned long rowCount );

	bool                SendMsgResExchange       ( char category, char protocol, int error );
	bool                SendMsgResExchangeEnd    ( TB_INVENTORY* table, unsigned long rowCount );

	// 노점 관련 변수정의.
private:
	// 노점 아이템(ITEM)
	bool                mStallSell;
	wchar_t             mStallSellTitle[ MAX_STALL_TITLE_LEN ];
	StallSellItem       mStallSellItems[ MAX_STALL_ITEM ];
	unsigned long       mStallSellItemOffset;

	unsigned long       mStallSellGuests[ MAX_STALL_GUEST ];
	unsigned long       mStallSellGuestOffset;

	// 노점 게스트(GUEST)
	sObject             mStallSellOwner;

	// 노점 관련 메소드.
public:
	void                StallSellSearch          ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_SEARCH* msg );

	bool                IsStallSellOpen          ( ) { return mStallSell; }
	void                StallSellOpen            ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_OPEN* msg );
	void                StallSellClose           ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_CLOSE* msg );

	void                StallSellOpenDie         ( );
	void                StallSellOpenShutdown    ( bool shutdown=false );

	void                StallSellUseDie          ( );
	void                StallSellUseShutdown     ( bool shutdown=false );

	StallSellItem*      GetStallSellItem         ( TB_INVENTORY* inventory, long price );
	StallSellItem*      GetStallSellItem         ( TB_INVENTORY* inventory );
	bool                ReleaseStallSellItem     ( StallSellItem* stallSellItem );
	void                ClearStallSellItem       ( );

	bool                GetStallSellGuest        ( unsigned long characterIdx );
	bool                ReleaseStallSellGuest    ( unsigned long characterIdx );
	void                ReleaseStallSellAllGuests( );

	void                StallSellRename          ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_RENAME* msg );

	void                StallSellAdd             ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_ADD* msg );
	void                StallSellDel             ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_DEL* msg );
	void                StallSellMod             ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_MOD* msg );

	void                StallSellJoin            ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_JOIN* msg );
	void                StallSellJoin            ( cPlayer* player );
	void                StallSellLeave           ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_LEAVE* msg );
	bool                StallSellLeave           ( cPlayer* player );
	void                StallSellLeave           ( int error );
	void                StallSellGet             ( ULONG_PTR socketContext, MSG_REQ_ITEM_STALL_SELL_GET* msg );

	bool                SendMsgResStallSell      ( char category, char protocol, int error );
	void                SendMsgSynStallSell      ( char category, char protocol, TB_INVENTORY* inventory, long price );

	// 타로 관련 변수정의.
private:
	wchar_t             mTarotTitle[ MAX_TAROT_TITLE ];
	unsigned long       mTarotPrice;
	unsigned short      mTarotUserCount;
	short               mTarotItemCount;
	bool                mTarotCloseReserved;

	unsigned long       mTarotGuests[ MAX_TAROT_GUEST ];
	int					mTarotGuestOffset;

	unsigned long       mTarotReaderIdx;
	TB_INVENTORY*       mTarotCards[ MAX_TAROT_CARDS ];
	TB_INVENTORY*       mSpread[ MAX_SPREAD ];
	int                 mSpreadOffset;

	unsigned long       mTarotResultIndex;
	unsigned long       mTarotResultValue;

	// 타로 관련 메소드 - 타로는 Reader와 Seeker로 구분.
public:
	void                SetTarotResultIndex      ( long index ) { mTarotResultIndex=index; }
	void                SetTarotResultValue      ( long value ) { mTarotResultValue=value; }

	wchar_t*            GetTarotTitle            ( ) { return mTarotTitle; }
	unsigned long       GetTarotPrice            ( ) { return mTarotPrice; }

	bool				IsTarotReaderClose       ( );

	void				TarotReaderReady         ( ULONG_PTR socketContext, MSG_REQ_TAROT_READER_READY* msg );
	void				TarotReaderOpen          ( ULONG_PTR socketContext, MSG_REQ_TAROT_READER_OPEN* msg );
	void				TarotReaderClose         ( ULONG_PTR socketContext, MSG_REQ_TAROT_READER_CLOSE* msg );
	void				TarotReaderClose         ( int error );

	bool                GetTarotCloseReserved    ( ) { return mTarotCloseReserved; }
	bool                GetTarotGuest            ( unsigned long characterIdx );
	bool                ReleaseTarotGuest        ( unsigned long characterIdx );
	void                ReleaseTarotAllGuests    ( );

	bool                GetTarotCards            ( TB_INVENTORY* inventory[] );
	void                GetSpreads               ( TB_INVENTORY* inventory[], int& offset );
	short               GetTarotItemCount        ( ) { return mTarotItemCount; }
	void                UseTarotCard             ( sObject object, long money, long itemDefineIndex );

	void                TarotSeekerOpen          ( ULONG_PTR socketContext, MSG_REQ_TAROT_SEEKER_OPEN* msg );
	void                TarotSeekerClose         ( ULONG_PTR socketContext, MSG_REQ_TAROT_SEEKER_CLOSE* msg );
	void                TarotSeekerJoin          ( ULONG_PTR socketContext, MSG_REQ_TAROT_SEEKER_JOIN* msg );
	void                TarotSeekerResult        ( ULONG_PTR socketContext, MSG_REQ_TAROT_SEEKER_RESULT* msg );
	void                TarotSeekerAccept        ( ULONG_PTR socketContext, MSG_REQ_TAROT_SEEKER_ACCEPT* msg );

	void                TarotReaderDie           ( );
	void                TarotSeekerDie           ( );
	void                TarotReaderShutdown      ( bool shutdown=false );
	void                TarotSeekerShutdown      ( bool shutdown=false );

	bool                SendMsgResTarot          ( char category, char protocol, int error );

	bool                SendTarotReaderJoin      ( wchar_t* seekerName );
	bool                SendTarotReaderLeave     ( wchar_t* seekerName );

	bool                SendTarotStoreOpen       ( wchar_t* readerName, wchar_t* tarotTitle, unsigned long price );
	bool                SendTarotStoreJoin       ( wchar_t* tarotTitle, unsigned long price );

	// 퀘스트 관련 데이터
private:
	///	개인 보유 퀘스트
	TB_QUEST_PROGRESS	mQuest[ MAX_KEEPQUEST ];

	/// 해당 맵의 npc 상태 저장
	typedef tHashMap<unsigned long, eNpcQuestStatus> cNpcQuestStatusMap;
	cNpcQuestStatusMap	mNpcStatusMap;

	/// 완료된 퀘스트 목록 ( 보상까지 )
	typedef	tHashSet<unsigned long> cCompleteQuestSet;
	cCompleteQuestSet	mCompleteQuestSet;

	/// 완료된 퀘스트 그룹 목록
	typedef	tHashSet<unsigned int> cCompleteGroupQuestSet;
	cCompleteGroupQuestSet	mCompleteGroupQuestSet;

	// 퀘스트 관련 메소드
public:
	TB_QUEST_PROGRESS*  GetQuest				 ( int number );
	bool                SendQuest		         ( ULONG_PTR socketContext );
	bool				SaveQuestProgress		 ( ULONG_PTR socketContext );	/// DB 에 퀘스트 진행정보 갱신		
	bool				SendDefaultReward		 ( unsigned long questIdx, unsigned long* skillList, unsigned char skillListCnt );
	bool				SendRewardBuff			 ( unsigned long buffIdx );
	bool				SendLimitPenalty		 ( unsigned long questIdx, bool gameIn = false );	/// 제약사항 걸기
	bool				SendFailPenalty			 ( unsigned long questIdx );	/// 실패로 인한 패널티
	bool				SendEndPenalty			 ( unsigned long questIdx );	/// 퀘스트 종료시의 처리

	/// 퀘스트 진행 검사 ( targetIdx : 몬스터, npc 종류인덱스 )
	void				UpdateDutyHunt			 ( unsigned int classIdx );	
	void				UpdateDutyItem			 ( );
//	void				UpdateDutyItem			 ( unsigned long itemIndex, unsigned int count );

	int					IsRegistQuest			 ( eQUESTADD_TYPE type, unsigned long questIdx, unsigned long npcIdx );	/// 신규가능한 퀘스트인지 검사
	int					IsRegistQuestItem		 ( unsigned long questIdx );	/// 신규가능한 퀘스트인지 검사
	bool				IsEquipQuestItem		 ( unsigned long questIdx );	/// 퀘스트진행 아이템을 착용하고 있는지 검사
	int					IsUseQuestItem			 ( unsigned int number, unsigned long& questIdx );		/// 의뢰아이템을 사용할수 있는지 체크
	bool				QuestMapChange			 ( unsigned long posIdx );
	void				InitQuestAura            ( );
	bool				IsCompleteGathering		 ( unsigned long questIndex );

	int					IsKeepQuest				 ( int arrIdx, long questIdx ); /// 보유중인 퀘스트인지 검사
	int					IsKeepQuest				 ( long questIdx );
	int					IsKeepGroupQuest		 ( long questIdx );				/// 해당 퀘스트와 동일한 그룹의 퀘스트 보유중 검사
	bool				IsCompleteQuest			 ( long questIdx );				/// 완전 완료한 퀘스트인지 검사
	bool				IsCompleteGrouptQuest	 ( long questIdx );				/// 해당 퀘스트와 동일한 그룹의 퀘스트를 완료했는지 검사
	bool				AddCompleteQuest		 ( unsigned long questIdx );	/// 완전히 완료한 퀘스트 목록
	int					FindEmptyQuest			 ( );
	void				ClearQuestList			 ( );
	void				ClearCompleteList		 ( );
	void				DeleteQuest				 ( int arrIdx );	
	unsigned int		GetDropItemCount		 ( unsigned int arrIdx, unsigned long itemIdx );	/// 몬스터 드랍에 필요한 아이템 갯수 리턴

	bool				ResetQuestNpcStatus		 ( );							/// 현재 맵의 전체 npc 퀘스트 상태 초기화 (map단위)
	bool				ResNpcQuestStatus		 ( HANDLE handle, void* msg );
	bool				ResNpcQuestStatus		 ( );							/// NPC 상태 SEND
	bool				SendMapChangeNpcStatus	 ( );							/// 맵체인지시 해당 맵의 전체 npc 상태 체크 후 send 
	bool				SendNpcQuestStatus		 ( );
	bool				SendNpcNewQuestList		 ( unsigned long npcIdx );		/// npc 클릭시 신규 가능 퀘스트 목록 보내주기

	int					SaveQuestInsert			  ( ULONG_PTR socketContext, long characterIdx, long questIdx );
	int					SaveQuestInsertByItem	  ( ULONG_PTR socketContext, long characterIdx, unsigned long questIndex, unsigned short number );
	int					SaveQuestComplete		  ( ULONG_PTR socketContext, MSG_REQ_NPC_QUEST_COMPLETE* msg, unsigned int dbIdx );	
	int                 SaveQuestReward           ( ULONG_PTR socketContext, MSG_REQ_NPC_QUEST_REWARD* msg, unsigned int dbIdx );
	bool				SaveQuestDelete			  ( ULONG_PTR socketContext, MSG_REQ_QUEST_DEL* msg, unsigned int dbIdx );
	bool				SaveQuestDeleteAuto		  ( ULONG_PTR socketContext, MSG_REQ_QUEST_DELAUTO* msg, unsigned int dbIdx );
	void				GetQuestStatus            ( eNpcQuestStatus& status, unsigned long npcIdx );

	// 커뮤니티 메소드 - 친구.
private:
	TB_FRIEND           mFriends[ MAX_FRIEND ];

public:
	void                ClearFriends             ( );
	TB_FRIEND*          SelectFriend             ( short offset=0 );
	bool                UpdateFriend             ( );
	void                SendFriendList           ( ULONG_PTR socketContext );

	// 네트워크 관련 메소드.
public:
	bool                SendPlayerInfo           ( char category, char protocol, ULONG_PTR socketContext );
	bool                SendSightIn              ( char category, char protocol, unsigned long connectionIdx );
	bool                SendSightOut             ( char category, char protocol, unsigned long connectionIdx );
	bool				SendBuff				 ( char protocol, unsigned long connectionIdx );

	bool				SendHeroInfo();

	/// 치트
protected:
	bool mCheatHideMode;
	bool mCheatUndeadMode;
	unsigned long mCheatChatDuration;
	unsigned long mCheatChatAccumTime;
	unsigned long mCheatStopDuration;

public:
	void SetCheatHideMode( bool hide );
	bool GetCheatHideMode() const;

	void SetCheatUndeadMode( bool undead );
	void CheatRecover();
	void CheatRebirth();

	void CheatStop( unsigned long duration );
	void CheatCancelStop();

	void SetCheatSpeedUp( unsigned long speedUp );
	void CalcCheatSpeedUp();

	/// 호칭관리
private:
	/// 플레이어가 소유한 호칭 맵
	typedef tPointerHashSet<unsigned long> cHaveTitleSet;
	cHaveTitleSet mHaveTitleSet;

	/// 호칭 셋팅으로 인해 적용된 효과의 고유 인덱스( 효과삭제를 위해 저장 )
	unsigned long mTitleUniqIndex;
	
public:
	bool SendHaveTitleList( ULONG_PTR socketContext );	/// 보유 호칭 목록 send
	void SendHaveTitle( unsigned long titleIdx );		/// 보유 호칭 send
	
	void ClearHaveTitleList();							/// 보유 호칭 목록 초기화
	bool AddHaveTitle( unsigned long titleIdx );		/// 보유 호칭 추가

	bool InitTitle();
	bool ChangeTitle( unsigned long titleIdx );			/// 현재 호칭으로 설정

public:
	void				SetPartyIndex( unsigned long idx );
	unsigned long		GetPartyIndex()	{ return mPlayerExrInfo.mPartyIndex; }

public:
	void SetGuildAddReq( bool set ) { mIsGuildAddReq = set; }
	bool IsGuildAddReq() { return mIsGuildAddReq; }		/// 길드 초대하고 있는지 여부

	bool ChangeGuild( unsigned long guildIndex, char position, wchar_t* name, unsigned long markIndex );
	void ChangeGuildPosition( char position );
	void ChangeGuildMarkIndex( unsigned long markIndex );

private:
	/// 옵션 값
	sGameOption		mOptionData1;

public:
	void		SetOptionData( long option ) { mOptionData1.optionData1 = option; }
	sGameOption*		GetOptionData() { return &mOptionData1; }

private:
	/// NPC 점집 이용
	TIMESTAMP_STRUCT mFortuneThru[5];

public:
	TIMESTAMP_STRUCT* GetFortuneThru( int i );
	bool SaveFortuneData( ULONG_PTR socketContext );

	bool SendInitTodayWord();
	bool ChangeTodayWord( ULONG_PTR socketContext, wchar_t* word, unsigned long color );


	// 블록 관련 변수 정의
public:
	bool   mBlockApply;
	time_t mBlockValidThru;

	// 블록 관련 메소드 정의
public:
	bool IsBlock  ( );
	bool SetBlock ( bool apply, unsigned long second );
};

inline void cPlayer::SetName( wchar_t* name ) 
{
	::wcsncpy( mPlayerInfo.strName, name, MAX_NAME_SIZE ); 
	mPlayerInfo.strName[MAX_NAME_SIZE] = 0;
}

inline void cPlayer::SetRace( char race )
{
	mPlayerInfo.Race = race;
}

inline void cPlayer::SetGender( char gender )
{
	mPlayerInfo.Gender = gender;
}

inline void	cPlayer::SetStaticFaceIndex( unsigned long faceIdx )
{
	mPlayerInfo.HeadInfo[eHEAD_FACE_STATIC] = faceIdx;
}

inline void cPlayer::SetRangeTarget( float tPosX, float tPosY, sObject& tInfo, float range )
{
	mRange = range;
	mRangeTargetPos = NiPoint2(tPosX, tPosY);
	mRangeTarget = tInfo;
}

inline bool cPlayer::MonsterImportancePlus( unsigned char importance )
{
	if( mMonsterImportance + importance > 100 )
	{
		//printf("\n 100 < importancePlus [%d]\n", mMonsterImportance + importance );
		return false;
	}

	//printf("\n mMonsterImportance[%d] + ", mMonsterImportance );
	mMonsterImportance = mMonsterImportance + importance;
	//printf("importance[%d] = MonsterImportancePlus[%d] \n", importance, mMonsterImportance );
	return true;
}

inline void cPlayer::MonsterImportanceMinus( unsigned char importance )
{
	if( mMonsterImportance - importance < 0 )
	{
		//printf("\n 0 > importancePlus [%d]\n", mMonsterImportance - importance );
		mMonsterImportance = 0;
		return;
	}

	//printf("\n mMonsterImportance[%d] - ", mMonsterImportance );
	mMonsterImportance = mMonsterImportance - importance;
	//printf("importance[%d] = MonsterImportancePlus[%d] \n", importance, mMonsterImportance);

}

inline void cPlayer::ApplyMapTargetPos( )
{
	mMapNumber = mMapTargetPos.mMapNumber;
	mGotoX = mObjectPos.x = mMapTargetPos.mPosX;
	mGotoY = mObjectPos.y = mMapTargetPos.mPosY;
	mDirection = mMapTargetPos.mRotAngle;
}

inline bool cPlayer::IsInventory(TB_INVENTORY* inventory)
{
	if ( inventory != NULL )
		return ((inventory->idx > 0) && (inventory->count > 0));
	return false;
}

inline bool cPlayer::IsInventoryRange(unsigned short number)
{
	return !(number > MAX_INVENTORY);
}

inline bool cPlayer::IsInventoryEquip(unsigned short number)
{
	return !(number > INVENTORY_EQUIP_END);
}

inline bool cPlayer::IsInventoryQuest(unsigned short number)
{
	return !(number < INVENTORY_QUEST_BEGIN || number > INVENTORY_QUEST_END);
}

inline bool cPlayer::IsInventoryMall(unsigned short number)
{
	return !(number < INVENTORY_MALL_BEGIN || number > INVENTORY_MALL_END);
}

inline bool cPlayer::IsInventoryWarehouse(unsigned short number)
{
	return !(number < INVENTORY_WAREHOUSE_BEGIN || number > INVENTORY_WAREHOUSE_END);
}

inline TB_INVENTORY* cPlayer::SelectInventory(short number)
{
	return (number < MIN_INVENTORY || number > MAX_INVENTORY) ? (NULL) : (mInventory + number);
}

inline TIMESTAMP_STRUCT* cPlayer::GetFortuneThru( int i )
{
	return ( i >= 0 && i < 5 ) ? mFortuneThru + i : NULL;
}

/// 배열 인덱스로 가져오기
inline TB_QUEST_PROGRESS* cPlayer::GetQuest( int number )
{
	return (number < 0 || number > MAX_KEEPQUEST ) ? (NULL) : (mQuest + number);
}

inline void cPlayer::ClearQuestList()
{
	memset( mQuest, 0, sizeof(mQuest) );
}

inline void cPlayer::ClearCompleteList()
{
	mCompleteQuestSet.Clear();
	mCompleteGroupQuestSet.Clear();
}

/// 치트
inline
bool cPlayer::GetCheatHideMode() const
{
	return mCheatHideMode;
}

inline
void cPlayer::SetCheatUndeadMode( bool mode )
{
	mCheatUndeadMode = mode;
}

//inline
//void cPlayer::SetCheatWatch( bool mode )
//{
//	mCheatWatch = mode;
//}

