Files
Leviathan/Client/Game/game/Player/SMonsterStateMachine.cpp
T
2026-06-01 12:46:52 +02:00

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 );
}