350 lines
10 KiB
C++
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 );
|
|
} |