void CStateMachinen::DoWalkAround(CMonster& monster, eStateEvent evt) { const BASE_MONSTER_LIST& baseMonsterList = monster.GetSMonsterList(); StateParameter& stateParamter = monster.mStateParamter; if( monster.GetAbnormalStatus()->IsStun || monster.GetAbnormalStatus()->IsFreezing || monster.GetAbnormalStatus()->IsStone || monster.GetAbnormalStatus()->IsSlip || monster.GetAbnormalStatus()->IsMoveStop || monster.GetAbnormalStatus()->IsParalysis ) { SetState( &monster, eMA_STAND); return; } switch(evt) { case eSEVENT_Enter: { // 소유주가 있을 경우 그 중심으로 행동한다 if(CObject* const ownerObject = g_pUserTable->FindUser(monster.GetOwnerIndex())) { if(ownerObject->GetObjectBattleState()) { SetState( &monster, eMA_STAND); break; } VECTOR3 ownerPosition = {0}; ownerObject->GetPosition( &ownerPosition); const float distance = ownerObject->GetRadius() * 3; VECTOR3 monsterPosition = {0}; monster.GetPosition( &monsterPosition); if(distance > CalcDistanceXZ(&ownerPosition, &monsterPosition)) { SetState( &monster, eMA_STAND); break; } const float randomRateX = float(rand()) / RAND_MAX; const float randomRateZ = float(rand()) / RAND_MAX; const float randomAxisX = (randomRateX < 0.5f ? -1.0f : 1.0f) * (ownerObject->GetRadius() * (1.0f + randomRateX)); const float randomAxisZ = (randomRateZ < 0.5f ? -1.0f : 1.0f) * (ownerObject->GetRadius() * (1.0f + randomRateZ)); monster.GetFiniteStateMachine().GetMemory().SetVariable( "__move_x__", int(ownerPosition.x + randomAxisX)); monster.GetFiniteStateMachine().GetMemory().SetVariable( "__move_z__", int(ownerPosition.z + randomAxisZ)); SetState( &monster, eMA_SCRIPT_RUN); // 이렇게 하지 않으면 eSEVENT_Process 루틴으로 들어가서 상태를 바꿔버린다 stateParamter.nextTime = gCurTime + 500; break; } monster.SetTObject(0); monster.DoWalkAround(); stateParamter.nextTime = gCurTime + CCharMove::GetMoveEstimateTime(&monster); break; } case eSEVENT_Process: { if( stateParamter.nextTime > gCurTime ) { break; } Mon_SpeechState speechState = eMon_Speech_MAX; const int rate = rand() % 100; if(0 <= rate && rate < baseMonsterList.StandRate ) { SetState( &monster, eMA_STAND); speechState = eMon_Speech_Stand; } else { SetState( &monster, eMA_WALKAROUND); speechState = eMon_Speech_KeepStand; } const MonSpeechInfo* const speechInfo = MON_SPEECHMGR->GetCurStateSpeechIndex( monster.GetMonsterKind(), speechState); if(0 == speechInfo) { break; } monster.AddSpeech( speechInfo->SpeechType, speechInfo->SpeechIndex); break; } } }
void CStateMachinen::DoStand(CMonster& monster, eStateEvent evt) { const BASE_MONSTER_LIST& baseMonsterList = monster.GetSMonsterList(); StateParameter& stateParamter = monster.mStateParamter; switch(evt) { case eSEVENT_Enter: { // 소유주가 전투중인 경우 도와주러 간다 if(CObject* const ownerObject = g_pUserTable->FindUser(monster.GetOwnerIndex())) { if(ownerObject->GetObjectBattleState() && TRUE == monster.SetTObject(ownerObject->GetTObject())) { SetState( &monster, eMA_PERSUIT); stateParamter.nextTime = gCurTime + 500; break; } } stateParamter.nextTime = gCurTime + baseMonsterList.StandTime; monster.DoStand(); if(FALSE == monster.IsNoCheckCollision()) { break; } VECTOR3 vPos = {0}; monster.GetPosition(&vPos); if(g_pServerSystem->GetMap()->CollisionTilePos( vPos.x, vPos.z, g_pServerSystem->GetMapNum())) { break; } monster.SetNoCheckCollision(FALSE); break; } case eSEVENT_Process: { if(stateParamter.nextTime > gCurTime) { break; } Mon_SpeechState speechState = eMon_Speech_MAX; const BYTE rate = BYTE(rand() % 100); if(rate < baseMonsterList.StandRate) { SetState( &monster, eMA_STAND); speechState = eMon_Speech_KeepWalkAround; } else { SetState( &monster, eMA_WALKAROUND); speechState = eMon_Speech_WalkAround; } // 100617 ONS 정지상태에서 타겟이 죽었을 경우, 배회상태로 변경한다. if( monster.GetTObject() && monster.GetTObject()->GetState() == eObjectState_Die ) { monster.SetTObject(0); SetState( &monster, eMA_WALKAROUND); } const MonSpeechInfo* const speechInfo = MON_SPEECHMGR->GetCurStateSpeechIndex( monster.GetMonsterKind(), speechState); if(0 == speechInfo) { break; } monster.AddSpeech( speechInfo->SpeechType, speechInfo->SpeechIndex); break; } } }