#include "StdAfx.h"
#include "GameSrv.h"
#include "actionfollow.h"

#include "Monster.h"
#include "Player.h"
#include "SkillManager.h"
#include "AIManager.h"



cActionFollow::cActionFollow(void) : cAction( eACT_FOLLOW )
{
	mRePathTime = 0;
}



cActionFollow::~cActionFollow(void)
{
}



void cActionFollow::ActionInit( cMonster* pMonster, unsigned long accumTime )
{
	cAction::ActionInit( pMonster, accumTime );

	/// 타겟 검사
	cBaseObject* pTarget = pMonster->GetTarget();
	if( pTarget == NULL || pTarget->GetStateDie() == true )
		return;

	mFollowTargetPos.x = pTarget->GetXPos();
	mFollowTargetPos.y = pTarget->GetYPos();

	mFirstFollowMove = true;

	mDelayTime = accumTime;

	mCantFollowPos = 0;

	mIsTalk = true;

	mNextSelectSkill = 0;
}



eACTION_CHANGE cActionFollow::Action( cMonster* pMonster, unsigned long deltaTime, unsigned long accumTime )
{

	const sMonsterScript* pMonsterScript = pMonster->GetMonsterInfo();
	if( pMonsterScript == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("cActionFollow::Action pMonsterScript == NULL");
		return eACTCH_ERROR;
	}

	/// 타겟에 대해 스킬 발동
	cPlayer* pPlayer = (cPlayer*)pMonster->GetTarget();
	if( pPlayer == NULL )
	{
		/// 081205 PKH 타겟 선정
		pMonster->ChangeActionTarget();
		return eACTCH_CONTINUE;
	}

	/// 스킬 재선정 체크
	float skillrange = pMonsterScript->mSkillMinRange;
	if( pMonster->GetAttackType() == eMONSTERATTACK_MAX || mNextSelectSkill < accumTime )
	{
		/// 스킬 사용후 지연시간 체크
		if( pMonster->IsSkillWaitEnd() == true )
		{
			eMONSTERATTACK_TYPE attackType = pMonster->SelectSkill();
			if( attackType != eMONSTERATTACK_MAX )
			{
				/// 부하 방지
				mNextSelectSkill = accumTime + 100;

				sMonsterSkillScript* pMonsterSkillScript = SKILLSCRIPT->GetMonsterSkillInfo( pMonster->GetRaceGender(), attackType );
				if( pMonsterSkillScript != NULL )	/// 스킬 발동 거리
					skillrange = pMonster->CalcStatusSkillRange( pMonsterSkillScript->mTargetDist, pMonsterSkillScript->mRangeType );
			}
		}
	}

	/// 몬스터 좌표, 타겟 오브젝트의 현재 좌표
	NiPoint3 monsterPos3( pMonster->GetXPos(), pMonster->GetYPos(), pMonster->Height() );
	NiPoint3 playerPos3( pPlayer->GetXPos(), pPlayer->GetYPos(), pPlayer->Height() );

	/// 공격거리 안에 들어온경우
	float tempRange = OBJECTMANAGER->ObjectSizeRange( pMonster, pPlayer, skillrange );
	mRangechk.SetRadius( tempRange );
	if( mRangechk.IsRange( monsterPos3, playerPos3 ) )
		return eACTCH_FOLLOW_ATTACK;

	/// 추적 범위
	mRangechk.SetRadius( (float)pMonsterScript->mFollowRange );

	if( mRangechk.IsNotRange( pMonster->GetPos(), pMonster->GetFollowStartPos() ) &&	/// 전투 시작 위치에서 거리를 벗어 나고
		pMonster->GetFollowEndTime() <= accumTime )										/// 공격(성공/맞음)시간이 지남
	{		
		/// 081205 PKH 타겟 선정
		pMonster->ChangeActionTarget();
		return eACTCH_CONTINUE;
	}

	/// 플레이어에 추적 퍼짐 위치 재신청 - 가운데 자리가 빈 경우 가운데로 이동
	pMonster->SetPlayerFollowPos( pPlayer->SelectFollowPos( pMonster->GetPlayerFollowPos() ) );

	/// 추적 퍼짐위치 선정 nipoint2 -> nipoint3
	NiPoint2 tempfollowPos = OBJECTMANAGER->CalcFollowPos( pMonster->GetPlayerFollowPos(), pPlayer->GetPos() );
	NiPoint3 followPos3( tempfollowPos.x, tempfollowPos.y, 0.0f );
	AIMANAGER->CalcHeight( pPlayer->GetMapNumber(), &followPos3.z, followPos3.x, followPos3.y );

	/// 몬스터 추변위치 설정인지 실제 위치인지 유무
	bool playerRealPos = false;

	/// 추적 퍼짐 위치가 이동 가능 지역인지 체크
	if( AIMANAGER->IsPassible( pPlayer->GetMapNumber(), followPos3.x, followPos3.y, pPlayer->GetObject() ) == true )
	{
		/// 추적 퍼짐 위치 까지 도달 한경우 실제 위치 설정
		mRangechk.SetRadius( FOLLOW_POS_DIAGONAL );
		if( mRangechk.IsRange( pMonster->GetPos(), tempfollowPos ) == true )
		{
			playerRealPos = true;
			followPos3 = playerPos3;
		}

	}
	else	/// 추적 퍼짐위치가 못가는 지역이므로 실제 위치로 간다.
		playerRealPos = true;

	/// 실제 위치로 이동 해야 하는데
	if( playerRealPos == true )
	{
		/// 못가는 지역 인경우
		if( AIMANAGER->IsPassible( pPlayer->GetMapNumber(), playerPos3.x, playerPos3.y, pPlayer->GetObject() ) == false )
		{
			/// 카운트 증가
			++mCantFollowPos;

			/// 랜덤 좌표 선택
			NiPoint2 randPos( playerPos3.x, playerPos3.y );

			float fixedSkillRange = pMonsterScript->mSkillMinRange;

			switch( mCantFollowPos )
			{
			case 1:	randPos.x -= fixedSkillRange / 2; break;	/// 높이 거리를 감안해 2로 나눈다.
			case 2:	randPos.x += fixedSkillRange / 2; break;
			case 3:	randPos.y -= fixedSkillRange / 2; break;
			case 4:	randPos.y += fixedSkillRange / 2; break;
			case 5:	randPos.x -= fixedSkillRange / 3; randPos.y += fixedSkillRange / 3; break;	/// 높이와 대각선 거리를 감안해 3으로 나눈다.
			case 6:	randPos.x += fixedSkillRange / 3; randPos.y += fixedSkillRange / 3; break;
			case 7:	randPos.x -= fixedSkillRange / 3; randPos.y -= fixedSkillRange / 3; break;
			case 8:	randPos.x += fixedSkillRange / 3; randPos.y -= fixedSkillRange / 3; break;
			}

			/// 못가는 지역 인경우
			if( AIMANAGER->IsPassible( pPlayer->GetMapNumber(), randPos.x, randPos.y, pPlayer->GetObject() ) == false )
			{
				/// 위에서 정한 8방향 좌표가 전부 못가는 지역일경우 도망
				if( mCantFollowPos >= 8 )
				{
					NETWORK2->PostServerEvent("ActionFollow MoveIsNotPassable - playerIdx[%d], map[%d], x[%f], y[%f]",
						pPlayer->GetObjectID(), pPlayer->GetMapNumber(), playerPos3.x, playerPos3.y );
			
					//return eACTCH_ESCAPE;
					pMonster->ChangeActionTarget();
				}

				return eACTCH_CONTINUE;
			}
			else
			{
				followPos3.x = randPos.x;
				followPos3.y = randPos.y;
				mCantFollowPos = 0;
				skillrange = 0.0f;
			}
		}
	}


	/// 몬스터 현재위치와 타겟 거리를 계산
	float range = ( pMonster->GetPos() - pPlayer->GetPos() ).Length() * 0.1f;

	/// range 값이 100보다 작을순 없다.
	if( range < 100 ) 
		range = 100; 

	/// 현재 타겟의 예전에 기록한 위치와 현재 위치의 거리차를 가져옴
	float objectLength = ( mFollowTargetPos - pPlayer->GetPos() ).Length();

	/// object기록 위치랑 현재위치가 range값보다 큰경우 위치 object위치기록 갱신 - 노드갱신
	if( objectLength > range )
	{
		/// 0.5초마다 검사 - 부하를 줄이기 위함
		if( mDelayTime > accumTime )
		{
			sObject target;
			target.index = pPlayer->GetObjectID();
			target.type = pPlayer->GetObjectType();

			/// 몬스터 추적 속도
			pMonster->SetMoveSpeed( pMonster->GetMonsterInfo()->mActionRunSpd, eMOVESPEED_RUN );

			/// 길찾기 노드 재생성
			pMonster->SetPath( followPos3.x, followPos3.y, skillrange - 10 , pPlayer->GetObject() );

			/// 스킬 사용 가능인지 체크
			if( pMonster->IsSkillWaitEnd() == true && mIsTalk == true )
			{
				mIsTalk = false;
				pMonster->SendSpeech( eMONSTERTALK_FOLLOW );
			}

			/// 플레이어가 이동 할 경우 길찾기 재설정을 위해 플레이어 위치 기록
			mFollowTargetPos.x = playerPos3.x;
			mFollowTargetPos.y = playerPos3.y;
		}
		else
			mDelayTime = mDelayTime + 500;

	}

	/// 몬스터 이동 - 이동값이 false인경우 경로 다시 셋팅
	if( pMonster->MoveUpdate( deltaTime ) == false || mFirstFollowMove == true )
	{
		mFirstFollowMove = false;
		sObject target;
		target.index = pPlayer->GetObjectID();
		target.type = pPlayer->GetObjectType();

		/// 몬스터 추적 속도
		pMonster->SetMoveSpeed( pMonster->GetMonsterInfo()->mActionRunSpd, eMOVESPEED_RUN );

		if(	mRePathTime < accumTime )
		{
			mRePathTime = accumTime + 300;
			/// 스킬 범위 밖이면 다시 이동 셋팅
			pMonster->SetPath( followPos3.x, followPos3.y, skillrange - 10 , pPlayer->GetObject() );
		}

		/// 스킬 사용 가능인지 체크
		if( pMonster->IsSkillWaitEnd() == true && mIsTalk == true )
		{
			mIsTalk = false;
			pMonster->SendSpeech( eMONSTERTALK_FOLLOW );
		}

		/// 플레이어가 이동 할 경우 길찾기 재설정을 위해 플레이어 위치 기록
		mFollowTargetPos.x = playerPos3.x;
		mFollowTargetPos.y = playerPos3.y;
	}

	/// 다른 이벤트가 걸리기 전까지 계속 추적모드
	return eACTCH_CONTINUE;
}
