402 lines
15 KiB
C++
402 lines
15 KiB
C++
#include "stdafx.h"
|
|
#include "SMonsterStateMachine.h"
|
|
#include "SGameInput.h"
|
|
#include "SGameMessage.h"
|
|
#include "SGameAvatarEx.h"
|
|
#include "SkillBase.h"
|
|
#include "ErrorCode/ErrorCode.h"
|
|
|
|
#include "SDebug_Util.h"
|
|
|
|
using namespace GAME_INPUT;
|
|
|
|
void SMonsterStateMachine::OnNetInput( struct SGameMessage * pMsg )
|
|
{
|
|
m_idState = SObjectState::ID::STATE_NONE;
|
|
m_infoState = SStateInfo();
|
|
|
|
m_infoState.hSelf = m_pReceiver->GetArID();
|
|
m_infoState.vSelfPos = *m_pReceiver->GetPosition();
|
|
m_infoState.fRange = m_pReceiver->GetAttackRange();
|
|
|
|
switch( pMsg->nType )
|
|
{
|
|
case MSG_ATTACK :
|
|
{
|
|
SMSG_ATTACK * pAttack = static_cast<SMSG_ATTACK*>(pMsg);
|
|
m_infoState.hSelf = pAttack->attacker_handle;
|
|
m_infoState.hTarget = pAttack->target_handle;
|
|
m_infoState.vTargetPos = pAttack->pos_target; //이동 할 위치
|
|
m_infoState.dwSpeed = pAttack->attack_speed; // ms
|
|
|
|
m_infoState.attack_action = pAttack->attack_action;
|
|
m_infoState.attack_flag = pAttack->attack_flag;
|
|
|
|
if( pAttack->attack_action == TS_ATTACK_EVENT::ATTACK_END )
|
|
m_idState = SObjectState::STATE_IDLE;
|
|
else
|
|
m_idState = SObjectState::STATE_ATTACK;
|
|
|
|
for ( int i=0 ; i < pAttack->count ; ++i )
|
|
{
|
|
m_infoState.vAttackInfoList.push_back( pAttack->m_vAttackInfoList[i] );
|
|
}
|
|
}
|
|
break;
|
|
case MSG_MOVE :
|
|
{
|
|
SMSG_MOVE * pMove = static_cast<SMSG_MOVE *>(pMsg);
|
|
m_infoState.bIsMovePos = true;
|
|
m_infoState.vTargetPos = pMove->pos_target; //이동 할 위치
|
|
m_infoState.dwSpeed = pMove->speed;
|
|
m_idState = SObjectState::STATE_MOVE;
|
|
if ( m_idNextState != SObjectState::STATE_NONE )
|
|
{
|
|
m_infoState = m_infoNext;
|
|
m_infoState.dwSpeed = pMove->speed; //추적 Speed 는 그대로 사용
|
|
m_idState = SObjectState::STATE_CHASE;
|
|
}
|
|
}
|
|
break;
|
|
case MSG_SKILL_EVENT :
|
|
{
|
|
SMSG_SKILL_EVENT * pSkillEvent = static_cast<SMSG_SKILL_EVENT *>(pMsg);
|
|
switch( pSkillEvent->status_type )
|
|
{
|
|
case TS_SC_SKILL::FIRE:
|
|
{
|
|
m_idState = SObjectState::STATE_FIRE;
|
|
m_infoState.dwDuration = 1500; //발사 후 지속 시간
|
|
m_infoState.nRepeat = pSkillEvent->fire.count; // 갯수
|
|
m_infoState.bMultiple = pSkillEvent->fire.bMultiple; // true 실시간 연타
|
|
m_infoState.range = pSkillEvent->fire.range; // 스킬 효과 범위
|
|
m_infoState.target_count = pSkillEvent->fire.target_count;// 타겟 수
|
|
m_infoState.fire_count = pSkillEvent->fire.fire_count;
|
|
//m_infoState.target_name = pSkillEvent->target_name; // Fraun performance tweak
|
|
m_hTargetHandle = pSkillEvent->target;
|
|
|
|
//기존 데이타 삭제 한다.
|
|
if( !m_infoState.vSkillResult.empty() )
|
|
m_infoState.vSkillResult.erase( m_infoState.vSkillResult.begin(), m_infoState.vSkillResult.end() );
|
|
|
|
for ( int i=0 ; i< (int)pSkillEvent->vSkillResult.size() ; ++i )
|
|
{
|
|
SkillResult skillresult;
|
|
skillresult = pSkillEvent->vSkillResult[i];
|
|
m_infoState.vSkillResult.push_back( skillresult );
|
|
|
|
if( skillresult.GetType() == SkillResult::RUSH )
|
|
{
|
|
if( skillresult.rush.bResult )
|
|
{
|
|
m_idNextState = SObjectState::STATE_ATTACK;
|
|
m_infoState.hTarget = skillresult.rush.hTarget;
|
|
m_infoState.vTargetPos = K3DVector( skillresult.rush.x, skillresult.rush.y, 0.0f );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
OutputDebugString("SMonsterStateMachine::OnNetInput - fire\n");
|
|
break;
|
|
case TS_SC_SKILL::CASTING:
|
|
{
|
|
if ( pSkillEvent->cast.nErrorCode == 0 )
|
|
{
|
|
m_idState = SObjectState::STATE_CAST;
|
|
m_infoState.dwSpeed = pSkillEvent->cast.tm;
|
|
}
|
|
else
|
|
{
|
|
m_idState = SObjectState::STATE_SKILL_END;
|
|
return;
|
|
}
|
|
OutputDebugString("SMonsterStateMachine::OnNetInput - casting\n");
|
|
}
|
|
break;
|
|
case TS_SC_SKILL::CANCEL:
|
|
{
|
|
m_idState = SObjectState::STATE_CAST_CANCEL;
|
|
return;
|
|
}
|
|
case TS_SC_SKILL::CASTING_UPDATE:
|
|
{
|
|
}
|
|
break;
|
|
case TS_SC_SKILL::REGION_FIRE:
|
|
{
|
|
}
|
|
break;
|
|
case TS_SC_SKILL::COMPLETE:
|
|
{
|
|
m_idState = SObjectState::STATE_SKILL_END;
|
|
OutputDebugString("SMonsterStateMachine::OnNetInput - complete\n");
|
|
}
|
|
break;
|
|
}
|
|
m_infoState.nSkillID = pSkillEvent->skill_id;
|
|
m_infoState.nSkillLv = pSkillEvent->skill_level;
|
|
m_infoState.hTarget = pSkillEvent->target;
|
|
}
|
|
break;
|
|
case MSG_RESULT:
|
|
{
|
|
SMSG_RESULT* pResult = static_cast<SMSG_RESULT*>(pMsg);
|
|
if( pResult->request_msg_id == TM_CS_SKILL )
|
|
{
|
|
if( pResult->result != RESULT_SUCCESS)
|
|
m_idState = SObjectState::STATE_SKILL_END;
|
|
}
|
|
else if( pResult->request_msg_id == TM_CS_USE_ITEM )
|
|
{
|
|
if( pResult->result != RESULT_SUCCESS )
|
|
{
|
|
if( m_pReceiver->IsUsingSkill() || m_pReceiver->IsAttack() )
|
|
return;
|
|
|
|
m_idState = SObjectState::STATE_SKILL_END;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
//============================================================================================================================
|
|
|
|
SLocalMonsterStateMachine::SLocalMonsterStateMachine()
|
|
{
|
|
AddState( CreateIdleState() );
|
|
AddState( CreateAttackState() );
|
|
AddState( CreateMoveState() );
|
|
AddState( CreateChaseState() );
|
|
AddState( CreateCastState() );
|
|
AddState( CreateCastCancelState() );
|
|
AddState( CreateFireState() );
|
|
AddState( CreateSkillEndState() );
|
|
|
|
// AddState()가 다 끝난 뒤에 호출할 것
|
|
SStateInfo info;
|
|
SetDefaultState( SObjectState::STATE_IDLE, info );
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateIdleState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_IDLE );
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateAttackState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_ATTACK );
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateMoveState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_MOVE );
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateChaseState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_CHASE );
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateCastState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_CAST );
|
|
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST_CANCEL, SObjectState::PERMIT_IMMEDIATELY );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateFireState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_FIRE );
|
|
|
|
pState->SetMotionCancelInfo( true );
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST_CANCEL, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_IMMEDIATELY );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateSkillEndState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_SKILL_END );
|
|
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST_CANCEL, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_PENDING );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
SObjectState* SLocalMonsterStateMachine::CreateCastCancelState()
|
|
{
|
|
SObjectState* pState = new SObjectState( SObjectState::STATE_CAST_CANCEL );
|
|
|
|
pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_CAST_CANCEL, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_FORBIDDEN );
|
|
pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN );
|
|
return pState;
|
|
}
|
|
|
|
void SLocalMonsterStateMachine::SendServerReq( SObjectState::ID state, const SStateInfo &infoState )
|
|
{
|
|
switch( state )
|
|
{
|
|
case SObjectState::STATE_NONE: // 없음 (사용되지 않음)
|
|
case SObjectState::STATE_IDLE:// 아이들
|
|
StartNewState( state, infoState );
|
|
break;
|
|
case SObjectState::STATE_ATTACK: // 공격 (1회)
|
|
_oprint( "Creature attack: %u\n", infoState.hTarget );
|
|
m_pReceiver->ReqAttack( infoState.hTarget );
|
|
break;
|
|
case SObjectState::STATE_MOVE: // 이동
|
|
case SObjectState::STATE_CHASE: // 추격
|
|
m_pReceiver->ReqMove( infoState.hSelf, ArPosition( infoState.vTargetPos.x, infoState.vTargetPos.y ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//사용자 입력(키보드, 마우스)
|
|
void SLocalMonsterStateMachine::OnInput( class SGameInput * pInput )
|
|
{
|
|
SObjectState::ID idState;
|
|
SStateInfo infoState;
|
|
|
|
infoState.hSelf = m_pReceiver->GetArID();
|
|
infoState.vSelfPos = *m_pReceiver->GetPosition();
|
|
m_idNextState = SObjectState::STATE_NONE;
|
|
|
|
switch( pInput->GetInputID() )
|
|
{
|
|
case RQ_MOVE:
|
|
{
|
|
SInputMove* pMove = static_cast<SInputMove*>(pInput);
|
|
idState = SObjectState::STATE_MOVE;
|
|
infoState.bIsMovePos = true;
|
|
infoState.vTargetPos = pMove->GetTargetPos();
|
|
break;
|
|
}
|
|
case RQ_ATTACK :
|
|
{
|
|
SInputAttack* pAttack = static_cast<SInputAttack*> (pInput);
|
|
idState = SObjectState::STATE_ATTACK;
|
|
infoState.hTarget = pAttack->GetTargetHandle();
|
|
infoState.fRange = m_pReceiver->GetAttackRange();
|
|
break;
|
|
}
|
|
case RQ_CAST :
|
|
{
|
|
SInputSkill* pCast = static_cast<SInputSkill*> (pInput);
|
|
idState = SObjectState::STATE_CAST;
|
|
|
|
infoState.hTarget = pCast->GetTargetHandle();
|
|
infoState.nSkillID = pCast->GetSkillID();
|
|
infoState.nSkillLv = pCast->GetSkillLv();
|
|
infoState.fRange = pCast->GetCastRange();
|
|
infoState.fSpellRange = pCast->GetSpellRange();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//타겟이 있는가?
|
|
if ( infoState.hTarget != 0 )
|
|
{
|
|
SGameObject *pTarget = NULL;
|
|
pTarget = m_pReceiver->GetGameObject( infoState.hTarget );
|
|
if ( pTarget == NULL ) return; //오브젝트가 없으면, 입력은 무효다
|
|
|
|
infoState.bIsMovePos = false;
|
|
infoState.vTargetPos = *pTarget->GetPosition();
|
|
}
|
|
//새로운 상태 요청
|
|
RequestNewState( idState, infoState );
|
|
}
|
|
|
|
//사용자 입력 응답(Server)
|
|
void SLocalMonsterStateMachine::OnNetInput( struct SGameMessage * pMsg )
|
|
{
|
|
SMonsterStateMachine::OnNetInput( pMsg );
|
|
|
|
if( m_idState == SObjectState::ID::STATE_NONE )
|
|
return;
|
|
|
|
if ( m_infoState.hTarget != 0 )
|
|
{
|
|
SGameObject *pTarget = m_pReceiver->GetGameObject( m_infoState.hTarget );
|
|
|
|
if ( pTarget == NULL ) return;
|
|
|
|
m_infoState.bIsMovePos = false;
|
|
m_infoState.vTargetPos = *pTarget->GetPosition();
|
|
}
|
|
StartNewState( m_idState, m_infoState );
|
|
}
|
|
|
|
//============================================================================================================================
|
|
|
|
void SOtherMonsterStateMachine::OnNetInput( struct SGameMessage * pMsg )
|
|
{
|
|
SMonsterStateMachine::OnNetInput( pMsg );
|
|
|
|
m_pReceiver->OnChangeState( m_idState, m_infoState );
|
|
}
|
|
|