/* ==========================================================================
* 파    일 : Monster.h
* 목    적 : 몬스터 클래스
* 작 성 자 : 박경희
* 작 성 일 : 2006-09-20
* 주의사항 : 몬스터는 풀에서 메모리를 할당 받기때문에 객체 생성소멸 override함
*===========================================================================*/

#pragma once

#include "BaseObject.h"

#include "actionmove.h"
#include "ActionDie.h"
#include "ActionAttack.h"
#include "ActionEscape.h"
#include "ActionFollow.h"
#include "ActionIdle.h"
#include "Monster_Common.h"
#include "RangeCheck.h"
#include "Skill_Common.h"

#include "TakeDamagePool.h"

class cPathFinder;
enum eOBJECTTYPE;

class cModeAgent;
class cMode;

const unsigned long TARGET_CHECK_RANGE = 5000;		/// 타겟 선정시 유효범위
const unsigned long	ESCAPE_HP50 = 50;				/// 도망시 조건
const unsigned long	ESCAPE_HP30 = 30;
const unsigned long SKILL_USE_HP40 = 40;			/// 스킬 사용 조건
const unsigned long SKILL_USE_HP80 = 80;
const unsigned long TALK_DELAY = 1000;				/// 대사간 최소 간격
const unsigned long SKILL_WAIT_TIME = 500;			/// 스킬 재사용 대기 시간

struct sMonsterTakeDamageInfo
{
	unsigned long takeDamage;
	unsigned long distressPoint;
};

class cMonster : public cBaseObject
{

public:
	/// 생성소멸
	cMonster( void );
	~cMonster( void );

	/// objectmanager의 메모리풀에서 몬스터 공간을 할당받음
	void* operator new ( size_t n ); 
	/// 메모리풀에서 할당 받은 몬스터를 제거해줌
	void operator delete ( void* ptr, size_t n );


	/// 일반적인 생성
	bool				Init( unsigned long uniqueidx, unsigned long classIdx, unsigned long regenIdx );
	void				Release();

	/// 리젠 스크립트로 생성된 몬스터가 아닌 외부 소환으로 생성된 몬스터
	void				SetSummonInfo( cMonster* pParent, unsigned short mapNumber, float regenX, float regenY, unsigned long regenRange, unsigned long destroyTime );

	unsigned long		GetfirstAttack()	{ return mFirstAttackCharacter; }
	void				SetFirstAttack( unsigned long playerIdx )	{ mFirstAttackCharacter = playerIdx; }

	cBaseObject*		GetTarget();
	bool				SetTarget ( unsigned char kind, unsigned long idx );

	void				OutsideDestroyTrue()	{ mOutsideDestroy = true; }
	bool				IsOutsideDestroy()	{ return mOutsideDestroy; }
	bool				IsCheatTempMonster()	{ return mOutsideAddMonster; }

	///*--------------- 스크립트 관련 참조 데이타 ---------------*/
	const sMonsterScript*	GetMonsterInfo()	{ return mpMonsterInfo; }
	const sRegenScript*	GetRegenMonsterInfo()	{ return mpRegenMonsterInfo; }


	/*--------------- 기본 정보 ---------------*/
	unsigned int		GetRaceGender()	{ return mpMonsterInfo->mMonsterClassIdx; }
	unsigned long		GetRegenGroupNum()	{ return mpRegenMonsterInfo->mGroupNumber; }
	float				GetDirection()	{ return mDirection; }
	unsigned char		GetLevel( ) { return mpMonsterInfo->mLevel; }


	/*--------------- 스킬 관련 ---------------*/
	/// 효과 목록 추가
	bool				AddInfluence( unsigned long /*uniqueIdx*/, unsigned long /*influenceClassIdx*/ );
	tHashSet<unsigned long>* GetInfluenceSet() { return &mInfluenceSet; }
	void				ReleaseInfluenceSet(); 
	void				DeleteInfluence( unsigned long influenceIdx );

