Files
2026-06-01 12:46:52 +02:00

350 lines
10 KiB
C++

#include "stdafx.h"
// sonador 10.2.1 팻 시스템 구현
#include "SPetStateMachine.h"
#include "SGameInput.h"
#include "SGameMessage.h"
#include "SGameAvatarEx.h"
#include "SGameLocalPet.h"
#include "ErrorCode/ErrorCode.h"
#include "SDebug_Util.h"
#include "SLog.h"
void SPetStateMachine::OnNetInput( SGameMessage* msg )
{
m_StateID = SObjectState::ID::STATE_NONE;
m_StateInfo.Reset();
m_StateInfo.hSelf = m_pReceiver->GetArID();
m_StateInfo.vSelfPos = *m_pReceiver->GetPosition();
m_StateInfo.fRange = m_pReceiver->GetAttackRange();
switch( msg->nType )
{
case MSG_MOVE:
{
SMSG_MOVE* msgMove = static_cast< SMSG_MOVE* >( msg );
/*
// 같은 위치라면 그대로 둔다.
K3DVector myPos = *m_pReceiver->GetPosition();
if( (int)myPos.x == (int)msgMove->pos_target.x &&
(int)myPos.y == (int)msgMove->pos_target.y )
{
break;
}
*/
m_StateInfo.bIsMovePos = true;
m_StateInfo.vTargetPos = msgMove->pos_target;
m_StateInfo.dwSpeed = msgMove->speed;
m_StateID = SObjectState::ID::STATE_MOVE;
if( m_idNextState != SObjectState::ID::STATE_NONE )
{
m_infoNext.vTargetPos = m_StateInfo.vTargetPos;
m_StateInfo = m_infoNext;
m_StateInfo.dwSpeed = msgMove->speed;
m_StateID = SObjectState::ID::STATE_CHASE;
}
if( !m_queInputState.empty() )
{
PENDING_INPUT_STATE* prevState = &m_queInputState.front();
if( prevState->nInputID == RQ_MOVE )
m_queInputState.pop();
}
}
break;
case MSG_SKILL_EVENT:
{
SMSG_SKILL_EVENT* SkillEvent = static_cast< SMSG_SKILL_EVENT* >( msg );
switch( SkillEvent->status_type )
{
case TS_SC_SKILL::FIRE:
{
m_StateID = SObjectState::STATE_FIRE;
m_StateInfo.dwDuration = 0; // ?
m_StateInfo.nRepeat = SkillEvent->fire.count; // must be 1
m_StateInfo.bMultiple = SkillEvent->fire.bMultiple; // must be false
m_StateInfo.range = SkillEvent->fire.range; // maybe 0?
m_StateInfo.target_count = SkillEvent->fire.target_count; // maybe 1?
m_StateInfo.fire_count = SkillEvent->fire.fire_count; // maybe 1?
// Fraun performance tweak
//m_StateInfo.target_name = SkillEvent->target_name; // maybe one of item, master and respawned monster
m_hTargetHandle = SkillEvent->target; // maybe one of item, master and respawned monster
if( m_StateInfo.vSkillResult.empty() == false )
m_StateInfo.vSkillResult.clear();
if( SkillEvent->vSkillResult.empty() == false )
{
SkillResult skillResult;
skillResult = SkillEvent->vSkillResult[ 0 ];
m_StateInfo.vSkillResult.push_back( skillResult );
}
}
break;
case TS_SC_SKILL::CASTING:
{
if( SkillEvent->cast.nErrorCode == 0 )
{
m_StateID = SObjectState::STATE_CAST;
m_StateInfo.dwSpeed = SkillEvent->cast.tm;
}
else if( SkillEvent->cast.nErrorCode == RESULT_TOO_FAR )
{
// 같은 대상에 같은 스킬을 쓰려고 했다면 다시 스킬 사용 시도
if( SkillEvent->skill_id == m_infoNext.nSkillID &&
SkillEvent->skill_level == m_infoNext.nSkillLv &&
SkillEvent->target == m_infoNext.hTarget )
{
SInputSkill inputSkill( m_infoNext.nSkillID,
m_infoNext.nSkillLv,
m_infoNext.hTarget,
m_infoNext.fRange,
m_infoNext.fSpellRange,
m_infoNext.vRegionTargetPos,
m_infoNext.isRegionTarget );
inputSkill.setIsValidToCorpse( m_infoNext.isValidToCorpse );
m_nNeedStopPos = NEED_STOP_POS;
OnInput( &inputSkill );
}
else
{
m_StateID = SObjectState::STATE_SKILL_END;
return;
}
}
else
{
m_StateID = SObjectState::STATE_SKILL_END;
return;
}
}
break;
case TS_SC_SKILL::CANCEL:
{
m_StateID = SObjectState::STATE_CAST_CANCEL;
return;
}
break;
case TS_SC_SKILL::COMPLETE:
{
m_StateID = SObjectState::STATE_SKILL_END;
}
break;
}
m_StateInfo.nSkillID = SkillEvent->skill_id; // maybe 6907( shovelling )
m_StateInfo.nSkillLv = SkillEvent->skill_level; // maybe 1...
}
break;
//case MSG_STATUS_CHANGE:
// {
// SMSG_STATUS_CHANGE* Status = static_cast< SMSG_STATUS_CHANGE* >( msg );
// if( Status->status & TS_ENTER::PetInfo::FLAG_SHOVELING_SEARCH )
// {
// m_StateID = SObjectState::STATE_SEARCH;
// }
// else if( Status->status & TS_ENTER::PetInfo::FLAG_SHOVELING_APPROACH )
// {
// m_StateID = SObjectState::STATE_APPROACH;
// }
// else if( Status->status & TS_ENTER::PetInfo::FLAG_SHOVELING_DIG )
// {
// m_StateID = SObjectState::STATE_DIG;
// }
// }
// break;
default:
break;
}
m_idPrevState = m_StateID;
}
SLocalPetStateMachine::SLocalPetStateMachine() : SPetStateMachine()
{
m_dwMoveUpdateTime = 0;
AddState( CreateIdleState() );
AddState( CreateMoveState() );
AddState( CreateChaseState() );
AddState( CreateTakeItemState() );
SStateInfo defaultInfo;
SetDefaultState( SObjectState::ID::STATE_IDLE, defaultInfo );
}
void SLocalPetStateMachine::OnInput( class SGameInput* input )
{
if( m_bInputFreezing )
return;
SObjectState::ID stateID;
SStateInfo stateInfo;
stateInfo.hSelf = m_pReceiver->GetArID();
stateInfo.vSelfPos = *m_pReceiver->GetPosition();
switch( input->GetInputID() )
{
case RQ_MOVE:
{
SInputMove* pMove = static_cast< SInputMove* >( input );
stateID = SObjectState::STATE_MOVE;
stateInfo.bIsMovePos = true;
stateInfo.vTargetPos = pMove->GetTargetPos();
stateInfo.SpeedSync = pMove->GetSpeedSync();
SetDefaultPrevState();
}
break;
case RQ_CAST:
{
SInputSkill* pCast = static_cast< SInputSkill* >( input );
stateID = SObjectState::STATE_CAST;
stateInfo.hTarget = pCast->GetTargetHandle();
stateInfo.nSkillID = pCast->GetSkillID();
stateInfo.nSkillLv = pCast->GetSkillLv();
stateInfo.fRange = pCast->GetCastRange();
stateInfo.fSpellRange = pCast->GetSpellRange();
}
break;
case RQ_TAKE_ITEM: // sonador #2.1.2.4.2 팻 아이템 줍기 기능 구현
{
SInputTakeItem* pTakeItem = static_cast< SInputTakeItem* >( input );
stateID = SObjectState::STATE_TAKEITEM;
stateInfo.fRange = GameRule::MAX_TAKE_ITEM_RANGE;
stateInfo.hTarget = pTakeItem->GetItemHandle();
}
break;
case RQ_CAST_CANCEL :
{
SInputCastCancel* pSkillCancel = static_cast<SInputCastCancel*>( input );
stateID = SObjectState::STATE_CAST_CANCEL;
stateInfo.hTarget = m_pReceiver->GetArID();
SetDefaultPrevState();
ClearPending();
ClearNextState();
}
break;
}
if( m_idNextState != stateID )
m_idNextState = SObjectState::STATE_NONE;
if( input->GetInputID() != RQ_MOVE )
{
if( !m_queInputState.empty() )
{
PENDING_INPUT_STATE* prevstate = &m_queInputState.front();
//첫번째 큐에 쌓인게 RQ_MOVE라면 서버에서 아직 응답을 안했다는 뜻
if( prevstate->nInputID == RQ_MOVE )
{
//현재 입력을 저장한다
PENDING_INPUT_STATE pendingstate( &stateInfo, input->GetInputID() );
m_queInputState.push( pendingstate );
return;
}
}
}
RequestNewState( stateID, stateInfo );
}
void SLocalPetStateMachine::SendServerReq( SObjectState::ID state, const SStateInfo& infoState )
{
//_oprint("SendServerReq : %d\n", state);
switch( state )
{
case SObjectState::STATE_NONE:
case SObjectState::STATE_IDLE:
StartNewState( state, infoState );
break;
case SObjectState::STATE_MOVE:
m_pReceiver->ReqMove( infoState.hSelf, ArPosition( infoState.vTargetPos.x, infoState.vTargetPos.y ), infoState.SpeedSync );
break;
case SObjectState::STATE_CHASE:
m_pReceiver->ReqMove( infoState.hSelf, ArPosition( infoState.vTargetPos.x, infoState.vTargetPos.y ), false, true );
break;
case SObjectState::STATE_TAKEITEM:
{
m_pReceiver->ReqTakeItem( infoState.hTarget );
StartNewState( SObjectState::STATE_IDLE, SStateInfo() );
}
break;
case SObjectState::STATE_CAST_CANCEL:
m_pReceiver->ReqCancelAction();
break;
}
}
void SLocalPetStateMachine::OnNetInput( struct SGameMessage* msg )
{
SPetStateMachine::OnNetInput( msg );
if( m_StateID == SObjectState::ID::STATE_NONE )
return;
StartNewState( m_StateID, m_StateInfo );
}
void SLocalPetStateMachine::Process( DWORD dwTime )
{
SObjectStateMachine::Process( dwTime );
}
SObjectState* SLocalPetStateMachine::CreateIdleState()
{
SObjectState* state = new SObjectState( SObjectState::ID::STATE_IDLE );
state->SetMode( Mode_All );
state->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_TAKEITEM, SObjectState::PERMIT_IMMEDIATELY );
return state;
}
SObjectState* SLocalPetStateMachine::CreateMoveState()
{
SObjectState* state = new SObjectState( SObjectState::ID::STATE_MOVE );
state->SetMode( Mode_All );
state->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
state->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_TAKEITEM, SObjectState::PERMIT_IMMEDIATELY );
return state;
}
SObjectState* SLocalPetStateMachine::CreateChaseState()
{
SObjectState* state = new SObjectState( SObjectState::ID::STATE_CHASE );
state->SetMode( Mode_Normal | Mode_Attack );
state->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
state->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_TAKEITEM, SObjectState::PERMIT_IMMEDIATELY );
return state;
}
SObjectState* SLocalPetStateMachine::CreateTakeItemState()
{
SObjectState* state = new SObjectState( SObjectState::STATE_TAKEITEM );
state->SetMode( Mode_All );
state->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN );
state->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY );
state->AddRequestCommand( SObjectState::STATE_TAKEITEM, SObjectState::PERMIT_IMMEDIATELY );
return state;
}
void SOtherPetStateMachine::OnNetInput( struct SGameMessage* msg )
{
SPetStateMachine::OnNetInput( msg );
m_pReceiver->OnChangeState( m_StateID, m_StateInfo );
}