#include "stdafx.h" #include "SummonIdle.h" #include "GameField.h" #include #include "AIParamParser.h" #include "Summoned.h" #include "PublicMath.h" #include "MoveStateControl.h" #include "TargetManager.h" #include "ChaoState.h" #include "Player.h" #ifdef _NA_007667_20141001_WITCHBLADE_SKILL #include "SummonManager.h" #include "SummonedNPCs.h" #endif //_NA_007667_20141001_WITCHBLADE_SKILL SummonIdle::SummonIdle() { } SummonIdle::~SummonIdle() { } void SummonIdle::Init() { } void SummonIdle::SetNPC(NPC* pNpc) { m_pSummoned = DOWNCASTER_SELECT(pNpc); if (m_pSummoned == NULL || pNpc->IsEqualObjectKind(SUMMON_OBJECT) == false) { SUNLOG(eCRITICAL_LOG, "["__FUNCTION__"]|Unexpected type %08X", pNpc->GetObjectType()); __debugbreak(); } State::SetNPC(pNpc); } void SummonIdle::OnEnter(LPARAM param1, LPARAM param2, LPARAM param3) { State::OnEnter(param1, param2, param3); m_SearchTimer.SetTimer(m_pAITypeInfo->m_wSEARCH_PERIOD); m_TrackTimer.SetTimer(m_pAITypeInfo->m_wTRACK_PERIOD); m_SpawnTimer.SetTimer(param1); m_pSummoned->SetTargetChar(NULL); m_pSummoned->SetSkillUseDelegate(false); // ¼Òȯü°¡ °ø°ÝÀ» ÇÏ´Ù°¡ Idle·Î µ¹¾Æ¿À´Â ½ÃÁ¡¿¡¼­ °­Á¦°ø°Ý Ç÷¡±×¸¦ ²ö´Ù. Player* const player = m_pSummoned->GetPlayerOwner(); if (player) { player->SetForceAttack(false); } } void SummonIdle::OnExit() { State::OnExit(); } BOOL SummonIdle::OnUpdate(DWORD dwDeltaTick) { // ÃÖÃÊ ½ºÆù½Ã°£À» À§Çؼ­ ÀÏÁ¤½Ã°£ ±â´Ù·ÁÁØ´Ù. if (!m_SpawnTimer.IsExpired(false)) return true; if (obj_util::IsValid(m_pSummoned, __FUNCTION__, __LINE__) == false) { return true; } Character* const m_pSummoner = m_pSummoned->GetSummoner(); if (m_pSummoner == NULL) return true; m_vSummonedPos = *m_pSummoned->GetPosPtr(); m_vSummonerPos = *m_pSummoner->GetPosPtr(); // (CHANGES) (100206) (WAVERIX) PCC_CONTINUING_NPC_UPDATE Ãß°¡¿¡ µû¸¥ AttackStateÀ¯Áö »óŸ¦ // ¹Ù²Ü Çʿ伺ÀÌ »ý°å´Ù. GameField* game_field = m_pSummoned->GetField(); //assert not null DWORD references = 0; { SECTOR_IDX sector_index = m_pSummoned->GetSectorIndex(); Sector* sector = sector_index != INVALID_SECTOR_INDEX ? game_field->GetSector(sector_index) : NULL; // 'sector == NULL' ¹ß»ýÇØ¼­´Â ¾ÈµÇÁö¸¸, °æ¿ì¿¡ µû¶ó // (3DEngine¿¡¼­ ¹Ì¹¦ÇÑ °è»ê ¿ÀÂ÷¿¡ µû¸¥ »ç·Ê Á¸Àç) °¡´É¼ºÀÌ Á¸ÀçÇÑ´Ù. references = sector != NULL ? sector->GetReferenceCount() : 0; }; #ifdef _NA_007667_20141001_WITCHBLADE_SKILL // °íÁ¤Çü ¼Òȯ¼ö´Â ÃßÀû»óÅÂÀüȯ, À̵¿Ã³¸® ½ºÅµ if (m_pSummoned->GetSummonType() == eSUMMON_IMMOVABLE) { UseConstantSkill(); } else { // (lst1024)(080923) Àû±º Ç÷¹ÀÌ¾î °ø°Ý¹ö±×¸¦ À§ÇØ _NONPK ¸ðµå Ãß°¡ ÇÊ¿ä. // Summoned¿¡ SearchTargetÇÔ¼ö¸¦ Ãß°¡ ÇÏ¿© Àû±º Ç÷¹À̾î À¯Àú¸¦ ãÁö ¾Ê´Â ÆÄÀδõ »ç¿ë. // ¾Æ±ºµµ ½ºÅ³ »ç¿ë ¹üÀ§¿¡ ³ÖÀ» °æ¿ì ÀÚ±â Àڽŵµ ¾Æ±ºÀ̹ǷΠSummonIdle»óÅ·Πµ¹¾Æ¿ÀÁö ¾Ê´Â´Ù. // if (references != 0 && // skip target searching m_SearchTimer.IsExpired() && (m_pSummoned->IsOffensive() || m_pSummoned->IsNonPVP())) { // ÁÖº¯¿¡ ÀûÀÌ ÀÖ´ÂÁö Ž»ö Character* pTargetChar = m_pSummoned->SearchTarget(); if (pTargetChar) { m_pSummoned->SetTargetChar(pTargetChar); m_pSummoned->ChangeState(STATE_ID_TRACK); return true; } } } #else // (lst1024)(080923) Àû±º Ç÷¹ÀÌ¾î °ø°Ý¹ö±×¸¦ À§ÇØ _NONPK ¸ðµå Ãß°¡ ÇÊ¿ä. // Summoned¿¡ SearchTargetÇÔ¼ö¸¦ Ãß°¡ ÇÏ¿© Àû±º Ç÷¹À̾î À¯Àú¸¦ ãÁö ¾Ê´Â ÆÄÀδõ »ç¿ë. // ¾Æ±ºµµ ½ºÅ³ »ç¿ë ¹üÀ§¿¡ ³ÖÀ» °æ¿ì ÀÚ±â Àڽŵµ ¾Æ±ºÀ̹ǷΠSummonIdle»óÅ·Πµ¹¾Æ¿ÀÁö ¾Ê´Â´Ù. // if (references != 0 && // skip target searching m_SearchTimer.IsExpired() && (m_pSummoned->IsOffensive() || m_pSummoned->IsNonPVP())) { // ÁÖº¯¿¡ ÀûÀÌ ÀÖ´ÂÁö Ž»ö Character* pTargetChar = m_pSummoned->SearchTarget(); if (pTargetChar) { m_pSummoned->SetTargetChar(pTargetChar); m_pSummoned->ChangeState(STATE_ID_TRACK); return true; } } #endif //_NA_007667_20141001_WITCHBLADE_SKILL // ¼ÒȯÀÚ¿ÍÀÇ °Å¸®°¡ ÀÏÁ¤¹üÀ§ ³»À̸é À̵¿À» ÇÏÁö ¾Ê´Â´Ù. static const float SummonFollowDistance = AIParamParser::AICommonInfo.m_fSUMMON_FOLLOW_DISTANCE * AIParamParser::AICommonInfo.m_fSUMMON_FOLLOW_DISTANCE; float fDistance2 = Math_Vector2DLength2(&(m_vSummonedPos - m_vSummonerPos)); if (fDistance2 <= SummonFollowDistance) return true; if (m_TrackTimer.IsExpired() == false) return true; // ¼Òȯü°¡ ¾ÆÁ÷ ¸ñÇ¥Á¡¿¡ µµ´ÞÇÏÁö ¾Ê¾Ò´õ¶óµµ, Ž»öÁֱⰡ ´Ù µÇ¾ú°í ¼ÒȯÀÚ°¡ ¿òÁ÷À̰í ÀÖ´Ù¸é ´Ù½Ã ¸ñÇ¥Á¡À» Àâ´Â´Ù. if (references != 0 && m_pSummoned->IsMoving()) { // if (!m_TrackTimer.IsExpired()) return; // ¼ÒȯÀÚ°¡ ¸ØÃç¹ö¸®¸é ¸ñÇ¥Á¡À» ´Ù½Ã ã´Â´Ù. if (m_pSummoner->IsMoving() == false) { FollowSummoner(m_pSummoner); } else { m_vSummonerDestPos = m_pSummoned->GetPathExplorer()->GetTargetPos(); // ¼ÒȯÀÚ°¡ ¼Òȯü°¡ ¶Ù·Á´Â ¹æÇâÀÇ ºÎä²ÃÀ» ¹þ¾î³­ °¢¿¡ À§Ä¡Çϴ°¡? BOOLEAN bOutOfAngle = !Math_IsPositionInFanshapedArea(&m_vSummonerPos, &m_vSummonedPos, &(m_vSummonerDestPos - m_vSummonedPos), AIParamParser::AICommonInfo.m_wTRACK_INNER_ANGLE); // ¼ÒȯÀÚ°¡ ¼Òȯü°¡ ¶Ù·Á´Â ¸ñÀûÁö¿¡¼­ ¸Ö¸®Àִ°¡? BOOLEAN bOutOfRange = \ Math_VectorLength2(m_vSummonerDestPos, m_vSummonerPos) > SummonFollowDistance; if (bOutOfAngle && bOutOfRange) { FollowSummoner(m_pSummoner); // printf("Moving Track!! DiffTick[%d]\n", GetTickCount()-m_dwPrevTick); // m_dwPrevTick = GetTickCount(); } } } else { FollowSummoner(m_pSummoner); // printf("Stop Track!! DiffTick[%d]\n", GetTickCount()-m_dwPrevTick); // m_dwPrevTick = GetTickCount(); } return true; } void SummonIdle::DecideMovement() { // ¼ÒȯÀÚ°¡ À̵¿Çϰí ÀÖ´Â °æ¿ì¿¡¸¸ À̵¿¿¹»ó ¸ñÇ¥Á¡(TargetPos)À» ÀÌ¿ëÇÑ´Ù. Character* m_pSummoner = m_pSummoned->GetSummoner(); if (m_pSummoner && m_pSummoner->IsMoving()) { m_vSummonerDestPos = m_pSummoner->GetPathExplorer()->GetTargetPos(); } else { m_vSummonerDestPos = m_vSummonerPos; } // ¸ñÀûÁö ÁÂÇ¥°¡ À¯È¿ÇÑ ÁÂÇ¥ÀÎÁö üũ GameField* pField = m_pSummoned->GetField(); if (pField) { if (!pField->IsMovableCoordinates(&m_vSummonerDestPos)) { SUNLOG(eMIDDLE_LOG, "[DecideMovement] Is Not MovableCoordinates!"); m_vSummonerDestPos = m_vSummonerPos; } } // ¹æÇâ°¢ °áÁ¤(¼Òȯü¿Í ¼ÒȯÀÚÀÇ ÃִܰŸ® ¹æÇâÀ¸·Î °áÁ¤) WzVector wvNormal; VectorNormalize(&wvNormal, &(m_vSummonedPos - m_vSummonerDestPos)); float max_value = static_cast(AIParamParser::AICommonInfo.m_fSUMMON_FOLLOW_DISTANCE); float min_value = max_value * 0.5f; float fDistance = (float)dRandom(min_value, max_value); m_vMovement = wvNormal * fDistance; } void SummonIdle::FollowSummoner(Character* m_pSummoner) { #ifdef _NA_007667_20141001_WITCHBLADE_SKILL // °íÁ¤Çü ¼Òȯ¼ö´Â ¿òÁ÷ÀÌÁö ¾Ê´Â´Ù if (m_pSummoned->GetSummonType() == eSUMMON_IMMOVABLE) { // °íÁ¤Çü ¼Òȯ¼ö´Â ÀÏÁ¤°Å¸®¸¦ ¹þ¾î³ª¸é ¼Ò¸êµÈ´Ù. if (m_pSummoner->GetDist2(m_pSummoned) > AIParamParser::AICommonInfo.m_fSUMMON_MAX_FOLLOW_DISTANCE * AIParamParser::AICommonInfo.m_fSUMMON_MAX_FOLLOW_DISTANCE) { SummonManager* summon_manager = SummonManager::Instance(); if (summon_manager != NULL) { SummonedNPCs* summoned_list = summon_manager->FindSummonNPCs(m_pSummoner->GetObjectKey()); if (summoned_list != NULL) { summoned_list->Destroy(m_pSummoned->GetObjectKey()); } } } return; } #endif //_NA_007667_20141001_WITCHBLADE_SKILL // ¼ÒȯÀÚ¿¡´ëÇÑ »ó´ë ÁÂÇ¥¸¦ ±¸ÇÑ´Ù. DecideMovement(); WzVector vDestPos = m_vSummonerDestPos + m_vMovement; eCHAR_MOVE_STATE eMoveState = m_pSummoner->GetMoveStateControl()->GetMoveState(); if (eMoveState != CMS_WALK) { eMoveState = CMS_RUN; } // ÀÏÁ¤°Å¸®¸¦ ¹þ¾î³ª¸é ÅÚ·¹Æ÷Æ®ÇÑ´Ù. if (m_pSummoner->GetDist2(m_pSummoned) > AIParamParser::AICommonInfo.m_fSUMMON_MAX_FOLLOW_DISTANCE * AIParamParser::AICommonInfo.m_fSUMMON_MAX_FOLLOW_DISTANCE) { Teleport(m_vSummonerPos); return; } // ±æÃ£±â if (m_pSummoned->MoveAndBroadcast(&vDestPos, eMoveState) == false) { vDestPos = m_vSummonerPos; if (m_pSummoned->MoveAndBroadcast(&m_vSummonerPos, eMoveState) == false) { // SUNLOG(eFULL_LOG, "[FollowSummoner] MoveAndBroadcast Fail!"); } } // ¸®ÅÏ»óŸ¦ ¹æÁöÇϱâ À§Çؼ­ ¸ñÀûÁö ÁÂÇ¥¸¦ ¸®Á¨ÁÂÇ¥·Î ¼ÂÆÃÇÑ´Ù. m_pSummoned->SetRegenPos(vDestPos); m_TrackTimer.SetTimer(m_pAITypeInfo->m_wTRACK_PERIOD); } void SummonIdle::Teleport(WzVector &vDestPos) { GameField* pField = m_pSummoned->GetField(); if (pField == NULL) return; pField->TeleportObject(m_pSummoned, &vDestPos); } void SummonIdle::OnMsgAttacked(const AI_MSG* pMsg) { #ifdef _NA_007667_20141001_WITCHBLADE_SKILL // °íÁ¤Çü ¼Òȯ¼ö´Â °ø°Ý»óÅ·Π¾È³Ñ¾î°£´Ù if (m_pSummoned->GetSummonType() == eSUMMON_IMMOVABLE) { return; } #endif //_NA_007667_20141001_WITCHBLADE_SKILL State::OnMsgAttacked(pMsg); // µÚµû¸§ »óÅÂÀÌ¸é ¹ÝÀÀÇÏÁö ¾Ê´Â´Ù. if (m_pSummoned->IsFollowing()) { return; } const AI_MSG_ATTACKED* pAttackMsg = static_cast(pMsg); GameField* pField = m_pSummoned->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_pSummoned->GetTargetChar() == NULL) { if (m_pSummoned->IsFriend(pAttacker) == USER_RELATION_ENEMY) { m_pSummoned->SetTargetChar(pAttacker); m_pSummoned->ChangeState(STATE_ID_TRACK, 0, 0, pAttackMsg->dwMsgID); } } #endif //_NA_007667_20141001_WITCHBLADE_SKILL } #ifdef _NA_007667_20141001_WITCHBLADE_SKILL void SummonIdle::UseConstantSkill() { m_pSummoned->SelectSkill(); SLOTCODE skill_code = m_pSummoned->GetSelectedSkill(); m_pSummoned->UseSkill(skill_code); } #endif //_NA_007667_20141001_WITCHBLADE_SKILL