#include "StdAfx.h" #include "GameSrv.h" #include "actionfollow.h" #include "Monster.h" #include "Player.h" #include "SkillManager.h" #include "AIManager.h" #include "ObjectManager.h" #include "GridManager.h" #include "MonsterScript.h" cActionFollow::cActionFollow(void) : cAction( eACT_FOLLOW ) { mRePathTime = 0; } cActionFollow::~cActionFollow(void) { } void cActionFollow::ActionInit( cMonster* pMonster, unsigned long accumTime ) { if( pMonster == NULL ) return; cAction::ActionInit( pMonster, accumTime ); /// Ÿ°Ù °Ë»ç cBaseObject* pTarget = pMonster->GetTarget(); if( pTarget == NULL || pTarget->GetStateDie() == true ) return; mFollowTargetPos.x = pTarget->GetXPos(); mFollowTargetPos.y = pTarget->GetYPos(); mFirstFollowMove = true; mDelayTime = accumTime; mCantFollowPos = 0; mIsTalk = true; mNextSelectSkill = 0; /// °ø°Ý ¼º°øÀ̸é ÃßÀû ½Ã°£ Àç¼³Á¤ const sMonsterScript* pMonsterScript = pMonster->GetMonsterInfo(); if( pMonsterScript == NULL ) { assert(NULL); NETWORK2->PostServerEvent("cActionFollow::ActionInit pMonsterScript == NULL"); return; } pMonster->SetFollowEndTime( accumTime + pMonsterScript->mFollowTime ); } eACTION_CHANGE cActionFollow::Action( cMonster* pMonster, unsigned long deltaTime, unsigned long accumTime ) { if( pMonster == NULL ) return eACTCH_ERROR; const sMonsterScript* pMonsterScript = pMonster->GetMonsterInfo(); if( pMonsterScript == NULL ) { assert(NULL); NETWORK2->PostServerEvent("cActionFollow::Action pMonsterScript == NULL"); return eACTCH_ERROR; } /// Ÿ°Ù¿¡ ´ëÇØ ½ºÅ³ ¹ßµ¿ cBaseObject* pTarget = (cBaseObject*)pMonster->GetTarget(); if( pTarget == NULL || pTarget->GetStateDie() == true ) { /// 081205 PKH Ÿ°Ù ¼±Á¤ pMonster->ChangeActionTarget(); return eACTCH_CONTINUE; } /// ½ºÅ³ Àç¼±Á¤ üũ float skillrange = pMonster->CalcStatusSkillRange( pMonsterScript->mSkillMinRange, (eRANGETYPE)pMonsterScript->mSkillMinRangeType ); if( pMonster->GetAttackType() == eMONSTERATTACK_MAX || mNextSelectSkill < accumTime ) { /// ½ºÅ³ »ç¿ëÈÄ Áö¿¬½Ã°£ üũ if( pMonster->IsSkillWaitEnd() == true ) { eMONSTERATTACK_TYPE attackType = pMonster->SelectSkill(); pMonster->SetAttackType( attackType ); pTarget = (cBaseObject*)pMonster->GetTarget(); if( pTarget == NULL || pTarget->GetStateDie() == true ) return eACTCH_CONTINUE; if( attackType != eMONSTERATTACK_MAX ) { sMonsterSkillScript* pMonsterSkillScript = SKILLSCRIPT->GetMonsterSkillInfo( pMonster->GetRaceGender(), attackType ); if( pMonsterSkillScript != NULL ) /// ½ºÅ³ ¹ßµ¿ °Å¸® { if( pMonsterSkillScript->mApplyType == eAPPLYTYPE_ENEMY ) mNextSelectSkill = accumTime + 100; /// ºÎÇÏ ¹æÁö else mNextSelectSkill = accumTime + 3000; /// µ¿·áÇÑÅ× ¾²´Â ½ºÅ³Àº 3Ãʰ£ ¾µ¶§±îÁö ÂѾư¨ if( pMonsterSkillScript->mBoundType == eBOUNDTYPE_FIELD ) { mRangechk.SetRadius( OBJECTMANAGER->ObjectSizeRange( pTarget, pMonster, (float)pMonsterScript->mSeekRange ) ); if( mRangechk.IsNotRange( pTarget->GetPos(), pMonster->GetPos() ) == true ) { pMonster->ChangeActionTarget(); return eACTCH_CONTINUE; } else return eACTCH_FOLLOW_ATTACK; } else skillrange = pMonster->CalcStatusSkillRange( pMonsterSkillScript->mTargetDist, pMonsterSkillScript->mRangeType ); } } } } /// À̵¿ ¾ÈÇÏ´Â ¸ó½ºÅÍ Àΰæ¿ì if( pMonsterScript->mActionRunSpd == 0 && pMonsterScript->mActionWalkSpd == 0 ) { /// ½Ã¾Æ ¹üÀ§¾È¿¡ ¸ó½ºÅͰ¡ µé¾î¿ÍÀÖÀ¸¸é °ø°ÝÇÑ´Ù. cPlayer* pPlayer = TargetSelect( pMonster, pMonsterScript->mSeekRange ); if( pPlayer != NULL) { const sRegenScript* pRegen = pMonster->GetRegenMonsterInfo(); if( pRegen != NULL && pRegen->mFamilyNum != 0 ) AIMANAGER->FamilyAttack( pMonster->GetObjectID(), pRegen->mFamilyNum, pPlayer->GetObject() ); pMonster->AddTakeDamage( pPlayer->GetObject(), 0, 0, eTAKEDAMAGETYPE_ADDPLAYER ); return eACTCH_FOLLOW_ATTACK; } else return eACTCH_CONTINUE; } /// °ø°Ý°Å¸® ¾È¿¡ µé¾î¿Â°æ¿ì float totalRange = OBJECTMANAGER->ObjectSizeRange( pMonster, pTarget, skillrange ); mRangechk.SetRadius( totalRange ); if( mRangechk.IsRange( pMonster->GetPos(), pTarget->GetPos() ) ) { if( SKILLMANAGER->MonsterAttack( pMonster->GetObjectID(), pMonster->GetAttackType(), pTarget->GetObject() ) == true ) return eACTCH_FOLLOW_ATTACK; else return eACTCH_CONTINUE; } /// ÃßÀû ½Ã°£ üũ mRangechk.SetRadius( (float)pMonsterScript->mFollowRange ); bool isFollowEnd = false; if( pMonster->GetFollowEndTime() <= accumTime ) isFollowEnd = true; if( mRangechk.IsNotRange(pMonster->GetPos(), pMonster->GetFollowStartPos()) ) isFollowEnd = true; if( isFollowEnd == true ) { if( pMonster->IsFollowContinue() == false ) { /// ȸ±â »óÅ ¼³Á¤ pMonster->ClearTakeDamage(); pMonster->Comeback(); return eACTCH_FOLLOW_END; } else { pTarget = (cBaseObject*)pMonster->GetTarget(); if( pTarget == 0 ) { pMonster->ClearTakeDamage(); pMonster->Comeback(); return eACTCH_FOLLOW_END; } } } NiPoint2 followPos = pTarget->GetPos(); if( pTarget->GetObjectType() == eOBJECTTYPE_PLAYER ) { cPlayer* pPlayer = (cPlayer*)pTarget; /// Ç÷¹À̾ ÃßÀû ÆÛÁü À§Ä¡ Àç½Åû - °¡¿îµ¥ ÀÚ¸®°¡ ºó °æ¿ì °¡¿îµ¥·Î À̵¿ pMonster->SetPlayerFollowPos( pPlayer->SelectFollowPos( pMonster->GetPlayerFollowPos() ) ); /// ÃßÀû ÆÛÁüÀ§Ä¡ ¼±Á¤ nipoint2 -> nipoint3 followPos = OBJECTMANAGER->CalcFollowPos( pMonster->GetPlayerFollowPos(), pPlayer->GetPos(), totalRange ); /// ¸ó½ºÅÍ Ãߺ¯À§Ä¡ ¼³Á¤ÀÎÁö ½ÇÁ¦ À§Ä¡ÀÎÁö À¯¹« bool playerRealPos = false; /// ÃßÀû ÆÛÁü À§Ä¡°¡ À̵¿ °¡´É Áö¿ªÀÎÁö üũ if( AIMANAGER->IsPossible( pPlayer->GetMapNumber(), followPos.x, followPos.y, pPlayer->GetObject() ) == true ) { /// ÃßÀû ÆÛÁü À§Ä¡ ±îÁö µµ´Þ ÇѰæ¿ì ½ÇÁ¦ À§Ä¡ ¼³Á¤ mRangechk.SetRadius( totalRange ); if( mRangechk.IsRange( pMonster->GetPos(), followPos ) == true ) { playerRealPos = true; followPos = pPlayer->GetPos(); if( SKILLMANAGER->MonsterAttack( pMonster->GetObjectID(), pMonster->GetAttackType(), pPlayer->GetObject() ) == true ) return eACTCH_FOLLOW_ATTACK; } } else /// ÃßÀû ÆÛÁüÀ§Ä¡°¡ ¸ø°¡´Â Áö¿ªÀ̹ǷΠ½ÇÁ¦ À§Ä¡·Î °£´Ù. playerRealPos = true; /// ½ÇÁ¦ À§Ä¡·Î À̵¿ ÇØ¾ß Çϴµ¥ if( playerRealPos == true ) { /// ¸ø°¡´Â Áö¿ª Àΰæ¿ì if( AIMANAGER->IsPossible( pPlayer->GetMapNumber(), pPlayer->GetXPos(), pPlayer->GetYPos(), pPlayer->GetObject() ) == false ) { /// Ä«¿îÆ® Áõ°¡ ++mCantFollowPos; /// ·£´ý ÁÂÇ¥ ¼±Åà NiPoint2 randPos( pPlayer->GetXPos(), pPlayer->GetYPos() ); float fixedSkillRange = pMonsterScript->mSkillMinRange; switch( mCantFollowPos ) { case 1: randPos.x -= fixedSkillRange / 2; break; /// ³ôÀÌ °Å¸®¸¦ °¨¾ÈÇØ 2·Î ³ª´«´Ù. case 2: randPos.x += fixedSkillRange / 2; break; case 3: randPos.y -= fixedSkillRange / 2; break; case 4: randPos.y += fixedSkillRange / 2; break; case 5: randPos.x -= fixedSkillRange / 3; randPos.y += fixedSkillRange / 3; break; /// ³ôÀÌ¿Í ´ë°¢¼± °Å¸®¸¦ °¨¾ÈÇØ 3À¸·Î ³ª´«´Ù. case 6: randPos.x += fixedSkillRange / 3; randPos.y += fixedSkillRange / 3; break; case 7: randPos.x -= fixedSkillRange / 3; randPos.y -= fixedSkillRange / 3; break; case 8: randPos.x += fixedSkillRange / 3; randPos.y -= fixedSkillRange / 3; break; } /// ¸ø°¡´Â Áö¿ª Àΰæ¿ì if( AIMANAGER->IsPossible( pPlayer->GetMapNumber(), randPos.x, randPos.y, pPlayer->GetObject() ) == false ) { /// À§¿¡¼­ Á¤ÇÑ 8¹æÇâ ÁÂÇ¥°¡ ÀüºÎ ¸ø°¡´Â Áö¿ªÀϰæ¿ì µµ¸Á if( mCantFollowPos >= 8 ) { //return eACTCH_ESCAPE; pMonster->ChangeActionTarget(); } return eACTCH_CONTINUE; } else { followPos.x = randPos.x; followPos.y = randPos.y; mCantFollowPos = 0; totalRange = 0.0f; skillrange = 0.0f; } } } } /// ¸ó½ºÅÍ ÇöÀçÀ§Ä¡¿Í Ÿ°Ù °Å¸®¸¦ °è»ê float range = ( pMonster->GetPos() - pTarget->GetPos() ).Length() * 0.1f; /// range °ªÀÌ 100º¸´Ù ÀÛÀ»¼ø ¾ø´Ù. if( range < 100 ) range = 100; /// ÇöÀç Ÿ°ÙÀÇ ¿¹Àü¿¡ ±â·ÏÇÑ À§Ä¡¿Í ÇöÀç À§Ä¡ÀÇ °Å¸®Â÷¸¦ °¡Á®¿È float objectLength = ( mFollowTargetPos - pTarget->GetPos() ).Length(); /// object±â·Ï À§Ä¡¶û ÇöÀçÀ§Ä¡°¡ range°ªº¸´Ù Å«°æ¿ì À§Ä¡ objectÀ§Ä¡±â·Ï °»½Å - ³ëµå°»½Å if( objectLength > range ) { /// 0.5Ãʸ¶´Ù °Ë»ç - ºÎÇϸ¦ ÁÙÀ̱â À§ÇÔ if( mDelayTime > accumTime ) { sObject target; target.index = pTarget->GetObjectID(); target.type = pTarget->GetObjectType(); /// ¸ó½ºÅÍ ÃßÀû ¼Óµµ pMonster->SetMoveSpeed( pMonster->GetMonsterInfo()->mActionRunSpd, eMOVESPEED_RUN ); /// ±æÃ£±â ³ëµå Àç»ý¼º pMonster->SetPath( followPos.x, followPos.y, skillrange, pTarget->GetObject() ); /// ½ºÅ³ »ç¿ë °¡´ÉÀÎÁö üũ if( pMonster->IsSkillWaitEnd() == true && mIsTalk == true ) { mIsTalk = false; pMonster->SendSpeech( eMONSTERTALK_FOLLOW ); } /// Ç÷¹À̾ À̵¿ ÇÒ °æ¿ì ±æÃ£±â Àç¼³Á¤À» À§ÇØ Ç÷¹À̾î À§Ä¡ ±â·Ï mFollowTargetPos.x = pTarget->GetXPos(); mFollowTargetPos.y = pTarget->GetYPos(); } else mDelayTime = mDelayTime + 500; } /// ¸ó½ºÅÍ À̵¿ if( pMonster->MoveUpdate( deltaTime ) == false || mFirstFollowMove == true ) { mFirstFollowMove = false; sObject target; target.index = pTarget->GetObjectID(); target.type = pTarget->GetObjectType(); /// ¸ó½ºÅÍ ÃßÀû ¼Óµµ pMonster->SetMoveSpeed( pMonster->GetMonsterInfo()->mActionRunSpd, eMOVESPEED_RUN ); if( mRePathTime < accumTime ) { mRePathTime = accumTime + 300; /// ½ºÅ³ ¹üÀ§ ¹ÛÀÌ¸é ´Ù½Ã À̵¿ ¼ÂÆÃ pMonster->SetPath( followPos.x, followPos.y, skillrange, pTarget->GetObject() ); } /// ½ºÅ³ »ç¿ë °¡´ÉÀÎÁö üũ if( pMonster->IsSkillWaitEnd() == true && mIsTalk == true ) { mIsTalk = false; pMonster->SendSpeech( eMONSTERTALK_FOLLOW ); } /// Ç÷¹À̾ À̵¿ ÇÒ °æ¿ì ±æÃ£±â Àç¼³Á¤À» À§ÇØ Ç÷¹À̾î À§Ä¡ ±â·Ï mFollowTargetPos.x = pTarget->GetXPos(); mFollowTargetPos.y = pTarget->GetYPos(); } /// ´Ù¸¥ À̺¥Æ®°¡ °É¸®±â Àü±îÁö °è¼Ó ÃßÀû¸ðµå return eACTCH_CONTINUE; } cPlayer* cActionFollow::TargetSelect( cMonster* pMonster, unsigned long seekRange ) { if( pMonster == NULL ) return NULL; float tempRange; /// ÁÖº¯ ±×¸®µå¿¡ Ç÷¹À̾ ÀÖ´ÂÁö ¸ÕÀú üũ - ºÎÇϹæÁö if( GRIDMANAGER->IsPlayer( pMonster ) == 0 ) return NULL; /// °¢°¢ÀÇ Ç÷¹À̾ °Ë»öÇÔ cPlayer* pPlayer = GRIDMANAGER->FindFirstPlayer( pMonster ); while( pPlayer != NULL ) { /// Ÿ°Ù ¼±Á¤Àü ºñÁß È®ÀÎ if( pPlayer->GetMonsterImportance() + pMonster->GetFollowImportance() > 100 ) { pPlayer = GRIDMANAGER->FindNextPlayer(); continue; } /// ¸ó½ºÅÍ·Î º¯½ÅÇÑ Äɸ¯ÅÍÀÎ °æ¿ì if( pPlayer->GetChgMonsterIdx() != 0 || pPlayer->GetStateOddity( eODDITYTYPE_AVOID_MON_LOOK ) != 0 ) { /// ÇØ´ç ¸ó½ºÅͰ¡ º¯½ÅÇÑ Ç÷¹À̾ ÀνÄÇÏ´ÂÁö ¾ÈÇÏ´ÂÁö Á¤º¸¸¦ ¾òÀ½ sMonsterScript* pScript = MONSTERSCRIPT->GetMonsterListInfo( pMonster->GetRaceGender() ); if( pScript != NULL && pScript->mIsChgMonCheck == false ) { /// °ø°ÝÀ» ¹ÞÀº Á¤º¸°¡ ÀÖ´ÂÁö üũ PerTakeDamage* per = TAKEDAMAGEPOOL->GetTakeDamage( pMonster->GetTakeDamageRoot(), pPlayer->GetObjectID() ); if( per == NULL ) { pPlayer = GRIDMANAGER->FindNextPlayer(); continue; } } } /// Ç÷¹À̾ Á×Áö ¾ÊÀº °æ¿ì¸¸ if( pPlayer->GetStateDie() != true ) { tempRange = OBJECTMANAGER->ObjectSizeRange( pMonster, pPlayer, (float)seekRange ); /// ¸ó½ºÅÍ ¹üÀ§ ¼³Á¤ mRangechk.SetRadius( tempRange ); /// ¸ó½ºÅÍ À§Ä¡ NiPoint3 monsterpoint( pMonster->GetXPos(), pMonster->GetYPos(), pMonster->Height() ); /// Ç÷¹À̾î À§Ä¡ NiPoint3 playerpoint( pPlayer->GetXPos(), pPlayer->GetYPos(), pPlayer->Height() ); /// ¸ø°¡´Â Áö¿ªÀΰæ¿ì Åë°ú if( AIMANAGER->IsPossible( pPlayer->GetMapNumber(), playerpoint.x, playerpoint.y, pPlayer->GetObject() ) == false ) { pPlayer = GRIDMANAGER->FindNextPlayer(); continue; } /// ¸ó½ºÅÍ¿Í Ç÷¹À̾î Ãæµ¹ üũ if( mRangechk.IsRange( monsterpoint, playerpoint ) ) { return pPlayer; } } pPlayer = GRIDMANAGER->FindNextPlayer(); } return NULL; }