#include "stdafx.h" #include #include #include #include "WanderState.h" #include "GameField.h" #include "Monster.h" #include "StatusManager.h" #ifdef _NA_007009_20131226_RETURN_TO_POSITION_IF_SAFETYZONE #include "../MovingPlanner.h" #endif //_NA_007009_20131226_RETURN_TO_POSITION_IF_SAFETYZONE WanderState::WanderState() { } WanderState::~WanderState() { } void WanderState::Init() { } void WanderState::SetNPC(NPC* pNpc) { m_pMonster = DOWNCASTER_SELECT(pNpc); if (m_pMonster == NULL || pNpc->IsEqualObjectKind(MONSTER_OBJECT) == false) { SUNLOG(eCRITICAL_LOG, "["__FUNCTION__"]|Unexpected type %08X", pNpc->GetObjectType()); __debugbreak(); } State::SetNPC(pNpc); } void WanderState::OnEnter(LPARAM param1, LPARAM param2, LPARAM param3) { State::OnEnter(param1, param2, param3); m_bDestSelected = false; m_bTouchedSomething = false; //m_SearchTimer.SetTimer(m_pAITypeInfo->m_wSEARCH_PERIOD); m_SearchTimer.SetTimer(m_SearchTimer.eStaticTimer_Search, 5000); } void WanderState::OnExit() { State::OnExit(); } BOOL WanderState::OnUpdate(DWORD dwDeltaTick) { __UNUSED(dwDeltaTick); #ifdef _NA_007009_20131226_RETURN_TO_POSITION_IF_SAFETYZONE //ÀÚ½ÅÀÇ À§Ä¡°¡ ¾ÈÀüÁö´ë ŸÀÏÀÌ¸é ¿øÀ§Ä¡·Î µ¹¾Æ°£´Ù. const nsAI::TileEvent* tile_event = 0; if (m_pNPC->GetStatusManager()->CanMove() && (m_pNPC->PlanEvent->GetTileEvent(&tile_event) == false || (tile_event->Attr & PTA_SAFETY_ZONE))) { m_pNPC->SetTargetChar(NULL); m_pNPC->ChangeState(STATE_ID_RETURN); return true; } #endif //_NA_007009_20131226_RETURN_TO_POSITION_IF_SAFETYZONE if (m_SearchTimer.IsExpired() && m_pMonster->CanAttack()) { if (!m_pNPC->GetStatusManager()->Status.IsPassConstraint(m_pNPC, (SkillScriptInfo*)0)) return true; // ÁÖº¯¿¡ ÀûÀÌ ÀÖ´ÂÁö Ž»ö Character* pTargetChar = m_pMonster->SearchTarget(); if (pTargetChar) { // ±×·ìÀÇ ÀÏ¿øÀÌ¸é ¸â¹öµé¿¡°Ô Àû ¹ß°ß ¸Þ¼¼Áö¸¦ º¸³½´Ù. if (m_pMonster->IsGroupMember()) { AI_MSG_ENEMY_FOUND aiMsg; aiMsg.dwTargetObjectKey = pTargetChar->GetObjectKey(); m_pMonster->SendAIMessageToGroupExceptMe(&aiMsg, sizeof(aiMsg)); } m_pMonster->SetTargetChar(pTargetChar); m_pMonster->ChangeState(STATE_ID_TRACK); return true; } // ¸ñÀûÁö°¡ ¾ø´Â »óÅÂÀÌ¸é ¸ñÀûÁö ¼±Åà if (m_bDestSelected == false) { // (CHANGES) (091231) (WAVERIX) if mob had group, change policy #if WAVERIX_CODE_RENEWAL BOOLEAN member_state = !!m_pNPC->IsGroupMember(); BOOLEAN leader_state = false; if (member_state) { leader_state = !!m_pNPC->IsLeader(); if (leader_state == false) { NPC* leader = m_pNPC->GetLeaderInField(); if (leader == NULL) { // leader ÇöÀç Çʵå»ó¿¡ ¾ø´Ù. member_state = false; // change to normal mob state logic } } } // member_state | leader_state // 0 0 - wander // 0 1 - x // 1 0 - follower : return or wander by command // 1 1 - wander if (!(member_state ^ leader_state)) { // NXOR m_bDestSelected = (DoWander() != false); } #else if (m_pMonster->IsLeader() || !m_pMonster->IsLeaderAlive()) //if (m_pMonster->GetGroupState().IsLeader() || !m_pMonster->GetGroupState().IsLeaderAlive()) { m_bDestSelected = DoWander(); } #endif } } // ¸ñÀûÁö¿¡ µµ´ÞÇÑ »óÅÂÀΰ¡ if (m_bDestSelected && m_pMonster->IsMoving() == false) { m_bDestSelected = false; // Àå¾Ö¹°¿¡ °É·Á¼­ Á¶±Ý¹Û¿¡ À̵¿À» ¸øÇÑ »óŰ¡ ¾Æ´Ï¶ó¸é IDLE·Î ÀüȯÇÑ´Ù. if (!m_bTouchedSomething) { m_pMonster->ChangeState(STATE_ID_IDLE); } } return true; } inline void WanderState::_UpdateTouchedSomething(BOOL bSet) { BOOL bSrc = m_bTouchedSomething; if ((!!bSet) != (!!bSrc)) m_bTouchedSomething = !bSet; } // ¸ñÀûÁö ¼±Åÿ¡ ¼º°øÇϸé true¸¦ ¸®ÅÏ BOOL WanderState::DoWander() { // À̵¿ÇÒ °Å¸®¸¦ ±¸ÇÑ´Ù. float MOVE_DISTANCE = (float)dRandom(AIParamParser::AICommonInfo.m_fMIN_MOVE_DISTANCE, AIParamParser::AICommonInfo.m_fMAX_MOVE_DISTANCE); const WzVector& wvCurPos = *m_pMonster->GetPosPtr(); GameField* pField = m_pMonster->GetField(); if (pField == NULL) return false; WzVector wvMovement; // ¸ñÀûÁö ÁÂÇ¥¸¦ ã´Â´Ù. if (m_bTouchedSomething) { // ÀÌÀü ±æÃ£±â¿¡¼­ ¹«¾ð°¡¿¡ ´êÀº °æ¿ì 49µµ ȸÀü½Ã۰í m_bTouchedSomething = false; wvMovement = m_wvRotatedVector; } else if (m_pMonster->IsOutOfWanderRadius()) { // ¹æÈ² ¹üÀ§¸¦ ¹þ¾î³µÀ¸¸é ¾ÈÂÊÀ¸·Î À̵¿ WzVector direction = m_pMonster->GetRegenPos(); ; direction -= wvCurPos; VectorNormalize(&wvMovement, &direction); wvMovement *= MOVE_DISTANCE; } else { // ·£´ýÇÑ ¹æÇâÀ¸·Î Æ÷ÀÎÆÃ int iAngle = State::GetStateRandomNo() % 360; wvMovement.x = (float)(MOVE_DISTANCE * g_SinTable.FCOS(iAngle)); wvMovement.y = (float)(MOVE_DISTANCE * g_SinTable.FSIN(iAngle)); wvMovement.z = 0.0f; } WzVector wvDestPos = wvCurPos; ; wvDestPos += wvMovement; // À̵¿°¡´É ¿©ºÎ¸¦ üũÈÄ ÆÐŶÀ» ³¯¸°´Ù. BOOL bRef = !!m_bTouchedSomething; if (!m_pMonster->ThrustMoveAndBroadcast(&wvDestPos, CMS_WALK, bRef, m_wvRotatedVector)) { _UpdateTouchedSomething(bRef); return false; } _UpdateTouchedSomething(bRef); // ±×·ìÀÇ ¸®´õÀÌ¸é ±×·ì Â̵û±¸µéÇÑÅ× AI ¸Þ¼¼Áö¸¦ º¸³½´Ù. if (m_pMonster->IsLeader()) //if (m_pMonster->GetGroupState().IsLeader()) { AI_MSG_LETSGO letsgoMsg; letsgoMsg.wvDestPos = wvDestPos; letsgoMsg.byMoveState = CMS_WALK; m_pMonster->SendAIMessageToGroupExceptMe(&letsgoMsg, sizeof(letsgoMsg), (DWORD)dRandom(AIParamParser::AICommonInfo.m_wGROUP_AIMESSAGE_MIN_DELAY, AIParamParser::AICommonInfo.m_wGROUP_AIMESSAGE_MAX_DELAY)); } return true; } void WanderState::OnMsgAttacked(const AI_MSG* pMsg) { State::OnMsgAttacked(pMsg); const AI_MSG_ATTACKED* pAttackMsg = static_cast(pMsg); GameField* pField = m_pMonster->GetField(); if (pField == NULL) return; Character* pAttacker = pField->FindCharacter(pAttackMsg->dwAttackerKey); if (pAttacker == NULL) return; // »ó´ë°¡ Àû±ºÀÌ¸é °ø°Ý »óÅ·ΠÀüÀÌ #ifdef _NA_007667_20141001_WITCHBLADE_SKILL State::SetTarget(pMsg, STATE_ID_TRACK); #else if (m_pMonster->IsFriend(pAttacker) == USER_RELATION_ENEMY) { m_pMonster->SetTargetChar(pAttacker); m_pMonster->ChangeState(STATE_ID_TRACK, 0, 0, pAttackMsg->dwMsgID); } #endif //_NA_007667_20141001_WITCHBLADE_SKILL } void WanderState::OnMsgLetsGo(const AI_MSG* pMsg) { State::OnMsgLetsGo(pMsg); m_bDestSelected = true; }