#include "gamesrv.h" #include "stdafx.h" #include "Monster.h" #include "Totem.h" #include "../Common/Protocol.h" #include "Status_Common.h" #include "ObjectManager.h" #include "SkillManager.h" #include "AIManager.h" #include "MonsterScript.h" #include "DamageCalc.h" #include "Player.h" #include "StatusCalc_Server.h" #include "drop.h" #include "PathFinder.h" #include "mode.h" #include "Party.h" #include "PartyManager.h" #include "GridManager.h" #include "ThemeObject.h" #include "ThemeManager.h" #include "RandomTable.h" #include "Gathering.h" #include "BaseDeathMatch.h" #include "DeathMatchObject.h" #include "PVPManager.h" extern bool InfLeftTimeSort( unsigned long arg1, unsigned long arg2 ); extern bool InfChangeMPMinSort( unsigned long arg1, unsigned long arg2 ); int DistressCompare( const void *arg1, const void *arg2 ) { PerTakeDamage* per1 = (PerTakeDamage*)arg1; PerTakeDamage* per2 = (PerTakeDamage*)arg2; // ³»¸²Â÷¼ø Á¤·Ä return per1->distressPoint > per2->distressPoint; } cMonster::cMonster( void ) : cBaseObject( eOBJECTTYPE_MONSTER ) , mPathFinder( 0 ) , mPathCount( 0 ) , mPathIndex( 0 ) , mpAction( NULL ) , mMoveStopRange( 0 ) , mGroupRegen( false ) , mMoveOverTime( 0 ) , mAttackType( eMONSTERATTACK_MAX ) , mTalkDealyEndTime( 0 ) , mTalkState( eMONSTERTALK_MAX ) , mDestroyTime( 0 ) , mFollowImportance( 0 ) , mPatternPos( 0 ) , mPatternDir( 1 ) , mPatternWait( 0 ) , mServerPosTime( 0 ) , mAutoDummy( 0 ) { mModeSkillIdx = eMONSTERATTACK_MAX; mModeInitSkillIdx = eMONSTERATTACK_MAX; mTFixedPlayerIdx = 0; mTFixedInfIdx = 0; mReservationComeback = false; mIdleEndTime = 0; mLastUsedSkillIdx = eMONSTERATTACK_MAX; mDeathMonster = false; mDMTeamType = ePVPDM_TEAMTYPE_MAX; mGroupMoveReady = 1; } cMonster::~cMonster( void ) { mpAction = NULL; } void* cMonster::operator new( size_t n ) { if( n != sizeof(cMonster) ) { assert(0); return NULL; } return OBJECTMANAGER->AllocMonster(); } void cMonster::operator delete( void* ptr, size_t n ) { /// NULL Æ÷ÀÎÅÍ °Ë»ç if( ptr == 0 ) { assert(0); return; } if( n != sizeof(cMonster) ) { assert(0); return; } OBJECTMANAGER->FreeMonster( static_cast(ptr) ); return; } bool cMonster::Init( unsigned long uniqueidx, unsigned long classIdx, unsigned long regenIdx, unsigned short mapNumber, unsigned char modeNum ) { /// ÃʱâÈ­ memset( &mStatusPlus, 0 , sizeof(mStatusPlus) ); memset( &mStatusPer, 0 , sizeof(mStatusPer) ); memset( mODDITY, 0, sizeof(mODDITY) ); mTakeDamageRoot.pool = NULL; mTakeDamageRoot.root = NULL; mIsParentLink = false; mParentMonsterIdx = 0; mNextTargetChangeTime = 0; mFollowEndMove = false; mFirstAttackCharacter = 0; mLastAttacker = 0; mFirstAttackParty = 0; mIsFirstMove = true; mCriDie = false; mOutsideDestroy = false; mSkillWaitEndTime = 0; mPathCount = 0; mPathIndex = 0; SetTarget( eOBJECTTYPE_NONE, 0 ); SetMoveStopRange( 0 ); mPlayerFollowPos = FOLLOW_POS_MAX; mpRegenMonsterInfo = NULL; mpMovePattern = NULL; ActionChange( eACT_MOVE ); mOutsideAddMonster = false; mDestroyTime = 0; mAutoDummy = 0; /// ¸ðµå mIsCombat = false; mTotalTime = 0; mModeTime = 0; mModeAgent = MONSTERSCRIPT->GetMonsterModeAgent( classIdx ); mCurrentMode = 0; mIdleEndTime = 0; mReservationComeback = false; mFixedObjectSizePer = 0; mLastUsedSkillIdx = eMONSTERATTACK_MAX; mGuardAry.Clear(); mChangeMPDamageAry.Clear(); mDeleteTypeDamagedAry.Clear(); mDeathMonster = false; mGroupMoveReady = 1; /// ClearImmune(); mSkillCoolTimeMap.Clear(); mEliteCoolTimeMap.Clear(); mGenTotemCoolTimeMap.Clear(); mGenMonCoolTimeMap.Clear(); mGenGatheringCoolTimeMap.Clear(); if( mSummonListMap.IsEmpty() == false ) { cPHashMap::cIterator b = mSummonListMap.Begin(); cPHashMap::cIterator end = mSummonListMap.End(); for( ; b!=end; b++ ) { cHashSet* pSet = (cHashSet*)(*b).mSecond; SAFE_DELETE( pSet ); } mSummonListMap.Clear(); } mSummonGatherAry.Clear(); /// ¼³Á¤°ª ¼ÂÆÃ mObject.index = uniqueidx; mSkillLastAttack = mObject; mSkillLastKind = eDAMAGE_MISS; /// ¸ó½ºÅÍ ½ºÅ©¸³Æ® sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( classIdx ); if( !pMonsterScript ) { NETWORK2->PostServerEvent("Monster::Init pMonsterScript[%d]", classIdx ); return false; } mpMonsterInfo = pMonsterScript; mMoveSpeed = (float)mpMonsterInfo->mActionWalkSpd; mHP = mpMonsterInfo->mMaxHp; mMP = mpMonsterInfo->mMaxMp; mFollowImportance = mpMonsterInfo->mImportance; SetFixedObjectSizePer( mFixedObjectSizePer ); if( mpMonsterInfo->mMonsterScale <= 0.0f ) { NETWORK2->PostServerEvent("cMonsterScript MonsterScale ERROR - %d", mpMonsterInfo->mMonsterScale ); return false; } mFixedObjectSize = mpMonsterInfo->mMonsterFixSize * mpMonsterInfo->mMonsterScale; cArray* pMonsterSkillAry = (cArray*)SKILLSCRIPT->GetMonsterBaseSkillArr( mpMonsterInfo->mMonsterClassIdx ); if( pMonsterSkillAry == NULL ) { NETWORK2->PostServerEvent("Monster::Init pMonsterSkillAry[%d]", mpMonsterInfo->mMonsterClassIdx ); return false; } sMonsterSkillScript* pMonsterSkill; for( unsigned long i = 0 ; i< pMonsterSkillAry->GetSize() ; ++i ) { pMonsterSkill = (sMonsterSkillScript*)(*pMonsterSkillAry)[i]; if( pMonsterSkill == NULL ) { NETWORK2->PostServerEvent("Monster::Init pMonsterSkill == NULL" ); continue; } mSkillCoolTimeMap.Insert( pMonsterSkill->mAttackType, 0 ); } /// ¸®Á¨ Á¤º¸ - ÀÖ´Â °æ¿ì¸¸ ¼ÂÆÃ - ¾ø´Â °æ¿ì ¼Òȯ ¸ó½ºÅÍ sRegenScript* pRegenScript = MONSTERSCRIPT->GetRegenMonsterInfo( modeNum, regenIdx ); if( pRegenScript ) { mpRegenMonsterInfo = pRegenScript; SetMapNumber( mpRegenMonsterInfo->mMapNumber ); mDestroyTime = pRegenScript->mRegenLifeTime; sRegenGroupScript* pRegenGroupScript = MONSTERSCRIPT->GetRegenGroupInfo( modeNum, pRegenScript->mGroupNumber ); if( pRegenGroupScript == NULL ) { NETWORK2->PostServerEvent("cActionRegen::Action pRegenGroupScript == NULL"); return false; } float regenX = mpRegenMonsterInfo->mRegenX; float regenY = mpRegenMonsterInfo->mRegenY; unsigned long regenRange = pRegenGroupScript->mRegenRange; /// µ¿Á·ÀÌ ÀÖ´Â ¸ó½ºÅÍ´Â ºñÁßÀ» ¹«½ÃÇÑ´Ù. if( pRegenScript->mFamilyNum != 0 ) mFollowImportance = 0; /// À̵¿ ÆÐÅÏ µ¥ÀÌÅÍ ÂüÁ¶ mPatternPos = 0; mPatternDir = 1; mpMovePattern = MONSTERSCRIPT->GetMonsterPattern( modeNum, pRegenScript->mPatternIdx ); if( mpMovePattern != NULL ) { AIMANAGER->FamilyNextPattern( mapNumber, pRegenScript->mFamilyNum, &mPatternPos, &mPatternDir ); mGroupMoveReady = 2; if( (long)mpMovePattern->mPosAry.GetSize() > mPatternPos ) { sMonsterPatternPos* pPos = (sMonsterPatternPos*)mpMovePattern->mPosAry[mPatternPos]; if( pPos != NULL ) { regenX = pPos->mPosX; regenY = pPos->mPosY; regenRange = pPos->mRange; } } } bool isRandPos = false; /// À̵¿ÁÂÇ¥°¡ ¸ø°¡´Â Áö¿ªÀÏ °æ¿ì ¹üÀ§¸¦ ÂÎÇô°¡¸é¼­ À̵¿À§Ä¡¸¦ Àâ´Â´Ù. if( regenRange > MAP_RANGE_CHECK_RING ) { for( int i = MAP_RANGE_CHECK_RING ; i > 0 ; --i ) { NiPoint2 pos; /// ÃÖ´ë ¹üÀ§¿¡¼­ 20%¾¿ ÁÙ¿©°¡¸é¼­ üũ int range = (int)(regenRange * i * ( 1.0f / MAP_RANGE_CHECK_RING )); if( range <= 0 ) continue; pos.x = regenX + ( rand() % range ) - ( rand() % range ); pos.y = regenY + ( rand() % range ) - ( rand() % range ); if( AIMANAGER->IsPossible( mMapNumber, pos.x, pos.y, mObject ) == true ) { regenX = pos.x; regenY = pos.y; isRandPos = true; break; } } } if( isRandPos == false ) { if( AIMANAGER->IsPossible( mMapNumber, mpRegenMonsterInfo->mRegenX, mpRegenMonsterInfo->mRegenY, mObject ) == false ) { return false; Verbose->WriteLog("MonsterInit PositionError[ Map:%d Group:%d X:%.0f Y:%.0f ]", mMapNumber, pRegenScript->mGroupNumber, pRegenScript->mRegenX, pRegenScript->mRegenY ); //return false; } regenX = mpRegenMonsterInfo->mRegenX; regenY = mpRegenMonsterInfo->mRegenY; } mRegenPos.x = regenX; mRegenPos.y = regenY; mObjectPos = mRegenPos; mDirection = pRegenScript->mDirection; /// ¹æÇâ°ª if( pRegenScript->mDirection >= 1000.0f ) /// 1000 Àΰæ¿ì ·£´ý ¹æÇâ°ª mDirection = S_ToRadian( ( rand() % 359 ) - 179 ); /// -179 ~ +179 »çÀÌ °ªÀ» ·£´ýÇÏ°Ô °áÁ¤ } mLastPos = mRegenPos; if( mapNumber != 0 ) SetMapNumber( mapNumber ); return true; } void cMonster::SetSummonInfo( cMonster* pParent, unsigned short mapNumber, float regenX, float regenY, unsigned long regenMin, unsigned long regenMax, unsigned long destroyTime, bool isRand, bool isAutuDummy ) { SetMapNumber( mapNumber ); mObjectPos.x = regenX; mObjectPos.y = regenY; if( isRand == true ) mObjectPos = CalcMinMaxRandPos( regenX, regenY, regenMin, regenMax ); mRegenPos.x = mObjectPos.x; mRegenPos.y = mObjectPos.y; mDirection = S_ToRadian( ( rand() % 358 ) - 179 ); /// ¹æÇâ°ª -179 ~ +179 »çÀÌ °ªÀ» ·£´ýÇÏ°Ô °áÁ¤ mOutsideAddMonster = true; mDestroyTime = destroyTime; mAutoDummy = isAutuDummy; if( mAutoDummy == 1 ) { // ¿ÀÅä ´õ¹ÌÀΰæ¿ì mHP = GetMaxHP(); } /// ±×¸®µå Ãß°¡ÇÑ´Ù. if( GRIDMANAGER->AddMonster( this ) == false ) { OBJECTMANAGER->RemoveMonster( GetObjectID() ); NETWORK2->PostServerEvent("cAIManager::BossSummonMonRegen GRIDMANAGER->AddMonster( pMonster ) == false" ); return; } SendRegen(); if( pParent != NULL ) { mIsParentLink = true; mParentMonsterIdx = pParent->GetObjectID(); mFollowImportance = 0; /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ TakeDamageRoot* pRoot = pParent->GetTakeDamageRoot(); if( pRoot != NULL ) { unsigned long randSelect = 0; if( pRoot->count != 0 ) randSelect = rand() % pRoot->count; unsigned long cnt = 0; PerTakeDamage* per = (PerTakeDamage*)pRoot->pool; while( per ) { sObject player = { eOBJECTTYPE_PLAYER, per->playerIdx }; if( cnt == randSelect ) AddTakeDamage( player, 0, 2000, eTAKEDAMAGETYPE_ADDPLAYER ); else AddTakeDamage( player, 0, 0, eTAKEDAMAGETYPE_ADDPLAYER ); per = (PerTakeDamage*)per->next; ++cnt; } } ActionChange( eACT_FOLLOW ); } } void cMonster::Release( bool parentLinkRelase ) { if( parentLinkRelase == true ) { if( mIsParentLink == true ) { cMonster* pParent = OBJECTMANAGER->GetMonster( mParentMonsterIdx ); if( pParent != NULL ) pParent->DieSummonMonster( mObject.index, mObjectPos ); pParent = OBJECTMANAGER->GetDeathMonster( mParentMonsterIdx ); if( pParent != NULL ) pParent->DieSummonMonster( mObject.index, mObjectPos ); } } SetTarget( eOBJECTTYPE_NONE, 0 ); ClearTakeDamage(); ReleaseInfluenceSet( false ); ClearImmune(); mGenTotemCoolTimeMap.Clear(); mGenMonCoolTimeMap.Clear(); mGenGatheringCoolTimeMap.Clear(); if( mSummonListMap.IsEmpty() == false ) { cPHashMap::cIterator b = mSummonListMap.Begin(); cPHashMap::cIterator end = mSummonListMap.End(); for( ; b!=end; b++ ) { cHashSet* pSet = (cHashSet*)(*b).mSecond; SAFE_DELETE( pSet ); } mSummonListMap.Clear(); } for( unsigned long i = 0 ; i < mSummonGatherAry.GetSize() ; ++i ) { cGathering* pGather = OBJECTMANAGER->GetGathering( mSummonGatherAry[i] ); if( pGather != NULL ) pGather->GatheringDie( 0 ); } mSummonGatherAry.Clear(); PerNode* node = mSummonPatternRoot.pool; while ( node != NULL ) { sSummonPatternInfo* pInfo = (sSummonPatternInfo*)node; node = node->next; SUMMONPATTERNPOOL->ReleaseSummonPattern( &mSummonPatternRoot, pInfo ); } } cBaseObject* cMonster::GetTarget( ) { /// Ÿ°Ù Á¾·ù¿¡ µû¶ó switch( mTarget.type ) { case eOBJECTTYPE_PLAYER: /// Ç÷¹ÀÌ¾î Æ÷ÀÎÅÍ ¹Ýȯ return (cBaseObject*)NearGridFindPlayer( mTarget.index, true ); case eOBJECTTYPE_MONSTER: return GRIDMANAGER->GetMonster( mTarget.index ); default: /// ¾øÀ¸¸é NULLÆ÷ÀÎÅÍ ¹Ýȯ return NULL; } } bool cMonster::SetTarget( unsigned char kind, unsigned long idx ) { if( kind == mTarget.type && idx == mTarget.index ) return true; /// ÃßÀû ÆÛÁü À§Ä¡ ÀúÀå unsigned char oldPlayerFollowPos = mPlayerFollowPos; unsigned char newPlayerFollowPos = FOLLOW_POS_MAX; bool isNewFight = false; bool isFightEnd = false; if( kind == eOBJECTTYPE_PLAYER ) { //pPlayer = NearGridFindPlayer( idx ); /// ¡Ø °´Ã¼°¡ ÀÖÁö¸¸ ±×¸®µå ¹üÀ§ ¹ÛÀ¸·Î ³ª°¬À» ¼ö ÀÖÀ¸´Ï objectmanager¿¡¼­ ã¾Æ¿Â´Ù. cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( idx ); if( pPlayer == NULL || pPlayer->GetStateDie() == true ) return false; /// »õ·Î¿î Ÿ°Ù¿¡ ¸ó½ºÅÍ ºñÁß °è»êÇØ °¡´ÉÇÏ´Ù¸é ¼³Á¤ if( pPlayer->MonsterImportancePlus( mFollowImportance ) == false ) return false; /// ±âÁ¸ Ÿ°Ù À¯Áö /// ½Å±Ô Ÿ°Ù¿¡ ¸Â´Â ÃßÀû ÆÛÁü À§Ä¡ ¼±Á¤ newPlayerFollowPos = pPlayer->SelectFollowPos( oldPlayerFollowPos ); /// ÃßÀû ½ÃÀÛ À§Ä¡, ½Ã°£ ¼³Á¤ // mFollowStartPos = mObjectPos; mFollowEndTime = NETWORK2->GetAccumTime() + mpMonsterInfo->mFollowTime; /// Ÿ°ÙÀÌ ¾ø´Ù°¡ »ý±è if( GetTarget() == NULL ) isNewFight = true; } mPlayerFollowPos = newPlayerFollowPos; if( mTarget.type == eOBJECTTYPE_PLAYER ) { /// ±âÁ¸Å¸°Ù¿¡ ¸ó½ºÅÍ ºñÁßÀ» °¨¼Ò /// ¡Ø °´Ã¼°¡ ÀÖÁö¸¸ ±×¸®µå ¹üÀ§ ¹ÛÀ¸·Î ³ª°¬À» ¼ö ÀÖÀ¸´Ï objectmanager¿¡¼­ ã¾Æ¿Â´Ù. cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( mTarget.index ); if( pPlayer != NULL && pPlayer->GetStateDie() == false ) { pPlayer->MonsterImportanceMinus( mFollowImportance ); /// ±âÁ¸ Ÿ°ÙÀÇ ÃßÀû ÆÛÁü À§Ä¡ ¹Ýȯ pPlayer->UnSelectFollowPos( oldPlayerFollowPos ); newPlayerFollowPos = FOLLOW_POS_MAX; } /// Ÿ°ÙÀÌ Àִµ¥ ÇØÁ¦ÇÔ if( kind == eOBJECTTYPE_NONE ) { mAttackType = eMONSTERATTACK_MAX; /// Á×Áö ¾ÊÀº °æ¿ì¸¸ ÃßÀû Æ÷±â ´ë»ç ó¸® if( pPlayer != NULL && pPlayer->GetStateDie() == false ) isFightEnd = true; } } /// ³»°¡ Á×´Â °æ¿ì¸¦ Á¦¿ÜÇϰí´Â ÃßÀûÀ» Æ÷±âÇÏ´Â °æ¿ì´Ù /// ¡ØÅ¸°Ù ÇØÁ¦ÇϱâÀü¿¡ ´ë»ç ¹ß¼Û if( isFightEnd == true && mHP != 0 ) SendSpeech( eMONSTERTALK_GIVEUP ); cBaseObject::SetTarget( kind, idx ); /// Ÿ°Ù ¼³Á¤ ÈÄ¿¡ ´ë»ç ¹ß¼Û if( isNewFight == true ) SendSpeech( eMONSTERTALK_FIGHT ); return true; } void cMonster::Die() { unsigned long dropPlayerIdx = GetfirstAttack(); if( NETWORK2->GetInDunMapNum() == MAP_DEATHMATCH ) { cDeathMatchObject* pDM = (cDeathMatchObject*)PVPMANAGER->GetPvPDMObject( mMapNumber ); if( pDM != NULL ) pDM->DeleteStone( mDMTeamType, mLastAttacker ); } else { if( mOutsideDestroy == false && mAutoDummy == 0 ) { unsigned long partyIdx = 0; cPlayer* player = NearGridFindPlayer( GetfirstAttack(), false ); if( player ) { partyIdx = player->GetPartyIndex(); if( partyIdx > 0 ) { /// ÆÄƼ Àüü °»½Å PARTYMAN->SendToPartyHunt( this, player, GetRaceGender() ); } else { /// ÀÚ±âÀڽŸ¸ °»½Å player->UpdateDutyHunt( GetRaceGender(), player->GetObjectID() ); } } /// µå¶ø ¼ÒÀ¯±Ç °è»ê - ¼±°ø À¯Àú°¡ ¸ó½ºÅÍHPÀÇ 20%¸¦ ±ðÀ¸¸é ¼±°øÀ¯Àú ¼ÒÀ¯ unsigned long damage = GetTakeDamage( dropPlayerIdx ); if( (float)damage < GetMaxHP() * 0.2f ) { /// ¼±°ø À¯Àú°¡ 20%¸¦ ±ðÁö¸øÇÏ¸é °¡Àå µ¥¹ÌÁö°¡ Å«À¯Àú°¡ ¼ÒÀ¯ TakeDamageRoot* pTakeDamageRoot = GetTakeDamageRoot(); if( pTakeDamageRoot != NULL ) { PerTakeDamage* per = (PerTakeDamage*)pTakeDamageRoot->pool; while( per ) { if( damage < per->takeDamage ) { damage = per->takeDamage; dropPlayerIdx = per->playerIdx; } per = (PerTakeDamage*)per->next; } } else NETWORK2->PostServerEvent("cMonster::Drop pTakeDamageMap == NULL"); } /// µå¶ø ó¸® DROP->MonsterDrop( GetObjectID(), dropPlayerIdx, partyIdx ); DROP->MonsterQuestDrop( GetObjectID(), dropPlayerIdx, partyIdx ); short type = -1; switch( GetRaceGender() ) { case 10006: type = EVENT_RESERVED_THEME_01; break; case 15006: type = EVENT_RESERVED_THEME_01; break; case 10013: type = EVENT_RESERVED_THEME_02; break; case 15013: type = EVENT_RESERVED_THEME_02; break; case 10018: type = EVENT_RESERVED_THEME_03; break; } /// Àδø ÃÖÁ¾ º¸½ºÁ×Àγ»¿ë ·Î±×¿¡±â·Ï - ¿¹¿Üó¸® if( type != -1 ) { /// Å׸¶¼­¹ö¿¡¼­ ġƮ¸ó½ºÅͰ¡ ¾Æ´Ñ Á¤»ó¸ó½ºÅÍ ÀâÀº °æ¿ì if( NETWORK2->GetServerType() == _E_ST_ID_THEME_ && IsCheatTempMonster() == false ) { cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( dropPlayerIdx ); if( pPlayer != NULL ) { if( pPlayer->GetPartyIndex() == 0 ) { NETWORK2->PostReservedEvent( type, pPlayer->GetObjectID(), pPlayer->GetConnectionIdx() ); } else { cParty* pParty = PARTYMAN->GetParty( pPlayer->GetPartyIndex() ); if( pParty != NULL ) { unsigned long* partyPlayerIdx = pParty->GetUserArr(); if( partyPlayerIdx != NULL ) { for( unsigned long j = 0 ; j < pParty->GetCount() ; ++j ) { cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( partyPlayerIdx[j] ); if ( pPlayer != NULL ) NETWORK2->PostReservedEvent( type, pPlayer->GetObjectID(), pPlayer->GetConnectionIdx() ); } } } } } } } LinkObstruction(); LinkTeleportPortal(); } } Release(); /// ¸®Á¨ ´ë±â ¸ó½ºÅÍ ¸ñ·Ï¿¡ ³ÖÀ½ const sRegenScript* pScript = GetRegenMonsterInfo(); if( pScript != NULL && IsCheatTempMonster() == false ) AIMANAGER->InsertReadyMonster( GetObjectID(), pScript->mRegenIdx, pScript->mGroupNumber ); } void cMonster::SendRegen() { if( mDMTeamType == ePVPDM_TEAMTYPE_MAX ) { /// ¸Þ¼¼Áö ¹ß¼Û MSG_MONSTER_INFO Msg; Msg.Category = NM_MONSTER; Msg.Protocol = NM_MONSTER_REGEN_SYN; Msg.mMonsterInfo.mMonsterIdx = GetObjectID(); Msg.mMonsterInfo.mMonsterClassIdx = GetRaceGender(); Msg.mMonsterInfo.mPosX = GetXPos(); Msg.mMonsterInfo.mPosY = GetYPos(); Msg.mMonsterInfo.mDirection = GetDirection(); Msg.mMonsterInfo.mHP = GetHP(); Msg.mMonsterInfo.mMaxHP = GetMaxHP(); Msg.mMonsterInfo.mMP = GetMP(); Msg.mMonsterInfo.mMaxMP = GetMaxMP(); Msg.mMonsterInfo.mScale = GetFixedObjectSizePer(); Msg.mMonsterInfo.mAutoDummy = mAutoDummy; Msg.mCount = 0; NETWORK2->QuickSend( this, (char*)&Msg, Msg.GetMsgLength() ); } else { /// ¸Þ¼¼Áö ¹ß¼Û MSG_MONSTERTEAM_INFO Msg; Msg.Category = NM_MONSTER; Msg.Protocol = NM_MONSTER_TEAMREGEN_SYN; Msg.mMonsterInfo.mMonsterIdx = GetObjectID(); Msg.mMonsterInfo.mMonsterClassIdx = GetRaceGender(); Msg.mMonsterInfo.mPosX = GetXPos(); Msg.mMonsterInfo.mPosY = GetYPos(); Msg.mMonsterInfo.mDirection = GetDirection(); Msg.mMonsterInfo.mHP = GetHP(); Msg.mMonsterInfo.mMaxHP = GetMaxHP(); Msg.mMonsterInfo.mMP = GetMP(); Msg.mMonsterInfo.mMaxMP = GetMaxMP(); Msg.mMonsterInfo.mScale = GetFixedObjectSizePer(); Msg.mMonsterInfo.mAutoDummy = mAutoDummy; Msg.mCount = 0; Msg.mTeamType = mDMTeamType; NETWORK2->QuickSend( this, (char*)&Msg, Msg.GetMsgLength() ); } } NiPoint2 cMonster::CalcMinMaxRandPos( float centerX, float centerY, unsigned long rangeMin, unsigned long rangeMax ) { NiPoint2 center; center.x = centerX; center.y = centerY; NiPoint2 dest; dest.x = centerX; dest.y = centerY; if( rangeMin >= rangeMax ) return dest; unsigned long randRange = rand() % ( rangeMax - rangeMin ); float isPositiveNumber = 1; if( rand() % 2 == 0 ) isPositiveNumber = -1; float randDir = (float)(rand() % 180); randDir = randDir * isPositiveNumber; float radian = S_ToRadian( randDir ); NiPoint2 dir = NiPoint2( -sinf(radian), -cosf(radian) ); dir.Unitize(); unsigned long divideRange = ( rangeMin + randRange ) / 10; for( unsigned long i = 0 ; i < 10 ; ++i ) { dest = center + dir * (float)( ( rangeMin + randRange ) - ( i * divideRange ) ); if( AIMANAGER->IsPossible( mMapNumber, dest.x, dest.y, mObject ) == true ) return dest; } return center; } eACTION_CHANGE cMonster::Update( unsigned long elapsedTime, unsigned long accumTime ) { /// ÀÏÁ¤½Ã°£ °ø°Ý»óÅ·Π°¡Áö ¾Ê´Â°æ¿ì Á¦°Åó¸® if( mIsParentLink == true ) { /// ºÎ¸ð°¡ ¾ø´Â°æ¿ì cMonster* pParent = OBJECTMANAGER->GetMonster( mParentMonsterIdx ); if( pParent == 0 ) { pParent = OBJECTMANAGER->GetDeathMonster( mParentMonsterIdx ); if( pParent == 0 ) { mIsParentLink = false; mParentMonsterIdx = 0; /// »èÁ¦½Ã°£ ¼³Á¤ mDestroyTime = 5000; } } else { if( pParent->GetDeathMonster() == false && ( pParent->GetStateDie() == true || pParent->IsCombat() == false ) ) { /// ºÎ¸ð¿ÍÀÇ ¿¬°áÁ¤º¸ ÃʱâÈ­ mIsParentLink = false; mParentMonsterIdx = 0; /// »èÁ¦½Ã°£ ¼³Á¤ mDestroyTime = 5000; } } } mTotalTime += elapsedTime; if( mIsCombat == false ) { if( mDestroyTime != 0 ) { if( mDestroyTime <= elapsedTime ) { mDestroyTime = 0; OutsideDestroy(); } else { mDestroyTime -= elapsedTime; } } } else { /// Mode Process if( mModeAgent != 0 && mCurrentMode != 0 ) { /// ¼Óµµ üũÈÄ - ´ÜÀ§½Ã°£´ç üũ¸¦ ³Ö¾îº¸ÀÚ!! UpdateMode( elapsedTime, accumTime ); } } /// SpeechProcess(); ProcessTakeDamage( elapsedTime, accumTime ); /// ¼Òȯ¹° ÆÐÅÏ Ã³¸® //for( unsigned long i = mSummonPatternInfoAry.GetSize() ; i > 0 ; --i ) //{ // sSummonPatternInfo* pInfo = (sSummonPatternInfo*)mSummonPatternInfoAry[i-1]; // if( pInfo == NULL ) // { // delete( pInfo ); // mSummonPatternInfoAry.PopAt( i-1 ); // continue; // } // if( pInfo->mNextPatternTime > accumTime ) // continue; // cArray* pPatterAry = MONSTERSCRIPT->GetSummonPattern( pInfo->mSummonPatternIdx ); // if( pPatterAry == NULL ) // { // delete( pInfo ); // mSummonPatternInfoAry.PopAt( i-1 ); // continue; // } // sSummonPatternScript* pScript = (sSummonPatternScript*)(*pPatterAry)[pInfo->mNowPatternPos]; // if( pScript == NULL ) // { // delete( pInfo ); // mSummonPatternInfoAry.PopAt( i-1 ); // continue; // } // // for( unsigned long j = 0 ; j < pInfo->mCount ; ++j ) // { // NiPoint2 centerPos; // centerPos.x = pInfo->mCenterPos.x; // centerPos.y = pInfo->mCenterPos.y; // unsigned long genRangeMin = pInfo->mRangeMin; // unsigned long genRangeMax = pInfo->mRangeMax; // float radian = pInfo->mCenterDir; // NiPoint2 dir = NiPoint2( -sinf(radian), -cosf(radian) ); // dir.Unitize(); // float randRange = (float)( genRangeMax - genRangeMin ); // if( randRange > 0 ) // randRange = (float)( ( rand() % (unsigned long)randRange ) + genRangeMin ); // NiPoint2 pos = centerPos + dir * randRange; // /// ½ºÅ©¸³Æ® ¹æÇâÀ¸·Î ȸÀü // float direction = pScript->mDir; // float cos = cosf( direction ); // float sin = sinf( direction ); // NiPoint2 changePos; // changePos.x = ( ( pos.x - centerPos.x ) * cos + ( pos.y - centerPos.y ) * sin ); // changePos.y = ( ( pos.y - centerPos.y ) * cos - ( pos.x - centerPos.x ) * sin ); // changePos = changePos + centerPos; // switch( pInfo->mObject.type ) // { // case eOBJECTTYPE_MONSTER: // { // /// ¸ó½ºÅÍ ¼Òȯ & ´ÙÀ½ ¸®Á¨½Ã°£ ±â·Ï // AIMANAGER->BossSummonMonRegen( this, mMapNumber, changePos.x, changePos.y, genRangeMin, genRangeMax, // 1, pInfo->mObject.index, false ); // } // break; // case eOBJECTTYPE_TOTEM: // { // cTotem* pTotem = OBJECTMANAGER->AddTotem( pInfo->mObject.index, 0, 0, changePos, mObject, eAPPLYTYPE_ENEMY, eATTRIBUTETYPE_PHYSICAL, 0, mDirection ); // if( pTotem != NULL ) // GRIDMANAGER->AddTotem( pTotem ); // } // break; // case eOBJECTTYPE_GATHERING: // { // cGathering* pGathering = OBJECTMANAGER->AddGathering( 0, pInfo->mObject.index, mMapNumber, changePos.x, changePos.y, mDirection, 0 ); // if( pGathering != NULL ) // { // GRIDMANAGER->AddGathering( pGathering ); // pGathering->SendRegenSync(); // break; // } // } // break; // } // } // pInfo->mNowPatternPos = pInfo->mNowPatternPos + 1; // if( pPatterAry->GetSize() <= pInfo->mNowPatternPos ) // { // delete( pInfo ); // mSummonPatternInfoAry.PopAt( i-1 ); // } // else // { // sSummonPatternScript* pNextScript = (sSummonPatternScript*)(*pPatterAry)[pInfo->mNowPatternPos]; // if( pNextScript != NULL ) // pInfo->mNextPatternTime = accumTime + pNextScript->mDelayTime; // else // { // delete( pInfo ); // mSummonPatternInfoAry.PopAt( i-1 ); // } // } //} PerNode* node = mSummonPatternRoot.pool; while ( node != NULL ) { sSummonPatternInfo* pInfo = (sSummonPatternInfo*)node; if( pInfo == NULL ) { node = node->next; SUMMONPATTERNPOOL->ReleaseSummonPattern( &mSummonPatternRoot, pInfo ); continue; } if( pInfo->mNextPatternTime > accumTime ) { node = node->next; continue; } cArray* pPatterAry = MONSTERSCRIPT->GetSummonPattern( pInfo->mSummonPatternIdx ); if( pPatterAry == NULL ) { node = node->next; SUMMONPATTERNPOOL->ReleaseSummonPattern( &mSummonPatternRoot, pInfo ); continue; } sSummonPatternScript* pScript = (sSummonPatternScript*)(*pPatterAry)[pInfo->mNowPatternPos]; if( pScript == NULL ) { node = node->next; SUMMONPATTERNPOOL->ReleaseSummonPattern( &mSummonPatternRoot, pInfo ); continue; } for( unsigned long j = 0 ; j < pInfo->mCount ; ++j ) { NiPoint2 centerPos; centerPos.x = pInfo->mCenterPos.x; centerPos.y = pInfo->mCenterPos.y; unsigned long genRangeMin = pInfo->mRangeMin; unsigned long genRangeMax = pInfo->mRangeMax; float radian = pInfo->mCenterDir; NiPoint2 dir = NiPoint2( -sinf(radian), -cosf(radian) ); dir.Unitize(); float randRange = (float)( genRangeMax - genRangeMin ); if( randRange > 0 ) randRange = (float)( ( rand() % (unsigned long)randRange ) + genRangeMin ); NiPoint2 pos = centerPos + dir * randRange; /// ½ºÅ©¸³Æ® ¹æÇâÀ¸·Î ȸÀü float direction = pScript->mDir; float cos = cosf( direction ); float sin = sinf( direction ); NiPoint2 changePos; changePos.x = ( ( pos.x - centerPos.x ) * cos + ( pos.y - centerPos.y ) * sin ); changePos.y = ( ( pos.y - centerPos.y ) * cos - ( pos.x - centerPos.x ) * sin ); changePos = changePos + centerPos; switch( pInfo->mObject.type ) { case eOBJECTTYPE_MONSTER: { /// ¸ó½ºÅÍ ¼Òȯ & ´ÙÀ½ ¸®Á¨½Ã°£ ±â·Ï AIMANAGER->BossSummonMonRegen( this, mMapNumber, changePos.x, changePos.y, genRangeMin, genRangeMax, 1, pInfo->mObject.index, false ); } break; case eOBJECTTYPE_TOTEM: { cTotem* pTotem = OBJECTMANAGER->AddTotem( pInfo->mObject.index, 0, 0, changePos, mObject, (eAPPLYTYPE)pInfo->mApplyType, eATTRIBUTETYPE_PHYSICAL, 0, mDirection, 0 ); if( pTotem != NULL ) { GRIDMANAGER->AddTotem( pTotem ); } } break; case eOBJECTTYPE_GATHERING: { cGathering* pGathering = OBJECTMANAGER->AddGathering( 0, pInfo->mObject.index, mMapNumber, changePos.x, changePos.y, mDirection, 0 ); if( pGathering != NULL ) { GRIDMANAGER->AddGathering( pGathering ); pGathering->SendRegenSync(); mSummonGatherAry.PushBack( pGathering->GetObjectID() ); } } break; } } pInfo->mNowPatternPos = pInfo->mNowPatternPos + 1; if( pPatterAry->GetSize() <= pInfo->mNowPatternPos ) { node = node->next; SUMMONPATTERNPOOL->ReleaseSummonPattern( &mSummonPatternRoot, pInfo ); continue; } else { sSummonPatternScript* pNextScript = (sSummonPatternScript*)(*pPatterAry)[pInfo->mNowPatternPos]; if( pNextScript != NULL ) pInfo->mNextPatternTime = accumTime + pNextScript->mDelayTime; else { node = node->next; SUMMONPATTERNPOOL->ReleaseSummonPattern( &mSummonPatternRoot, pInfo ); continue; } } node = node->next; } return mpAction->Action( this, elapsedTime, accumTime ); } void cMonster::UpdateMode( unsigned long elapsedTime, unsigned long /*accumTime*/ ) { /// ¸ðµå ½Ã°£ Áõ°¡ mModeTime += elapsedTime; if( GetStateDie() == true ) return; if( IsSkillWaitEnd() == false ) return; if( mCurrentMode == NULL ) return; /// ¸ðµå Àüȯ ½ÃÁ¡ üũ cModeInfoArr* conArr = mCurrentMode->GetConditionModeInfoArr(); if( conArr != NULL ) { for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*conArr)[i]); if( p == NULL ) continue; if( p->type != eMODEINFO_MODECHANGE ) { /// error assert(0); continue; } sModeChange* pInfo = (sModeChange*)p; bool modeChange = true; for( unsigned int i=0; i<2; i++ ) { if( ConditionValueCheck( pInfo->mCondition[i].conType, pInfo->mCondition[i].conValue ) == false ) { modeChange = false; break; } } if( modeChange == true ) { ChangeCurrentMode( pInfo->mModeIdx ); return; } } } /// ¸ðµå Áö¼Óó¸® üũ cModeInfoArr* processArr = mCurrentMode->GetProcessModeInfoArr(); if( processArr != NULL ) { for( unsigned int i=0; iGetSize(); i++ ) { /// º¸À¯ ¼Òȯ¹°¿¡ ´ëÇÑ ½Ã°£ ó¸® ¹®Á¦ üũ sModeInfoBase* p = (sModeInfoBase*)((*processArr)[i]); if( p == NULL ) continue; switch( p->type ) { case eMODEINFO_GENMONSTER: { sModeGenMonster* pMonMode = (sModeGenMonster*)p; if( pMonMode == NULL ) return; /// ¹Ýº¹ ¿©ºÎ üũ - ¹Ýº¹ ÇÏ´Â °Í¸¸ ÄðŸÀÓÀÌ µé¾î ÀÖÀ½ cHashMap::cIterator find = mGenMonCoolTimeMap.Find( pMonMode->mOrderNum ); if( find != mGenMonCoolTimeMap.End() ) { unsigned long cooltime = (*find).mSecond; if( cooltime < NETWORK2->GetAccumTime() ) { (*find).mSecond = NETWORK2->GetAccumTime() + pMonMode->mDelayTime; /// ¼Òȯ ÆÐÅÏÀÌ Àִ°æ¿ì ÆÐÅÏ´ë·Î »ý¼º ½ÃÄÑ ÁØ´Ù. bool pattern = false; if( pMonMode->mGenPatternIdx != 0 ) { cArray* pAryScript = MONSTERSCRIPT->GetSummonPattern( pMonMode->mGenPatternIdx ); if( pAryScript != NULL && pAryScript->GetSize() > 0 ) { sSummonPatternScript* pScript = (sSummonPatternScript*)(*pAryScript)[0]; if( pScript != NULL ) { pattern = true; //sSummonPatternInfo* pPattern = new sSummonPatternInfo; //pPattern->mObject.index = pMonMode->mGenMonsterIdx; //pPattern->mObject.type = eOBJECTTYPE_MONSTER; //pPattern->mCount = pMonMode->mCount; //pPattern->mSummonPatternIdx = pMonMode->mGenPatternIdx; //pPattern->mCenterPos = mObjectPos; //pPattern->mCenterDir = mDirection; //pPattern->mRangeMin = pMonMode->mGenRangeMin; //pPattern->mRangeMax = pMonMode->mGenRangeMax; //pPattern->mNowPatternPos = 0; //pPattern->mNextPatternTime = pScript->mDelayTime + NETWORK2->GetAccumTime(); //mSummonPatternInfoAry.PushBack( pPattern ); sObject object = { eOBJECTTYPE_MONSTER, pMonMode->mGenMonsterIdx }; SUMMONPATTERNPOOL->AddSummonPattern( &mSummonPatternRoot, object, pMonMode->mGenPatternIdx, pMonMode->mCount, mObjectPos, mDirection, pMonMode->mGenRangeMin, pMonMode->mGenRangeMax, 0, 0, pScript->mDelayTime + NETWORK2->GetAccumTime() ); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pScript != NULL"); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pAryScript != NULL && pAryScript->GetSize > 0"); } /// ÆÐÅÏÀÌ ¾ø´Â°æ¿ì ·£´ýÀ§Ä¡·Î ¼Òȯ if( pattern == false ) { /// ¸ó½ºÅÍ ¼Òȯ & ´ÙÀ½ ¸®Á¨½Ã°£ ±â·Ï AIMANAGER->BossSummonMonRegen( this, mMapNumber, mObjectPos.x, mObjectPos.y, pMonMode->mGenRangeMin, pMonMode->mGenRangeMax, pMonMode->mCount, pMonMode->mGenMonsterIdx ); } } } } break; case eMODEINFO_GENTOTEM: { sModeGenTotem* pTotemMode = (sModeGenTotem*)p; if( pTotemMode == NULL ) return; cHashMap::cIterator find = mGenTotemCoolTimeMap.Find( pTotemMode->mOrderNum ); if( find != mGenTotemCoolTimeMap.End() ) { unsigned long coolTime = (*find).mSecond; if( coolTime < NETWORK2->GetAccumTime() ) { (*find).mSecond = NETWORK2->GetAccumTime() + pTotemMode->mDelayTime; /// ¼Òȯ ÆÐÅÏÀÌ Àִ°æ¿ì ÆÐÅÏ´ë·Î »ý¼º ½ÃÄÑ ÁØ´Ù. bool pattern = false; if( pTotemMode->mGenPatternIdx != 0 ) { cArray* pAryScript = MONSTERSCRIPT->GetSummonPattern( pTotemMode->mGenPatternIdx ); if( pAryScript != NULL && pAryScript->GetSize() > 0 ) { sSummonPatternScript* pScript = (sSummonPatternScript*)(*pAryScript)[0]; if( pScript != NULL ) { pattern = true; //sSummonPatternInfo* pPattern = new sSummonPatternInfo; //pPattern->mObject.index = pTotemMode->mGenTotemIdx; //pPattern->mObject.type = eOBJECTTYPE_TOTEM; //pPattern->mCount = pTotemMode->mCount; //pPattern->mSummonPatternIdx = pTotemMode->mGenPatternIdx; //pPattern->mCenterPos = mObjectPos; //pPattern->mCenterDir = mDirection; //pPattern->mRangeMin = pTotemMode->mGenRangeMin; //pPattern->mRangeMax = pTotemMode->mGenRangeMax; //pPattern->mNowPatternPos = 0; //pPattern->mNextPatternTime = pScript->mDelayTime + NETWORK2->GetAccumTime(); //mSummonPatternInfoAry.PushBack( pPattern ); sObject object = { eOBJECTTYPE_TOTEM, pTotemMode->mGenTotemIdx }; SUMMONPATTERNPOOL->AddSummonPattern( &mSummonPatternRoot, object, pTotemMode->mGenPatternIdx, pTotemMode->mCount, mObjectPos, mDirection, pTotemMode->mGenRangeMin, pTotemMode->mGenRangeMax, pTotemMode->mApplyType, 0, pScript->mDelayTime + NETWORK2->GetAccumTime() ); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pScript != NULL"); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pAryScript != NULL && pAryScript->GetSize > 0"); } /// ÆÐÅÏÀÌ ¾ø´Â°æ¿ì ·£´ýÀ§Ä¡·Î ¼Òȯ if( pattern == false ) { unsigned long genRangeMin = pTotemMode->mGenRangeMin; unsigned long genRangeMax = pTotemMode->mGenRangeMax; for( unsigned char i = 0 ; i < pTotemMode->mCount ; ++i ) { NiPoint2 pos = CalcMinMaxRandPos( mObjectPos.x, mObjectPos.y, genRangeMin, genRangeMax ); cTotem* pTotem = OBJECTMANAGER->AddTotem( pTotemMode->mGenTotemIdx, 0, 0, pos, mObject, (eAPPLYTYPE)pTotemMode->mApplyType, eATTRIBUTETYPE_PHYSICAL, 0, mDirection, 0 ); if( pTotem != NULL ) GRIDMANAGER->AddTotem( pTotem ); } } } } } break; case eMODEINFO_GENGATHERING: { sModeGenGathering* pGatheringMode = (sModeGenGathering*)p; if( pGatheringMode == NULL ) return; cHashMap::cIterator find = mGenGatheringCoolTimeMap.Find( pGatheringMode->mOrderNum ); if( find != mGenGatheringCoolTimeMap.End() ) { unsigned long coolTime = (*find).mSecond; if( coolTime < NETWORK2->GetAccumTime() ) { (*find).mSecond = NETWORK2->GetAccumTime() + pGatheringMode->mDelayTime; /// ¼Òȯ ÆÐÅÏÀÌ Àִ°æ¿ì ÆÐÅÏ´ë·Î »ý¼º ½ÃÄÑ ÁØ´Ù. bool pattern = false; if( pGatheringMode->mGenPatternIdx != 0 ) { cArray* pAryScript = MONSTERSCRIPT->GetSummonPattern( pGatheringMode->mGenPatternIdx ); if( pAryScript != NULL && pAryScript->GetSize() > 0 ) { sSummonPatternScript* pScript = (sSummonPatternScript*)(*pAryScript)[0]; if( pScript != NULL ) { pattern = true; //sSummonPatternInfo* pPattern = new sSummonPatternInfo; //pPattern->mObject.index = pGatheringMode->mGenGatheringIdx; //pPattern->mObject.type = eOBJECTTYPE_GATHERING; //pPattern->mCount = pGatheringMode->mCount; //pPattern->mSummonPatternIdx = pGatheringMode->mGenPatternIdx; //pPattern->mCenterPos = mObjectPos; //pPattern->mCenterDir = mDirection; //pPattern->mRangeMin = pGatheringMode->mGenRangeMin; //pPattern->mRangeMax = pGatheringMode->mGenRangeMax; //pPattern->mNowPatternPos = 0; //pPattern->mNextPatternTime = pScript->mDelayTime + NETWORK2->GetAccumTime(); //mSummonPatternInfoAry.PushBack( pPattern ); sObject object = { eOBJECTTYPE_GATHERING, pGatheringMode->mGenGatheringIdx }; SUMMONPATTERNPOOL->AddSummonPattern( &mSummonPatternRoot, object, pGatheringMode->mGenPatternIdx, pGatheringMode->mCount, mObjectPos, mDirection, pGatheringMode->mGenRangeMin, pGatheringMode->mGenRangeMax, 0, 0, pScript->mDelayTime + NETWORK2->GetAccumTime() ); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pScript != NULL"); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pAryScript != NULL && pAryScript->GetSize > 0"); } /// ÆÐÅÏÀÌ ¾ø´Â°æ¿ì ·£´ýÀ§Ä¡·Î ¼Òȯ if( pattern == false ) { unsigned long genRangeMin = pGatheringMode->mGenRangeMin; unsigned long genRangeMax = pGatheringMode->mGenRangeMax; for( unsigned char i = 0 ; i < pGatheringMode->mCount ; ++i ) { NiPoint2 pos = CalcMinMaxRandPos( mObjectPos.x, mObjectPos.y, genRangeMin, genRangeMax ); cGathering* pGathering = OBJECTMANAGER->AddGathering( 0, pGatheringMode->mGenGatheringIdx, mMapNumber, pos.x, pos.y, mDirection, 0 ); if( pGathering != NULL ) { GRIDMANAGER->AddGathering( pGathering ); pGathering->SendRegenSync(); mSummonGatherAry.PushBack( pGathering->GetObjectID() ); } } } } } } break; } } } /// ¸ðµå »ç¿ë½ºÅ³ üũ if( GetActionID() == eACT_FOLLOW || GetActionID() == eACT_ATTACK ) { if( mModeInitSkillIdx == eMONSTERATTACK_MAX && mModeSkillIdx == eMONSTERATTACK_MAX ) { mTempSelectSkill.Clear(); unsigned long totalRate = 0; cModeInfoArr* skillArr = mCurrentMode->GetCheckSkillModeInfoArr(); for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*skillArr)[i]); if( p == NULL ) continue; if( p->type != eMODEINFO_USESKILL ) { /// error assert(0); continue; } sModeSkill* pInfo = (sModeSkill*)p; //if( pInfo->mModeDelayTime < mModeTime ) // continue; bool useSkill = true; for( unsigned int i=0; i<2; i++ ) { if( ConditionValueCheck( pInfo->mCondition[i].conType, pInfo->mCondition[i].conValue ) == false ) { useSkill = false; break; } } if( useSkill == false ) continue; sMonsterSkillScript* pScript = SKILLSCRIPT->GetMonsterSkillInfo( mpMonsterInfo->mMonsterClassIdx, (eMONSTERATTACK_TYPE)pInfo->mSkillIdx ); if( pScript == NULL ) continue; if( mMP < pScript->mUseMP ) continue; if( IsCantSkill( pScript->mAttributeType ) == true ) continue; cCoolTime::cIterator begin = mEliteCoolTimeMap.Find( pInfo->mSkillIdx ); cCoolTime::cIterator end = mEliteCoolTimeMap.End(); if( begin != end ) { if( (*begin).mSecond > NETWORK2->GetAccumTime() ) continue; } cBaseObject* pTarget = GetTarget(); if( pTarget == NULL ) continue; long useRate = CalcSkillRate( pTarget, (eMONSTERATTACK_TYPE)pInfo->mSkillIdx, (long)pInfo->mActionPer ); totalRate += useRate; /// Á¶°Ç¿¡ ¸¸Á·ÇÏ´Â °ø°ÝŸÀÔÀ» ´ã´Â´Ù. mTempSelectSkill.Insert( (eMONSTERATTACK_TYPE)pInfo->mSkillIdx, useRate ); } if( totalRate != 0 ) { /// ¼±ÅÃµÈ °ø°ÝŸÀÔÀÇ ºñÀ² Àüü ÇÕ°èÁß ÇÑÁöÁ¡À» Á¤ÇÑ´Ù. unsigned long randSelect = rand() % totalRate + 1; /// ¼±ÅÃµÈ ÇÑÁöÁ¡ÀÇ °ø°ÝŸÀÔ°ªÀ» ã¾Æ ¸®ÅÏÇÑ´Ù. cHashMap::cIterator sI = mTempSelectSkill.Begin(); cHashMap::cIterator sE = mTempSelectSkill.End(); for( ; sI != sE ; ++sI ) { unsigned long attackType = (*sI).mFirst; unsigned long rate = (*sI).mSecond; if( rate >= randSelect ) { mModeSkillIdx = (eMONSTERATTACK_TYPE)attackType; break; } randSelect = randSelect - rate; } } } } } bool cMonster::DeathUpdate() { bool end = true; if( mSummonListMap.GetSize() != 0 ) { cPHashMap::cIterator b = mSummonListMap.Find( 0 ); cPHashMap::cIterator e = mSummonListMap.End(); if( b != e ) { cHashSet* pIdxSet = (cHashSet*)(*b).mSecond; if( pIdxSet != NULL && pIdxSet->GetSize() != 0 ) end = false; } } if( end == true ) { OBJECTMANAGER->RecoverDeathMonster( this ); Die(); /// ±×¸®µå/¿ÀºêÁ§Æ® ¸Þ´ÏÀú¿¡¼­ Á¦°Å GRIDMANAGER->RemoveMonster( this ); OBJECTMANAGER->InsertDeleteMonster( mObject.index ); } return end; } unsigned long cMonster::DamageCalc( sObject target, unsigned long skillIdx, unsigned long attributeType, unsigned long rangeType, unsigned long skillDamage, unsigned long skillDamagePer,bool isIgnoreDefence, float addTotalDamage, float addPerTotalDamage ) { //return DAMAGECALC->MonsterDamageCalc( mObject.index, target, (eMONSTERATTACK_TYPE)skillIdx, (eATTRIBUTETYPE)attributeType, (eRANGETYPE)rangeType ); unsigned long damage = 0; sMonsterSkillScript* pMonsterSkill = SKILLSCRIPT->GetMonsterSkillInfo( GetRaceGender(), (eMONSTERATTACK_TYPE)skillIdx ); if( pMonsterSkill == NULL ) { NETWORK2->PostServerEvent("cMonster::DamageCalc pMonsterSkill[%d,%d,%d,%d,%d] == NULL", GetRaceGender(), mObject.index, skillIdx, attributeType, rangeType ); return 0; } //// ¿ÀÅä´õ¹Ì °ø°Ý·Â //if( IsAutoDummy() == true ) // return 1; /// ±âº»Á¤º¸ unsigned char attackerLv = GetLevel(); unsigned char targetLv = 0; /// ¹°¸® ½ºÅ³ ¼º°øÈ®·ü °è»ê ó¸® if( attributeType == eATTRIBUTETYPE_PHYSICAL ) { unsigned long minAttack = 0; unsigned long maxAttack = 0; if( rangeType == eRANGETYPE_CLOSE ) { minAttack = CalcPhysicAttack( pMonsterSkill->mMinAttackValue ); maxAttack = CalcPhysicAttack( pMonsterSkill->mMaxAttackValue ); } else if( rangeType == eRANGETYPE_LONG ) { minAttack = CalcPhysicRangeAttack( pMonsterSkill->mMinAttackValue ); maxAttack = CalcPhysicRangeAttack( pMonsterSkill->mMaxAttackValue ); } else { NETWORK2->PostServerEvent("cMonster::DamageCalc rangeType[%d,%d,%d,%d,%d] ERROR", GetRaceGender(), mObject.index, skillIdx, attributeType, rangeType ); } /// ·£´ý °ø°Ý·Â °áÁ¤ unsigned long attackerStatusAttack = minAttack; if( minAttack < maxAttack ) { attackerStatusAttack = maxAttack - minAttack; if( attackerStatusAttack > 0 ) attackerStatusAttack = rand() % ( attackerStatusAttack + 1 ); attackerStatusAttack = minAttack + attackerStatusAttack; } unsigned long targetStatusDef = 0; if( target.type == eOBJECTTYPE_PLAYER ) { cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( target.index ); if( pPlayer == NULL ) { NETWORK2->PostServerEvent("cMonster::DamageCalc eATTRIBUTETYPE_PHYSICAL pPlayer == NULL" ); return 0; } targetStatusDef = FloatToInt( pPlayer->GetStatus2()->mPhysicDefense ); targetLv = pPlayer->GetLevel(); } else { NETWORK2->PostServerEvent("cMonster::DamageCalc eATTRIBUTETYPE_PHYSICAL target.type[%d,%d,%d,%d,%d] ERROR", GetRaceGender(), mObject.index, skillIdx, attributeType, rangeType ); return 0; } /// ¹æ¾î·Â DEFENSE_RANDOM_PER °ª¸¸Å­ ·£´ý ¼±Åà unsigned long randTargetDef = 0; if( isIgnoreDefence == false ) randTargetDef = targetStatusDef * ( DEFENSE_RANDOM_PER + ( rand() % ( 100 - DEFENSE_RANDOM_PER + 1 ) ) ) / 100; ///// ·£´ý ¹üÀ§ Á¦°Å - Å×½ºÆ®¿ë //attackerStatusAttack = ( maxAttack + minAttack ) / 2; //randTargetDef = targetStatusDef; damage = DAMAGECALC->PhyDamage500( eOBJECTTYPE_MONSTER, attackerLv, target.type, targetLv, attackerStatusAttack, skillDamage, skillDamagePer, randTargetDef, addTotalDamage, addPerTotalDamage ); } /// ¸¶¹ý ½ºÅ³ ¼º°øÈ®·ü °è»ê ó¸® else if( attributeType == eATTRIBUTETYPE_MAGIC ) { unsigned long minAttack = CalcMagicAttack( pMonsterSkill->mMinAttackValue ); unsigned long maxAttack = CalcMagicAttack( pMonsterSkill->mMaxAttackValue ); /// ·£´ý °ø°Ý·Â °áÁ¤ unsigned long attackerStatusAttack = minAttack; if( minAttack < maxAttack ) { attackerStatusAttack = maxAttack - minAttack; if( attackerStatusAttack > 0 ) attackerStatusAttack = rand() % ( attackerStatusAttack + 1 ); attackerStatusAttack = minAttack + attackerStatusAttack; } unsigned long targetStatusDef = 0; if( target.type == eOBJECTTYPE_PLAYER ) { cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( target.index ); if( pPlayer == NULL ) { NETWORK2->PostServerEvent("cMonster::DamageCalc eATTRIBUTETYPE_MAGIC pPlayer == NULL" ); return 0; } targetStatusDef = FloatToInt( pPlayer->GetStatus2()->mMagicDefense ); targetLv = pPlayer->GetLevel(); } else { NETWORK2->PostServerEvent("cMonster::DamageCalc eATTRIBUTETYPE_MAGIC target.type[%d,%d,%d,%d,%d] ERROR", GetRaceGender(), mObject.index, skillIdx, attributeType, rangeType ); return 0; } /// ¹æ¾î·Â DEFENSE_RANDOM_PER °ª¸¸Å­ ·£´ý ¼±Åà unsigned long randTargetDef = 0; if( isIgnoreDefence == false ) randTargetDef = targetStatusDef * ( DEFENSE_RANDOM_PER + ( rand() % ( 100 - DEFENSE_RANDOM_PER + 1 ) ) ) / 100; ///// ·£´ý ¹üÀ§ Á¦°Å - Å×½ºÆ®¿ë //attackerStatusAttack = ( maxAttack + minAttack ) / 2; //randTargetDef = targetStatusDef; damage = DAMAGECALC->MagDamage530( eOBJECTTYPE_MONSTER, attackerLv, target.type, targetLv, attackerStatusAttack, skillDamage, skillDamagePer, randTargetDef, addTotalDamage, addPerTotalDamage ); } else { NETWORK2->PostServerEvent("cDamageCalc::PlayerDamageCalc attributeType[%d,%d,%d,%d,%d,%d] ERROR", attributeType, GetRaceGender(), mObject.index, skillIdx, attributeType, rangeType ); return 0; } return damage; } unsigned long cMonster::DotDamageCalc( unsigned char attackerType, unsigned char attackerLv, unsigned long attackMin, unsigned long attackMax, unsigned char dotType, unsigned long skillDamage, unsigned long skillDamagePer, unsigned long totalTime, unsigned long dotTime ) { /// ±âº»Á¤º¸ unsigned long damage = 0; unsigned char targetLv = GetLevel(); switch( dotType ) { case eDOTTYPE_PHYSICALCLOSE: case eDOTTYPE_PHYSICALRANGE: { /// °ø°Ý·Â ¹üÀ§¾È¿¡¼­ ¼±Á¤ unsigned long attackerStatusAttack = attackMin; if( attackMin < attackMax ) { attackerStatusAttack = attackMax - attackMin; if( attackerStatusAttack > 0 ) attackerStatusAttack = rand() % ( attackerStatusAttack + 1 ); attackerStatusAttack = attackMin + attackerStatusAttack; } /// ¹æ¾î·Â »êÃâ unsigned long targetStatusDef = GetPhysicDefense(); /// ¹æ¾î·Â DEFENSE_RANDOM_PER °ª¸¸Å­ ·£´ý ¼±Åà targetStatusDef = targetStatusDef * ( DEFENSE_RANDOM_PER + ( rand() % ( 100 - DEFENSE_RANDOM_PER + 1 ) ) ) / 100; damage = DAMAGECALC->PhyDotDamage600( attackerType, attackerLv, mObject.type, targetLv, attackerStatusAttack, skillDamage, skillDamagePer, targetStatusDef, totalTime, dotTime ); } break; case eDOTTYPE_MAGIC: { /// °ø°Ý·Â ¹üÀ§¾È¿¡¼­ ¼±Á¤ unsigned long attackerStatusAttack = attackMin; if( attackMin < attackMax ) { /// ¸¶¹ý °ø°Ý·ÂÀ» ÃÖ´ë°ª¿¡¼­ ÃÖ¼Ò°ª »çÀÌ¿¡ ·£´ý °ªÀ¸·Î ¼³Á¤ attackerStatusAttack = attackMax - attackMin; if( attackerStatusAttack > 0 ) attackerStatusAttack = rand() % ( attackerStatusAttack + 1 ); attackerStatusAttack = attackMin + attackerStatusAttack; } /// Ÿ°ÙÀÇ ¹æ¾î·Â »êÃâ targetLv = GetLevel(); unsigned long targetStatusDef = GetMagicDefense(); /// ¹æ¾î·Â DEFENSE_RANDOM_PER °ª¸¸Å­ ·£´ý ¼±Åà targetStatusDef = targetStatusDef * ( DEFENSE_RANDOM_PER + ( rand() % ( 100 - DEFENSE_RANDOM_PER + 1 ) ) ) / 100; damage = DAMAGECALC->MagDotDamage630( attackerType, attackerLv, mObject.type, targetLv, attackerStatusAttack, skillDamage, skillDamagePer, targetStatusDef, totalTime, dotTime ); } break; default: NETWORK2->PostServerEvent("cDamageCalc::DotDamageCalc dotType[%d,%d,%d] ERROR", dotType, mObject.index, GetRaceGender() ); return 0; } return damage; } unsigned long cMonster::ConditionOdd( sObject target, long influenceRate, unsigned long skillClassIdx ) { cBaseObject* pTarget = OBJECTMANAGER->GetObject( target.type, target.index ); if( pTarget == NULL ) { NETWORK2->PostServerEvent( "cMonster::ConditionOdd pTarget == NULL[%d,%d,%d,%d]", target.type, target.index, influenceRate, skillClassIdx ); return 0; } /// ¸ó½ºÅÍÀÎ °æ¿ì ¸ó½ºÅÍ ½ºÅ©¸³Æ® ·Îµå sMonsterSkillScript* pMonsterSkill = (sMonsterSkillScript*)SKILLSCRIPT->GetMonsterSkillInfo( GetRaceGender(), (eMONSTERATTACK_TYPE)skillClassIdx ); if( pMonsterSkill == NULL ) { NETWORK2->PostServerEvent( "cMonster::ConditionOdd pMonsterSkill == NULL[%d,%d,%d,%d]", target.type, target.index, influenceRate, skillClassIdx ); return 0; } /// °ø°ÝÀÚ ·¹º§, Ÿ°Ù ·¹º§ unsigned char attackerLv = GetLevel(); unsigned char targetLv = pTarget->GetLevel(); unsigned long checkPer = 0; if( pMonsterSkill->mAttributeType == eATTRIBUTETYPE_PHYSICAL ) checkPer = DAMAGECALC->PhyConditionOdd900( influenceRate, attackerLv, targetLv ); else if( pMonsterSkill->mAttributeType == eATTRIBUTETYPE_MAGIC ) checkPer = DAMAGECALC->MagConditionOdd930( influenceRate, attackerLv, targetLv ); else { NETWORK2->PostServerEvent("cMonster::ConditionOdd pPlayerSkill->mAttributeType[%d][%d,%d,%d,%d] ERROR", pMonsterSkill->mAttributeType, target.type, target.index, influenceRate, skillClassIdx ); } return checkPer; } bool cMonster::AttackSuccess( sObject target, unsigned long attributeType, short accuracyValue, unsigned long instantSuccess, unsigned long instantSuccessPer ) { // return DAMAGECALC->MonsterAttackSuccess( mObject.index, target, (eMONSTERATTACK_TYPE)skillIdx, (eATTRIBUTETYPE)attributeType); /// ±âº»Á¤º¸ unsigned char attackerLv = GetLevel(); unsigned char targetLv = 0; /// ¹°¸® ½ºÅ³ ¼º°øÈ®·ü °è»ê ó¸® if( attributeType == eATTRIBUTETYPE_PHYSICAL ) { /// °ø°ÝÀÚ ½ºÅݼº°ø¼öÄ¡ unsigned long attackerStatusRate = GetPhysicAttackRate(); /// Ÿ°Ù ȸÇÇ ¼öÄ¡ unsigned long targetStatusAvoid = 0; /// Ÿ°Ù(Ç÷¹À̾î) if( target.type == eOBJECTTYPE_PLAYER ) { cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index ); if( pTargetPlayer == NULL ) { NETWORK2->PostServerEvent("cMonster::AttackSuccess pTargetPlayer[%d] == NULL", target.index ); return false; } targetLv = pTargetPlayer->GetLevel(); targetStatusAvoid = FloatToInt( pTargetPlayer->GetStatus2()->mPhysicAvoid ); } else { cMonster* pMonster = OBJECTMANAGER->GetMonster( target.index ); if( pMonster == NULL ) { NETWORK2->PostServerEvent("cMonster::AttackSuccess pMonster[%d] == NULL", target.index ); return false; } targetLv = pMonster->GetLevel(); targetStatusAvoid = pMonster->GetPhysicAvoid(); } /// ¼º°øÀ² ÆÛ¼¾Æ® ¼öÄ¡ ȯ»ê unsigned long resultSuccess = DAMAGECALC->PhyAttackSuccess100( attackerStatusRate, targetStatusAvoid, accuracyValue, eOBJECTTYPE_PLAYER, attackerLv, targetLv, instantSuccess, instantSuccessPer ); /// È®·üüũ unsigned long randvalue = (unsigned long)(RANDOMTABLE->Get( ) * 100); if( randvalue > resultSuccess ) return false; } else if( attributeType == eATTRIBUTETYPE_MAGIC ) /// ¸¶¹ý ½ºÅ³ ¼º°øÈ®·ü °è»ê ó¸® { /// °ø°ÝÀÚ ½ºÅݼº°ø¼öÄ¡ unsigned long attackerStatusRate = GetMagicAttackRate(); /// Ÿ°Ù ȸÇÇ ¼öÄ¡ unsigned long targetStatusAvoid = 0; /// Ÿ°Ù(Ç÷¹À̾î) if( target.type == eOBJECTTYPE_PLAYER ) { cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index ); if( pTargetPlayer == NULL ) { NETWORK2->PostServerEvent("cMonster::AttackSuccess pTargetPlayer[%d] == NULL", target.index ); return false; } targetLv = pTargetPlayer->GetLevel(); targetStatusAvoid = FloatToInt( pTargetPlayer->GetStatus2()->mMagicAvoid ); } else { cMonster* pMonster = OBJECTMANAGER->GetMonster( target.index ); if( pMonster == NULL ) { NETWORK2->PostServerEvent("cMonster::AttackSuccess pMonster[%d] == NULL", target.index ); return false; } targetLv = pMonster->GetLevel(); targetStatusAvoid = pMonster->GetMagicAvoid(); } /// ¼º°øÀ² ÆÛ¼¾Æ® ¼öÄ¡ ȯ»ê unsigned long resultSuccess = DAMAGECALC->MagAttackSuccess130( attackerStatusRate, targetStatusAvoid, accuracyValue, eOBJECTTYPE_PLAYER, attackerLv, targetLv, instantSuccess, instantSuccessPer ); /// È®·üüũ unsigned long randvalue = (unsigned long)(RANDOMTABLE->Get( ) * 100); if( randvalue > resultSuccess ) return false; } else { NETWORK2->PostServerEvent("cMonster::AttackSuccess attributeType[%d] ERROR", attributeType ); return false; } return true; } bool cMonster::CriticalSuccess( sObject target, unsigned long attributeType, unsigned short criticalValue, unsigned long /*instantCri*/, unsigned long /*instantCriPer*/ ) { // return DAMAGECALC->MonsterCritical( mObject.index, target, (eMONSTERATTACK_TYPE)skillIdx, (eATTRIBUTETYPE)attributeType ); if( target.type != eOBJECTTYPE_PLAYER ) { assert(NULL); return false; } cPlayer* pTarget = OBJECTMANAGER->GetPlayer( target.index ); if( pTarget == NULL ) { NETWORK2->PostServerEvent("cMonster::CriticalSuccess pTarget[%d,%d] == NULL", target.type, target.index ); return false; } sEquipAbility* pTargetItem = pTarget->GetEquipAbility(); if( pTargetItem == NULL ) { NETWORK2->PostServerEvent("cMonster::CriticalSuccess pTargetItem[%d,%d] == NULL", target.type, target.index ); return false; } /// ±âº»Á¤º¸ unsigned char attackerLv = GetLevel(); unsigned char targetLv = pTarget->GetLevel(); unsigned long criSuccess = 0; /// ¹°¸® ½ºÅ³ ¼º°øÈ®·ü °è»ê ó¸® if( attributeType == eATTRIBUTETYPE_PHYSICAL ) { long attackerPer = (long)GetStatusPer()->mPhysicCriticalDef; long attackerPlus = (long)GetStatusPlus()->mPhysicCriticalDef; float targetCriDef = pTarget->GetStatus2()->mPhyCriDef; criSuccess = DAMAGECALC->MonsterCritical260( criticalValue, attackerLv, targetLv, attackerPer, attackerPlus, targetCriDef ); } else if( attributeType == eATTRIBUTETYPE_MAGIC ) { long attackerPer = (long)GetStatusPer()->mMagicCriticalDef; long attackerPlus = (long)GetStatusPlus()->mMagicCriticalDef; float targetCriDef = pTarget->GetStatus2()->mMagCriDef; criSuccess = DAMAGECALC->MonsterCritical260( criticalValue, attackerLv, targetLv, attackerPer, attackerPlus, targetCriDef ); } else { NETWORK2->PostServerEvent("cMonster::CriticalSuccess attributeType[%d] ERROR", attributeType ); return false; } /// È®·üüũ unsigned long randvalue = (unsigned long)(RANDOMTABLE->Get( ) * 100 + 1); if( randvalue > criSuccess ) return false; return true; } void cMonster::StatusCalc() { STATUSCALC->CalcMonster( mObject.index ); } void cMonster::SkillEscape( unsigned long type ) { if( IsModeState() == false ) return; cPArray* pImmune = GetBuffImmune(); if( pImmune == NULL ) return; for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*pImmune)[i]); if( p == NULL ) return; if( p->type != eMODEINFO_IMMUNE ) continue; sModeImmune* pInfo = (sModeImmune*)p; if( pInfo->mSkillApplyType == 0 ) return; if( pInfo->mSkillApplyType == (unsigned long)type ) return; } SetEscape(); } void cMonster::SetEscape() { switch( GetActionID() ) { case eACT_ESCAPE: case eACT_DIE: return; } ActionChange( eACT_ESCAPE ); } void cMonster::Comeback() { /// Ÿ°Ù Á¦°Å SetTarget( eOBJECTTYPE_NONE, 0 ); /// È¿°ú Á¦°Å ReleaseInfluenceSet( false ); /// ¿ø·¡ Áö¿ªÀ¸·Î À̵¿Áß - ¼±°ø¸ó½ºÅÍ °ø°Ý ¾ÈÇÏ°Ô ÇÔ SetFollowEndMove( true ); /// ¼±°ø µå¶ø À¯Àú Ŭ¸®¾î mFirstAttackCharacter = 0; mFirstAttackParty = 0; mLastAttacker = 0; /// ÀÚÀ¯À̵¿ ¹üÀ§ ¹Û¿¡ ÀÖ´Â °æ¿ì¸¸ RUN unsigned long freeRange = mpMonsterInfo->mFreeMoveRange; long moveSpeed = 0; mRangeCheck.SetRadius( (float)freeRange ); if( mRangeCheck.IsRange( mObjectPos, mRegenPos ) == false ) moveSpeed = SetMoveSpeed( mpMonsterInfo->mActionRunSpd, eMOVESPEED_RUN ); /// ¸ó½ºÅÍ È¸±Í ¼Óµµ else moveSpeed = SetMoveSpeed( mpMonsterInfo->mActionWalkSpd, eMOVESPEED_WALK ); /// À̵¿ ¾ÈÇÏ´Â ¸ó½ºÅÍ Àΰæ¿ì if( moveSpeed != 0 ) { float targetPosX = mRegenPos.x; float targetPosY = mRegenPos.y; /// ÆÐÅÏ À̵¿ÁßÀÌ¸é ±âÁ¸¸ñÀûÁö¸¦ Ÿ°ÙÀ¸·Î Àâ´Â´Ù. if( mpMovePattern != NULL && mpRegenMonsterInfo->mPatternIdx != 0) { cArray* pAry = &mpMovePattern->mPosAry; sMonsterPatternPos* pPos = (sMonsterPatternPos*)(*pAry)[mPatternPos]; if( pPos != NULL) { freeRange = pPos->mRange; targetPosX = pPos->mPosX; targetPosY = pPos->mPosY; } } /// ¹üÀ§¾È¿¡¼­ ·£´ý ÁÂÇ¥ÀÇ ¸®Á¨ À§Ä¡ if( freeRange == 0 ) freeRange = 1; targetPosX = targetPosX + ( rand() % freeRange ) - ( rand() % freeRange ); targetPosY = targetPosY + ( rand() % freeRange ) - ( rand() % freeRange ); /// °¥¼ö ÀÖ´ÂÁö ¿ªÀÎÁö üũ if( AIMANAGER->IsPossible( mMapNumber, targetPosX, targetPosY, mObject ) == true ) { /// À̵¿ ÃʱâÈ­ MoveStop( true ); SetMoveStopRange( 0 ); /// ¸ó½ºÅͰ¡ À̵¿ÇÒ °æ·Î ¼ÂÆÃ SetPath( targetPosX, targetPosY ); } } /// hp/mp ȸº¹ ¼³Á¤ üũ if( mpMonsterInfo->mIsRecovery == true ) { if( mHP != GetMaxHP() ) HPHeal( GetMaxHP(), true, mObject, 0, eTAKEDAMAGETYPE_NONE ); if( mMP != GetMaxMP() ) MPHeal( GetMaxMP(), false ); } /// ÀÚÀ¯ À̵¿À¸·Î º¯°æ ActionChange( eACT_MOVE ); SetCombatFlag( false ); /// ClearImmune(); mGenTotemCoolTimeMap.Clear(); mGenMonCoolTimeMap.Clear(); mGenGatheringCoolTimeMap.Clear(); if( mSummonListMap.IsEmpty() == false ) { cPHashMap::cIterator b = mSummonListMap.Begin(); cPHashMap::cIterator end = mSummonListMap.End(); for( ; b!=end; b++ ) { cHashSet* pSet = (cHashSet*)(*b).mSecond; if( pSet ) pSet->Clear(); } } for( unsigned long i = 0 ; i < mSummonGatherAry.GetSize() ; ++i ) { cGathering* pGather = OBJECTMANAGER->GetGathering( mSummonGatherAry[i] ); if( pGather != NULL ) pGather->GatheringDie( 0 ); } mSummonGatherAry.Clear(); } void cMonster::ReservationComeback() { mReservationComeback = true; mTFixedPlayerIdx = 0; /// ÀÚÀ¯ À̵¿À¸·Î º¯°æ ActionChange( eACT_MOVE ); /// ClearImmune(); mGenTotemCoolTimeMap.Clear(); mGenMonCoolTimeMap.Clear(); mGenGatheringCoolTimeMap.Clear(); if( mSummonListMap.IsEmpty() == false ) { cPHashMap::cIterator b = mSummonListMap.Begin(); cPHashMap::cIterator end = mSummonListMap.End(); for( ; b!=end; b++ ) { cHashSet* pSet = (cHashSet*)(*b).mSecond; if( pSet ) pSet->Clear(); } } for( unsigned long i = 0 ; i < mSummonGatherAry.GetSize() ; ++i ) { cGathering* pGather = OBJECTMANAGER->GetGathering( mSummonGatherAry[i] ); if( pGather != NULL ) pGather->GatheringDie( 0 ); } mSummonGatherAry.Clear(); } void cMonster::CheckComback() { if( mReservationComeback == true ) { Comeback(); mReservationComeback = false; } } bool cMonster::MoveUpdate( unsigned long deltaTime ) { if( mpMonsterInfo->mActionRunSpd == 0 && mpMonsterInfo->mActionWalkSpd == 0 ) return false; /// À̵¿ºÒ°¡ »óÅ ÀÌ»óÀÎ °æ¿ì if( IsCantMove() == true ) return false; if( mPathCount == 0 ) return false; /// °æ·Î°¡ ¼³Á¤µÇÁö ¾Ê¾Ò´Ù if( mNextPos.x < 0.0f || mNextPos.y < 0.0f ) return false; float moveDeltaTime = (float)(deltaTime) / SECOND_THOUSAND; /// ¸ó½ºÅÍÀÇ À̵¿¼Óµµ NiPoint2 pos = mObjectPos; float speed = static_cast(GetMoveSpeed()); /// ¹æÇâ ¼³Á¤ NiPoint2 dir1; dir1.x = mNextPos.x - pos.x; dir1.y = mNextPos.y - pos.y; dir1.Unitize(); const float limitOverTime = 0.01f; float plusTime; /// ¸ñÀûÁöÁ¡ ³Ñ¾î¼­ ÀúÀåµÈ ½Ã°£À» À̵¿½Ã + if( mMoveOverTime > limitOverTime ) plusTime = limitOverTime; else plusTime = mMoveOverTime; mMoveOverTime = mMoveOverTime - plusTime; /// ¼Óµµ * °æ°ú½Ã°£ ¸¸Å­ÀÇ ¿¹»ó À̵¿ À§Ä¡ °è»ê pos.x += (speed * ( moveDeltaTime + plusTime ) * dir1.x); pos.y += (speed * ( moveDeltaTime + plusTime ) * dir1.y); /// ¸ñÀûÁö ÁÂÇ¥¿Í ¿¹»ó À̵¿ À§Ä¡¸¦ ºñ±³ NiPoint2 dir2; dir2.x = mNextPos.x - pos.x; dir2.y = mNextPos.y - pos.y; dir2.Unitize(); bool keepMoving = true; /// ¿¹»ó À̵¿À§Ä¡°¡ ¸ñÀûÁö ÁÂÇ¥¸¦ ³Ñ¾î°¡¸é ¸ñÀûÁö µµ´Þ·Î ÆÇÁ¤ if( dir2.Dot(dir1) <= 0.0f ) { NiPoint2 overPoint( pos.x, pos.y ); /// ±æÃ£±â °æ·Î ¸ñÀû ÁöÁ¡À» ³Ñ¾î¼± °æ¿ì ³ÑÀº °Å¸®¸¸Å­ ½Ã°£ º¸°ü float overLength = ( overPoint - mNextPos ).Length(); mMoveOverTime = mMoveOverTime + ( overLength / speed ); //CONSOLE->WriteLog("OverLength, MoveOverTime %f %f", overLength, mMoveOverTime ); pos.x = mNextPos.x; pos.y = mNextPos.y; if( mPathIndex < mPathCount-1 ) { mNextPos = mPathArray[++mPathIndex]; float viewPosX, viewPosY; viewPosX = mObjectPos.x - mNextPos.x; viewPosY = mObjectPos.y - mNextPos.y; mDirection = atan2( viewPosX, viewPosY ); } else { mPathCount = 0; mPathIndex = 0; mMoveOverTime = 0.0f; keepMoving = false; } } /// ¸ó½ºÅͰ¡ ¸ñÀûÁö¿¡¼­ ±Ùó(ÀÏÁ¤¹üÀ§)±îÁö µµ´ÞÇϸé Á¤ÁöÇÏ´Â ¸ðµâ if( mMoveStopRange != 0.0f ) { /// Ÿ°Ù ¿ÀºêÁ§Æ®ÀÇ ÃÖÁ¾ ¸ñÀûÁö NiPoint3 targetPos; NiPoint3 monsterGuessPos( pos.x, pos.y, 0.0f ); AIMANAGER->CalcHeight( mMapNumber, &monsterGuessPos.z, monsterGuessPos.x, monsterGuessPos.y ); NiPoint3 monsterNowPos( GetXPos(), GetYPos(), Height() ); /// ½ÇÁ¦ Ÿ°ÙÀÇ ÇöÀçÀ§Ä¡ cBaseObject* pBaseObject = GetTarget(); if( pBaseObject ) { /// Ÿ°Ù ¿ÀºêÁ§Æ®°¡ Àִ°æ¿ì ¿ÀºêÁ§Æ®ÀÇ ½ÇÁ¦ À§Ä¡¸¦ °¡Á®¿È targetPos.x = pBaseObject->GetXPos(); targetPos.y = pBaseObject->GetYPos(); targetPos.z = pBaseObject->Height(); } else { /// Ÿ°Ù ¿ÀºêÁ§Æ®°¡ ¾ø´Â°æ¿ì ±â·ÏµÇÀÖ´ø Ÿ°Ù ¿ÀºêÁ§Æ®ÀÇ À§Ä¡¸¦ °¡Á®¿È targetPos.x = mLastPos.x; targetPos.y = mLastPos.y; AIMANAGER->CalcHeight( mMapNumber, &targetPos.z, targetPos.x, targetPos.y ); } float moveStopRangeFix = OBJECTMANAGER->ObjectSizeRange( this, pBaseObject, mMoveStopRange ); mRangeCheck.SetRadius( moveStopRangeFix ); /// À̵¿ ¿¹»ó À§Ä¡¿Í ½ÇÁ¦ Ÿ°Ù ¿ÀºêÁ§Æ®ÀÇ Ãæµ¹Ã¼Å© if( mRangeCheck.IsRange( monsterGuessPos, targetPos ) ) { /// ÁÂÇ¥ º¸Á¤ NiPoint3 p; NiPoint3 d = monsterNowPos - targetPos; d.Unitize(); p.x = targetPos.x + ((moveStopRangeFix-1.0f)*d.x); p.y = targetPos.y + ((moveStopRangeFix-1.0f)*d.y); SetPos( p.x, p.y ); SetMoveStopRange( 0.0f ); mLastPos.x = p.x; mLastPos.y = p.y; return false; } } SetPos( pos.x, pos.y ); #ifdef _DEBUG /// Å×½ºÆ®ÄÚµå static bool check = false; static unsigned long delayTime = 100; static bool sync = false; if( check == true && mServerPosTime < NETWORK2->GetAccumTime() ) { mServerPosTime += delayTime; MSG_SERVERPOS_TEST syncMsg; syncMsg.Category = NM_PLAYER; syncMsg.Protocol = NM_PLAYER_TEST_SERVERPOS; syncMsg.mCharacterIdx = mObject.index; syncMsg.mServerPosX = mObjectPos.x; syncMsg.mServerPosY = mObjectPos.y; NETWORK2->QuickSend( this, (char*)&syncMsg, sizeof( MSG_SERVERPOS_TEST ) ); } #endif return keepMoving; } bool cMonster::PushPullUpdate( unsigned long deltaTime ) { if( mpMonsterInfo->mActionRunSpd == 0 && mpMonsterInfo->mActionWalkSpd == 0 ) return false; /// °æ·Î°¡ ¼³Á¤µÇÁö ¾Ê¾Ò´Ù if( mNextPos.x < 0.0f || mNextPos.y < 0.0f ) return false; float moveDeltaTime = (float)(deltaTime) / SECOND_THOUSAND; /// ¸ó½ºÅÍÀÇ À̵¿¼Óµµ NiPoint2 pos = mObjectPos; float speed = SKILL_PUSHPULL_SPEED; /// ¹æÇâ ¼³Á¤ NiPoint2 dir1; dir1.x = mNextPos.x - pos.x; dir1.y = mNextPos.y - pos.y; dir1.Unitize(); const float limitOverTime = 0.01f; float plusTime; /// ¸ñÀûÁöÁ¡ ³Ñ¾î¼­ ÀúÀåµÈ ½Ã°£À» À̵¿½Ã + if( mMoveOverTime > limitOverTime ) plusTime = limitOverTime; else plusTime = mMoveOverTime; mMoveOverTime = mMoveOverTime - plusTime; /// ¼Óµµ * °æ°ú½Ã°£ ¸¸Å­ÀÇ ¿¹»ó À̵¿ À§Ä¡ °è»ê pos.x += (speed * ( moveDeltaTime + plusTime ) * dir1.x); pos.y += (speed * ( moveDeltaTime + plusTime ) * dir1.y); /// ¸ñÀûÁö ÁÂÇ¥¿Í ¿¹»ó À̵¿ À§Ä¡¸¦ ºñ±³ NiPoint2 dir2; dir2.x = mNextPos.x - pos.x; dir2.y = mNextPos.y - pos.y; dir2.Unitize(); /// ¿¹»ó À̵¿À§Ä¡°¡ ¸ñÀûÁö ÁÂÇ¥¸¦ ³Ñ¾î°¡¸é ¸ñÀûÁö µµ´Þ·Î ÆÇÁ¤ if( dir2.Dot(dir1) <= 0.0f ) { pos.x = mNextPos.x; pos.y = mNextPos.y; return false; } SetPos( pos.x, pos.y ); #ifdef _DEBUG /// Å×½ºÆ®ÄÚµå static bool check = false; static unsigned long delayTime = 100; static bool sync = false; if( check == true && mServerPosTime < NETWORK2->GetAccumTime() ) { mServerPosTime += delayTime; MSG_SERVERPOS_TEST syncMsg; syncMsg.Category = NM_PLAYER; syncMsg.Protocol = NM_PLAYER_TEST_SERVERPOS; syncMsg.mCharacterIdx = mObject.index; syncMsg.mServerPosX = mObjectPos.x; syncMsg.mServerPosY = mObjectPos.y; NETWORK2->QuickSend( this, (char*)&syncMsg, sizeof( MSG_SERVERPOS_TEST ) ); } #endif return true; } bool cMonster::SelectNextPath( float* pPosX, float* pPosY ) { if( pPosX == NULL || pPosY == NULL ) return false; /// À̵¿ ÆÐÅÏ ¼³Á¤ÀÌ ¾øÀ¸¸é ÀÚÀ¯À̵¿ float targetPosX = GetRegenPos().x; float targetPosY = GetRegenPos().y; unsigned long freeRange = mpMonsterInfo->mFreeMoveRange; /// À̵¿ ÆÐÅÏÀÌ ¼³Á¤µÈ°æ¿ì ¸ñÀûÁö¸¦ ã¾Æ³½´Ù. if( mpRegenMonsterInfo != NULL && mpRegenMonsterInfo->mPatternIdx != 0 ) { try { if( mpMovePattern == NULL ) throw 1; cArray* pAry = &mpMovePattern->mPosAry; if( pAry == NULL ) throw 2; if( pAry->GetSize() <= 1 ) throw 3; if( (long)pAry->GetSize() <= mPatternPos ) throw 4; long pos = mPatternPos; char dir = mPatternDir; if( mpMovePattern->mType == true ) { /// ¼øÈ¯ pos = pos + mPatternDir; if( (long)pAry->GetSize() <= pos ) pos = 0; } else { /// ¿ªÁÖÇà if( pos + dir >= (long)pAry->GetSize() ) dir = -1; else if( pos + dir < 0 ) dir = 1; pos = pos + dir; } sMonsterPatternPos* pPos = (sMonsterPatternPos*)(*pAry)[pos]; if( pPos == NULL ) throw 5; mPatternPos = pos; mPatternDir = dir; targetPosX = pPos->mPosX; targetPosY = pPos->mPosY; freeRange = pPos->mRange; if( pPos->mRelaxPoint == true ) mPatternWait = pPos->mWaitTime; } catch ( int error ) { mPatternPos = 0; mPatternDir = 1; NETWORK2->PostServerEvent( "cMonster::SelectNextPath [%d][%d,%d,%d,%d]", error, mObject.index, GetRaceGender(), mpRegenMonsterInfo->mPatternIdx, mPatternPos ); } } /// ¹üÀ§¾È¿¡¼­ ·£´ý ÁÂÇ¥ ¼³Á¤ if( freeRange == 0 ) freeRange = 1; targetPosX = targetPosX + ( rand() % (int)freeRange ) - ( rand() % (int)freeRange ); targetPosY = targetPosY + ( rand() % (int)freeRange ) - ( rand() % (int)freeRange ); if( targetPosX < 0 ) targetPosX = 0; if( targetPosY < 0 ) targetPosY = 0; *pPosX = targetPosX; *pPosY = targetPosY; return true; } void cMonster::GetNextPattern( long* pPatternPos, char* pPatternDir ) { if( pPatternPos == NULL || pPatternDir == NULL ) return; *pPatternPos = mPatternPos; *pPatternDir = mPatternDir; } unsigned int cMonster::SetPath( float targetX, float targetY ) { /// À̵¿ºÒ°¡ »óÅ ÀÌ»óÀÎ °æ¿ì if( IsCantMove() == true ) return 0; /// Ÿ°Ù ÁÂÇ¥¿Í ¸ó½ºÅÍ ÁÂÇ¥°¡ °°À¸¸é °æ·Î ¼³Á¤¾ÈÇÔ if( GetXPos() == targetX && GetYPos() == targetY ) { /// °æ·Î ¾øÀ½ return 0; } /// À̵¿ ÇÒ ÃÖÁ¾ Æ÷ÀÎÆ®¸¦ ±â·ÏÇØµÒ mLastPos.x = targetX; mLastPos.y = targetY; unsigned long timetick = GetTickCount(); /// ±æÃ£±â ½ÇÇà if( FindPath( NiPoint2( targetX, targetY ) ) == false ) { return 0; } unsigned int pathCount = GetPathCount(); assert( pathCount ); unsigned long now = GetTickCount(); if( now - timetick > 1000 ) { NETWORK2->PostServerEvent("PathDelay[%d] cnt[%d] %.0f,%.0f -> %.0f,%.0f", now - timetick, pathCount, GetXPos(), GetYPos(), targetX, targetY ); Verbose->WriteLog("PathDelay[%d] cnt[%d] %.0f,%.0f -> %.0f,%.0f", now - timetick, pathCount, GetXPos(), GetYPos(), targetX, targetY ); } /// À̵¿ ¸ñÀûÁö(ÁÂÇ¥)±îÁö À̵¿ÇÏ´Â ÇüÅ SetMoveStopRange( 0 ); PerIoContext* perIoContext = NETWORK2->GetIoContext( IOCP_REQUEST_WRITE ); /// À̵¿ ¸Þ¼¼Áö ¹ß¼Û MSG_SYN_MOVE_MONSTER* msg = (MSG_SYN_MOVE_MONSTER*)perIoContext->buffer; msg->Category = NM_MONSTER; msg->Protocol = NM_MONSTER_MOVE_SYN; msg->mMonsterIdx = GetObjectID(); for( unsigned int i = 0 ; i < pathCount ; ++i ) msg->mPathArray[i] = GetPathArray()[i]; msg->mMoveSpeed = (unsigned short)GetMoveSpeed(); msg->mMoveSpeedType = (unsigned char)mMoveSpeedType; msg->mCount = (unsigned short)pathCount; NETWORK2->QuickSend( this, (char*)msg, msg->GetMsgLength() ); perIoContext->offset = msg->GetMsgLength(); NETWORK2->ReleaseIoContext( perIoContext, "cMonster::SetPath:MSG_SYN_MOVE_MONSTER" ); return pathCount; } unsigned int cMonster::SetPath( float targetX, float targetY, float range, sObject target ) { /// À̵¿ºÒ°¡ »óÅ ÀÌ»óÀÎ °æ¿ì if( IsCantMove() == true ) return 0; /// Ÿ°Ù ÁÂÇ¥¿Í ¸ó½ºÅÍ ÁÂÇ¥°¡ °°À¸¸é °æ·Î ¼³Á¤¾ÈÇÔ if( GetXPos() == targetX && GetYPos() == targetY ) { /// °æ·Î ¾øÀ½ return 0; } /// À̵¿ ÇÒ ÃÖÁ¾ Æ÷ÀÎÆ®¸¦ ±â·ÏÇØµÒ mLastPos.x = targetX; mLastPos.y = targetY; /// ±æÃ£±â ½ÇÇà if( FindPath( NiPoint2(targetX, targetY) ) == false ) { return 0; } unsigned int pathCount = GetPathCount(); assert( pathCount ); PerIoContext* perIoContext = NETWORK2->GetIoContext( IOCP_REQUEST_WRITE ); /// À̵¿³¡±îÁö °¡±âÀü¿¡ range¹üÀ§ ¾È¿¡ µé¾î¿À¸é À̵¿À» ¸ØÃß´Â À̵¿ÇüÅ SetMoveStopRange( range ); /// ¿¡ÀÌÀüÆ® -> Ŭ¶óÀÌ¾ðÆ®¿¡ Àü¼Û MSG_SYN_ACTIONMOVE_MONSTER* msg = (MSG_SYN_ACTIONMOVE_MONSTER*)perIoContext->buffer; msg->Category = NM_MONSTER; msg->Protocol = NM_MONSTER_ACTIONMOVE_SYN; for( unsigned int i = 0 ; i < pathCount ; ++i ) msg->mPathArray[i] = GetPathArray()[i]; msg->mMonsterIdx = GetObjectID(); msg->mMoveSpeed = (unsigned short)GetMoveSpeed(); msg->mCount = (unsigned short)pathCount; msg->mTarget = target; msg->mRange = range; NETWORK2->QuickSend( this, (char*)msg, msg->GetMsgLength() ); perIoContext->offset = msg->GetMsgLength(); NETWORK2->ReleaseIoContext( perIoContext, "cMonster::SetPath:MSG_SYN_ACTIONMOVE_MONSTER" ); return pathCount; } void cMonster::ActionChange( eACTION_ID state ) { switch( state ) { case eACT_MOVE: SetAction( mActionMove ); SetCombatFlag( false ); break; case eACT_DIE: SetAction( mActionDie ); SetCombatFlag( false ); break; case eACT_ATTACK: SetAction( mActionAttack ); SetCombatFlag( true ); break; case eACT_ESCAPE: SetAction( mActionEscape ); break; case eACT_FOLLOW: SetAction( mActionFollow ); SetCombatFlag( true ); break; case eACT_IDLE: SetAction( mActionIdle ); break; case eACT_PUSHPULL: SetAction( mActionPushPull ); break; } } void cMonster::SetAction( cAction& pNewAtion ) { if( mpAction != NULL && mpAction->GetActionID() == eACT_DIE && pNewAtion.GetActionID() != eACT_IDLE ) { return; } /// ÀÌ¹Ì »ç¿ëÁßÀÎ »óÅÂ¸é ±»ÀÌ ¹Ù²Ü ÇÊ¿ä´Â ¾ø´Ù. if( mpAction == &pNewAtion ) return; mpAction = NULL; mpAction = &pNewAtion; mpAction->ActionInit( this, NETWORK2->GetAccumTime() ); } //bool cMonster::AddInfluence( unsigned long uniqueIdx, unsigned long influenceClassIdx ) bool cMonster::AddInfluence( cInfluenceObject* pInf ) { if( pInf == NULL ) return false; if( mInfluenceSet.Insert( pInf->GetUniqueIdx() ) == false ) { assert(NULL); NETWORK2->PostServerEvent("cMonster[%d]::AddSkillInfluence mInfluenceSet.Insert( %d, %d ) == false", mObject.index, pInf->GetUniqueIdx(), pInf->GetInfluenceClassIdx() ); return false; } sInfluenceScript* pScript = SKILLSCRIPT->GetInfluenceInfo( pInf->GetInfluenceClassIdx() ); if( pScript != NULL ) { switch( pInf->GetChangeMPType() ) { case eINFCHANGEMPTYPE_NONE: break; case eINFCHANGEMPTYPE_PHY: case eINFCHANGEMPTYPE_MAG: case eINFCHANGEMPTYPE_ALL: { mChangeMPDamageAry.PushBack( pInf->GetUniqueIdx() ); std::sort( mChangeMPDamageAry.Begin(), mChangeMPDamageAry.End(), InfChangeMPMinSort ); } break; default: NETWORK2->PostServerEvent("cMonster::AddSkillInfluence pInf->GetChangeMPType[%d,%d](%d,%d,%d) == false", mObject.index, GetRaceGender(), pInf->GetUniqueIdx(), pInf->GetInfluenceClassIdx(), pInf->GetChangeMPType() ); } switch( pInf->GetGuardType() ) { case eINFGUARDTYPE_NONE: break; case eINFGUARDTYPE_PHY: case eINFGUARDTYPE_MAG: case eINFGUARDTYPE_ALL: { mGuardAry.PushBack( pInf->GetUniqueIdx() ); std::sort( mGuardAry.Begin(), mGuardAry.End(), InfLeftTimeSort ); } break; default: NETWORK2->PostServerEvent("cMonster[%d]::AddSkillInfluence pInf->GetGuardType(%d,%d,%d,%d) == false", mObject.index, pInf->GetUniqueIdx(), pInf->GetInfluenceClassIdx(), pInf->GetChangeMPType() ); } /// µ¥¹ÌÁö¸¦ ¹ÞÀ¸¸é »èÁ¦ÇÒ °ÇÁö üũÇÏ¿© »ðÀÔ switch( pInf->GetDeleteType() ) { case eDELETETYPE_PLAYER_DIE: case eDELETETYPE_NODELETE_PLAYER_DIE: break; case eDELETETYPE_PLAYER_DAMAGED: { mDeleteTypeDamagedAry.PushBack( pInf->GetUniqueIdx() ); } break; default: NETWORK2->PostServerEvent("cMonster::AddSkillInfluence pInf->GetDeleteType(%d,%d,%d,%d) == false", mObject.index, pInf->GetUniqueIdx(), pInf->GetInfluenceClassIdx(), pInf->GetDeleteType() ); break; } /// ÇöÀç Áö¼Ó È¿°ú ¹øÈ£°¡ 3°³ ¹Û¿¡ ¾ø¾î¼­ 3¹ø¸¸ üũ for( int checkCount = 0; checkCount < 3; ++checkCount ) { unsigned short checkStatusPlusIdx = eSTATUSPLUS_NONE; switch(checkCount) { case 0: checkStatusPlusIdx = pScript->mStatusPlusIdx1; break; case 1: checkStatusPlusIdx = pScript->mStatusPlusIdx2; break; case 2: checkStatusPlusIdx = pScript->mStatusPlusIdx3; break; } if( checkStatusPlusIdx != eSTATUSPLUS_NONE ) { if( pScript->mType == eINFLUENCETYPE_BUF ) { cApplyValueTypeMap::cIterator findPos = mBuffmap.Find( checkStatusPlusIdx ); if( findPos != mBuffmap.End() ) { /// ÀÌ¹Ì µé¾î°¡ ÀÖ´Â °æ¿ì cHashSet& influenceSet = (*findPos).mSecond; influenceSet.Insert( pInf->GetUniqueIdx() ); } else { /// »õ·Î Ãß°¡ÇÑ °æ¿ì cHashSet influenceSet; influenceSet.Insert( pInf->GetUniqueIdx() ); mBuffmap.Insert( checkStatusPlusIdx, influenceSet ); } } else if( pScript->mType == eINFLUENCETYPE_DEBUF ) { cApplyValueTypeMap::cIterator findPos = mDeBuffmap.Find( checkStatusPlusIdx ); if( findPos != mDeBuffmap.End() ) { /// ÀÌ¹Ì µé¾î°¡ ÀÖ´Â °æ¿ì cHashSet& influenceSet = (*findPos).mSecond; influenceSet.Insert( pInf->GetUniqueIdx() ); } else { /// »õ·Î Ãß°¡ÇÑ °æ¿ì cHashSet influenceSet; influenceSet.Insert( pInf->GetUniqueIdx() ); mDeBuffmap.Insert( checkStatusPlusIdx, influenceSet ); } } } else { /// È¿°ú´Â ¼øÂ÷ÀûÀ¸·Î Áý¾î ³Ö±â ¶§¹®¿¡ Çϳª¶óµµ ºó À妽º°¡ ³ª¿À¸é ³ª¸ÓÁö´Â üũÇÒ Çʿ䰡 ¾ø´Ù. break; } } } return true; } void cMonster::DeleteInfluence( unsigned long influenceIdx ) { for( unsigned long i = 0 ; i < mGuardAry.GetSize() ; ++i ) { if( influenceIdx == mGuardAry[i] ) mGuardAry.PopAt( i ); } for( unsigned long i = 0 ; i < mChangeMPDamageAry.GetSize() ; ++i ) { if( influenceIdx == mChangeMPDamageAry[i] ) mChangeMPDamageAry.PopAt( i ); } for( unsigned long i = 0 ; i < mDeleteTypeDamagedAry.GetSize() ; ++i ) { if( influenceIdx == mDeleteTypeDamagedAry[i] ) mDeleteTypeDamagedAry.PopAt( i ); } /// ¹öÇÁ/µð¹öÇÁ °ü¸® map ¿¡¼­ »©±â cInfluenceObject* pInf = SKILLMANAGER->GetInfluence( influenceIdx ); if( pInf != NULL ) { sInfluenceScript* pScript = SKILLSCRIPT->GetInfluenceInfo( pInf->GetInfluenceClassIdx() ); if( pScript != NULL ) { /// ÇöÀç Áö¼Ó È¿°ú ¹øÈ£°¡ 3°³ ¹Û¿¡ ¾ø¾î¼­ 3¹ø¸¸ üũ for( int checkCount = 0; checkCount < 3; ++checkCount ) { unsigned short checkStatusPlusIdx = eSTATUSPLUS_NONE; switch(checkCount) { case 0: checkStatusPlusIdx = pScript->mStatusPlusIdx1; break; case 1: checkStatusPlusIdx = pScript->mStatusPlusIdx2; break; case 2: checkStatusPlusIdx = pScript->mStatusPlusIdx3; break; } if( checkStatusPlusIdx != eSTATUSPLUS_NONE ) { if( pScript->mType == eINFLUENCETYPE_BUF ) { cApplyValueTypeMap::cIterator findPos = mBuffmap.Find( checkStatusPlusIdx ); if( findPos != mBuffmap.End() ) { /// ãÀº °æ¿ì ÇØ´ç set¿¡¼­ »èÁ¦ cHashSet& influenceSet = (*findPos).mSecond; influenceSet.Erase( pInf->GetUniqueIdx() ); } else { /// È¿°ú ¸Ê¿¡´Â ÀÖÁö¸¸ ¹öÇÁ ¸Ê¿¡ ¾ø´Â °æ¿ì mInfluenceSet °ú mBuffmap ÀÌ µ¿±âÈ­ ¾È¸Â¾ÒÀ½! NETWORK2->PostServerEvent("cMonster::DeleteInfluence mBuffmap.Find(%d)==mBuffmap.End (%d,%d,%d)", checkStatusPlusIdx, mObject.index, pInf->GetUniqueIdx(), pInf->GetInfluenceClassIdx() ); } } else if( pScript->mType == eINFLUENCETYPE_DEBUF ) { cApplyValueTypeMap::cIterator findPos = mDeBuffmap.Find( checkStatusPlusIdx ); if( findPos != mDeBuffmap.End() ) { /// ãÀº °æ¿ì ÇØ´ç set¿¡¼­ »èÁ¦ cHashSet& influenceSet = (*findPos).mSecond; influenceSet.Erase( pInf->GetUniqueIdx() ); } else { /// È¿°ú ¸Ê¿¡´Â ÀÖÁö¸¸ ¹öÇÁ ¸Ê¿¡ ¾ø´Â °æ¿ì mInfluenceSet °ú mBuffmap ÀÌ µ¿±âÈ­ ¾È¸Â¾ÒÀ½! NETWORK2->PostServerEvent("cMonster::DeleteInfluence mDeBuffmap.Find(%d)==mDeBuffmap.End (%d,%d,%d)", checkStatusPlusIdx, mObject.index, pInf->GetUniqueIdx(), pInf->GetInfluenceClassIdx() ); } } } else { /// È¿°ú´Â ¼øÂ÷ÀûÀ¸·Î Áý¾î ³Ö±â ¶§¹®¿¡ Çϳª¶óµµ ºó À妽º°¡ ³ª¿À¸é ³ª¸ÓÁö´Â üũÇÒ Çʿ䰡 ¾ø´Ù. break; } } } } if( mInfluenceSet.Erase( influenceIdx ) == false ) NETWORK2->PostServerEvent("cMonster::EraseSkillInfluence[%d][%d]", mObject.index, influenceIdx ); // cInfluenceObject* pInf = SKILLMANAGER->GetInfluence( influenceIdx ); if( pInf != NULL ) { sInfluenceScript* pScript = SKILLSCRIPT->GetInfluenceInfo( pInf->GetInfluenceClassIdx() ); if( pScript != NULL ) { if( pScript->mStatusPlusIdx1 >= eSTATUSPLUS_GUARDMP_PHY && pScript->mStatusPlusIdx1 <= eSTATUSPLUS_GUARDMP_ALL ) std::sort( mChangeMPDamageAry.Begin(), mChangeMPDamageAry.End(), InfChangeMPMinSort ); else if( pScript->mStatusPlusIdx2 >= eSTATUSPLUS_GUARDMP_PHY && pScript->mStatusPlusIdx2 <= eSTATUSPLUS_GUARDMP_ALL ) std::sort( mChangeMPDamageAry.Begin(), mChangeMPDamageAry.End(), InfChangeMPMinSort ); else if( pScript->mStatusPlusIdx3 >= eSTATUSPLUS_GUARDMP_PHY && pScript->mStatusPlusIdx3 <= eSTATUSPLUS_GUARDMP_ALL ) std::sort( mChangeMPDamageAry.Begin(), mChangeMPDamageAry.End(), InfChangeMPMinSort ); else if( pScript->mStatusPlusIdx1 >= eSTATUSPLUS_GUARDCNT_PHY && pScript->mStatusPlusIdx1 <= eSTATUSPLUS_GUARDCNT_ALL ) std::sort( mGuardAry.Begin(), mGuardAry.End(), InfLeftTimeSort ); else if( pScript->mStatusPlusIdx2 >= eSTATUSPLUS_GUARDCNT_PHY && pScript->mStatusPlusIdx2 <= eSTATUSPLUS_GUARDCNT_ALL ) std::sort( mGuardAry.Begin(), mGuardAry.End(), InfLeftTimeSort ); else if( pScript->mStatusPlusIdx3 >= eSTATUSPLUS_GUARDCNT_PHY && pScript->mStatusPlusIdx3 <= eSTATUSPLUS_GUARDCNT_ALL ) std::sort( mGuardAry.Begin(), mGuardAry.End(), InfLeftTimeSort ); } } } void cMonster::ReleaseInfluenceSet( bool logOut ) { cSkillInfluenceSet::cIterator start = mInfluenceSet.Begin(); cSkillInfluenceSet::cIterator end = mInfluenceSet.End(); unsigned long infIdx = 0; while( start != end ) { infIdx = *start++; if( logOut == true ) { cInfluenceObject* pInf = SKILLMANAGER->GetInfluence( infIdx ); if( pInf != NULL ) { pInf->NoSendDelMsg(); pInf->NoStatusCalc(); } } SKILLMANAGER->DeleteInfluenceList( infIdx ); } } bool cMonster::IsParentEqual( unsigned long parentUniqueIdx ) { cSkillInfluenceSet::cIterator beginAura = mInfluenceSet.Begin(); cSkillInfluenceSet::cIterator endAura = mInfluenceSet.End(); cInfluenceObject* pInf = NULL; while( beginAura != endAura ) { /// º¸À¯ È¿°ú ¿ÀºêÁ§Æ® pInf = SKILLMANAGER->GetInfluence( *beginAura++ ); if( !pInf ) { assert(NULL); NETWORK2->PostServerEvent("cSkillManager::IsParentEqual pHaveInfluenceObject==NULL Aura" ); //-/-//InsertDeleteInfluenceObject( pHaveInfluenceObject ); /// °´Ã¼ »èÁ¦ ´ë±â¿­¿¡ ³Ö´Â´Ù. continue; } if( pInf->GetSwitchType() == eSWITCHTYPE_PARENT && pInf->GetRarentIdx() == parentUniqueIdx ) return true; } return false; } void cMonster::AttackDummy( sObject attacker ) { if( attacker.type != eOBJECTTYPE_PLAYER ) return; if( IsAutoDummy() == false ) return; cPlayer* player = OBJECTMANAGER->GetPlayer( attacker.index ); if( player != NULL ) { // ¿ÀÅä´õ¹ÌÀÎ °æ¿ì, °æ°í¸Þ¼¼Áö ¹ß¼Û HANDLE handle = NULL; MSG_SYN_CHAT_AUTODUMMY* sendMsg = (MSG_SYN_CHAT_AUTODUMMY*)NETWORK2->GetMsgRoot( &handle, player->GetConnectionIdx(), NM_CHAT, NM_CHAT_AUTODUMMY_SYN ); if ( sendMsg != NULL ) { NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_CHAT_AUTODUMMY) ); } // ¿ÀÅä °ø°Ý Á¤º¸ cHashMap::cIterator i = mAutoAttackerMap.Find( attacker.index ); if( i != mAutoAttackerMap.End() ) { unsigned long& count = (unsigned long)(*i).mSecond; count++; if( count >= MAX_DUMMY_DAMAGE ) { // ¿ÀÅäÆÇÁ¤ player->AutoLimit(); // Á¤º¸ »èÁ¦ mAutoAttackerMap.Erase( attacker.index ); } } else { mAutoAttackerMap.Insert( attacker.index, 1 ); } } } void cMonster::AddTakeDamage( sObject attacker, unsigned long damage, long distressPoint, eTAKEDAMAGE_TYPE type ) { unsigned long playerIdx = attacker.index; if( attacker.type == eOBJECTTYPE_TOTEM ) { cTotem* totem = OBJECTMANAGER->GetTotem( attacker.index ); if( totem == 0 ) return; sObject o = totem->GetAttacker(); if( o.type != eOBJECTTYPE_PLAYER ) return; playerIdx = o.index; } else if( attacker.type == eOBJECTTYPE_PLAYER ) { cPlayer* pAttacker = OBJECTMANAGER->GetPlayer( attacker.index ); if( pAttacker == NULL ) return; } else { return; } float distressPer = 0.0f; float distressPlus = 0.0f; cPlayer* pAttacker = OBJECTMANAGER->GetPlayer( playerIdx ); if( pAttacker ) { distressPer = pAttacker->GetStatus2Per( ePLAYER_STATUS_EXT_DISTRESS ); distressPlus = pAttacker->GetStatus2Plus( ePLAYER_STATUS_EXT_DISTRESS ); } /// ÃßÀû ½ÃÀ۽𣠰»½Å, ÃßÀû ½ÃÀÛÀ§Ä¡ °»½Å mFollowEndTime = NETWORK2->GetAccumTime() + mpMonsterInfo->mFollowTime; mFollowStartPos = mObjectPos; /// µî·Ï°ª °è»ê.. long calcPoint = 0; unsigned long calcDamage = 0; switch( type ) { case eTAKEDAMAGETYPE_DAMAGE: { /// ÃÖÃÊ °ø°ÝÀÚ¿¡ ´ëÇÑ Á¤º¸ µî·Ï.. if( mFirstAttackCharacter == 0 ) { mFirstAttackCharacter = playerIdx; cPlayer* pPlayer = NearGridFindPlayer( playerIdx, false ); if( pPlayer != NULL ) mFirstAttackParty = pPlayer->GetPartyIndex(); } calcPoint = (long)(damage * AGGRO_DAMAGE_RATE) + distressPoint; calcDamage = damage; if( distressPlus != 0.0f || distressPer != 0.0f ) { calcPoint = (long)(calcPoint + ( (calcPoint * distressPer) / 100) + distressPlus); } } break; case eTAKEDAMAGETYPE_DAMAGE_SETTARGET: { calcPoint = (long)(damage * AGGRO_DAMAGE_RATE) + distressPoint; calcDamage = damage; } break; case eTAKEDAMAGETYPE_HEAL: { calcPoint = (long)(damage * AGGRO_HEAL_RATE) + distressPoint; if( distressPlus != 0.0f || distressPer != 0.0f ) { calcPoint = (long)(calcPoint + ( (calcPoint * distressPer) / 100) + distressPlus); } } break; case eTAKEDAMAGETYPE_POTION: { calcPoint = (long)(damage * AGGRO_POTION_RATE) + distressPoint; } break; case eTAKEDAMAGETYPE_ADDPLAYER: { calcPoint = distressPoint; } break; default: return; } /// damage List¿¡ µî·Ï ¶Ç´Â °»½Å PerTakeDamage* perTakeDamage = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, playerIdx ); if( perTakeDamage == 0 ) { perTakeDamage = TAKEDAMAGEPOOL->AddTakeDamage( &mTakeDamageRoot, playerIdx, calcDamage, calcPoint ); if( perTakeDamage ) { /// player¿¡ µî·ÏÇÑ´Ù. cPlayer* pPlayer = GRIDMANAGER->GetPlayer( playerIdx ); if( pPlayer ) pPlayer->AddTargetingMonster( GetObjectID() ); } else { assert(0); } /// party Á¤º¸ µî·Ï cPlayer* pPlayer = GRIDMANAGER->GetPlayer( playerIdx ); if( pPlayer != NULL ) { unsigned long partyIdx = pPlayer->GetPartyIndex(); cParty* partyInfo = PARTYMAN->GetParty( partyIdx ); if( partyInfo ) { unsigned long* userArr = partyInfo->GetUserArr(); for( unsigned int i = 0; i < partyInfo->GetCount(); ++i, ++userArr ) { if( playerIdx == (*userArr) ) continue; cPlayer* pPartyPlayer = GRIDMANAGER->GetPlayer( (*userArr) ); if( pPartyPlayer == 0 ) continue; if( TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, (*userArr) ) == 0 ) { unsigned long partyDistress = 0; if( eTAKEDAMAGETYPE_DAMAGE == type ) partyDistress = 1; if( TAKEDAMAGEPOOL->AddTakeDamage( &mTakeDamageRoot, (*userArr), 0, partyDistress ) ) { /// player¿¡ µî·ÏÇÑ´Ù. pPartyPlayer->AddTargetingMonster( GetObjectID() ); } else { assert(0); } } } } } } else { perTakeDamage->takeDamage += calcDamage; if( calcPoint < 0 ) { if( perTakeDamage->distressPoint < (unsigned long)(calcPoint*(-1)) ) perTakeDamage->distressPoint = 0; else perTakeDamage->distressPoint += calcPoint; } else perTakeDamage->distressPoint += calcPoint; perTakeDamage->noChangeTime = 0; perTakeDamage->changeFlag = true; } if( GetStateDie() == true ) return; if( type == eTAKEDAMAGETYPE_DAMAGE_SETTARGET ) { if( SetTarget( eOBJECTTYPE_PLAYER, playerIdx ) == true ) ActionChange( eACT_ATTACK ); return; } else if( type == eTAKEDAMAGETYPE_NONETARGET ) return; /// Ÿ°Ù °»½Å.. cBaseObject* pCurTarget = GetTarget(); if( pCurTarget == 0 || calcPoint < 0 ) { /// ½Å±Ô °»½Å.. cPlayer* pNewTarget = 0; unsigned long maxPoint = 0; if( mTFixedPlayerIdx != 0 ) { cPlayer* perTarget = NearGridFindPlayer( mTFixedPlayerIdx, true ); if( perTarget ) SetTarget( eOBJECTTYPE_PLAYER, mTFixedPlayerIdx ); } PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { cPlayer* perTarget = NearGridFindPlayer( per->playerIdx, true ); if( perTarget ) { if( maxPoint < per->distressPoint ) pNewTarget = perTarget; } per = (PerTakeDamage*)per->next; } if( pNewTarget ) { /// Ÿ°Ù °»½Å if( SetTarget( pNewTarget->GetObjectType(), pNewTarget->GetObjectID() ) == false ) { /// ±âÁ¸ Ÿ°Ùµµ ¾ø°í ½Å±ÔŸ°Ùµµ ÀâÀ»¼ö ¾ø´Â °æ¿ì ȸ±Í È£Ãâ ClearTakeDamage(); ReservationComeback(); return; } } else { /// Ÿ°ÙÀ» »õ·Î ÀâÀ» ¼ö ¾ø´Â °æ¿ì if( SetTarget( eOBJECTTYPE_PLAYER, playerIdx ) == false ) { /// ±âÁ¸ Ÿ°Ùµµ ¾ø°í ½Å±ÔŸ°Ùµµ ÀâÀ»¼ö ¾ø´Â °æ¿ì ȸ±Í È£Ãâ ClearTakeDamage(); ReservationComeback(); return; } } ActionChange( eACT_ATTACK ); } else { PerTakeDamage* per = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, pCurTarget->GetObjectID() ); if( per == 0 ) { NETWORK2->PostServerEvent("cMonster::AddTakeDamage per == 0[%d]", pCurTarget->GetObjectID() ); cPlayer* pCheck = NearGridFindPlayer( playerIdx, true ); if( pCheck ) { /// ÇöÀç °ø°ÝÀÚ Å¸°ÙÆÃ.. SetTarget( eOBJECTTYPE_PLAYER, playerIdx ); } return; } if( mTFixedPlayerIdx == 0 ) { if( perTakeDamage == NULL ) { assert(NULL); return; } unsigned long maxPoint = (unsigned long)((float)per->distressPoint * 1.1f); if( maxPoint <= perTakeDamage->distressPoint ) { cPlayer* pCheck = NearGridFindPlayer( playerIdx, true ); if( pCheck ) { /// Ÿ°Ù º¯°æ if( SetTarget( eOBJECTTYPE_PLAYER, playerIdx ) == false ) return; } } } } } void cMonster::DelTakeDamagePlayer( unsigned long playerIdx ) { TAKEDAMAGEPOOL->ReleaseTakeDamage( &mTakeDamageRoot, playerIdx ); } void cMonster::ClearDistressPointPlayer( unsigned long playerIdx ) { PerTakeDamage* per = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, playerIdx ); if( per ) per->distressPoint = 0; else assert(0); if( mTarget.index == playerIdx ) ChangeActionTarget(); } void cMonster::ClearDistressPoint() { /// ½Å±Ô °»½Å.. PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { per->distressPoint = 0; per = (PerTakeDamage*)per->next; } } void cMonster::ClearTakeDamage() { /// ½Å±Ô °»½Å.. PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { unsigned long playerIdx = per->playerIdx; cPlayer* perPlayer = NearGridFindPlayer( per->playerIdx, false ); if( perPlayer ) perPlayer->DelTargetingMonster( GetObjectID() ); else { perPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( perPlayer ) perPlayer->DelTargetingMonster( GetObjectID() ); } per = (PerTakeDamage*)per->next; TAKEDAMAGEPOOL->ReleaseTakeDamage( &mTakeDamageRoot, playerIdx ); } TAKEDAMAGEPOOL->Shutdown(); } //void cMonster::AddTakeDamage( unsigned long playerIdx, unsigned long takeDamage ) //{ // /// óÀ½ °ø°ÝÀÚ ¿ì¼±±Ç ¼³Á¤ // if( mFirstAttackCharacter == 0 ) // { // mFirstAttackCharacter = playerIdx; // cPlayer* pPlayer = NearGridFindPlayer( playerIdx ); // if( pPlayer != NULL ) // mFirstAttackParty = pPlayer->GetPartyIndex(); // } // // /// °ø°Ý ¼º°øÀ̸é ÃßÀû ½Ã°£ Àç¼³Á¤ // mFollowEndTime = NETWORK2->GetAccumTime() + mpMonsterInfo->mFollowTime; // // cTakeDamageMap::cIterator find = mTakeDamageMap.Find( playerIdx ); // cTakeDamageMap::cIterator end = mTakeDamageMap.End(); // // if( find == end ) // { // if( mTakeDamageMap.Insert( playerIdx, takeDamage ) == NULL ) // assert(NULL); // } // else // (*find).mSecond = (*find).mSecond + takeDamage; // // /// ÃßÀûÀ̵¿ ³¡ - ¿ø·¡ À§·Î º¹±Í À̵¿ÀÎÁö üũ // if( mFollowEndMove == true ) // SetFollowEndMove( false ); /// º¹±ÍÁßÀÌ ¾Æ´ÔÀ¸·Î º¯°æ // // /// ¼±Á¤µÈ Ÿ°ÙÀÌ ¾øÀ¸¸é Ÿ°Ù º¯°æ // if( GetTarget() == NULL ) // { // SetTarget( eOBJECTTYPE_PLAYER, playerIdx ); // } // // if( GetStateDie() != true ) // SendSpeech( eMONSTERTALK_DAMAGE ); //} unsigned long cMonster::GetTakeDamage( unsigned long playerIdx ) { PerTakeDamage* per = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, playerIdx ); if( per ) return per->takeDamage; return 0; } eMONSTERATTACK_TYPE cMonster::SelectSkill() { ///// ÇöÀç ¼±Á¤µÅÀÖÀ¸¸é ¸®ÅÏ //if( mAttackType != eMONSTERATTACK_MAX ) // return mAttackType; /// Ÿ°Ù °´Ã¼ È®ÀÎ cPlayer* pTarget = (cPlayer*)GetTarget(); if( pTarget == NULL || pTarget->GetStateDie() == true ) { mAttackType = eMONSTERATTACK_MAX; return mAttackType; } // ¿ÀÅä´õ¹Ì´Â ÀϹݽºÅ³¸¸ »ç¿ë if( IsAutoDummy() == true ) return eMONSTERATTACK_NORMAL1; if( mModeInitSkillIdx != eMONSTERATTACK_MAX ) { sMonsterSkillScript* pMonsterSkillScript = SKILLSCRIPT->GetMonsterSkillInfo( mpMonsterInfo->mMonsterClassIdx, mModeInitSkillIdx ); if( pMonsterSkillScript == NULL ) { assert(NULL); return eMONSTERATTACK_MAX; } if( pMonsterSkillScript->mApplyType == eAPPLYTYPE_ENEMY && mTarget.type != eOBJECTTYPE_PLAYER ) ChangeActionTarget(); return SelectApplyTargetSkill( mpMonsterInfo->mMonsterClassIdx, mModeInitSkillIdx ); } /// ¸ðµå½ºÅ³ ¼±Á¤µÈ°ÍÀÌ ÀÖ°í ´ë»óÀÌ À̵¿ »óŰ¡ ¾Æ´Ï¸é ¸ðµå½ºÅ³ »ç¿ë if( mModeSkillIdx != eMONSTERATTACK_MAX && pTarget->GetState() != eOBJECT_STATE_MOVE ) { sMonsterSkillScript* pMonsterSkillScript = SKILLSCRIPT->GetMonsterSkillInfo( mpMonsterInfo->mMonsterClassIdx, mModeSkillIdx ); if( pMonsterSkillScript == NULL ) { assert(NULL); return eMONSTERATTACK_MAX; } if( pMonsterSkillScript->mApplyType == eAPPLYTYPE_ENEMY && mTarget.type == eOBJECTTYPE_MONSTER ) ChangeActionTarget(); mAttackType = mModeSkillIdx; return SelectApplyTargetSkill( mpMonsterInfo->mMonsterClassIdx, mModeSkillIdx ); } cCoolTime::cIterator iter; mTempSelectSkill.Clear(); if( mODDITY[eODDITYTYPE_SLEEP] != 0 ) { mAttackType = eMONSTERATTACK_MAX; return mAttackType; } if( mODDITY[eODDITYTYPE_STUN] != 0 ) { mAttackType = eMONSTERATTACK_MAX; return mAttackType; } unsigned long useTotalPer = 0; eMONSTERATTACK_TYPE attackType; for( iter = mSkillCoolTimeMap.Begin() ; iter != mSkillCoolTimeMap.End() ; ++iter ) { attackType = (eMONSTERATTACK_TYPE)(*iter).mFirst; /// ÄðŸÀÓ ½Ã°£ ¾ÈµÊ if( (*iter).mSecond > NETWORK2->GetAccumTime() ) { continue; } sMonsterSkillScript* pMonsterSkillScript = SKILLSCRIPT->GetMonsterSkillInfo( mpMonsterInfo->mMonsterClassIdx, attackType ); if( pMonsterSkillScript == NULL ) { assert(NULL); NETWORK2->PostServerEvent("Monster::SelectSkill pMonsterSkillScript[%d,%d] == NULL", mpMonsterInfo->mMonsterClassIdx, attackType); continue; } if( IsCantSkill( pMonsterSkillScript->mAttributeType, attackType ) == true ) continue; switch( pMonsterSkillScript->mUseHPCheck ) { case eMONSTERHPCHECK_NONE: break; case eMONSTERHPCHECK_LOWHP40: { if( GetMaxHP() == 0 ) { NETWORK2->PostServerEvent("0 divide 3"); continue; } if( mHP * 100 / GetMaxHP() >= SKILL_USE_HP40 ) continue; } break; case eMONSTERHPCHECK_LOWHP80: { if( GetMaxHP() == 0 ) { NETWORK2->PostServerEvent("0 divide 4"); continue; } if( mHP * 100 / GetMaxHP() >= SKILL_USE_HP80 ) continue; } break; } if( mMP < pMonsterSkillScript->mUseMP ) { continue; } if( pMonsterSkillScript->mSkillUsePer == 0 ) continue; /// ½ºÅ³ ¼±Á¤¿¡ ÇÊ¿äÇÑ Ç׸ñ ºñÀ² °è»ê unsigned long skillRate = CalcSkillRate( pTarget, attackType, pMonsterSkillScript->mSkillUsePer ); useTotalPer = useTotalPer + skillRate; /// Á¶°Ç¿¡ ¸¸Á·ÇÏ´Â °ø°ÝŸÀÔÀ» ´ã´Â´Ù. mTempSelectSkill.Insert( attackType, skillRate ); } if( useTotalPer == 0 ) return eMONSTERATTACK_MAX; /// ¼±ÅÃµÈ °ø°ÝŸÀÔÀÇ ºñÀ² Àüü ÇÕ°èÁß ÇÑÁöÁ¡À» Á¤ÇÑ´Ù. unsigned long randSelect = rand() % useTotalPer + 1; /// ¼±ÅÃµÈ ÇÑÁöÁ¡ÀÇ °ø°ÝŸÀÔ°ªÀ» ã¾Æ ¸®ÅÏÇÑ´Ù. cHashMap::cIterator sI = mTempSelectSkill.Begin(); cHashMap::cIterator sE = mTempSelectSkill.End(); for( ; sI != sE ; ++sI ) { unsigned long attackType = (*sI).mFirst; unsigned long rate = (*sI).mSecond; if( rate >= randSelect ) { //mAttackType = (eMONSTERATTACK_TYPE)attackType; //return mAttackType; mAttackType = (eMONSTERATTACK_TYPE)attackType; break; } randSelect = randSelect - rate; } return SelectApplyTargetSkill( mpMonsterInfo->mMonsterClassIdx, mAttackType ); } eMONSTERATTACK_TYPE cMonster::SelectApplyTargetSkill( unsigned long monsClassIdx, eMONSTERATTACK_TYPE attackType ) { sMonsterSkillScript* pMonsterSkillScript = SKILLSCRIPT->GetMonsterSkillInfo( monsClassIdx, attackType ); if( pMonsterSkillScript == NULL ) return eMONSTERATTACK_MAX; cRangeCheck rangeCheck; switch( pMonsterSkillScript->mApplyType ) { case eAPPLYTYPE_SELF: SetTarget( mObject.type, mObject.index ); return attackType; case eAPPLYTYPE_ENEMY: { if( mTarget.type == eOBJECTTYPE_MONSTER ) ChangeActionTarget(); return attackType; } break; case eAPPLYTYPE_BUDDY: { cLongAry buddyAry; buddyAry.Clear(); cMonster* pMonster = GRIDMANAGER->FindFirstMonster( this ); while( pMonster != NULL ) { if( pMonster->GetStateDie() == true ) { pMonster = GRIDMANAGER->FindNextMonster(); continue; } if( pMonster->GetTakeDamageRoot()->count == 0 ) { pMonster = GRIDMANAGER->FindNextMonster(); continue; } rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); if( rangeCheck.IsNotRange( mObjectPos, pMonster->GetPos() ) ) { pMonster = GRIDMANAGER->FindNextMonster(); continue; } buddyAry.PushBack( pMonster->GetObjectID() ); pMonster = GRIDMANAGER->FindNextMonster(); } if( buddyAry.GetSize() != 0 ) { unsigned long selectRand = rand() % buddyAry.GetSize(); SetTarget( eOBJECTTYPE_MONSTER, buddyAry[selectRand] ); return attackType; } } break; case eAPPLYTYPE_FAR: { /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; unsigned long selectPlayer = 0; float topValue = 0; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { /// ½Ã¾ß ¹üÀ§ ¾È¿¡ ÀÕ´Â Ç÷¹À̾îÁß °¡Àå ¸Õ Äɸ¯ÅÍ float value = ( mObjectPos - pPlayer->GetPos() ).Length(); if( mpMonsterInfo->mSeekRange >= value ) { if( value > topValue ) { topValue = value; selectPlayer = per->playerIdx; } } } per = (PerTakeDamage*)per->next; } SetTarget( eOBJECTTYPE_PLAYER, selectPlayer ); return attackType; } break; case eAPPLYTYPE_RANDOM: { cLongAry randAry; randAry.Clear(); /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { if( rangeCheck.IsRange( mObjectPos, pPlayer->GetPos() ) == true ) randAry.PushBack( per->playerIdx ); } per = (PerTakeDamage*)per->next; } if( randAry.GetSize() != 0 ) { unsigned long selectRand = rand() % randAry.GetSize(); SetTarget( eOBJECTTYPE_PLAYER, randAry[selectRand] ); return attackType; } } break; case eAPPLYTYPE_DISTRESS2: { cPArray sortAry; sortAry.Clear(); /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { if( rangeCheck.IsRange( mObjectPos, pPlayer->GetPos() ) == true ) sortAry.PushBack( per ); } per = (PerTakeDamage*)per->next; } std::sort( sortAry.Begin(), sortAry.End(), DistressCompare ); for( unsigned long i = 2 ; i > 0 ; --i ) { if( i <= sortAry.GetSize() ) { if( i > 0 ) { PerTakeDamage* per2 = (PerTakeDamage*)sortAry[i-1]; if( per2 != NULL ) { SetTarget( eOBJECTTYPE_PLAYER, per2->playerIdx ); return attackType; } } } } } break; case eAPPLYTYPE_DISTRESS3: { cPArray sortAry; sortAry.Clear(); /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { if( rangeCheck.IsRange( mObjectPos, pPlayer->GetPos() ) == true ) sortAry.PushBack( per ); } per = (PerTakeDamage*)per->next; } std::sort( sortAry.Begin(), sortAry.End(), DistressCompare ); for( unsigned long i = 3 ; i > 0 ; --i ) { if( i <= sortAry.GetSize() ) { if( i > 0 ) { PerTakeDamage* per2 = (PerTakeDamage*)sortAry[i-1]; if( per2 != NULL ) { SetTarget( eOBJECTTYPE_PLAYER, per2->playerIdx ); return attackType; } } } } } break; case eAPPLYTYPE_DISTRESSMIN: { /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; unsigned long selectPlayer = 0; unsigned long topValue = ULONG_MAX; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { if( rangeCheck.IsRange( mObjectPos, pPlayer->GetPos() ) == true ) { unsigned long value = per->distressPoint; if( value < topValue ) { topValue = value; selectPlayer = per->playerIdx; } } } per = (PerTakeDamage*)per->next; } if( selectPlayer != 0 ) { SetTarget( eOBJECTTYPE_PLAYER, selectPlayer ); return attackType; } } break; case eAPPLYTYPE_HPMAX: { /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; unsigned long selectPlayer = 0; unsigned long topValue = 0; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); if( rangeCheck.IsRange( mObjectPos, pPlayer->GetPos() ) == true ) { unsigned long value = pPlayer->GetMaxHP(); if( value > topValue ) { topValue = value; selectPlayer = per->playerIdx; } } } per = (PerTakeDamage*)per->next; } if( selectPlayer == 0 ) { SetTarget( eOBJECTTYPE_PLAYER, selectPlayer ); return attackType; } } break; case eAPPLYTYPE_HPMIN: { /// º¸½º¸¦ °ø°ÝÇÏ´ø °ø°ÝÀÚ ¸ñ·ÏÀ» ÀڽĿ¡ ³ÖÀ½ if( mTakeDamageRoot.count == 0 ) return eMONSTERATTACK_MAX; unsigned long selectPlayer = 0; unsigned long topValue = ULONG_MAX; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { cPlayer* pPlayer = GRIDMANAGER->GetPlayer( per->playerIdx ); if( pPlayer != NULL ) { rangeCheck.SetRadius( (float)mpMonsterInfo->mSeekRange ); if( rangeCheck.IsRange( mObjectPos, pPlayer->GetPos() ) == true ) { unsigned long value = pPlayer->GetMaxHP(); if( value < topValue ) { topValue = value; selectPlayer = per->playerIdx; } } } per = (PerTakeDamage*)per->next; } if( selectPlayer == 0 ) { SetTarget( eOBJECTTYPE_PLAYER, selectPlayer ); return attackType; } } break; } return eMONSTERATTACK_MAX; } void cMonster::UpdateSkillCoolTime( eMONSTERATTACK_TYPE attackType ) { if( eMONSTERATTACK_MAX > attackType ) { cCoolTime::cIterator iter = mSkillCoolTimeMap.Find( attackType ); cCoolTime::cIterator end = mSkillCoolTimeMap.End(); sMonsterSkillScript* pSkill = SKILLSCRIPT->GetMonsterSkillInfo( mpMonsterInfo->mMonsterClassIdx, attackType ); if( pSkill == NULL ) { assert(NULL); NETWORK2->PostServerEvent("monster coolTime error - script MonClassIdx[%d], attackType[%d]",mpMonsterInfo->mMonsterClassIdx, attackType ); return; } if( iter != end ) { (*iter).mSecond = NETWORK2->GetAccumTime() + pSkill->mCoolTime; } } else { cCoolTime::cIterator iter = mEliteCoolTimeMap.Find( attackType ); cCoolTime::cIterator end = mEliteCoolTimeMap.End(); sMonsterSkillScript* pSkill = SKILLSCRIPT->GetMonsterSkillInfo( mpMonsterInfo->mMonsterClassIdx, attackType ); if( pSkill == NULL ) { assert(NULL); NETWORK2->PostServerEvent("monster coolTime error - script MonClassIdx[%d], attackType[%d]",mpMonsterInfo->mMonsterClassIdx, attackType ); return; } if( iter != end ) { (*iter).mSecond = NETWORK2->GetAccumTime() + pSkill->mCoolTime; } else { mEliteCoolTimeMap.Insert( attackType, NETWORK2->GetAccumTime() + pSkill->mCoolTime ); } } } void cMonster::CalcSkillWaitTime( unsigned long skillEndTime ) { mSkillWaitEndTime = skillEndTime + SKILL_WAIT_TIME; } bool cMonster::IsSkillWaitEnd() { return mSkillWaitEndTime <= NETWORK2->GetAccumTime(); } inline bool cMonster::GetStateDie() { switch( GetActionID() ) { case eACT_DIE: return true; } return false; } void cMonster::OutsideDestroy() { mOutsideDestroy = true; ActionChange( eACT_DIE ); MSG_SYN_MONSTER_DESTROY synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_DESTROY_SYN; synMsg.mMonsterIdx = mObject.index; NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_DESTROY) ); } void cMonster::SetStateOddity( long* pOddity ) { for( int i = 0 ; i < eODDITYTYPE_MAX ; ++i ) { if( mODDITY[i] != pOddity[i] ) { mODDITY[i] = pOddity[i]; if( pOddity[i] != 0 ) { /// »óÅ ÀÌ»óÁß Å¬¶óÀÌ¾ðÆ®¿¡ ¸Þ¼¼Áö¸¦ ¹ß¼Û ÇØÁà¾ß ÇÏ´Â ºÎºÐ ó¸® switch(i) { case eODDITYTYPE_CANTSKILL_PHY: { if( GetActionID() == eACT_ATTACK /*&& IsImmuneApplyType( eSTATUSPLUS_STOPSKILL_PHY ) == false*/ ) SKILLMANAGER->CastSkillCancel( mObject, true, eATTRIBUTETYPE_PHYSICAL ); } break; case eODDITYTYPE_CANTSKILL_MAG: { if( GetActionID() == eACT_ATTACK /*&& IsImmuneApplyType( eSTATUSPLUS_STOPSKILL_MAG ) == false*/ ) SKILLMANAGER->CastSkillCancel( mObject, true, eATTRIBUTETYPE_MAGIC ); } break; case eODDITYTYPE_CANTMOVE: { MoveStop( true ); } break; case eODDITYTYPE_SLEEP: { MoveStop( true ); if( GetActionID() == eACT_ATTACK /*&& IsImmuneApplyType( eSTATUSPLUS_SLEEP ) == false */) SKILLMANAGER->CastSkillCancel( mObject, true, eATTRIBUTETYPE_NONE ); } break; case eODDITYTYPE_STUN: { MoveStop( true ); if( GetActionID() == eACT_ATTACK /*&& IsImmuneApplyType( eSTATUSPLUS_STUN ) == false*/ ) SKILLMANAGER->CastSkillCancel( mObject, true, eATTRIBUTETYPE_NONE ); } break; } } } } } bool cMonster::IsCantSkill( unsigned long attributeType ) { if( mODDITY[eODDITYTYPE_SLEEP] != 0 ) return true; if( mODDITY[eODDITYTYPE_STUN] != 0 ) return true; if( eMONSTERATTACK_NORMAL1 == mAttackType || eMONSTERATTACK_NORMAL2 == mAttackType || eMONSTERATTACK_MAX == mAttackType ) return false; if( attributeType == eATTRIBUTETYPE_PHYSICAL ) { if( mODDITY[eODDITYTYPE_CANTSKILL_PHY] == 0 ) return false; else return true; } else { if( mODDITY[eODDITYTYPE_CANTSKILL_MAG] == 0 ) return false; else return true; } } bool cMonster::IsCantSkill( unsigned long attributeType, eMONSTERATTACK_TYPE attackType ) { if( mODDITY[eODDITYTYPE_SLEEP] != 0 ) return true; if( mODDITY[eODDITYTYPE_STUN] != 0 ) return true; if( eMONSTERATTACK_NORMAL1 == attackType || eMONSTERATTACK_NORMAL2 == attackType || eMONSTERATTACK_MAX == attackType ) return false; if( attributeType == eATTRIBUTETYPE_PHYSICAL ) { if( mODDITY[eODDITYTYPE_CANTSKILL_PHY] == 0 ) return false; else return true; } else { if( mODDITY[eODDITYTYPE_CANTSKILL_MAG] == 0 ) return false; else return true; } } void cMonster::TargetChange( sObject attacker, long distressPoint ) { /// ¾î±×·Î ¼öÄ¡ Áõ°¡ AddTakeDamage( attacker, 0, distressPoint, eTAKEDAMAGETYPE_DAMAGE_SETTARGET ); /// ÃßÀû »óÅ ¼³Á¤ if( GetStateDie() == false ) ActionChange( eACT_ATTACK ); } void cMonster::SetSkillPushPull( unsigned short type, cBaseObject* pAttacker, unsigned long range ) { if( pAttacker == NULL ) return; if( GetActionID() == eACT_DIE && GetActionID() == eACT_PUSHPULL ) return; NiPoint2 attackerPos = pAttacker->GetPos(); if( type == 0 ) return; /// °ø°ÝÀÚ¿¡¼­ Ÿ°Ù(ÇöÀç¿ÀºêÁ§Æ®)ÀÇ ¹æÇâ»êÃâ NiPoint2 dir; dir.x = mObjectPos.x - attackerPos.x; dir.y = mObjectPos.y - attackerPos.y; dir.Unitize(); float fixRange = 0.0f; NiPoint2 targetPos = mObjectPos; if( type == eSTATUSPLUS_AROUND_PUSH ) { fixRange = OBJECTMANAGER->ObjectSizeRange( this, pAttacker, (float)range ); if( (mObjectPos - attackerPos).Length() > fixRange ) return; targetPos = attackerPos + dir * fixRange; } else if( type == eSTATUSPLUS_AROUND_PULL ) { fixRange = OBJECTMANAGER->ObjectSizeRange( this, pAttacker, 100.0f ); if( (mObjectPos - attackerPos).Length() < fixRange ) return; targetPos = attackerPos + dir * fixRange; } else if( type == eSTATUSPLUS_TARGET_PUSH ) { targetPos = mObjectPos + dir * (float)range; } NiPoint2 destPos = mObjectPos; /// ¸ñÀûÁö±îÁöÀÇ ¹æÇâÁ¤º¸ NiPoint2 divideDir = targetPos - mObjectPos; float moveRange = divideDir.Unitize(); /// ºÐÇÒ ¼ýÀÚ unsigned long divideCnt = 10; /// À̵¿°Å¸®¸¦ ºÐÇÒ float divideRange = moveRange / (float)divideCnt; for( unsigned long i = 0 ; i < divideCnt ; ++i ) /// ¸ÕÀú ¼±ÃâµÈ ³¡Á¡ºÎÅÍ °ø°ÝÀÚ¿¡ °¡±î¿î À§Ä¡·Î üũ { /// ¸ñÀûÁö¿¡¼­ ºÐÇÒÇÑ °Å¸®¸¸Å­ »©°¡¸é¼­ À̵¿°¡´ÉÇÑÁö üũÈÄ °¡´ÉÇÏ¸é ±×À§Ä¡·Î À̵¿ÇÑ´Ù. NiPoint2 pos = mObjectPos + ( divideDir * ( moveRange - ( divideRange * i ) ) ); if( IsPushPullPossible( mObjectPos, pos ) == true ) { destPos = pos; break; } } MSG_SYN_SKLL_PUSHPULL sync; sync.Category = NM_SKILL; sync.Protocol = NM_SKILL_PUSHPULL_SYN; sync.mTarget = mObject; sync.mPosX = destPos.x; sync.mPosY = destPos.y; NETWORK2->QuickSend( this, (char*)&sync, sizeof(sync) ); mNextPos = destPos; ActionChange( eACT_PUSHPULL ); } bool cMonster::IsPushPullPossible( NiPoint2 startPos, NiPoint2 goalPos ) { switch( NETWORK2->GetServerType() ) { case _E_ST_ID_PVP_: { cBaseDeathMatch* pDMObject = PVPMANAGER->GetPvPDMObject( mMapNumber ); if( pDMObject == NULL ) return false; if( pDMObject->IsMovePossible( startPos, goalPos ) == false ) return false; } break; case _E_ST_ID_THEME_: case _E_ST_ID_TUTORIAL_: { cThemeObject* ptheme = THEMEMANAGER->GetThemeObject( mMapNumber ); if( ptheme == NULL ) return false; if( ptheme->IsMovePossible( startPos, goalPos ) == false ) return false; } break; } /// Á÷¼± ÄÚ½º À̵¿ °¡´É ÀÎÁö È®ÀÎ if( AIMANAGER->IsPossible( mMapNumber, startPos, goalPos, mObject ) == false ) return false; return true; } unsigned long cMonster::CalcPhysicAttack( unsigned long skillAttack ) { float num391 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 391 ); // °ø°Ý·Â(¸ó½ºÅÍ) // A = ¸ó½ºÅÍ °ø°Ý·Â // B = [¸ó½ºÅÍ] Lv * {num391} // C = (( 100 + ¹öÇÁ¼º °ø°Ý·Â[%]°ª) / 100 ) // D = ((A + B ) * C) + ¹öÇÁ¼º °ø°Ý·Â[+-]°ª float valueA = (float)skillAttack; float valueB = mpMonsterInfo->mLevel * num391; float valueC = (( 100 + mStatusPer.mPhysicAttack ) / 100 ); float attack = (( valueA + valueB ) * valueC ) + mStatusPlus.mPhysicAttack; if( attack < 0.0f ) return 0; return FloatToInt( attack ); } unsigned long cMonster::CalcPhysicRangeAttack( unsigned long skillAttack ) { float num391 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 391 ); // °ø°Ý·Â(¸ó½ºÅÍ) // A = ¸ó½ºÅÍ °ø°Ý·Â // B = [¸ó½ºÅÍ] Lv * {num391} // C = (( 100 + ¹öÇÁ¼º °ø°Ý·Â[%]°ª) / 100 ) // D = ((A + B ) * C) + ¹öÇÁ¼º °ø°Ý·Â[+-]°ª float valueA = (float)skillAttack; float valueB = mpMonsterInfo->mLevel * num391; float valueC = (( 100 + mStatusPer.mPhysicRangeAttack ) / 100 ); float attack = (( valueA + valueB ) * valueC ) + mStatusPlus.mPhysicRangeAttack; if( attack < 0.0f ) return 0; return FloatToInt( attack ); } unsigned long cMonster::CalcMagicAttack( unsigned long skillAttack ) { float num391 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 391 ); // °ø°Ý·Â(¸ó½ºÅÍ) // A = ¸ó½ºÅÍ °ø°Ý·Â // B = [¸ó½ºÅÍ] Lv * {num391} // C = (( 100 + ¹öÇÁ¼º °ø°Ý·Â[%]°ª) / 100 ) // D = ((A + B ) * C) + ¹öÇÁ¼º °ø°Ý·Â[+-]°ª float valueA = (float)skillAttack; float valueB = mpMonsterInfo->mLevel * num391; float valueC = (( 100 + mStatusPer.mMagicAttack ) / 100 ); float attack = (( valueA + valueB ) * valueC ) + mStatusPlus.mMagicAttack; if( attack < 0.0f ) return 0; return FloatToInt( attack ); } unsigned long cMonster::GetPhysicDefense() { float num401 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 401 ); // ¹æ¾î·Â(¹°¸®) // A = ij¸¯ÅÍ ½ºÅȹ°¸® ¹æ¾î·Â // B = ¾ÆÀÌÅÛ ¹°¸® ¹æ¾î·Â // C = ((100 + ¹öÇÁ¼º ¹°¸® ¹æ¾î·Â[%]°ª + ¾ÆÀÌÅÛ ¹°¸® ¹æ¾î·Â[%]°ª) / 100) // D = ((A / {num401} + B / {num402} ) * C) + ¹öÇÁ¼º ¹°¸® ¹æ¾î·Â[+-]°ª + ¾ÆÀÌÅÛ ¹°¸® ¹æ¾î·Â[+-]°ª // ¸ó½ºÅÍÀÇ °æ¿ì: ½ºÅÈ ¹°¸® ¹æ¾î·Â = ¸ó½ºÅÍ ¹°¸® ¹æ¾î·Â // ¡Ø ¸ó½ºÅÍ´Â ¾ÆÀÌÅÛÀÌ ¾ø´Ù. float valueA = mpMonsterInfo->mDef; float valueC = (( 100 + mStatusPer.mPhysicDefense ) / 100 ); float def = (( valueA / num401 ) * valueC ) + mStatusPlus.mPhysicDefense; if( def < 0.0f ) return 0; return FloatToInt( def ); } unsigned long cMonster::GetMagicDefense() { float num431 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 431 ); // ¹æ¾î·Â(¸¶¹ý) // A = ij¸¯ÅÍ ½ºÅȸ¶¹ý ¹æ¾î·Â // B = ¾ÆÀÌÅÛ ¸¶¹ý ¹æ¾î·Â // C = ((100 + ¹öÇÁ¼º ¸¶¹ý ¹æ¾î·Â[%]°ª + ¾ÆÀÌÅÛ ¸¶¹ý ¹æ¾î·Â[%]°ª) / 100) // D = ((A /{num431} + B / {num432} ) * C) + ¹öÇÁ¼º ¹°¸® ¹æ¾î·Â[+-]°ª + ¾ÆÀÌÅÛ ¸¶¹ý ¹æ¾î·Â[+-]°ª // ¸ó½ºÅÍÀÇ °æ¿ì: ½ºÅÈ ¸¶¹ý ¹æ¾î·Â = ¸ó½ºÅÍ ¸¶¹ý ¹æ¾î·Â // ¡Ø ¸ó½ºÅÍ´Â ¾ÆÀÌÅÛÀÌ ¾ø´Ù. float valueA = mpMonsterInfo->mMdef; float valueC = (( 100 + mStatusPer.mMagicDefense ) / 100 ); float def = (( valueA / num431 ) * valueC ) + mStatusPlus.mMagicDefense; if( def < 0.0f ) return 0; return FloatToInt( def ); } unsigned long cMonster::GetPhysicAvoid() { float num102 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 102 ); /// ¸ó½ºÅÍÀÇ °æ¿ì, [( [¹æ¾îÀÚ] ij¸¯ÅÍ ½ºÅÈ È¸ÇÇ(ÀúÇ×·Â) ¼öÄ¡ + ¾ÆÀÌÅÛ È¸ÇÇ(ÀúÇ×·Â) ¼öÄ¡ ) = ȸÇÇ ¼öÄ¡]·Î °è»ê float avoid = mpMonsterInfo->mAvoid; // C = (( [¹æ¾îÀÚ] ij¸¯ÅÍ ½ºÅÈ È¸ÇÇ ¼öÄ¡ + ¾ÆÀÌÅÛ È¸ÇÇ ¼öÄ¡ ) * ((100 + ¹öÇÁ¼º ȸÇÇ ¼öÄ¡[%]°ª) / 100) + ¹öÇÁ¼º ȸÇÇ ¼öÄ¡[+-]°ª )) * {num102} avoid = (avoid * ( ( 100 + mStatusPer.mPhysicAvoid ) / 100 ) + mStatusPlus.mPhysicAvoid ) * num102; if( avoid < 0.0f ) return 0; return FloatToInt( avoid ); } unsigned long cMonster::GetMagicAvoid() { float num132 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 132 ); /// ¸ó½ºÅÍÀÇ °æ¿ì, [( [¹æ¾îÀÚ] ij¸¯ÅÍ ½ºÅÈ È¸ÇÇ(ÀúÇ×·Â) ¼öÄ¡ + ¾ÆÀÌÅÛ È¸ÇÇ(ÀúÇ×·Â) ¼öÄ¡ ) = ȸÇÇ ¼öÄ¡]·Î °è»ê float avoid = mpMonsterInfo->mAvoid; // C = (( [¹æ¾îÀÚ] ij¸¯ÅÍ ½ºÅÈ È¸ÇÇ ¼öÄ¡ + ¾ÆÀÌÅÛ È¸ÇÇ ¼öÄ¡ ) * ((100 + ¹öÇÁ¼º ȸÇÇ ¼öÄ¡[%]°ª) / 100) + ¹öÇÁ¼º ȸÇÇ ¼öÄ¡[+-]°ª )) * {num132} avoid = (avoid * ( ( 100 + mStatusPer.mMagicAvoid ) / 100 ) + mStatusPlus.mMagicAvoid ) * num132; if( avoid < 0.0f ) return 0; return FloatToInt( avoid ); } unsigned long cMonster::GetPhysicAttackRate() { float num101 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 101 ); float num102 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 102 ); // ¸ó½ºÅÍÀÇ °æ¿ì, [( [°ø°ÝÀÚ] ij¸¯ÅÍ ½ºÅÈ ¸íÁß(¸¶¹ý ¸íÁß) ¼öÄ¡ + ¾ÆÀÌÅÛ ¸íÁß(¸¶¹ý ¸íÁß) ¼öÄ¡ ) = ¸íÁß ¼öÄ¡]·Î °è»ê // A = {num101} + (( [°ø°ÝÀÚ] ij¸¯ÅÍ ½ºÅÈ ¸íÁß ¼öÄ¡) * ((100 + [°ø°ÝÀÚ]¾ÆÀÌÅÛ ¸íÁß ¼öÄ¡[%]°ª + [°ø°ÝÀÚ]¹öÇÁ¼º ¸íÁß ¼öÄ¡[%]°ª) / 100) + [°ø°ÝÀÚ]¾ÆÀÌÅÛ ¸íÁß ¼öÄ¡[+-]°ª + [°ø°ÝÀÚ]¹öÇÁ¼º ¸íÁß ¼öÄ¡[+-]°ª ) * {num102} float attackRate = (float)mpMonsterInfo->mHit; attackRate = num101 + (( attackRate * ( ( 100 + mStatusPer.mPhysicAttackRate ) / 100 ) + mStatusPlus.mPhysicAttackRate ) * num102 ); if( attackRate < 0.0f ) return 0; return FloatToInt( attackRate ); } unsigned long cMonster::GetMagicAttackRate() { float num131 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 131 ); float num132 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 132 ); // ¡Ø ¸ó½ºÅÍ ±âº» ¸¶¹ý ¸íÁßÀ²Àº ½ºÅ©¸³Æ®¿¡ ÀÖ´Â ¸íÁßÀ²À» °°ÀÌ ¾´´Ù. - °ªÀÌ Æ²¸®Áö ¾Ê¾Æ µû·Î ±âÀÔÇÒ ÇÊ¿ä ¾ø´Ù°íÇÔ // ¸ó½ºÅÍÀÇ °æ¿ì, [( [°ø°ÝÀÚ] ij¸¯ÅÍ ½ºÅÈ ¸íÁß(¸¶¹ý ¸íÁß) ¼öÄ¡ + ¾ÆÀÌÅÛ ¸íÁß(¸¶¹ý ¸íÁß) ¼öÄ¡ ) = ¸íÁß ¼öÄ¡]·Î °è»ê // A = {num131} + (( [°ø°ÝÀÚ] ij¸¯ÅÍ ½ºÅÈ ¸¶¹ý ¸íÁß ¼öÄ¡) * ((100 + [°ø°ÝÀÚ]¾ÆÀÌÅÛ ¸¶¹ý ¸íÁß ¼öÄ¡[%]°ª + [°ø°ÝÀÚ]¹öÇÁ¼º ¸¶¹ý ¸íÁß ¼öÄ¡[%]°ª) / 100) + [°ø°ÝÀÚ]¾ÆÀÌÅÛ ¸¶¹ý ¸íÁß ¼öÄ¡[+-]°ª + [°ø°ÝÀÚ]¹öÇÁ¼º ¸¶¹ý ¸íÁß ¼öÄ¡[+-]°ª ) * {num132} float attackRate = (float)mpMonsterInfo->mHit; attackRate = num131 + (( attackRate * ( ( 100 + mStatusPer.mMagicAttackRate ) / 100 ) + mStatusPlus.mMagicAttackRate ) * num132 ); if( attackRate < 0.0f ) return 0; return FloatToInt( attackRate ); } //unsigned long cMonster::CalcPhysicCritical( unsigned long physicCritical ) //{ // long tempPhysicCritical = (long)( physicCritical // + ( physicCritical * mStatusPer.mPhysicCritical / 100 ) // + mStatusPlus.mPhysicCritical ); // // return tempPhysicCritical < 0 ? 0 : tempPhysicCritical; //} // // //unsigned long cMonster::CalcMagicCritical( unsigned long magicCritical ) //{ // long tempMagicCritical = (long)( magicCritical // + ( magicCritical * mStatusPer.mMagicCritical / 100 ) // + mStatusPlus.mMagicCritical ); // // return tempMagicCritical < 0 ? 0 : tempMagicCritical; //} float cMonster::GetAttackSpeed() { if( mStatusPer.mAttackSpeed == 0.0f ) return 1.0f; float attackSpeed = ( 100 + mStatusPer.mAttackSpeed ) / 100; if( attackSpeed <= 0.0f ) attackSpeed = 0.1f; if( attackSpeed >= 2.0f ) attackSpeed = 1.9f; return attackSpeed; } float cMonster::CalcStatusSkillRange( float skillRange, eRANGETYPE mRangeType ) { /// ½ºÅ³ »ç°Å¸® float range = skillRange; /// È¿°ú »ç°Å¸® float statusRangePlus = 0; float statusRangePer = 0; if( mRangeType == eRANGETYPE_CLOSE ) { statusRangePlus = mStatusPlus.mInRange; statusRangePer = mStatusPer.mInRange; } else if( mRangeType == eRANGETYPE_LONG ) { statusRangePlus = mStatusPlus.mOutRange; statusRangePer = mStatusPer.mOutRange; } else { assert(NULL); NETWORK2->PostServerEvent("cMonster::CalcStatusSkillRange mRangeType[%d] Err", mRangeType ); } /// »ç°Å¸® °è»ê range = range * ( ( 100 + statusRangePer ) / 100 ) + statusRangePlus; return range; } unsigned short cMonster::GetMoveSpeed() { float moveSpeed = ( mStatusBase.mMoveSpeed + ( mStatusBase.mMoveSpeed * mStatusPer.mMoveSpeed / 100 ) + mStatusPlus.mMoveSpeed ); return moveSpeed < 0.0f ? 0 : (unsigned short)moveSpeed; } unsigned short cMonster::SetMoveSpeed( unsigned long moveSpeed, eMOVE_SPEED_TYPE moveSpeedType ) { mMoveSpeedType = moveSpeedType; mStatusBase.mMoveSpeed = (float)moveSpeed; return GetMoveSpeed(); } void cMonster::SendMoveSpeed() { MSG_SYN_MONSTER_MOVESPEED synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_MOVESPEED_SYN; synMsg.mMonsterIdx = mObject.index; synMsg.mMoveSpeed = (unsigned short)GetMoveSpeed(); NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(synMsg) ); } unsigned long cMonster::HPDamage( sObject attacker, unsigned long damage, bool* die, bool msgSend, bool cri ) { if( GetMaxHP() == 0 ) { NETWORK2->PostServerEvent("0 divide 5"); return 0; //¼öÁ¤ÇÔ realDamage; } /// µµ¸Á Á¶°Ç üũ unsigned long beforeHPPer = mHP * 100 / GetMaxHP(); /// ÀÌÀü hp % /// ½ÇÁ¦ Àû¿ëµÈ µ¥¹ÌÁö unsigned long realDamage = 0; *die = false; if( IsAutoDummy() == true ) damage = 1; if( GetStateDie() == true ) { *die = true; return realDamage; } if( mpRegenMonsterInfo && mpRegenMonsterInfo->mFamilyNum != 0 ) AIMANAGER->FamilyAttack( mObject.index, mpRegenMonsterInfo->mFamilyNum, attacker ); /// ÇöÀç HP°¡ °ø°Ý ¹ÞÀº µ¥¹ÌÁö º¸´Ù ÀÛÀº°æ¿ì if( mHP <= damage ) { if( attacker.type == eOBJECTTYPE_PLAYER ) mLastAttacker = attacker.index; /// ¸ó½ºÅÍHP 0À¸·Î ¹Ù²Ù°í ³²¾ÆÀÖ´ø HP¸¸Å­¸¸ ¸®ÅÏ realDamage = mHP; mHP = 0; *die = true; ActionChange( eACT_DIE ); /// Á×À» ¶§ ´ë»ç ±¸ºÐ mCriDie = cri; } else { /// Àáµé¾î ÀÖ´Â »óŶó¸é Ç®¾î ÁØ´Ù. if( mODDITY[eODDITYTYPE_SLEEP] != 0 ) { cSkillInfluenceSet::cIterator begin = mInfluenceSet.Begin(); cSkillInfluenceSet::cIterator end = mInfluenceSet.End(); cInfluenceObject* pInf = NULL; unsigned long influenceIdx = 0; while( begin != end ) { influenceIdx = (*begin++); pInf = SKILLMANAGER->GetInfluence( influenceIdx ); if( pInf == NULL ) continue; if( pInf->IsSleep() == true ) SKILLMANAGER->DeleteInfluenceList( influenceIdx ); } } /// µ¥¹ÌÁö¸¦ ¹ÞÀ¸¸é Ç®¸®´Â È¿°úµé »èÁ¦Çϱâ if( mDeleteTypeDamagedAry.GetSize() > 0 ) { cLongAry::cIterator begin = mDeleteTypeDamagedAry.Begin(); cLongAry::cIterator end = mDeleteTypeDamagedAry.End(); cInfluenceObject* pInf = NULL; unsigned long influenceIdx = 0; while( begin != end ) { influenceIdx = (*begin++); pInf = SKILLMANAGER->GetInfluence( influenceIdx ); if( pInf == NULL ) continue; if( pInf->GetDeleteType() == eDELETETYPE_PLAYER_DAMAGED ) SKILLMANAGER->DeleteInfluenceList( influenceIdx ); } } /// µ¥¹ÌÁö ¸¸Å­ °¨¼Ò½ÃŰ°í µ¥¹ÌÁö·® ¸®ÅÏ realDamage = damage; mHP -= damage; } /// °ø°Ý ¼º°øÀ̸é ÃßÀû ½Ã°£ Àç¼³Á¤ mFollowEndTime = NETWORK2->GetAccumTime() + mpMonsterInfo->mFollowTime; /// µµ¸Á Á¶°Ç üũ unsigned long afterHPPer = mHP * 100 / GetMaxHP(); /// ÇöÀç hp % switch( mpMonsterInfo->mEscapeType ) { case eESCAPETYPE_HP50LOW: { if( beforeHPPer > ESCAPE_HP50 && afterHPPer < ESCAPE_HP50 ) { unsigned long randSelect = rand() % 100 + 1; if( mpMonsterInfo->mEscapePer >= randSelect ) SetEscape(); } } break; case eESCAPETYPE_HP30LOW: { if( beforeHPPer > ESCAPE_HP30 && afterHPPer < ESCAPE_HP30 ) { unsigned long randSelect = rand() % 100 + 1; if( mpMonsterInfo->mEscapePer >= randSelect ) SetEscape(); } } break; } if( msgSend == true ) { MSG_SYN_MONSTER_HP synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_HP_SYN; synMsg.mMonsterIdx = GetObjectID(); synMsg.mHP = mHP; synMsg.mMaxHP = GetMaxHP(); synMsg.mDie = GetStateDie(); NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_HP) ); } /// ¼®»ó ¸ó½ºÅÍ Àΰæ¿ì ÀüÀå ÆÀ¿øµé¿¡°Ô ¸Þ¼¼Áö ¹ß¼Û if( mDMTeamType != ePVPDM_TEAMTYPE_MAX ) { if( NETWORK2->GetInDunMapNum() == MAP_DEATHMATCH ) { cDeathMatchObject* pObject = (cDeathMatchObject*)PVPMANAGER->GetPvPDMObject( mMapNumber ); if( pObject != NULL ) pObject->SyncStoneHP( mDMTeamType, mHP ); } } return realDamage; } void cMonster::HPUse( unsigned long useValue, bool msgSend ) { /// ÇöÀç MP°¡ °ø°Ý ¹ÞÀº µ¥¹ÌÁö º¸´Ù ÀÛÀº°æ¿ì if( mHP <= useValue ) { assert(NULL); NETWORK2->PostServerEvent("cMonster::HPUse [%d,%d,%d]", mObject.index, useValue, mHP ); mHP = 1; } else mHP -= useValue; if( msgSend == true ) { MSG_SYN_MONSTER_HP synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_HP_SYN; synMsg.mMonsterIdx = GetObjectID(); synMsg.mHP = mHP; synMsg.mMaxHP = GetMaxHP(); synMsg.mDie = GetStateDie(); NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_HP) ); } } void cMonster::HPHeal( unsigned long hp, bool /*msgSend*/, sObject /*healer*/, long /*distressPoint*/, eTAKEDAMAGE_TYPE /*type*/ ) { /// ÈúÀ» ¹ÞÀº HP¾çÀÌ ÃÖ´ëÄ¡¸¦ ³Ñ¾î ¼­´Â °æ¿ì if( GetMaxHP() < mHP + hp ) { /// hp°ªÀ» ÃÖ´ëÄ¡·Î º¯°æ mHP = GetMaxHP(); } else { /// ÈúÀ» ¹ÞÀº ¾çÀ» ´õÇØÁÜ mHP += hp; } MSG_SYN_MONSTER_HP synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_HP_SYN; synMsg.mMonsterIdx = GetObjectID(); synMsg.mHP = mHP; synMsg.mMaxHP = GetMaxHP(); synMsg.mDie = GetStateDie(); NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_HP) ); } void cMonster::MPDamage( unsigned long damage, bool msgSend ) { /// °ø°ÝÀ» ¹Þ¾Æ MP¸¦ ¼Ò¸ðÇÏ´Â °æ¿ì¿¡ ´ëÇÑ Ãß°¡ ÀÚ¸® /// µ¥¹ÌÁö¸¦ ¹ÞÀ¸¸é Ç®¸®´Â È¿°úµé »èÁ¦Çϱâ if( mDeleteTypeDamagedAry.GetSize() > 0 ) { cLongAry::cIterator begin = mDeleteTypeDamagedAry.Begin(); cLongAry::cIterator end = mDeleteTypeDamagedAry.End(); cInfluenceObject* pInf = NULL; unsigned long influenceIdx = 0; while( begin != end ) { influenceIdx = (*begin++); pInf = SKILLMANAGER->GetInfluence( influenceIdx ); if( pInf == NULL ) continue; if( pInf->GetDeleteType() == eDELETETYPE_PLAYER_DAMAGED ) SKILLMANAGER->DeleteInfluenceList( influenceIdx ); } } MPUse( damage, msgSend ); } void cMonster::MPUse( unsigned long useValue, bool msgSend ) { /// ÇöÀç MP°¡ °ø°Ý ¹ÞÀº µ¥¹ÌÁö º¸´Ù ÀÛÀº°æ¿ì if( mMP <= useValue ) mMP = 0; else mMP -= useValue; if( msgSend == true ) { MSG_SYN_MONSTER_MP synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_MP_SYN; synMsg.mMonsterIdx = GetObjectID(); synMsg.mMP = mMP; synMsg.mMaxMP = GetMaxMP(); NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_MP) ); } } void cMonster::MPHeal( unsigned long heal, bool /*msgSend*/ ) { /// ÈúÀ» ¹ÞÀº MP¾çÀÌ ÃÖ´ëÄ¡¸¦ ³Ñ¾î ¼­´Â °æ¿ì if( GetMaxMP() < mMP + heal ) { /// mp°ªÀ» ÃÖ´ëÄ¡·Î º¯°æ mMP = GetMaxMP(); } else { /// ÈúÀ» ¹ÞÀº ¾çÀ» ´õÇØÁÜ mMP += heal; } //MSG_SYN_MONSTER_MP synMsg; //synMsg.Category = NM_MONSTER; //synMsg.Protocol = NM_MONSTER_MP_SYN; //synMsg.mMonsterIdx = GetObjectID(); //synMsg.mMP = mMP; //synMsg.mMaxMP = GetMaxMP(); //NETWORK2->QuickSendExcept( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_MP) ); } void cMonster::MoveStop( bool sendMsg ) { mPathCount = 0; mPathIndex = 0; mNextPos = mObjectPos; mLastPos = mObjectPos; if( sendMsg == true ) { /// À̵¿ÁßÀÌ´ø Ŭ¶óÀÌ¾ðÆ®´Â Á¤Áö ½ÃŲ´Ù. MSG_SYN_MONSTER_MOVESTOP synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_MOVESTOP_SYN; synMsg.mMonsterIdx = mObject.index; synMsg.mMonsterPos.x = mObjectPos.x; synMsg.mMonsterPos.y = mObjectPos.y; NETWORK2->QuickSend( this, (char*)&synMsg, sizeof(synMsg) ); } } void cMonster::CalcDirection( NiPoint2 targetPos ) { float viewPosX, viewPosY; viewPosX = mObjectPos.x - targetPos.x; viewPosY = mObjectPos.y - targetPos.y; mDirection = atan2( viewPosX, viewPosY ); } bool cMonster::FindPath( const NiPoint2& goal ) { if( mPathFinder == NULL ) { assert(NULL); NETWORK2->PostServerEvent("cMonster::FindPath == NULL"); return false; } if( mPathFinder->FindPath( mPathArray, &mPathCount, MAX_PATH_COUNT, NiPoint2(mObjectPos.x, mObjectPos.y), goal ) == false ) return false; mPathIndex = 0; mLastPos.x = goal.x; mLastPos.y = goal.y; mNextPos.x = mPathArray[0].x; mNextPos.y = mPathArray[0].y; float viewPosX, viewPosY; viewPosX = mObjectPos.x - mNextPos.x; viewPosY = mObjectPos.y - mNextPos.y; mDirection = atan2( viewPosX, viewPosY ); return true; } void cMonster::SetFixedObjectSizePer( short sizePer ) { mFixedObjectSizePer = 100 + sizePer; if( 100 + sizePer < 0 ) { assert(NULL); NETWORK2->PostServerEvent("cMonster::GetFixedObjectSize() sizePer < -100"); sizePer = -100; } float objectSize = mpMonsterInfo->mMonsterFixSize * mpMonsterInfo->mMonsterScale * ( (float)( 100 + sizePer ) / 100 ); if( objectSize <= 0.0f ) { assert(NULL); NETWORK2->PostServerEvent("cMonster::GetFixedObjectSize() <= 0"); objectSize = 1.0f; } mFixedObjectSize = objectSize; } void cMonster::SendMonsterSize() { MSG_SYN_MONSTER_SCALE synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_SCALE_SYN; synMsg.mMonsterIdx = mObject.index; synMsg.mScale = GetFixedObjectSizePer(); NETWORK2->QuickSend( this, (char*)&synMsg, sizeof(synMsg) ); } void cMonster::SendSpeech( unsigned long talkState ) { if( talkState == eMONSTERTALK_MAX ) { mTalkState = (unsigned char)talkState; return; } sMonsterTalk* pMonsterTalk = MONSTERSCRIPT->GetMonsterTalkInfo( mpMonsterInfo->mMonsterClassIdx, (unsigned char)talkState ); if( pMonsterTalk == NULL ) return; /// ÇÁ·Î¼¼½Ì ¼³Á¤ switch( talkState ) { case eMONSTERTALK_ATTACK1: /// ¹ßµ¿ÇÏ¸é ±âÁ¸ ´ë»ç ÇÁ·Î¼¼½Ì ÇÏ´ø°ÍÀ» Á¾·á case eMONSTERTALK_ATTACK2: case eMONSTERTALK_SKILL1: case eMONSTERTALK_SKILL2: case eMONSTERTALK_SKILL3: case eMONSTERTALK_GIVEUP: mTalkState = eMONSTERTALK_MAX; break; case eMONSTERTALK_STAND: /// ÇÁ·Î¼¼½Ì ÇØ¾ßÇÏ´Â Ç׸ñ case eMONSTERTALK_WORK: case eMONSTERTALK_RUN: case eMONSTERTALK_FOLLOW: case eMONSTERTALK_ESCAPE: { mTalkState = (unsigned char)talkState; /// ´ÙÀ½ üũ ½Ã°£ ¼³Á¤ mTalkProcessCheckTime = NETWORK2->GetAccumTime() + pMonsterTalk->mCheckTime; } break; } /// TALK_DELAYÃʰ£ ´Ù¸¥ ´ëÈ­ ¹ß¼Û ºÒ°¡ if( mTalkDealyEndTime > NETWORK2->GetAccumTime() ) return; if( pMonsterTalk->mViewPercent == 0 ) return; /// ´ë»ç Ç¥½Ã È®·ü üũ unsigned long randSelect = rand() % 100 + 1; if( pMonsterTalk->mViewPercent < randSelect ) return; /// ¼±ÅÃµÈ ´ë»ç üũ unsigned char randType = (unsigned char)( rand() % MONSTER_TALK_SIZE ); unsigned long talkIdx = pMonsterTalk->mTalkIdx[randType]; if( talkIdx == 0 ) return; /// ¸Þ¼¼Áö ¹ß¼Û MSG_SYN_MONSTER_SPEECH synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_SPEECH_SYN; synMsg.mMonsterIdx = GetObjectID(); synMsg.mViewType = pMonsterTalk->mViewType; synMsg.mTalkIdx = talkIdx; synMsg.mCharacterIdx = 0; /// È®ÀÎÄÚµå - ÀÌ °æ¿ì ¿ÜÀÇ Å¸°Ù Á¤º¸´Â Ÿ°Ù ¼±Á¤ ¹æ¹ýÀ» °áÁ¤ÇÑ ÈÄ¿¡ ³ÖÀÚ! switch( talkState ) { case eMONSTERTALK_FIGHT: case eMONSTERTALK_ATTACK1: case eMONSTERTALK_ATTACK2: case eMONSTERTALK_SKILL1: case eMONSTERTALK_SKILL2: case eMONSTERTALK_SKILL3: case eMONSTERTALK_DAMAGE: /// Ÿ°Ù°ú °ø°ÝÀÚ°¡ Ʋ¸®´õ¶óµµ Ÿ°Ù Á¤º¸·Î ¹ß¼Û ÇÑ´Ù. case eMONSTERTALK_FOLLOW: case eMONSTERTALK_ESCAPE: case eMONSTERTALK_GIVEUP: case eMONSTERTALK_DIE1: case eMONSTERTALK_DIE2: synMsg.mCharacterIdx = mTarget.index; break; } /// ¿ÜÄ¡±â ¼³Á¤¿¡ µû¸¥ ¹ß¼Û ¹üÀ§ ¼±Åà if( pMonsterTalk->mViewType == eM_TALKVIEW_SHOUT ) NETWORK2->QuickSendMap( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_SPEECH) ); else NETWORK2->QuickSend( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_SPEECH) ); /// TALK_DELAY Ãʰ£ ¹ß¼Û Á¦¾à ½Ã°£ ¼³Á¤ mTalkDealyEndTime = NETWORK2->GetAccumTime() + TALK_DELAY; } void cMonster::SpeechProcess() { if( mTalkProcessCheckTime > NETWORK2->GetAccumTime() ) return; SendSpeech( mTalkState ); } void cMonster::AddSummonMonster( unsigned long monsterIdx ) { unsigned int modeIdx = 0; cHashSet* pSet = 0; if( mDeathMonster == true ) { /// Àá¼ö »óÅ pSet = (cHashSet*)mSummonListMap.GetAt( modeIdx ); } else { /// ÀÏ¹Ý Á¦°Å if( mCurrentMode == NULL ) return; modeIdx = mCurrentMode->GetModeIndex(); pSet = (cHashSet*)mSummonListMap.GetAt( modeIdx ); } if( pSet == 0 ) { pSet = new cHashSet; mSummonListMap.Insert( modeIdx, pSet ); } if( pSet == 0 || pSet->Insert( monsterIdx ) == false ) NETWORK2->PostServerEvent("cMonster::AddSummonMonster[%d] mDeathMonster mSummonListSet.Insert( %d, %d ) == false", mObject.index, monsterIdx, modeIdx ); } void cMonster::DieSummonMonster( unsigned long monsterIdx, NiPoint2 diePos ) { unsigned int modeIdx = 0; if( mDeathMonster == true ) { /// Àá¼ö »óÅ mObjectPos = diePos; } else { /// ÀÏ¹Ý Á¦°Å if( mCurrentMode == NULL ) return; modeIdx = mCurrentMode->GetModeIndex(); } cHashSet* pSet = (cHashSet*)mSummonListMap.GetAt( modeIdx ); if( pSet == NULL ) return; pSet->Erase( monsterIdx ); } void cMonster::ModeSkillEnd() { if( mModeInitSkillIdx != eMONSTERATTACK_MAX && mModeInitSkillIdx == mAttackType ) { mModeInitSkillIdx = eMONSTERATTACK_MAX; } if( mModeSkillIdx != eMONSTERATTACK_MAX && mModeSkillIdx == mAttackType ) { mModeSkillIdx = eMONSTERATTACK_MAX; } } void cMonster::TargetFixed( unsigned long playerIdx, unsigned long influenceIdx ) { mTFixedPlayerIdx = playerIdx; mTFixedInfIdx = influenceIdx; sObject object = { eOBJECTTYPE_PLAYER, playerIdx }; TargetChange( object, 0 ); } void cMonster::TargetFixedEnd() { mTFixedPlayerIdx = 0; mTFixedInfIdx = 0; } void cMonster::LinkObstruction() { if( NETWORK2->GetServerType() != _E_ST_ID_THEME_ && NETWORK2->GetServerType() != _E_ST_ID_TUTORIAL_ ) return; unsigned long mapNumber = GetMapNumber(); cThemeObject* pTheme = THEMEMANAGER->GetThemeObject( mapNumber ); if( pTheme == NULL ) return; /// ½Å±Ô ¸ðµå InitÁ¤º¸ ó¸® cModeAgent* pAgent = MONSTERSCRIPT->GetMonsterModeAgent( mpMonsterInfo->mMonsterClassIdx ); if( pAgent == NULL ) return; cLongAry* pAry = pAgent->GetDeathDoor(); if( pAry == NULL ) return; for( unsigned long i = 0 ; i < pAry->GetSize() ; ++i ) { unsigned long deathDoorIdx = (*pAry)[i]; pTheme->DeleteObstruction( deathDoorIdx ); } } void cMonster::DeathGenMonster() { /// ½Å±Ô ¸ðµå InitÁ¤º¸ ó¸® cModeAgent* pAgent = MONSTERSCRIPT->GetMonsterModeAgent( mpMonsterInfo->mMonsterClassIdx ); if( pAgent == NULL ) return; cPArray* pAry = pAgent->GetDeathMonster(); if( pAry == NULL ) return; if( pAry->GetSize() == 0 ) return; mDeathMonster = true; for( unsigned long i = 0 ; i < pAry->GetSize() ; ++i ) { sModeDeathMonster* pDeathMonster = (sModeDeathMonster*)((*pAry)[i]); if( pDeathMonster == NULL ) continue; /// ¼Òȯ ¸ó½ºÅÍ Ãß°¡ AIMANAGER->BossSummonMonRegen( this, mMapNumber, mObjectPos.x, mObjectPos.y, pDeathMonster->mGenRangeMin, pDeathMonster->mGenRangeMax, pDeathMonster->mCount, pDeathMonster->mGenMonsterIdx ); } } void cMonster::LinkTeleportPortal() { if( NETWORK2->GetServerType() != _E_ST_ID_THEME_ && NETWORK2->GetServerType() != _E_ST_ID_TUTORIAL_ ) return; unsigned long mapNumber = GetMapNumber(); cThemeObject* pTheme = THEMEMANAGER->GetThemeObject( mapNumber ); if( pTheme == NULL ) return; /// ½Å±Ô ¸ðµå InitÁ¤º¸ ó¸® cModeAgent* pAgent = MONSTERSCRIPT->GetMonsterModeAgent( mpMonsterInfo->mMonsterClassIdx ); if( pAgent == NULL ) return; cLongAry* pAry = pAgent->GetTeleportPortal(); if( pAry == NULL ) return; for( unsigned long i = 0 ; i < pAry->GetSize() ; ++i ) { unsigned long mapChangePosIdx = (*pAry)[i]; pTheme->AddTeleportPortal( mapChangePosIdx ); } } bool cMonster::SendSightIn(char category, char protocol, unsigned long connectionIdx) { if( GetStateDie() == true ) return true; if( mDMTeamType == ePVPDM_TEAMTYPE_MAX ) { HANDLE handle = NULL; MSG_MONSTER_INFO* sendMsg = (MSG_MONSTER_INFO*)NETWORK2->GetMsgRoot( &handle, connectionIdx, category, protocol ); if ( sendMsg != NULL ) { sMonsterData* monsterData = &sendMsg->mMonsterInfo; sMonsterInfluence* pMonsterInfluence = sendMsg->mInfluence; monsterData->mMonsterIdx = mObject.index; monsterData->mMonsterClassIdx = mpMonsterInfo->mMonsterClassIdx; monsterData->mPosX = mObjectPos.x; monsterData->mPosY = mObjectPos.y; monsterData->mDirection = mDirection; monsterData->mHP = mHP; monsterData->mMaxHP = GetMaxHP(); monsterData->mMP = mMP; monsterData->mMaxMP = GetMaxMP(); monsterData->mScale = mFixedObjectSizePer; monsterData->mAutoDummy = mAutoDummy; sendMsg->mCount = 0; cSkillInfluenceSet::cIterator iter = mInfluenceSet.Begin(); cSkillInfluenceSet::cIterator end = mInfluenceSet.End(); cInfluenceObject* pInfluence = NULL; while( iter != end ) { pInfluence = SKILLMANAGER->GetInfluence( *iter++ ); if( pInfluence == NULL ) { assert(NULL); NETWORK2->PostServerEvent("cMonster::SendSightIn pInfluence == NULL" ); //-/-//SKILLMANAGER->InsertDeleteInfluenceObject( pInfluence ); continue; } pMonsterInfluence->mUniqueIdx = pInfluence->GetUniqueIdx(); pMonsterInfluence->mInfluenceClassIdx = pInfluence->GetInfluenceClassIdx(); ++pMonsterInfluence; ++sendMsg->mCount; } if ( NETWORK2->SendMsgRoot( handle, sendMsg->GetMsgLength() ) ) { //-- TO ij¸¯ÅÍ FROM ±×¸®µå(±×¸®µå À̵¿Á¤º¸). if( GetActionID() == eACT_PUSHPULL ) { HANDLE handle = NULL; MSG_SYN_SKLL_PUSHPULL* sendMsg = (MSG_SYN_SKLL_PUSHPULL*)NETWORK2->GetMsgRoot( &handle, connectionIdx, NM_SKILL, NM_SKILL_PUSHPULL_SYN ); if ( sendMsg != NULL ) { sendMsg->mTarget = mObject; sendMsg->mPosX = mNextPos.x; sendMsg->mPosY = mNextPos.y; NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_SKLL_PUSHPULL) ); } } return SendMonsterMove( connectionIdx ); } else return false; } } else { HANDLE handle = NULL; MSG_MONSTERTEAM_INFO* sendMsg = (MSG_MONSTERTEAM_INFO*)NETWORK2->GetMsgRoot( &handle, connectionIdx, category, NM_MONSTER_TEAMSIGHT_IN_RES ); if ( sendMsg != NULL ) { sMonsterData* monsterData = &sendMsg->mMonsterInfo; sMonsterInfluence* pMonsterInfluence = sendMsg->mInfluence; monsterData->mMonsterIdx = mObject.index; monsterData->mMonsterClassIdx = mpMonsterInfo->mMonsterClassIdx; monsterData->mPosX = mObjectPos.x; monsterData->mPosY = mObjectPos.y; monsterData->mDirection = mDirection; monsterData->mHP = mHP; monsterData->mMaxHP = GetMaxHP(); monsterData->mMP = mMP; monsterData->mMaxMP = GetMaxMP(); monsterData->mScale = mFixedObjectSizePer; monsterData->mAutoDummy = mAutoDummy; sendMsg->mTeamType = mDMTeamType; sendMsg->mCount = 0; cSkillInfluenceSet::cIterator iter = mInfluenceSet.Begin(); cSkillInfluenceSet::cIterator end = mInfluenceSet.End(); cInfluenceObject* pInfluence = NULL; while( iter != end ) { pInfluence = SKILLMANAGER->GetInfluence( *iter++ ); if( pInfluence == NULL ) { assert(NULL); NETWORK2->PostServerEvent("cMonster::SendSightIn pInfluence == NULL" ); //-/-//SKILLMANAGER->InsertDeleteInfluenceObject( pInfluence ); continue; } pMonsterInfluence->mUniqueIdx = pInfluence->GetUniqueIdx(); pMonsterInfluence->mInfluenceClassIdx = pInfluence->GetInfluenceClassIdx(); ++pMonsterInfluence; ++sendMsg->mCount; } if ( NETWORK2->SendMsgRoot( handle, sendMsg->GetMsgLength() ) ) { //-- TO ij¸¯ÅÍ FROM ±×¸®µå(±×¸®µå À̵¿Á¤º¸). if( GetActionID() == eACT_PUSHPULL ) { HANDLE handle = NULL; MSG_SYN_SKLL_PUSHPULL* sendMsg = (MSG_SYN_SKLL_PUSHPULL*)NETWORK2->GetMsgRoot( &handle, connectionIdx, NM_SKILL, NM_SKILL_PUSHPULL_SYN ); if ( sendMsg != NULL ) { sendMsg->mTarget = mObject; sendMsg->mPosX = mNextPos.x; sendMsg->mPosY = mNextPos.y; NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_SKLL_PUSHPULL) ); } } return SendMonsterMove( connectionIdx ); } else return false; } } return false; } bool cMonster::SendSightOut(char category, char protocol, unsigned long connectionIdx) { if( GetStateDie() == true ) return true; HANDLE handle = NULL; MSG_MONSTER_SIGHTOUT* sendMsg = (MSG_MONSTER_SIGHTOUT*)NETWORK2->GetMsgRoot( &handle, connectionIdx, category, protocol ); if ( sendMsg != NULL ) { //unsigned long* pInfluenceIdx = sendMsg->mInfluenceUniqueIdx; sendMsg->mMonsterIdx = mObject.index; //sendMsg->mCount = 0; //cSkillInfluenceSet::cIterator iter = mInfluenceSet.Begin(); //cSkillInfluenceSet::cIterator end = mInfluenceSet.End(); //cInfluenceObject* pInfluence = NULL; //while( iter != end ) //{ // pInfluence = SKILLMANAGER->GetInfluence( *iter++ ); // if( pInfluence == NULL ) // { // assert(NULL); // NETWORK2->PostServerEvent("cMonster::SendSightOut pInfluence == NULL" ); // //-/-//SKILLMANAGER->InsertDeleteInfluenceObject( pInfluence ); // continue; // } // (*pInfluenceIdx) = pInfluence->GetUniqueIdx(); // ++pInfluenceIdx; // ++sendMsg->mCount; //} return NETWORK2->SendMsgRoot( handle, sizeof( MSG_MONSTER_SIGHTOUT ) ); } return false; } bool cMonster::SendMonsterMove(unsigned long connectionIdx) { // 061122 PKH Á×Áö ¾ÊÀº ¸ó½ºÅ͸¸ º¸³½´Ù. if ( GetStateDie() == true ) return true; // ±æÃ£±â °æ·Î °³¼ö unsigned int pathCount = GetPathCount(); // ±æÃ£±â°¡ ¸¸µé¾îÁ® ÀÖÁö ¾ÊÀº °æ¿ì ´ÙÀ½ ¸ó½ºÅÍ °Ë»ö if ( pathCount == 0 ) return true; // À̵¿ °æ·Î°¡ ÃÖÁ¾¸ñÀûÁö Æ÷ÀÎÆ®±îÁö À̵¿À̸é if ( GetMoveStopRange() == 0 ) { HANDLE handle = NULL; MSG_SYN_MOVE_MONSTER* msg = (MSG_SYN_MOVE_MONSTER*)NETWORK2->GetMsgRoot( &handle, connectionIdx, NM_MONSTER, NM_MONSTER_MOVE_SYN ); if ( msg != NULL ) { msg->mMonsterIdx = GetObjectID(); for( unsigned int i = 0 ; i < pathCount ; ++i ) msg->mPathArray[i] = GetPathArray()[i]; msg->mMoveSpeed = (unsigned short)GetMoveSpeed(); msg->mMoveSpeedType = (unsigned char)mMoveSpeedType; msg->mCount = (unsigned short)pathCount; return NETWORK2->SendMsgRoot( handle, msg->GetMsgLength() ); } } else // À̵¿ °æ·Î°¡ ÃÖÁ¾¸ñÀûÁö Æ÷ÀÎÆ®Àü RANGE¹üÀ§±îÁö Àΰæ¿ì { cBaseObject* player = GetTarget(); if ( player != NULL ) { sObject target; target.index = player->GetObjectID(); target.type = player->GetObjectType(); HANDLE handle = NULL; MSG_SYN_ACTIONMOVE_MONSTER* msg = (MSG_SYN_ACTIONMOVE_MONSTER*)NETWORK2->GetMsgRoot( &handle, connectionIdx, NM_MONSTER, NM_MONSTER_ACTIONMOVE_SYN ); if ( msg != NULL ) { msg->mMonsterIdx = GetObjectID(); msg->mTarget = target; msg->mRange = GetMoveStopRange(); for( unsigned int i = 0 ; i < pathCount ; ++i ) msg->mPathArray[i] = GetPathArray()[i]; msg->mMoveSpeed = (unsigned short)GetMoveSpeed(); msg->mCount = (unsigned short)pathCount; return NETWORK2->SendMsgRoot( handle, msg->GetMsgLength() ); } } } return false; } cPlayer* cMonster::NearGridFindPlayer( unsigned long playerIdx, bool diePass ) { /// ±×¸®µå ÁÂÇ¥¸¦ ³Ö°í °Ë»öÇÏ´Â ºÎºÐÀ¸·Î ¹Ù²ãº¸ÀÚ!! cPlayer* pPlayer = GRIDMANAGER->FindFirstPlayer( this ); /// °¢°¢ÀÇ Ç÷¹À̾ °Ë»öÇÔ while( pPlayer != NULL ) { if( diePass == true && pPlayer->GetStateDie() == true ) { pPlayer = GRIDMANAGER->FindNextPlayer(); continue; } if( pPlayer->GetObjectID() == playerIdx ) return pPlayer; pPlayer = GRIDMANAGER->FindNextPlayer(); } return NULL; } long cMonster::CalcSkillRate( cBaseObject* pTarget, eMONSTERATTACK_TYPE attackType, long scriptRate ) { if( pTarget == NULL ) return 0; sMonsterSkillScript* pScript = SKILLSCRIPT->GetMonsterSkillInfo( GetRaceGender(), attackType ); if( pScript == NULL ) return 0; if( pScript->mAttackSpd == 0 ) return 0; /// ¼±Åà Ȯ·ü °è»ê /// ( (°ø°Ý·Â(¼Ò) + °ø°Ý·Â(´ë) ) / 2 ) / ( °ø°Ý¼Óµµ/1000 ) - (Àý´ë°ª)( (´ë»ó°úÀÇ °Å¸® - »ç°Å¸®) / 10 ) + »ç¿ëÈ®·ü float averageAttack = (float)( pScript->mMinAttackValue + pScript->mMaxAttackValue) / 2; float speedAttack = averageAttack / ( (float)pScript->mAttackSpd / 1000 ); float range = (mObjectPos - pTarget->GetPos()).Length(); float rangeRate = ( range - pScript->mTargetDist ) / 10; float rangeAttack = speedAttack - abs(rangeRate); float useRate = rangeAttack + scriptRate; if( useRate < 0.0f ) return 0; return (unsigned long)useRate; } tPointerArray* cMonster::GetBuffImmune() { if( mCurrentMode != NULL ) return mCurrentMode->GetImmuneModeInfoArr(); return false; } void cMonster::ChangeActionTarget() { if( mTFixedPlayerIdx != 0 ) { cPlayer* pTarget = NearGridFindPlayer( mTFixedPlayerIdx, true ); if( pTarget == NULL ) SKILLMANAGER->DeleteInfluence( mObject, mTFixedInfIdx ); else { SetTarget( eOBJECTTYPE_PLAYER, mTFixedPlayerIdx ); return; } } eOBJECTTYPE objectType = eOBJECTTYPE_NONE; cBaseObject* target = GetTarget(); if( target != NULL ) objectType = (eOBJECTTYPE)target->GetObjectType(); /// Take Damage List¸¦ °Ë»çÇÑ´Ù. unsigned long maxPoint = 0; cPlayer* newTarget = 0; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { cPlayer* player = NearGridFindPlayer( per->playerIdx, true ); if( player && player != GetTarget() && player->GetStateDie() == false ) { if( objectType == eOBJECTTYPE_MONSTER ) { if( maxPoint <= per->distressPoint ) { maxPoint = per->distressPoint; newTarget = player; } } else { if( maxPoint < per->distressPoint ) { maxPoint = per->distressPoint; newTarget = player; } } } per = (PerTakeDamage*)per->next; } if( newTarget ) { /// Ÿ°Ù ¼³Á¤ if( SetTarget( newTarget->GetObjectType(), newTarget->GetObjectID() ) == false ) return; /// ÃßÀû »óÅ ¼³Á¤ ActionChange( eACT_ATTACK ); } else { /// ȸ±â »óÅ ¼³Á¤ ClearTakeDamage(); ReservationComeback(); } } void cMonster::ChangeTargetDeleteSkill() { if( mTakeDamageRoot.count == 1 ) return; ChangeActionTarget(); } void cMonster::AddImmuneApplyType( unsigned char InfluenceType, unsigned short applyType ) { SKILLMANAGER->ClearImmuneApplyType( mObject, InfluenceType, applyType ); if( InfluenceType == eINFLUENCETYPE_BUF ) { mImmuneBuffSet.Insert( applyType ); } else if( InfluenceType == eINFLUENCETYPE_DEBUF ) { mImmuneDebuffSet.Insert( applyType ); } else assert(0); } void cMonster::AddImmuneKind( unsigned long infKind ) { SKILLMANAGER->ClearImmuneKind( mObject, infKind ); mImmuneKindSet.Insert( infKind ); } bool cMonster::IsImmuneApplyType( unsigned char InfluenceType, unsigned long applyType ) { if( applyType == 0 ) return false; if( IsModeState() == true ) { cPArray* pImmune = GetBuffImmune(); if( pImmune != NULL ) { for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*pImmune)[i]); if( p == NULL ) continue; if( p->type != eMODEINFO_IMMUNE ) continue; sModeImmune* pInfo = (sModeImmune*)p; if( pInfo->mSkillApplyType == (unsigned long)applyType ) return true; if( pInfo->mSkillApplyType == 0 ) { switch( applyType ) { case eSTATUSPLUS_STOPMOVE: case eSTATUSPLUS_STOPSKILL: case eSTATUSPLUS_STOPSKILL_PHY: case eSTATUSPLUS_STOPSKILL_MAG: case eSTATUSPLUS_ATTACKERTARGETING: case eSTATUSPLUS_SLEEP: case eSTATUSPLUS_STUN: return true; } } } } } /// ¸é¿ª ¸ñ·Ï¿¡¼­ ã¾ÆºÁ¼­ ÀÖÀ¸¸é ¸é¿ª if( InfluenceType == eINFLUENCETYPE_BUF ) { cHashSet::cIterator i = mImmuneBuffSet.Find( applyType ); if( i != mImmuneBuffSet.End() ) return true; } else if( InfluenceType == eINFLUENCETYPE_DEBUF ) { cHashSet::cIterator i = mImmuneDebuffSet.Find( applyType ); if( i != mImmuneDebuffSet.End() ) return true; } return false; } bool cMonster::IsImmuneApplyAll( unsigned long applyType ) { if( applyType == 0 ) return false; if( IsModeState() == true ) { cPArray* pImmune = GetBuffImmune(); if( pImmune != NULL ) { for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*pImmune)[i]); if( p == NULL ) continue; if( p->type != eMODEINFO_IMMUNE ) continue; sModeImmune* pInfo = (sModeImmune*)p; if( pInfo->mSkillApplyType == (unsigned long)applyType ) return true; if( pInfo->mSkillApplyType == 0 ) { switch( applyType ) { case eSTATUSPLUS_STOPMOVE: case eSTATUSPLUS_STOPSKILL: case eSTATUSPLUS_STOPSKILL_PHY: case eSTATUSPLUS_STOPSKILL_MAG: case eSTATUSPLUS_ATTACKERTARGETING: case eSTATUSPLUS_SLEEP: case eSTATUSPLUS_STUN: return true; } } } } } /// ¸é¿ª ¸ñ·Ï¿¡¼­ ã¾ÆºÁ¼­ ÀÖÀ¸¸é ¸é¿ª cHashSet::cIterator i; i = mImmuneBuffSet.Find( applyType ); if( i != mImmuneBuffSet.End() ) return true; i = mImmuneDebuffSet.Find( applyType ); if( i != mImmuneDebuffSet.End() ) return true; return false; } bool cMonster::IsImmuneKind( unsigned long infKind ) { if( infKind == 0 ) return false; /// ¸é¿ª ¸ñ·Ï¿¡¼­ ã¾ÆºÁ¼­ ÀÖÀ¸¸é ¸é¿ª cHashSet::cIterator b = mImmuneKindSet.Find( infKind ); cHashSet::cIterator e = mImmuneKindSet.End(); if( b != e ) return true; return false; } unsigned long cMonster::CalcChangeMPDamage( unsigned char attributeType, unsigned long damage, bool applyHP ) { unsigned long leftDamage = damage; unsigned long calcMP = GetMP(); if( applyHP == true ) { for( unsigned long i = 0 ; i < mChangeMPDamageAry.GetSize() ; ++i ) { cInfluenceObject* pInf = SKILLMANAGER->GetInfluence( mChangeMPDamageAry[i] ); if( pInf == NULL || pInf->IsDelReady() == true ) continue; /// ¼Ó¼ºÈ®ÀÎ if( ( attributeType == eATTRIBUTETYPE_PHYSICAL && ( pInf->GetChangeMPType() == eINFCHANGEMPTYPE_PHY || pInf->GetChangeMPType() == eINFCHANGEMPTYPE_ALL ) ) || ( attributeType == eATTRIBUTETYPE_MAGIC && ( pInf->GetChangeMPType() == eINFCHANGEMPTYPE_MAG || pInf->GetChangeMPType() == eINFCHANGEMPTYPE_ALL ) ) ) { /// È¿°ú¿¡¼­ µ¥¹ÌÁömpº¯È¯ ¼öÄ¡ °è»ê unsigned long cutMP = (unsigned long)( GetMaxMP() * pInf->GetChangeMPValue() * 0.01f ); cutMP = GetMaxMP() - cutMP; /// °è»êµÈ ÇöÀçmp°¡ È¿°úÁ¦ÇѰªº¸´Ù Å«°æ¿ì¸¸ °è»ê if( calcMP > cutMP ) { /// µ¥¹ÌÁö Àû¿ë°ªÀÌ È¿°ú ĿƮ¶óÀÎ ³Ñ´ÂÁö üũ if( cutMP + leftDamage < calcMP ) { /// ³ÑÁö ¾Ê´Â°æ¿ì µ¥¹ÌÁö ¸¸Å­ °è»êµÈÇöÀçmp¿¡ Àû¿ë calcMP = calcMP - leftDamage; leftDamage = 0; } else { /// ³Ñ´Â °æ¿ì È¿°úµ¥¹ÌÁömpº¯È¯ °ª±îÁö¸¸ Àû¿ë leftDamage = leftDamage - calcMP - cutMP; calcMP = cutMP; /// ÇØ´ç È¿°ú´Â Áö¿î´Ù. SKILLMANAGER->DeleteInfluenceList( mChangeMPDamageAry[i] ); } } else { /// ÀÌ¹Ì ³Ñ´Â °æ¿ìÀ̹ǷΠȿ°ú´Â Áö¿î´Ù. SKILLMANAGER->DeleteInfluenceList( mChangeMPDamageAry[i] ); } } } } else /// mpµ¥¹ÌÁö À̹ǷΠµ¥¹ÌÁö´Â ÀüºÎ´Ù Àû¿ëÇϰí Çã¿ëÄ¡ ¹ØÀ¸·Î³»·Á°£ È¿°ú¸¸ ÀüºÎ Áö¿ö¹ö¸°´Ù. { calcMP = GetMP() - damage; leftDamage = damage; for( unsigned long i = 0 ; i < mChangeMPDamageAry.GetSize() ; ++i ) { cInfluenceObject* pInf = SKILLMANAGER->GetInfluence( mChangeMPDamageAry[i] ); if( pInf == NULL || pInf->IsDelReady() == true ) continue; /// ¼Ó¼ºÈ®ÀÎ if( pInf->GetChangeMPType() == eINFCHANGEMPTYPE_NONE ) continue; /// È¿°ú¿¡¼­ µ¥¹ÌÁömpº¯È¯ ¼öÄ¡ °è»ê unsigned long cutMP = (unsigned long)( GetMaxMP() * pInf->GetChangeMPValue() * 0.01f ); cutMP = GetMaxMP() - cutMP; if( calcMP <= cutMP ) SKILLMANAGER->DeleteInfluenceList( mChangeMPDamageAry[i] ); } } return leftDamage; } unsigned long cMonster::CalcGuard( unsigned char attributeType, unsigned long damage ) { unsigned long tempDamage = damage; for( unsigned long i = 0 ; i < mGuardAry.GetSize() ; ++i ) { cInfluenceObject* pInf = SKILLMANAGER->GetInfluence( mGuardAry[i] ); if( pInf == NULL || pInf->IsDelReady() == true ) continue; if( pInf->CalcLeftGuard( attributeType, &tempDamage ) == false ) continue; if( pInf->GetLeftGuardValue() == 0 || pInf->GetLeftGuardCnt() == 0 ) SKILLMANAGER->DeleteInfluenceList( mGuardAry[i] ); if( tempDamage != 0 ) continue; return true; } return tempDamage; } void cMonster::SetCombatFlag( bool set ) { if( mIsCombat == set ) return; mIsCombat = set; if( mIsCombat == true ) CombatStart(); else CombatEnd(); } void cMonster::CombatStart() { /// ÀüÅõ ½ÃÀÛ ½ÃÁ¡ mTotalTime = 0; ChangeCurrentMode( 0 ); } void cMonster::CombatEnd() { /// ÀüÅõ Á¾·á ½ÃÁ¡ mTotalTime = 0; if( mpRegenMonsterInfo != NULL ) mDestroyTime = mpRegenMonsterInfo->mRegenLifeTime; ChangeCurrentMode( -1 ); } void cMonster::ChangeCurrentMode( long modeIdx ) { mIdleEndTime = 0; if( mModeAgent == 0 ) return; if( GetStateDie() == true ) return; /// ¸ðµå º¯¼ö ó¸® if( modeIdx < 0 ) { mCurrentMode = NULL; } else { /// ¸ðµå º¯°æÀü ±âÁ¸ ¸ðµå ¼³Á¤ Ç׸ñ Á¦°Å if( mCurrentMode ) { cModeInfoArr* arr = mCurrentMode->GetInitModeInfoArr(); for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*arr)[i]); if( p == NULL ) continue; switch( p->type ) { /// ¹öÇÁ Á¦°Å case eMODEINFO_APPLYBUFF: { sModeBuff* pBuffMode = (sModeBuff*)p; if( pBuffMode == NULL ) return; if( pBuffMode->mModeDel == true && pBuffMode->mApplyBuffIdx != 0 ) SKILLMANAGER->DeleteInfluenceClassIdx( mObject, pBuffMode->mApplyBuffIdx ); } case eMODEINFO_APPLYAURA: { sModeAura* pAuraMode = (sModeAura*)p; if( pAuraMode == NULL ) return; if( pAuraMode->mModeDel == true && pAuraMode->mApplyBuffIdx != 0 ) SKILLMANAGER->DeleteInfluenceClassIdx( mObject, pAuraMode->mApplyBuffIdx ); } } } } cMode* mode = mModeAgent->GetMode( modeIdx ); //if( mCurrentMode == mode ) //{ // assert(0); // return; //} mCurrentMode = mode; } mModeTime = 0; mModeSkillIdx = eMONSTERATTACK_MAX; mModeInitSkillIdx = eMONSTERATTACK_MAX; SetAttackType( eMONSTERATTACK_MAX ); /// Net Msgó¸® MSG_SYN_MONSTER_MODECHANGE synMsg; synMsg.Category = NM_MONSTER; synMsg.Protocol = NM_MONSTER_MODECHANGE_SYN; synMsg.mMonsterIdx = mObject.index; synMsg.mModeIdx = (unsigned char)modeIdx; NETWORK2->QuickSend( this, (char*)&synMsg, sizeof( synMsg ) ); /// ¸ðµå ½ÃÀÛ ¼³Á¤ ó¸® if( mCurrentMode ) { cModeInfoArr* arr = mCurrentMode->GetInitModeInfoArr(); for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*arr)[i]); if( p == NULL ) continue; switch( p->type ) { case eMODEINFO_APPLYBUFF: { sModeBuff* pBuffMode = (sModeBuff*)p; if( pBuffMode == NULL ) return; if( pBuffMode->mApplyBuffIdx != 0 ) SKILLMANAGER->AddInfluence( mObject, mObject, pBuffMode->mApplyBuffIdx, 0, true ); } break; case eMODEINFO_APPLYAURA: { sModeAura* pAuraMode = (sModeAura*)p; if( pAuraMode == NULL ) return; if( pAuraMode->mApplyBuffIdx != 0 ) { SKILLMANAGER->AddInfMode( mObject, mObject, pAuraMode->mApplyBuffIdx, pAuraMode->mEnemyApply, pAuraMode->mRange, true ); } } break; case eMODEINFO_GENMONSTER: { sModeGenMonster* pMonMode = (sModeGenMonster*)p; if( pMonMode == NULL ) return; /// ¼Òȯ ÆÐÅÏÀÌ Àִ°æ¿ì ÆÐÅÏ´ë·Î »ý¼º ½ÃÄÑ ÁØ´Ù. bool pattern = false; if( pMonMode->mGenPatternIdx != 0 ) { cArray* pAryScript = MONSTERSCRIPT->GetSummonPattern( pMonMode->mGenPatternIdx ); if( pAryScript != NULL && pAryScript->GetSize() > 0 ) { sSummonPatternScript* pScript = (sSummonPatternScript*)(*pAryScript)[0]; if( pScript != NULL ) { pattern = true; //sSummonPatternInfo* pPattern = new sSummonPatternInfo; //pPattern->mObject.index = pMonMode->mGenMonsterIdx; //pPattern->mObject.type = eOBJECTTYPE_MONSTER; //pPattern->mCount = pMonMode->mCount; //pPattern->mSummonPatternIdx = pMonMode->mGenPatternIdx; //pPattern->mCenterPos = mObjectPos; //pPattern->mCenterDir = mDirection; //pPattern->mRangeMin = pMonMode->mGenRangeMin; //pPattern->mRangeMax = pMonMode->mGenRangeMax; //pPattern->mNowPatternPos = 0; //pPattern->mNextPatternTime = pScript->mDelayTime + NETWORK2->GetAccumTime(); //mSummonPatternInfoAry.PushBack( pPattern ); sObject object = { eOBJECTTYPE_MONSTER, pMonMode->mGenMonsterIdx }; SUMMONPATTERNPOOL->AddSummonPattern( &mSummonPatternRoot, object, pMonMode->mGenPatternIdx, pMonMode->mCount, mObjectPos, mDirection, pMonMode->mGenRangeMin, pMonMode->mGenRangeMax, 0, 0, pScript->mDelayTime + NETWORK2->GetAccumTime() ); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pScript != NULL"); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pAryScript != NULL && pAryScript->GetSize > 0"); } /// ÆÐÅÏÀÌ ¾ø´Â°æ¿ì ·£´ýÀ§Ä¡·Î ¼Òȯ if( pattern == false ) { /// ¼Òȯ ¸ó½ºÅÍ Ãß°¡ AIMANAGER->BossSummonMonRegen( this, mMapNumber, mObjectPos.x, mObjectPos.y, pMonMode->mGenRangeMin, pMonMode->mGenRangeMax, pMonMode->mCount, pMonMode->mGenMonsterIdx ); } /// ·çÇÁ¸¦ µµ´Â °Í¸¸ ÄðŸÀÓ Á¤º¸¸¦ ±â·ÏÇØ¼­ ¸ó½ºÅÍprocess½Ã Ãß°¡ ¸®Á¨ÇÑ´Ù. if( pMonMode->mLoop == true ) { unsigned long nextTime = NETWORK2->GetAccumTime() + pMonMode->mDelayTime; /// µî·ÏµÈ Á¤º¸¸¦ ã¾Æ Ãß°¡/º¯°æ cHashMap::cIterator find = mGenMonCoolTimeMap.Find( pMonMode->mOrderNum ); if( find == mGenMonCoolTimeMap.End() ) mGenMonCoolTimeMap.Insert( pMonMode->mOrderNum, nextTime ); else (*find).mSecond = nextTime; } } break; case eMODEINFO_GENTOTEM: { //bool mLoop; //unsigned long mDelayTime; sModeGenTotem* pTotemMode = (sModeGenTotem*)p; if( pTotemMode == NULL ) return; /// ¼Òȯ ÆÐÅÏÀÌ Àִ°æ¿ì ÆÐÅÏ´ë·Î »ý¼º ½ÃÄÑ ÁØ´Ù. bool pattern = false; if( pTotemMode->mGenPatternIdx != 0 ) { cArray* pAryScript = MONSTERSCRIPT->GetSummonPattern( pTotemMode->mGenPatternIdx ); if( pAryScript != NULL && pAryScript->GetSize() > 0 ) { sSummonPatternScript* pScript = (sSummonPatternScript*)(*pAryScript)[0]; if( pScript != NULL ) { pattern = true; //sSummonPatternInfo* pPattern = new sSummonPatternInfo; //pPattern->mObject.index = pTotemMode->mGenTotemIdx; //pPattern->mObject.type = eOBJECTTYPE_TOTEM; //pPattern->mCount = pTotemMode->mCount; //pPattern->mSummonPatternIdx = pTotemMode->mGenPatternIdx; //pPattern->mCenterPos = mObjectPos; //pPattern->mCenterDir = mDirection; //pPattern->mRangeMin = pTotemMode->mGenRangeMin; //pPattern->mRangeMax = pTotemMode->mGenRangeMax; //pPattern->mNowPatternPos = 0; //pPattern->mNextPatternTime = pScript->mDelayTime + NETWORK2->GetAccumTime(); //mSummonPatternInfoAry.PushBack( pPattern ); sObject object = { eOBJECTTYPE_TOTEM, pTotemMode->mGenTotemIdx }; SUMMONPATTERNPOOL->AddSummonPattern( &mSummonPatternRoot, object, pTotemMode->mGenPatternIdx, pTotemMode->mCount, mObjectPos, mDirection, pTotemMode->mGenRangeMin, pTotemMode->mGenRangeMax, pTotemMode->mApplyType, 0, pScript->mDelayTime + NETWORK2->GetAccumTime() ); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pScript != NULL"); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pAryScript != NULL && pAryScript->GetSize > 0"); } /// ÆÐÅÏÀÌ ¾ø´Â°æ¿ì ·£´ýÀ§Ä¡·Î ¼Òȯ if( pattern == false ) { unsigned long genRangeMin = pTotemMode->mGenRangeMin; unsigned long genRangeMax = pTotemMode->mGenRangeMax; for( unsigned char i = 0 ; i < pTotemMode->mCount ; ++i ) { NiPoint2 pos = CalcMinMaxRandPos( mObjectPos.x, mObjectPos.y, genRangeMin, genRangeMax ); cTotem* pTotem = OBJECTMANAGER->AddTotem( pTotemMode->mGenTotemIdx, 0, 0, pos, mObject, (eAPPLYTYPE)pTotemMode->mApplyType, eATTRIBUTETYPE_PHYSICAL, 0, mDirection, 0 ); if( pTotem != NULL ) GRIDMANAGER->AddTotem( pTotem ); } } /// ·çÇÁ¸¦ µµ´Â °Í¸¸ ÄðŸÀÓ Á¤º¸¸¦ ±â·ÏÇØ¼­ ¸ó½ºÅÍprocess½Ã Ãß°¡ ¸®Á¨ÇÑ´Ù. if( pTotemMode->mLoop == true ) { unsigned long nextTime = NETWORK2->GetAccumTime() + pTotemMode->mDelayTime; /// µî·ÏµÈ Á¤º¸¸¦ ã¾Æ Ãß°¡/º¯°æ cHashMap::cIterator find = mGenTotemCoolTimeMap.Find( pTotemMode->mOrderNum ); if( find == mGenTotemCoolTimeMap.End() ) mGenTotemCoolTimeMap.Insert( pTotemMode->mOrderNum, nextTime ); else (*find).mSecond = nextTime; } } break; case eMODEINFO_GENGATHERING: { //bool mLoop; //unsigned long mDelayTime; sModeGenGathering* pGatheringMode = (sModeGenGathering*)p; if( pGatheringMode == NULL ) return; /// ¼Òȯ ÆÐÅÏÀÌ Àִ°æ¿ì ÆÐÅÏ´ë·Î »ý¼º ½ÃÄÑ ÁØ´Ù. bool pattern = false; if( pGatheringMode->mGenPatternIdx != 0 ) { cArray* pAryScript = MONSTERSCRIPT->GetSummonPattern( pGatheringMode->mGenPatternIdx ); if( pAryScript != NULL && pAryScript->GetSize() > 0 ) { sSummonPatternScript* pScript = (sSummonPatternScript*)(*pAryScript)[0]; if( pScript != NULL ) { pattern = true; //sSummonPatternInfo* pPattern = new sSummonPatternInfo; //pPattern->mObject.index = pGatheringMode->mGenGatheringIdx; //pPattern->mObject.type = eOBJECTTYPE_GATHERING; //pPattern->mCount = pGatheringMode->mCount; //pPattern->mSummonPatternIdx = pGatheringMode->mGenPatternIdx; //pPattern->mCenterPos = mObjectPos; //pPattern->mCenterDir = mDirection; //pPattern->mRangeMin = pGatheringMode->mGenRangeMin; //pPattern->mRangeMax = pGatheringMode->mGenRangeMax; //pPattern->mNowPatternPos = 0; //pPattern->mNextPatternTime = pScript->mDelayTime + NETWORK2->GetAccumTime(); //mSummonPatternInfoAry.PushBack( pPattern ); sObject object = { eOBJECTTYPE_GATHERING, pGatheringMode->mGenGatheringIdx }; SUMMONPATTERNPOOL->AddSummonPattern( &mSummonPatternRoot, object, pGatheringMode->mGenPatternIdx, pGatheringMode->mCount, mObjectPos, mDirection, pGatheringMode->mGenRangeMin, pGatheringMode->mGenRangeMax, 0, 0, pScript->mDelayTime + NETWORK2->GetAccumTime() ); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pScript != NULL"); } else NETWORK2->PostServerEvent("cMonster::ChangeCurrentMode pAryScript != NULL && pAryScript->GetSize > 0"); } /// ÆÐÅÏÀÌ ¾ø´Â°æ¿ì ·£´ýÀ§Ä¡·Î ¼Òȯ if( pattern == false ) { unsigned long genRangeMin = pGatheringMode->mGenRangeMin; unsigned long genRangeMax = pGatheringMode->mGenRangeMax; for( unsigned char i = 0 ; i < pGatheringMode->mCount ; ++i ) { NiPoint2 pos = CalcMinMaxRandPos( mObjectPos.x, mObjectPos.y, genRangeMin, genRangeMax ); cGathering* pGathering = OBJECTMANAGER->AddGathering( 0, pGatheringMode->mGenGatheringIdx, mMapNumber, pos.x, pos.y, mDirection, 0 ); if( pGathering != NULL ) { GRIDMANAGER->AddGathering( pGathering ); pGathering->SendRegenSync(); mSummonGatherAry.PushBack( pGathering->GetObjectID() ); } } } /// ·çÇÁ¸¦ µµ´Â °Í¸¸ ÄðŸÀÓ Á¤º¸¸¦ ±â·ÏÇØ¼­ ¸ó½ºÅÍprocess½Ã Ãß°¡ ¸®Á¨ÇÑ´Ù. if( pGatheringMode->mLoop == true ) { unsigned long nextTime = NETWORK2->GetAccumTime() + pGatheringMode->mDelayTime; /// µî·ÏµÈ Á¤º¸¸¦ ã¾Æ Ãß°¡/º¯°æ cHashMap::cIterator find = mGenTotemCoolTimeMap.Find( pGatheringMode->mOrderNum ); if( find == mGenTotemCoolTimeMap.End() ) mGenTotemCoolTimeMap.Insert( pGatheringMode->mOrderNum, nextTime ); else (*find).mSecond = nextTime; } } break; //case eMODEINFO_SPEECH: // { // //sModeSpeech* pSpeechMode = (sModeSpeech*)p; // //if( pSpeechMode == NULL ) // // return; // ///// ¸Þ¼¼Áö ¹ß¼Û // //MSG_SYN_MOSTER_MODESPEECH synMsg; // //synMsg.Category = NM_MONSTER; // //synMsg.Protocol = NM_MONSTER_MODESPEECH_SYN; // //synMsg.mMonsterIdx = GetObjectID(); // //synMsg.mTalkIdx = pSpeechMode->mSpeechIdx; // //synMsg.mCharacterIdx = mTarget.index; // //NETWORK2->QuickSendMap( this, (char*)&synMsg, sizeof(MSG_SYN_MONSTER_SPEECH) ); // } break; case eMODEINFO_MODESTATE: { sModeState* pIdleMode = (sModeState*)p; if( pIdleMode == NULL ) return; mIdleEndTime = NETWORK2->GetAccumTime() + pIdleMode->mMaintainTime; ActionChange( eACT_IDLE ); } break; case eMODEINFO_AGGRO: { /// ÀÚ½ÅÀÇ ¾î±×·Î ÃʱâÈ­ ClearDistressPoint(); } break; case eMODEINFO_MODEINITSKILL: { cModeInfoArr* skillArr = mCurrentMode->GetCheckSkillModeInfoArr(); for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*skillArr)[i]); if( p == NULL ) continue; if( p->type != eMODEINFO_USESKILL ) { /// error assert(0); continue; } sModeSkill* pInfo = (sModeSkill*)p; mModeInitSkillIdx = (eMONSTERATTACK_TYPE)pInfo->mSkillIdx; } /* /// ¸ðµå ÁøÀԽà Á¶°Ç°¡´ÉÇÏ¸é ¹«Á¶°Ç ¼±Á¤ cHashMap successSkill; unsigned long sumRate = 0; cBaseObject* pTarget = GetTarget(); if( pTarget == NULL ) break; /// ¼±Åà °¡´É ½ºÅ³¸ñ·Ï ÀÛ¼º cModeInfoArr* skillArr = mCurrentMode->GetCheckSkillModeInfoArr(); for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*skillArr)[i]); if( p->type != eMODEINFO_USESKILL ) { /// error assert(0); continue; } sModeSkill* pInfo = (sModeSkill*)p; /// ÄðŸÀÓ Ã¼Å© cCoolTime::cIterator begin = mEliteCoolTimeMap.Find( pInfo->mSkillIdx ); cCoolTime::cIterator end = mEliteCoolTimeMap.End(); if( begin != end ) { if( (*begin).mSecond > NETWORK2->GetAccumTime() ) continue; } /// ¼±Åà ºñÀ²°ª °è»ê long useRate = CalcSkillRate( pTarget, (eMONSTERATTACK_TYPE)pInfo->mSkillIdx, (long)pInfo->mActionPer ); /// °¡´ÉÇÑ ½ºÅ³ ¸ñ·Ï¿¡ ÀúÀå successSkill.Insert( pInfo->mSkillIdx, useRate ); sumRate = sumRate + useRate; } /// °¡´ÉÇÑ ½ºÅ³ÀÌ ¾øÀ¸¸é Åë°ú if( sumRate == 0 ) break; /// °¡´ÉÇÑ ½ºÅ³Áß ¼±Åà unsigned long selectRand = rand() % sumRate; cHashMap::cIterator sI = successSkill.Begin(); cHashMap::cIterator sE = successSkill.End(); for( ; sI != sE ; ++sI ) { unsigned long rate = (*sI).mSecond; if( selectRand < rate ) { mModeSkillIdx = (eMONSTERATTACK_TYPE)(*sI).mFirst; break; } selectRand = selectRand - rate; } */ } break; default: assert(0); break; } } } } bool cMonster::ConditionValueCheck( unsigned char type, unsigned long value ) { switch( type ) { case 0: return true; case 1: // total time { if( value <= mTotalTime ) return true; } break; case 2: // mode time { if( value <= mModeTime ) return true; } break; case 3: // monster hp { if( GetMaxHP() == 0 ) { NETWORK2->PostServerEvent("0 divide 6"); return false; } unsigned long per = GetHP() * 100 / GetMaxHP(); if( value >= per ) return true; } break; case 4: // regenMonster die { /// ÀÚ½ÅÀǸðµå¿¡¼­ ¼ÒȯµÈ ¸ó½ºÅͰ¡ ¸ðµÎ Á×¾úÀ¸¸é ¸ðµå º¯°æ if( mCurrentMode != NULL ) { unsigned long modeIdx = mCurrentMode->GetModeIndex(); cHashSet* pSet = (cHashSet*)mSummonListMap.GetAt( modeIdx ); if( pSet == NULL ) return true; if( pSet->IsEmpty() == true ) return true; } } break; case 5: // mode skill use { /// »ç¿ëÇÑ ½ºÅ³À» Ã¼Å©ÇØ¼­ º¯È¯Á¶°Ç°ú °°À¸¸é ¸ðµå º¯°æ if( mLastUsedSkillIdx == (eMONSTERATTACK_TYPE)value ) { mLastUsedSkillIdx = eMONSTERATTACK_MAX; return true; } } break; default: assert(0); break; } return false; } eMONSTERATTACK_TYPE cMonster::GetModeSkill() { if( mModeInitSkillIdx != eMONSTERATTACK_MAX ) return mModeInitSkillIdx; return mModeSkillIdx; } bool cMonster::IsFollowContinue() { if( mpMonsterInfo == 0 ) { NETWORK2->PostServerEvent("cMonster::CombatContinue mpMonsterInfo == NULL"); return false; } cRangeCheck rangechk; rangechk.SetRadius( (float)mpMonsterInfo->mFollowRange ); cPlayer* newTarget = 0; PerTakeDamage* per = (PerTakeDamage*)mTakeDamageRoot.pool; while( per ) { cPlayer* player = NearGridFindPlayer( per->playerIdx, true ); if( player && player != GetTarget() && player->GetStateDie() == false ) { if( rangechk.IsRange( GetFollowStartPos(), player->GetPos() ) ) { newTarget = player; break; } } per = (PerTakeDamage*)per->next; } if( newTarget ) { NiPoint2 dir = GetPos() - GetFollowStartPos(); dir.Unitize(); mFollowStartPos = mFollowStartPos + dir*5.0f; SetTarget( newTarget->GetObjectType(), newTarget->GetObjectID() ); return true; } return false; } void cMonster::ProcessTakeDamage( unsigned long elapsedTime, unsigned long /*accumTime*/ ) { /// ¾î±×·Î °¨¼Ò ·çƾ.. TakeDamageRoot* pTakeDamageRoot = GetTakeDamageRoot(); if( pTakeDamageRoot == 0 ) return; if( pTakeDamageRoot->count == 0 ) return; PerTakeDamage* per = (PerTakeDamage*)pTakeDamageRoot->pool; while( per ) { if( per->changeFlag == false ) per->noChangeTime += elapsedTime; per->changeFlag = false; if( per->distressPoint > 1 ) { if( per->noChangeTime >= 8000 ) { /// unsigned long decrease = (unsigned long)(elapsedTime * 0.05f); if( decrease < 1 ) decrease = 1; if( per->distressPoint <= decrease ) per->distressPoint = 1; else per->distressPoint -= decrease; } } per = (PerTakeDamage*)per->next; } } unsigned long cMonster::GetMaxHP() { if( IsAutoDummy() == true ) return 9999; return (unsigned long)( mpMonsterInfo->mMaxHp + ( mpMonsterInfo->mMaxHp * mStatusPer.mMaxHP ) + mStatusPlus.mMaxHP ); } bool cMonster::IsHaveApplyBuffType( unsigned short applyValueType ) { cApplyValueTypeMap::cIterator findPos = mBuffmap.Find( applyValueType ); if( findPos != mBuffmap.End() ) { /// ÀÌ¹Ì µé¾î°¡ ÀÖ´Â °æ¿ì cHashSet& influenceSet = (*findPos).mSecond; if( influenceSet.IsEmpty() == false ) { /// ÇØ´ç ½ºÅ³ÀÌ À¯È¿ÇÑÁö °Ë»ç´Â »ý·« Áß return true; } } return false; } bool cMonster::IsHaveApplyDeBuffType( unsigned short applyValueType ) { cApplyValueTypeMap::cIterator findPos = mDeBuffmap.Find( applyValueType ); if( findPos != mDeBuffmap.End() ) { /// ÀÌ¹Ì µé¾î°¡ ÀÖ´Â °æ¿ì cHashSet& influenceSet = (*findPos).mSecond; if( influenceSet.IsEmpty() == false ) { /// ÇØ´ç ½ºÅ³ÀÌ À¯È¿ÇÑÁö °Ë»ç´Â »ý·« Áß return true; } } return false; } void cMonster::AddDistressPer( sObject attacker, long distressPointPer, eTAKEDAMAGE_TYPE type ) { unsigned long playerIdx = attacker.index; /// damage List¿¡ µî·Ï ¶Ç´Â °»½Å PerTakeDamage* perTakeDamage = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, playerIdx ); if( perTakeDamage == 0 ) { assert(0); AddTakeDamage( attacker, 0, 0, type ); } else { long distressPoint = perTakeDamage->distressPoint; distressPoint = long( ( distressPoint * distressPointPer ) / 100 ); AddTakeDamage( attacker, 0, distressPoint, type ); } } void cMonster::SwapDistressPoint( unsigned long attackerIdx, unsigned long targetIdx ) { long attakerDistressPoint = -1; long targetDistressPoint = -1; /// damage List¿¡ °Ë»ö PerTakeDamage* perTakeDamage = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, attackerIdx ); if( perTakeDamage != 0 ) { /// °ø°ÝÀÚ¿¡ ´ëÇÑ ¾î±×·Î°¡ ÀÖ´Ù¸é °ªÀ» ¹é¾÷ ½ÃŲ ÈÄ ÃʱâÈ­ ½ÃŲ´Ù. attakerDistressPoint = perTakeDamage->distressPoint; // = 0 ÀÎ °æ¿ì ChangeActionTarget() ¿¡¼­ »õ·Î¿î Ÿ°ÙÆÃÀ» ÇÒ¶§ ±âÁ¸ À¯Àú¸¦ ¹«½ÃÇÑ´Ù. = 1Àΰæ¿ì ChangeActionTarget()¿¡¼­ ¿ø·¡ À¯Àú¸¦ Ÿ°ÙÆÃ ½ÃµµÇÑ´Ù. perTakeDamage->distressPoint = 1; } perTakeDamage = TAKEDAMAGEPOOL->GetTakeDamage( &mTakeDamageRoot, targetIdx ); if( perTakeDamage != 0 ) { /// Ÿ°Ù¿¡ ´ëÇÑ ¾î±×·Î°¡ ÀÖ´Ù¸é °ªÀ» ¹é¾÷ ½ÃŲ ÈÄ ÃʱâÈ­ ½ÃŲ´Ù. targetDistressPoint = perTakeDamage->distressPoint; // = 0 ÀÎ °æ¿ì ChangeActionTarget() ¿¡¼­ »õ·Î¿î Ÿ°ÙÆÃÀ» ÇÒ¶§ ±âÁ¸ À¯Àú¸¦ ¹«½ÃÇÑ´Ù. = 1Àΰæ¿ì ChangeActionTarget()¿¡¼­ ¿ø·¡ À¯Àú¸¦ Ÿ°ÙÆÃ ½ÃµµÇÑ´Ù. perTakeDamage->distressPoint = 1; } if( attakerDistressPoint < 0 && targetDistressPoint < 0 ) { /// µÎ Ç÷¹ÀÌ¾î ¸ðµÎ °ø°ÝÀÚ ¸í´Ü¿¡ µé¾î°¡ÀÖÁö ¾Ê´Ù¸é ±³Ã¼ÇØ¾ß ÇÒ ´ë»óÀÌ À߸øµÈ°ÍÀÌ´Ù. assert(0); } else if( attakerDistressPoint >= 0 && targetDistressPoint < 0 ) { /// °ø°ÝÀÚÀÇ ¾î±×·Î Á¤º¸¸¸ ÀÖ´Â °æ¿ì, Ÿ°Ù¿¡ °ø°ÝÀÚÀÇ ¾î±×·Î Á¤º¸¸¦ ÀÔ·ÂÇÑ´Ù. sObject target = { eOBJECTTYPE_PLAYER, targetIdx }; AddTakeDamage( target, 0, attakerDistressPoint, eTAKEDAMAGETYPE_ADDPLAYER ); } else if( attakerDistressPoint < 0 && targetDistressPoint >= 0 ) { /// Ÿ°ÙÀÇ ¾î±×·Î Á¤º¸¸¸ ÀÖ´Â °æ¿ì, °ø°ÝÀÚ¿¡ Ÿ°ÙÀÇ ¾î±×·Î Á¤º¸¸¦ ÀÔ·ÂÇÑ´Ù. sObject attacker = { eOBJECTTYPE_PLAYER, attackerIdx }; AddTakeDamage( attacker, 0, targetDistressPoint, eTAKEDAMAGETYPE_ADDPLAYER ); } else if( attakerDistressPoint >= 0 && targetDistressPoint >= 0 ) { /// µÎ Ç÷¹ÀÌ¾î ¸ðµÎ ¾î±×·Î Á¤º¸°¡ ÀÖ´Â °æ¿ì, ¼­·Î¿¡°Ô ¾î±×·Î Á¤º¸¸¦ ÀÔ·ÂÇÑ´Ù. sObject attacker = { eOBJECTTYPE_PLAYER, attackerIdx }; sObject target = { eOBJECTTYPE_PLAYER, targetIdx }; AddTakeDamage( attacker, 0, targetDistressPoint, eTAKEDAMAGETYPE_ADDPLAYER ); AddTakeDamage( target, 0, attakerDistressPoint, eTAKEDAMAGETYPE_ADDPLAYER ); } else assert(0); }