void CStateMachinen::DoRunAway(CMonster& monster, eStateEvent evt) { StateParameter& stateParamter = monster.mStateParamter; if( monster.GetAbnormalStatus()->IsStun || monster.GetAbnormalStatus()->IsFreezing || monster.GetAbnormalStatus()->IsStone || monster.GetAbnormalStatus()->IsSlip || monster.GetAbnormalStatus()->IsMoveStop || monster.GetAbnormalStatus()->IsParalysis ) { return; } switch(evt) { case eSEVENT_Enter: { monster.RemoveAllAggro(); monster.SetTObject(0); VECTOR3 position = {0}; position.x = float(monster.GetFiniteStateMachine().GetMemory().GetVariable( "__runaway_x__")); position.z = float(monster.GetFiniteStateMachine().GetMemory().GetVariable( "__runaway_z__")); monster.OnMove( &position); stateParamter.nextTime = gCurTime + CCharMove::GetMoveEstimateTime(&monster) + 1000; break; } case eSEVENT_Process: { if(gCurTime > stateParamter.nextTime) { SetState( &monster, eMA_STAND); break; } break; } } }
void CStateMachinen::DoAttack(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()->IsParalysis ) { return; } switch(evt) { case eSEVENT_Enter: { stateParamter.AttackStartTime = 0; stateParamter.nextTime = 0; break; } case eSEVENT_Process: { if(stateParamter.AttackStartTime > gCurTime) { break; } else if(stateParamter.CurAttackKind >= baseMonsterList.AttackNum) { SetState( &monster, eMA_STAND); break; } else if(0 == monster.GetTObject() || (monster.GetTObject() && ( monster.GetTObject()->GetState() == eObjectState_Die || monster.GetTObject()->GetInited() == FALSE ))) { SetState( &monster, eMA_WALKAROUND); break; } else if(monster.IsInvalidTarget(*monster.GetTObject())) { monster.SetTObject( 0); SetState( &monster, eMA_STAND); break; } const size_t maxSkillSize = sizeof(baseMonsterList.SkillInfo) / sizeof(*baseMonsterList.SkillInfo); if(maxSkillSize <= stateParamter.CurAttackKind) { break; } cActiveSkillInfo* const activeSkillInfo = baseMonsterList.SkillInfo[stateParamter.CurAttackKind]; if(0 == activeSkillInfo) { break; } VECTOR3 ObjectPos = *CCharMove::GetPosition(&monster); VECTOR3 TObjectPos = *CCharMove::GetPosition(monster.GetTObject()); const DWORD Distance = (DWORD)CalcDistanceXZ( &ObjectPos, &TObjectPos ); if(Distance > activeSkillInfo->GetInfo().Range) { SetState( &monster, eMA_PERSUIT); break; } stateParamter.AttackStartTime = gCurTime + baseMonsterList.SkillInfo[stateParamter.CurAttackKind]->GetInfo().CoolTime; monster.DoAttack(baseMonsterList.AttackIndex[stateParamter.CurAttackKind]); RandCurAttackKind( baseMonsterList, stateParamter); break; } } }
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::DoPursuit(CMonster& monster, eStateEvent evt) { const BASE_MONSTER_LIST& baseMonsterList = monster.GetSMonsterList(); StateParameter& stateParamter = monster.mStateParamter; if(0 == baseMonsterList.SkillInfo[stateParamter.CurAttackKind]) { SetState( &monster, eMA_STAND); return; } else if(0 == monster.GetTObject() || (monster.GetTObject() && (eObjectState_Die == monster.GetTObject()->GetState())) || FALSE == monster.GetTObject()->GetInited()) { SetState( &monster, eMA_STAND); return; } else if( monster.GetAbnormalStatus()->IsStun || monster.GetAbnormalStatus()->IsFreezing || monster.GetAbnormalStatus()->IsStone || monster.GetAbnormalStatus()->IsSlip || monster.GetAbnormalStatus()->IsMoveStop || monster.GetAbnormalStatus()->IsParalysis ) { return; } switch(evt) { case eSEVENT_Enter: { stateParamter.PursuitForgiveStartTime = gCurTime + baseMonsterList.PursuitForgiveTime; stateParamter.nextTime = gCurTime + 1000; monster.DoPursuit(); RandCurAttackKind( baseMonsterList, stateParamter); monster.SetNoCheckCollision(TRUE); break; } case eSEVENT_Process: { VECTOR3 ObjectPos = *CCharMove::GetPosition(&monster); VECTOR3 TObjectPos = *CCharMove::GetPosition(monster.GetTObject()); DWORD Distance = 0; float fDist = CalcDistanceXZ( &ObjectPos, &TObjectPos ) - monster.GetRadius(); if( fDist > 0.f ) { Distance = (DWORD)fDist; } if( stateParamter.prePursuitForgiveTime == 0 && ( stateParamter.PursuitForgiveStartTime < gCurTime || baseMonsterList.PursuitForgiveDistance < Distance ) ) { monster.RemoveAllAggro(); stateParamter.SearchLastTime = gCurTime + 3000; //3초간 선공몹 서치를 안하게 하기 위해서. SetState( &monster, eMA_WALKAROUND); MonSpeechInfo* pTemp = MON_SPEECHMGR->GetCurStateSpeechIndex( monster.GetMonsterKind(), eMon_Speech_ForgivePursuit ); if( pTemp ) monster.AddSpeech( pTemp->SpeechType, pTemp->SpeechIndex ); } else if( Distance < baseMonsterList.SkillInfo[stateParamter.CurAttackKind]->GetInfo().Range ) { SetState( &monster, eMA_ATTACK); break; } else if( stateParamter.nextTime > gCurTime ) { break; } stateParamter.nextTime = gCurTime + 1000; monster.DoPursuit(); RandCurAttackKind( baseMonsterList, stateParamter); break; } } }
void CStateMachinen::SubProcess(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()->IsParalysis ) { return; } switch(stateParamter.stateCur) { case eMA_STAND: case eMA_WALKAROUND: { const cActiveSkillInfo* const skillInfo = baseMonsterList.SkillInfo[monster.mStateParamter.CurAttackKind]; if(0 == skillInfo) { break; } CObject* object = 0; if(monster.IsForeAttack() && (stateParamter.SearchLastTime < gCurTime)) { stateParamter.SearchLastTime = gCurTime + baseMonsterList.SearchPeriodicTime; CObject* const ownerObject = g_pUserTable->FindUser(monster.GetOwnerIndex()); if(0 == ownerObject) { object = monster.DoSearch(); } else if(eObjectKind_Player == ownerObject->GetObjectKind()) { object = monster.DoFriendSearch( skillInfo->GetInfo().Range); } else if(eObjectKind_Monster & ownerObject->GetObjectKind()) { object = monster.DoSearch(); } } else if(baseMonsterList.AttackNum && (stateParamter.CollSearchLastTime < gCurTime)) { stateParamter.CollSearchLastTime = gCurTime + 500; CObject* const ownerObject = g_pUserTable->FindUser(monster.GetOwnerIndex()); if(0 == ownerObject) { break; } else if(eObjectKind_Player == ownerObject->GetObjectKind()) { object = monster.DoFriendSearch( skillInfo->GetInfo().Range); } else if(eObjectKind_Monster & ownerObject->GetObjectKind()) { object = monster.DoSearch(); } } if(0 == object) { break; } else if(FALSE == monster.SetTObject(object)) { break; } SetState( &monster, eMA_PERSUIT); } break; } }