#include "stdafx.h" #include "SCreatureStateMachine.h" #include "SGameInput.h" #include "SGameMessage.h" #include "SGameAvatarEx.h" #include "SGameLocalCreature.h" #include "SSkillDB.h" #include "ErrorCode/ErrorCode.h" #include "SDebug_Util.h" using namespace GAME_INPUT; void SCreatureStateMachine::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 : { bool bEndAttack = false; SMSG_ATTACK * pAttack = static_cast(pMsg); m_infoState.bMultiple = false; 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.dwDuration = pAttack->attack_delay; m_hTargetHandle = pAttack->target_handle; m_hAttackTarget = pAttack->target_handle; m_infoState.attack_action = pAttack->attack_action; m_infoState.attack_flag = pAttack->attack_flag; m_infoState.count = pAttack->count; SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pReceiver->GetGameObject( m_infoState.hTarget ); if( pAttack->attack_action == TS_ATTACK_EVENT::ATTACK_END ) { m_idState = SObjectState::STATE_ATTACK_END; if( pTarget != NULL && pTarget->IsDead() == false ) bEndAttack = true; // sonador 7.0.18 Mantis 0002660: [크리처] 크리처 자동 공격 문제 if( !bEndAttack ) m_pReceiver->SetCreatureBattleModeOff(); } else if( pAttack->attack_action == TS_ATTACK_EVENT::ATTACK_CANCEL ) { m_idState = SObjectState::STATE_CAST_CANCEL; if( pTarget != NULL && pTarget->IsDead() == false ) bEndAttack = true; } else { m_idState = SObjectState::STATE_ATTACK; m_pReceiver->SetCreatureBattleModeOn(); } for ( int i=0 ; i < pAttack->count ; ++i ) { m_infoState.vAttackInfoList.push_back( pAttack->m_vAttackInfoList[i] ); } if( bEndAttack ) return; } break; case MSG_CANT_ATTACK : { SMSG_CANT_ATTACK* pCantAttack = static_cast(pMsg); //서버에서 공격 못 한다고 날아 왔다. // sonador 7.0.18 Mantis 0002660: [크리처] 크리처 자동 공격 문제 // 공격 불가의 이유가 'RESULT_ACCESS_DENIED' 라면, 전투 상태를 유지하자. if( pCantAttack->reason == RESULT_ACCESS_DENIED || pCantAttack->reason == RESULT_NOT_ACTABLE ) return; m_pReceiver->ReqCancelAction(); if( pCantAttack->reason == RESULT_TOO_FAR ) { if( pCantAttack->target_handle != 0 ) { // m_idState = SObjectState::STATE_CAST_CANCEL; m_nNeedStopPos = NEED_STOP_POS; SInputAttack inputAttack( pCantAttack->target_handle ); OnInput( &inputAttack ); return; } } else { _oprint( "CANT ATTACK : %d\n", pCantAttack->reason ); m_idState = SObjectState::STATE_IDLE; } m_pReceiver->SetCreatureBattleModeOff(); return; } break; case MSG_KMOVE: case MSG_MOVE : { SMSG_MOVE * pMove = static_cast(pMsg); /* // 같은 위치라면 그대로 둔다. K3DVector myPos = *m_pReceiver->GetPosition(); if( (int)myPos.x == (int)pMove->pos_target.x && (int)myPos.y == (int)pMove->pos_target.y ) { break; } */ 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_MOUNT_SUMMON : { SMSG_MOUNT_SUMMON* pMountMsg = static_cast(pMsg); m_idState = SObjectState::STATE_MOUNT; m_infoState.hSelf = pMountMsg->handle; m_infoState.hTarget = pMountMsg->summon_handle; } break; case MSG_UNMOUNT_SUMMON : { SMSG_UNMOUNT_SUMMON* pUnMountMsg = static_cast(pMsg); m_idState = SObjectState::STATE_UNMOUNT; m_infoState.hSelf = pUnMountMsg->handle; m_infoState.hTarget = pUnMountMsg->summon_handle; } break; case MSG_SKILL_EVENT : { SMSG_SKILL_EVENT * pSkillEvent = static_cast(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 ); } } } } break; case TS_SC_SKILL::CASTING: { if ( pSkillEvent->cast.nErrorCode == 0 ) { m_idState = SObjectState::STATE_CAST; m_infoState.dwSpeed = pSkillEvent->cast.tm; } else if( pSkillEvent->cast.nErrorCode == RESULT_TOO_FAR ) { // 같은 대상에 같은 스킬을 쓰려고 했다면 다시 스킬 사용 시도 if( pSkillEvent->skill_id == m_infoNext.nSkillID && pSkillEvent->skill_level == m_infoNext.nSkillLv && pSkillEvent->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_idState = SObjectState::STATE_SKILL_END; return; } } else { m_idState = SObjectState::STATE_SKILL_END; // StopCurrentState(); return; } } break; case TS_SC_SKILL::CANCEL: { m_idState = SObjectState::STATE_CAST_CANCEL; // m_pReceiver->SetCreatureBattleModeOff(); // StopCurrentState(); return; } case TS_SC_SKILL::CASTING_UPDATE: { //TODO CASTING_UPDATE 처리 } break; case TS_SC_SKILL::REGION_FIRE: { //TODO REGION_FIRE 처리 } break; case TS_SC_SKILL::COMPLETE: { //TODO COMPLETE 처리 m_idState = SObjectState::STATE_SKILL_END; // m_pReceiver->SetCreatureBattleModeOff(); SkillBaseEx* s_data = GetSkillDB().GetSkillData( pSkillEvent->skill_id ); if( s_data ) { // sonador 7.0.18 Mantis 0002660: [크리처] 크리처 자동 공격 문제 bool bCheck = ( /*s_data->IsPhysicalSkill() &&*/ s_data->IsHarmful() && (s_data->GetCastRange() >= -1 /*&& s_data->GetCastRange() <= 3*/ ) ); //포스칩만 예외처리 하자 // 2010.06.15 - prodongi //if( pSkillEvent->skill_id == FORCE_CHIP_SKILL_ID ) if( IS_AUTO_ATTACK_CHIP_SKILL_ID(pSkillEvent->skill_id)) bCheck = true; m_infoState.autoattack = bCheck; //NeedTarget이면 서버에서 보내준 타겟으로 설정 //NeedTarget아니면 셀프형 ( 이번 타겟으로 유지 ) if( s_data->IsNeedTarget() ) m_hAttackTarget = m_hTargetHandle; } else m_hAttackTarget = m_hTargetHandle; bool bPrevState = (GetPrevState() == SObjectState::STATE_ATTACK || GetPrevState() == SObjectState::STATE_SHOOTING); // 2008. 6. 20 floyd #2.3.1.25 // http://bug.nflavor.com/view.php?id=2849 // 크리쳐 자동공격중 다른 타겟에게 이로운 스킬을 ›㎱뻑?동작을 멈추는 문제 // 아래 문장의 &&를 ||로 수정함으로써 자동공격 중단하도록 수정 if( !m_infoState.autoattack || !bPrevState ) m_pReceiver->SetCreatureBattleModeOff(); } break; } m_infoState.nSkillID = pSkillEvent->skill_id; m_infoState.nSkillLv = pSkillEvent->skill_level; m_infoState.hTarget = pSkillEvent->target; // m_infoState.nPercentageHP = pSkillEvent->target_hp_percentage; } return; case MSG_RESULT: { SMSG_RESULT* pResult = static_cast(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; case MSG_USE_ITEM_RESULT: { if( m_pReceiver->IsUsingSkill() || m_pReceiver->IsAttack() ) return; m_idState = SObjectState::STATE_SKILL_END; return; } // 무시 default: return; } m_idPrevState = m_idState; //SKILL_EVENT를 제외한 이전 상태를 저장한다 } //============================================================================================================================ SLocalCreatureStateMachine::SLocalCreatureStateMachine() : m_dwMoveUpdateTime( 0 ) { AddState( CreateIdleState() ); AddState( CreateAttackState() ); AddState( CreateAttackEnd() ); AddState( CreateMoveState() ); AddState( CreateChaseState() ); AddState( CreateCastState() ); AddState( CreateCastCancelState() ); AddState( CreateFireState() ); AddState( CreateSkillEndState() ); AddState( CreateCreatureMount() ); AddState( CreateCreatureUnMount() ); // AddState()가 다 끝난 뒤에 호출할 것 SStateInfo info; SetDefaultState( SObjectState::STATE_IDLE, info ); } SObjectState* SLocalCreatureStateMachine::CreateIdleState() { SObjectState* pState = new SObjectState( SObjectState::STATE_IDLE ); pState->SetMode( Mode_All ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, 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_CAST_CANCEL, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN ); return pState; } SObjectState* SLocalCreatureStateMachine::CreateAttackState() { SObjectState* pState = new SObjectState( SObjectState::STATE_ATTACK ); pState->SetMode( Mode_All ); pState->SetMotionCancelInfo( true ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_MOVE, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_CHASE, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_CAST, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_FIRE, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_CAST_CANCEL, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN ); return pState; } SObjectState* SLocalCreatureStateMachine::CreateAttackEnd() { SObjectState* pState = new SObjectState( SObjectState::STATE_ATTACK_END ); pState->SetMode( Mode_Normal|Mode_Attack ); 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_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* SLocalCreatureStateMachine::CreateMoveState() { SObjectState* pState = new SObjectState( SObjectState::STATE_MOVE ); pState->SetMode( Mode_All ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, SObjectState::PERMIT_FORBIDDEN ); 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_CAST_CANCEL, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN ); return pState; } SObjectState* SLocalCreatureStateMachine::CreateChaseState() { SObjectState* pState = new SObjectState( SObjectState::STATE_CHASE ); pState->SetMode( Mode_Normal|Mode_Attack ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, SObjectState::PERMIT_FORBIDDEN ); 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_CAST_CANCEL, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_SKILL_END, SObjectState::PERMIT_FORBIDDEN ); return pState; } SObjectState* SLocalCreatureStateMachine::CreateCastState() { SObjectState* pState = new SObjectState( SObjectState::STATE_CAST ); pState->SetMode( Mode_Normal|Mode_Attack ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_IMMEDIATELY ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, 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_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* SLocalCreatureStateMachine::CreateFireState() { SObjectState* pState = new SObjectState( SObjectState::STATE_FIRE ); pState->SetMode( Mode_Normal|Mode_Attack ); pState->SetMotionCancelInfo( true ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_PENDING ); 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_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* SLocalCreatureStateMachine::CreateSkillEndState() { SObjectState* pState = new SObjectState( SObjectState::STATE_SKILL_END ); pState->SetMode( Mode_Normal|Mode_Attack ); pState->SetMotionCancelInfo( true ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_PENDING ); 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* SLocalCreatureStateMachine::CreateCastCancelState() { SObjectState* pState = new SObjectState( SObjectState::STATE_CAST_CANCEL ); pState->SetMode( Mode_Normal|Mode_Attack ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, 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; } SObjectState* SLocalCreatureStateMachine::CreateCreatureMount() { SObjectState* pState = new SObjectState( SObjectState::STATE_MOUNT ); pState->SetMode( Mode_All ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, 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 ); pState->AddRequestCommand( SObjectState::STATE_MOUNT, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_UNMOUNT, SObjectState::PERMIT_PENDING ); return pState; } SObjectState* SLocalCreatureStateMachine::CreateCreatureUnMount() { SObjectState* pState = new SObjectState( SObjectState::STATE_UNMOUNT ); pState->SetMode( Mode_All ); pState->AddRequestCommand( SObjectState::STATE_IDLE, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK, SObjectState::PERMIT_FORBIDDEN ); pState->AddRequestCommand( SObjectState::STATE_ATTACK_END, 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 ); pState->AddRequestCommand( SObjectState::STATE_MOUNT, SObjectState::PERMIT_PENDING ); pState->AddRequestCommand( SObjectState::STATE_UNMOUNT, SObjectState::PERMIT_FORBIDDEN ); return pState; } void SLocalCreatureStateMachine::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: // 이동 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 ), infoState.SpeedSync, true ); break; case SObjectState::STATE_CAST: // 캐스팅 { /// 2010.10.14 - prodongi m_pReceiver->ReqCast( infoState.hTarget, infoState.nSkillID, infoState.nSkillLv, infoState.vTargetPos ); } break; case SObjectState::STATE_FIRE: // 시전 // 오는 메시지 전용 스테이트 break; case SObjectState::STATE_CAST_CANCEL: m_pReceiver->ReqCancelAction(); break; } } //사용자 입력(키보드, 마우스) void SLocalCreatureStateMachine::OnInput( class SGameInput * pInput ) { if( m_bInputFreezing ) return; //입력 불가 SObjectState::ID idState; SStateInfo infoState; infoState.hSelf = m_pReceiver->GetArID(); infoState.vSelfPos = *m_pReceiver->GetPosition(); // m_idNextState = SObjectState::STATE_NONE; // 2010.06.15 - prodongi //m_bAutoAttack = false; setAutoAttack(false); switch( pInput->GetInputID() ) { case RQ_MOVE: { SInputMove* pMove = static_cast(pInput); idState = SObjectState::STATE_MOVE; infoState.bIsMovePos = true; infoState.vTargetPos = pMove->GetTargetPos(); infoState.SpeedSync = pMove->GetSpeedSync(); SetDefaultPrevState(); break; } case RQ_ATTACK : { SInputAttack* pAttack = static_cast (pInput); idState = SObjectState::STATE_ATTACK; infoState.hTarget = pAttack->GetTargetHandle(); infoState.fRange = m_pReceiver->GetAttackRange(); infoState.SpeedSync = true; m_pReceiver->SetCreatureBattleModeOn(); break; } case RQ_CAST : { SInputSkill* pCast = static_cast (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(); // 2010.05.24 - prodongi infoState.isValidToCorpse = pCast->isValidToCorpse(); SkillBaseEx* s_data = GetSkillDB().GetSkillData( infoState.nSkillID ); if (s_data && s_data->IsHarmful()) m_pReceiver->SetCreatureBattleModeOn(); break; } case RQ_CAST_CANCEL : { SInputCastCancel* pSkillCancel = static_cast(pInput); idState = SObjectState::STATE_CAST_CANCEL; infoState.hTarget = m_pReceiver->GetArID(); m_pReceiver->SetCreatureBattleModeOff(); SetDefaultPrevState(); ClearPending(); ClearNextState(); 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(); m_pReceiver->SetTargetMonster( infoState.hTarget ); } if( m_idNextState != idState ) m_idNextState = SObjectState::STATE_NONE; //새로운 상태 요청 RequestNewState( idState, infoState ); } //사용자 입력 응답(Server) void SLocalCreatureStateMachine::OnNetInput( struct SGameMessage * pMsg ) { SCreatureStateMachine::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(); } if( m_infoState.autoattack ) { // 2010.06.15 - prodongi //m_bAutoAttack = m_infoState.autoattack; setAutoAttack(m_infoState.autoattack); } StartNewState( m_idState, m_infoState ); } void SLocalCreatureStateMachine::Process( DWORD dwTime ) { SObjectStateMachine::Process( dwTime ); } //============================================================================================================================ void SOtherCreatureStateMachine::OnNetInput( struct SGameMessage * pMsg ) { SCreatureStateMachine::OnNetInput( pMsg ); 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(); } m_pReceiver->OnChangeState( m_idState, m_infoState ); }