	void				StatusCalc();

	bool				IsParentEqual( unsigned long parentUniqueIdx );

	/// 받은 데미지 정보 기록

	/// 몬스터에 피해를 주는 객체에 대한 정보를 등록
	void AddTakeDamage( sObject attacker, unsigned long damage, long distressPoint, eTAKEDAMAGE_TYPE type );
	void DelTakeDamagePlayer( unsigned long playerIdx );
	void ClearDistressPointPlayer( unsigned long playerIdx );
	void ClearDistressPoint();
	void ClearTakeDamage();

	//void				AddTakeDamage( unsigned long playerIdx, unsigned long takeDamage );
	unsigned long		GetTakeDamage( unsigned long playerIdx );
	TakeDamageRoot*		GetTakeDamageRoot() { return &mTakeDamageRoot; }

	/// 스킬 선정
	eMONSTERATTACK_TYPE	SelectSkill();
	/// 스킬 쿨타임 갱신
	void				UpdateSkillCoolTime( eMONSTERATTACK_TYPE attackType );

	/// 스킬 발동후 대기 시간
	void				CalcSkillWaitTime( unsigned long skillEndTime );
	bool				IsSkillWaitEnd();

	/// AI에 의해 공격대상이 변경되어야 하는경우 호출
	void				ChangeActionTarget();

	/// 타겟 제거 스킬에 인한 타겟 변경
	void				ChangeTargetDeleteSkill();

	/*--------------- 스테이터스 관련 ---------------*/
	sMonsterStatus*		GetStatusPlus()	{ return &mStatusPlus; }
	sMonsterStatus*		GetStatusPer()	{ return &mStatusPer; }

	long				CalcPhysicAttack( unsigned long physicAttack );
	long				CalcPhysicRangeAttack( unsigned long physicRangeAttack );
	long				CalcMagicAttack( unsigned long magicAttack );
	long				GetPhysicDefense();
	long				GetMagicDefense();
	long				GetAvoid();
	long				CalcPhysicAttackRate( unsigned long physicAttackRate );
	long				CalcMagicAttackRate( unsigned long magicAttackRate );
	long				CalcPhysicCritical( unsigned long physicCritical );
	long				CalcMagicCritical( unsigned long magicCritical );
	float				GetAttackSpeed();

	float				CalcStatusSkillRange( float skillRange, eRANGETYPE rangeType );

	/// 현재 몬스터의 이동속도
	long				GetMoveSpeed();
	long				SetMoveSpeed( unsigned long moveSpeed, eMOVE_SPEED_TYPE mMoveSpeedType );
	void				SendMoveSpeed();

	/// 최대 hp/mp
	unsigned long		GetMaxHP()	{ return (unsigned long)( mpMonsterInfo->mMaxHp + ( mpMonsterInfo->mMaxHp * mStatusPer.mMaxHP ) + mStatusPlus.mMaxHP ); }
	unsigned long		GetMaxMP()	{ return (unsigned long)( mpMonsterInfo->mMaxMp + ( mpMonsterInfo->mMaxMp * mStatusPer.mMaxMP ) + mStatusPlus.mMaxMP ); }

	/*--------------- 스테이터스 관련 기타---------------*/
	/// HP/MP 정보
	unsigned long		GetHP()	{ return mHP; }
	unsigned long		GetMP()	{ return mMP; }

	/// HP/MP 증감
	unsigned long		HPDamage( unsigned long damage, bool *die, bool msgSend, bool cri = false );
	void				HPHeal( unsigned long hp, bool msgSend, unsigned long healerIdx, long distressPoint, eTAKEDAMAGE_TYPE type );
	void				MPDamage( unsigned long damage, bool msgSend );
	void				MPHeal( unsigned long heal, bool msgSend );

