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