	/// 데미지 처리
	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 );

	/*--------------- 상태 관련 ---------------*/
	/// 액션 수행 - 액션 진행/중지 상태값 리턴
	eACTION_CHANGE		Update( unsigned long elapsedTime, unsigned long accumTime );
	void				UpdateMode( unsigned long elapsedTime, unsigned long accumTime );

	void				ActionChange( eACTION_ID state );
	eACTION_ID			GetActionID()	{ return mpAction->GetActionID(); }

	void				SetGroupRegen( bool groupRegen )	{ mGroupRegen = groupRegen; }
	bool				IsGroupRegen()	{ return mGroupRegen; };

	/// 추적시 공격범위에 들어온경우 공격형태
	void				SetAttackType( eMONSTERATTACK_TYPE attackType ) { mAttackType = attackType; }
	eMONSTERATTACK_TYPE	GetAttackType() { return mAttackType; }

	void				SetEscape();

	void				Comeback();

	/// 몬스터 생존 유무
	bool				GetStateDie();

	/// 외부 몬스터 삭제 설정
	void				OutsideDestroy();

	/// 대기 상태 종료시간
	unsigned long		GetIdleEndTime()	{ return mIdleEndTime; }

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

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

	void				TargetChange( sObject attacker, long distressPoint );

	/*--------------- 이동 관련 ---------------*/
	/// 이동 프로세스
	bool				MoveUpdate( unsigned long deltaTime );

	/// 이동 경로 셋팅
	unsigned int		SetPath( float targetX, float targetY );
	unsigned int		SetPath( float targetX, float targetY, float range , sObject target );

	/// 몬스터가 이동하려는 경로중 한노드의 목적지
	const NiPoint2&		GetNextPos() const { return mNextPos; }
	void				SetNextPos( const NiPoint2& pos ) { mNextPos = pos; }

	/// 이동좌표 최종 목적지까기 가기전 정지의 범위
	float				GetMoveStopRange() { return mMoveStopRange; }
	void				SetMoveStopRange( float moveStopRange ) { mMoveStopRange = moveStopRange; }

	/// 몬스터가 실제 리젠된 좌표
	const NiPoint2&		GetRegenPos() const	{ return mRegenPos; }

	/// 추적 시작시 기준 정보
	NiPoint2			GetFollowStartPos()	{ return mFollowStartPos; }
	void				SetFollowEndTime( unsigned long followEndTime )	{ mFollowEndTime = followEndTime; }
	unsigned long		GetFollowEndTime()	{ return mFollowEndTime; }		

	/// 추적하다가 원래 이동 구역으로 이동중
	bool				GetFollowEndMove()	{ return mFollowEndMove; }
	void				SetFollowEndMove( bool followEndMove )	{ mFollowEndMove = followEndMove; }

	/// 이동 정지
	void				MoveStop();

	/// 처음 이동
	bool				IsFirstMove()	{ return mIsFirstMove; }
	bool				FirstMoveEnd()	{ return mIsFirstMove = false; }

	unsigned char		GetPlayerFollowPos()	{ return mPlayerFollowPos; }
	void				SetPlayerFollowPos( unsigned char playerFollowPos )	{ mPlayerFollowPos = playerFollowPos; }

	/// 길찾기
	bool				FindPath( const NiPoint2& goal );
	void				SetPathFinder( cPathFinder* pathFinder );
	unsigned int		GetPathCount() const;
	const NiPoint2*		GetPathArray() const;

	/// 오브젝트의 거리 체크 수정 거리 - 적용 범위
	float				GetFixedObjectSize()	{ return mFixedObjectSize; }


	/*--------------- 대사 관련 ---------------*/
	/// 대사 선택 발송
	void				SendSpeech( unsigned long talkState );
	void				SpeechProcess();
	bool				IsCriDie()	{ return mCriDie; }

	
	/*--------------- 보스(엘리트) 관련 ---------------*/
	/// 소환된 몬스터 추가
	void				AddSummonMonster( unsigned long monsterIdx );
	void				DieSummonMonster( unsigned long monsterIdx );

	void				ModeSkillEnd();
	eMONSTERATTACK_TYPE	GetModeSkill() { return mModeSkillIdx; }

public:
	bool                SendSightIn     ( char category, char protocol, unsigned long connectionIdx );
	bool                SendSightOut    ( char category, char protocol, unsigned long connectionIdx );
	bool			    SendMonsterMove ( unsigned long connectionIdx );

	/// 몬스터 주변 그리드에 해당 플레이어가 존재하는지 검사
	cPlayer*			NearGridFindPlayer( unsigned long playerIdx );

	/// 변수 셋팅
	void SetCombatFlag( bool set );
	inline bool IsCombat() { return mIsCombat; }

	long				CalcSkillRate( cBaseObject* pTarget, eMONSTERATTACK_TYPE attackType, long scriptRate );

private:

	/// 액션 상태 변경
	void				SetAction( cAction& pNewAtion );

	/// 초기화
	bool				MonsterInit( unsigned long monsterClassIdx );

	/// 전투 시작/종료시점
	void CombatStart();
	void CombatEnd();

	/// 모드 변환
	void ChangeCurrentMode( long modeIdx );

	bool ConditionValueCheck( unsigned char type, unsigned long value );

private:

	typedef tArray<void*>	cArray;
	typedef tArray<unsigned long> cLongAry;
	typedef tHashSet<unsigned long> cHashSet;
	typedef tHashMap<unsigned long, unsigned long> cHashMap;


	/// 범위 검사
	cRangeCheck			mRangeCheck;
	/// 선공 플레이어
	unsigned long		mFirstAttackCharacter;
	unsigned long		mFirstAttackParty;
	/// 오브젝트의 거리 체크 수정 거리 - 적용 범위
	float				mFixedObjectSize;
	/// 정상 죽음이 아닌 외부삭제 명령으로 인한제거(경험치 관련 드롭안함)
	bool				mOutsideDestroy;
	/// 리젠 스크립트가 아닌 외부 호출로 생성된 몬스터
	bool				mOutsideAddMonster;

	///*--------------- 스크립트 관련 참조 데이타 ---------------*/
	sMonsterScript*		mpMonsterInfo;		/// 스크립트에서 참조한 몬스터 기본정보
	sRegenScript*		mpRegenMonsterInfo;	/// 몬스터 리젠정보

	unsigned char		mFollowImportance;
	/*--------------- 스킬 관련 ---------------*/
	/// 보유 효과 셋
	typedef tHashSet<unsigned long> cSkillInfluenceSet;
	cSkillInfluenceSet	mInfluenceSet;

	/// 받은 데미지
	TakeDamageRoot mTakeDamageRoot;

	/// 다음 타겟 변경 시간
	unsigned long		mNextTargetChangeTime;
	/// 쿨타임
	typedef tHashMap<unsigned long, unsigned long> cCoolTime;
	cCoolTime			mSkillCoolTimeMap;
	cCoolTime			mEliteCoolTimeMap;

	/// 스킬 공격 타입
	eMONSTERATTACK_TYPE	mAttackType;
	/// 스킬 재사용 가능 시간
	unsigned long		mSkillWaitEndTime;

	/// 스킬 선정시 가능한 스킬들 목록을 담아둘 임시 공간
	cHashMap			mTempSelectSkill;

	/*--------------- 스테이터스 관련 ---------------*/
	unsigned long		mHP;
	unsigned long		mMP;

	/// 몬스터 스텟 기본값
	sMonsterStatus		mStatusBase;
	/// 몬스터 스텟 확장값
	sMonsterStatus		mStatusPlus;		
	sMonsterStatus		mStatusPer;

	float				mMoveSpeed;	


	/*--------------- 상태 관련 ---------------*/
	cAction*			mpAction;			/// 수행중인 액션의 포인터
	bool				mGroupRegen;		/// 그룹 단위 리젠 설정

	/// 추적시 공격범위에 들어온경우 공격형태
	eMONSTERATTACK_TYPE	attackType;

	/// 몬스터에서 사용할 행동
	cActionMove			mActionMove;
	cActionDie			mActionDie;
	cActionAttack		mActionAttack;
	cActionEscape		mActionEscape;
	cActionFollow		mActionFollow;
	cActionIdle			mActionIdle;

	unsigned long		mDestroyTime;
	unsigned long		mIdleEndTime;

	/*--------------- 상태 이상 ---------------*/
	long				mODDITY[eODDITYTYPE_MAX];
	//sObject				mCantTargetChange;		/// 타겟 변경 불가
	//unsigned long		mCantTChangeInfluenceIdx;	/// 타겟 변경 불가 효과 번호 - 자신의 효과만 지우기 위해 기록


	/*--------------- 이동 관련 ---------------*/
	NiPoint2			mLastPos;			/// 이동 패스 최종 목적지
	NiPoint2			mNextPos;			/// 이동 패스 다음 노드 위치
	float				mMoveStopRange;		/// 목적지 전 정지 범위

	NiPoint2			mRegenPos;			/// 몬스터가 실제 리젠된 좌표

	NiPoint2			mFollowStartPos;	/// 추적 시작 위치
	unsigned long		mFollowEndTime;		/// 추적 종료 시간

	bool				mFollowEndMove;		/// 추적하다가 원래 이동 구역으로 이동중

	float				mMoveOverTime;		/// 경로 목적지까지 이동중 프로세스 간격에의해 넘어간 시간

	eMOVE_SPEED_TYPE	mMoveSpeedType;		/// 이동 방법

	bool				mIsFirstMove;		/// 처음 이동 인지 설정

	unsigned char		mPlayerFollowPos;

	float				mDirection;			/// 방향값

	/// 길찾기
	cPathFinder*		mPathFinder;
	NiPoint2			mPathArray[MAX_PATH_COUNT];
	unsigned int		mPathCount;
	unsigned int		mPathIndex;

	/*--------------- 대사 관련 ---------------*/
	unsigned long		mTalkDealyEndTime;
	unsigned char		mTalkState;
	unsigned long		mTalkProcessCheckTime;
	bool				mCriDie;

	/*--------------- 몬스터 모드 관련  ---------------*/
	bool mIsCombat;

	eMONSTERATTACK_TYPE	mModeSkillIdx;

	unsigned long mTotalTime;
	unsigned long mModeTime;

	cModeAgent* mModeAgent;
	cMode*		mCurrentMode;

	/// 부모 몬스터가 있는 경우 처리
	bool mIsParentLink;
	unsigned long mParentMonsterIdx;

	/// 소환된 몬스터 목록
	cHashSet			mSummonListSet;

	/// GenMonster cooltime
	/// typedef tHashMap<unsigned long orderNumMon, unsigned long nextGenTime> cGenMonCoolTimeMap;
	cHashMap			mGenMonCoolTimeMap;

	/// GenTotem CoolTime
	/// typedef tHashMap<unsigned long orderNumMon, unsigned long nextGenTime> cGenTotemCoolTimeMap;
	cHashMap			mGenTotemCoolTimeMap;

};

inline
void cMonster::SetPathFinder( cPathFinder* pathFinder )
{
	mPathFinder = pathFinder;
}

inline
unsigned int cMonster::GetPathCount() const
{
	int c = mPathCount - mPathIndex;

	if( c >= 0 )
	{
		return c;
	}
	else
	{
		assert( 0 );
		return 0;
	}
}

inline
const NiPoint2* cMonster::GetPathArray() const
{
	if( mPathIndex < mPathCount )
	{
		return &mPathArray[mPathIndex];
	}
	else
	{
		assert( 0 );
		return &mPathArray[0];
	}
}
