// Field.cpp: implementation of the Field class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include #include #include #include #include "Field.h" #include "EffectManager.h" #include "Summoned.h" #include "Sector.h" #include "SectorInfo.h" #include "FieldInfo.h" #include "MapNPC.h" #include "MapObject.h" #include "ObjectFactory.h" #include "TargetFinder.h" #include "Item.h" #include "Player.h" #include "MovementChecker.h" #include "Status/StatusManager.h" #include "GameServerEx.h" #include "MovingPlanner.h" //¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬¦¬ // Field::Field() : SectorGridRef( m_SectorGrid ) , m_pMovingPlanner( new nsAI::MovingPlanner ) //__NA001166_080922_TASK_SSQ_HUMANOID_AI_01__ { m_pFieldInfo = NULL; m_RoomIndex = -1; } Field::~Field() { Release(); SAFE_DELETE(m_pMovingPlanner); } VOID Field::Release() { if( m_pFieldInfo && m_RoomIndex >= 0 ) { m_pFieldInfo->Release( m_RoomIndex ); } m_pFieldInfo = NULL; m_pSharedFieldInfo = NULL; m_RoomIndex = -1; m_SectorGrid.Destroy(); //__NA001166_080922_TASK_SSQ_HUMANOID_AI_01__ m_pMovingPlanner->Release(); } VOID Field::BuildSector() { if( !FlowControl::FCAssert( m_pFieldInfo && !m_SectorGrid.SectorCount ) ) return; // (WAVERIX)(080810)(NOTE) // - ÀÌ ÇÔ¼ö°¡ È£ÃâµÇ´Â ½ÃÁ¡Àº ÀÌÀü±îÁö PreMapLoading, Player(OnEnter)½Ã¿¡ ¹ß»ýÇϰí ÀÖ¾ú´Ù. // ÀÌ°Í »ý°¢º¸´Ù ÆÐŶ·®ÀÌ ¸¹ÀÌ ¹ß»ýÇÑ´Ù. °¢Á¾ Object Enter // - ÀÌÁ¦ Field::Init ½ÃÁ¡¿¡ ¼öÇàÇϱâ·Î ÇÑ´Ù. m_SectorGrid.Build( m_pFieldInfo->SectorGridInfoRef ); } // Àӽ÷ΠInit¿¡¼­ pMapÀ» ¼ÂÆÃÇÏÁö¸¸ ³ªÁß¿¡ »¬¼ö ÀÖÀ¸¸é »«´Ù. VOID Field::Init( FieldInfo* pFieldInfo, bool bPreMapLoading, bool bUsingViewPort, bool bPreRegen ) { m_pFieldInfo = pFieldInfo; m_pSharedFieldInfo = pFieldInfo->GetSharedFieldInfo(); m_bViewport = bUsingViewPort; m_bPreMapLoading = bPreMapLoading; is_war_castle_ = (m_pSharedFieldInfo->IsWarCastle() != false); // CHANGES: f110308.1L m_RoomIndex = m_pFieldInfo->Init(); if( m_RoomIndex < 0 ) { SUNLOG( eCRITICAL_LOG, "[Field::Init] InValid RoomIndex[%d]", m_RoomIndex ); } //__NA001166_080922_TASK_SSQ_HUMANOID_AI_01__ m_pMovingPlanner->~MovingPlanner(); new (m_pMovingPlanner) nsAI::MovingPlanner( m_pSharedFieldInfo, m_RoomIndex ); { BuildSector(); } } VOID Field::Update( DWORD dwDeltaTick ) { } bool Field::IsMovableCoordinates(const WzVector* query_position, FiltersForMovableCoordinates* filter) { // X,YÁÂÇ¥»ó¿¡¼­ ÃÖ´ë°ªº¸´Ù Å« °ªÀ» Ŭ¶óÀÌ¾ðÆ®¿¡¼­ º¸³½ °æ¿ì const SectorGridInfo& sector_grid_info = m_pFieldInfo->SectorGridInfoRef; const SECTOR_IDX coordinates = sector_grid_info.GetSectorIndex(query_position); if (coordinates == INVALID_SECTOR_INDEX) { const DWORD* const boundary = sector_grid_info.GetBoundaries(); SUNLOG(eFULL_LOG, _T("["__FUNCTION__"] [Xmin, Xmax] = [%d, %d], [Ymin, Ymax] = [%d, %d] - ") _T("trying pos {%.f,%.f,%.f}"), boundary[SectorGridInfo::SG_X_MIN], boundary[SectorGridInfo::SG_X_MAX], boundary[SectorGridInfo::SG_Y_MIN], boundary[SectorGridInfo::SG_Y_MAX], query_position->x, query_position->y, query_position->z); return false; }; // CHANGES: f110321.2L, changes logic using filter options bool check_tile_attr = true; float correction_height_workingslot; float* correction_height = NULL; if (filter) { if (filter->skip_check_tile_attr) { check_tile_attr = false; }; if (filter->modified_position) { correction_height = &correction_height_workingslot; } }; // ¸Ê»ó¿¡¼­ À̵¿ °¡´ÉÇÑ ÁÂÇ¥ÀÎÁö °Ë»ç const int result_tile = check_tile_attr ? m_pMovingPlanner->GetAllowTileToStand(*query_position, correction_height, -1.0f, 100.0f) : m_pMovingPlanner->GetTileToStand(*query_position, correction_height, -1.0f, 100.0f); const bool validated = (result_tile != -1); if (validated && filter) { filter->result_tile_no = result_tile; // CHANGES: f110321.2L, changes logic using filter options if (correction_height) { assert(correction_height == &correction_height_workingslot); if (WzVector* modified_pos = filter->modified_position) { *modified_pos = *query_position; // NOTE: add value to solve floating precision problem. // selecting methodology of adding value is based on top-bottom ray calculation correction_height_workingslot += ((correction_height_workingslot > 0.0f) ? -0.9f : +1.1f); // diagram // ranges of correction_height_workingslot = (0.0f, 1.1f] // 1.1f (bottom) // | - safe // z = 0 --------------------------- // | - refer to the below comments // below surface point caused unexpected graphic outputs modified_pos->z -= correction_height_workingslot; }; } }; return validated; } BOOL Field::EnterField( Object* pObject, const WzVector* pwzVec, int iAngle ) { const DWORD ERRCODE_DEFAULT = 1000; const DWORD ERRCODE_INVALID_POS = ERRCODE_DEFAULT + 1; const DWORD ERRCODE_INVALID_SECTOR = ERRCODE_DEFAULT + 2; ////////////////////////////////////////////////////////////////////////// // FlowControl flow; FLOWCONTROL_START() { if( !FlowControl::FCAssert( pObject ) ) return FALSE; IfFailThenBreak(IsValidState(pObject) && "[EnterField]´íÎóµÄ״̬", ERRCODE_DEFAULT); // NOTE, below object types can standing on a tile having NO_WALK attribute // added by __NA001283_20090225_COLLECTION_USE if (0 == pObject->IsEqualObjectKind(COLLECTION_OBJECT) && 0 == pObject->IsEqualObjectKind(MAPNPC_OBJECT) ) // _NA001385_20090924_DOMINATION_TRIGGER { // ¿ø·¡´Â ¿©±â¼­µµ ŸÀϼӼº üũ¸¦ ÇØ¾ßÇÏÁö¸¸ // Æ®¸®°Å NPC°¡ »ý¼ºµÇÁö ¾Ê´Â ¹®Á¦¶§¹®¿¡ ¸ø°¡´Â ŸÀÏ À§¶óµµ ÀÏ´ÜÀº Çã¿ëÇØÁØ´Ù. // CHANGES: f110321.2L, changes logic using filter options FiltersForMovableCoordinates filter = { 0, }; filter.skip_check_tile_attr = true; IfFailThenBreak(IsMovableCoordinates(pwzVec, &filter) && "[EnterField]ͨ¹ýÁË´íÎóµÄλÖÃÏòÁ¿", ERRCODE_INVALID_POS); } // GameField& rGameField = * static_cast( this ); #ifdef _NA_007992_20150127_EVENT_MONSTER_INVASION #else rGameField.BuildInstanceInfo(); #endif //_NA_007992_20150127_EVENT_MONSTER_INVASION pObject->OnEnterField( rGameField, *pwzVec, iAngle ); // Post side-effect : sector positionÀÌ ±¸ÇØÁø´Ù. const SECTOR_IDX coordinates = pObject->GetSectorIndex(); SectorGrid3x3 OUT grid; IfFailThenBreak(m_SectorGrid.GetAroundSectors(coordinates, &grid), ERRCODE_INVALID_SECTOR); // Center¸¦ ¸ÕÀú ó¸®ÇÒ °ÍÀΰ¡ ±×°ÍÀÌ ¹®Á¦·Î´Ù... { // Center Processing Sector* const pSector = m_SectorGrid.GetSector( coordinates ); grid.Grid[ SectorGrid3x3::CENTER ] = INVALID_SECTOR_INDEX; // Center Á¦°Å const RC::eSECTOR_REULT result = pSector->EnterObject( pObject ); IfFailThenBreak(result == RC::RC_SECTOR_SUCCESS, result); pSector->UpdateReferenceCount( pObject, TRUE ); SpawnSector( coordinates, pObject ); }; // ÁÖº¯ ¼½Å͸¸ ó¸®ÇÑ´Ù. Center´Â ¾Õ ·ÎÁ÷¿¡¼­ Á¦°ÅµÇ¾úÀ½. FOREACH_ARRAY( const SECTOR_IDX sector_idx, grid.Grid, SectorGrid3x3::GridArray ) { if( INVALID_SECTOR_INDEX == sector_idx ) continue; Sector* const pSector = m_SectorGrid.GetSector( sector_idx ); //if( IsUsingViewPort() ) // ±âÁ¸ ·ÎÁ÷¿¡ ÀÇÇϸé, view_port¸¦ »ç¿ëÇÏÁö ¾Ê´Â °æ¿ì Àüü ¼½Å͸¦ ó¸®ÇÏ´Â ÇüÅ¿´´Ù. // ¿Ö Àüü ¼½Å͸¦ ´Ù ó¸®Çß¾ú´ÂÁö¸¦ ŸÀüÇØ º¼ °Í. // ÀÏ´Ü °¡´É¼ºÀº OldSector󸮻óÀÇ ¹®Á¦°¡ ÀÖÀ» ¼ö ÀÖ´Ù. pSector->OnEnterThisToNeighbor( pObject ); // ÀÚ½ÅÁ¤º¸¸¦ ÁÖº¯¿¡°Ô pSector->OnEnterNeighborToThis( pObject ); // ÁÖº¯Á¤º¸¸¦ Àڽſ¡°Ô pSector->UpdateReferenceCount( pObject, TRUE ); SpawnSector( sector_idx, pObject ); } // (NEW) // - OnEnterField ¿¡¼­ OldÀ妽º´Â º¯°æµÇÁö ¾Ê°í ÀÖ´Ù. // µû¶ó¼­ Player::Update¿¡¼­ ChangeSector°¡ ³ªÁß¿¡ ¹ß»ýÇÏ°Ô µÉ ÅÍ... // - ½ÇÇè ÄÚµå // (WAVERIX) (NOTE) (081229) Ãʱ⠼½ÅÍ º¯È­¿¡ ¿µÇâÀ» ÁØ´Ù. ¿ø·¡´ë·Î º¹±¸ÇÑ´Ù. // ¿©´ãÀ¸·Î, ÀÚÁÖ ´À³¢´Â °ÅÁö¸¸, ÀüüÀûÀÎ Ç÷ο찡 ÁÁ°Ô ¸»Çϸé Àý¹¦ÇϰÔ, // ³ª»Ú°Ô ¸»Çϸé, ¾îµð·Î Æ¥Áö ¸ð¸£°Ô º¹ÀâÇÏ´Ù. Ãʱ⠼³°è ÀÚü´Â ³ª»Û °ÍÀÌ ¾Æ´Ï¶ó »ý°¢µÇ´Âµ¥, °á°úÀûÀ¸·Î // ÀÌ·¸°Ô µÇ´Â °ÍÀº functionality, modularity¿¡ ´ëÇÑ Àç°íÂûÀÇ Çʿ伺À» ´À³¢°Ô ÇÑ´Ù. return TRUE; } FLOWCONTROL_END; SUNLOG( eCRITICAL_LOG, "["__FUNCTION__"][%3u] %s", flow.GetErrorCode(), flow.GetErrorString() ); return FALSE; } class ObjectGameFieldAutoClosure { public: ObjectGameFieldAutoClosure( Object* const pObject, GameField* const pGameField ) : m_pObject( pObject ) { m_pObject->SetField( pGameField ); }; ~ObjectGameFieldAutoClosure() { m_pObject->SetField( 0 ); } private: Object* m_pObject; }; BOOL Field::LeaveField( Object* pObject ) { if( !IsValidState(pObject) ) { SUNLOG( eCRITICAL_LOG, "[LeaveField]´¦ÓÚ´íÎó״̬." ); return FALSE; } SECTOR_IDX coordinates = pObject->GetSectorIndex(); SectorGrid3x3 OUT grid; if( !m_SectorGrid.GetAroundSectors( coordinates, &grid ) ) { SUNLOG( eCRITICAL_LOG, "[Field::LeaveField] FieldCode[%d] Invalid SectorIndex[%d] ", GetFieldCode(), coordinates ); // ¹º°¡ÀÇ ÀÌÀ¯·Î (¿¹:sector indexÀÇ ÃʱâÈ­ ¶Ç´Â º®¶Õ±â?) ãÀ» ¼ö ¾øÀ» ¼öµµ ÀÖÀ» °ÍÀÌ´Ù. if( coordinates == INVALID_SECTOR_INDEX ) { // (WAVERIX)(080810)(NOTE) // Á¤»óÀûÀÎ ·ÎÁ÷À» ŸÁö ¸øÇßÀ» °æ¿ì(ChangeSector), ¹®Á¦°¡ ¾ß±âµÉ ¼ö ÀÖÀ» ÅÍ. ¾Æ·¡ ·ÎÁ÷À¸·Î ÇØ°áÀ» ½ÃµµÇØ º¸ÀÚ. // ¾Æ·¡ÀÇ ·ÎÁ÷ÀÇ °ËÁõÀº ÀÏ´Ü ÀÌÁؼ® ÆÀÀå´ÔÇÑÅ× °¡´É¼º ŸÀü ÈÄ, Á¤¹Ð °ËÁõÇÒ Çʿ䰡 ÀÖ´Ù. if( coordinates != pObject->GetOldSectorIndex() ) { if( m_SectorGrid.GetAroundSectors( coordinates, &grid ) ) coordinates = pObject->GetOldSectorIndex(); } } } // Center¸¦ ¸ÕÀú ó¸®ÇÒ °ÍÀΰ¡ ±×°ÍÀÌ ¹®Á¦·Î´Ù... // Center Processing Sector* const pSector = m_SectorGrid.GetSector( coordinates ); grid.Grid[ SectorGrid3x3::CENTER ] = INVALID_SECTOR_INDEX; // Center Á¦°Å pObject->OnLeaveField(); ObjectGameFieldAutoClosure autoclosure( pObject, static_cast(this) ); // ¼½ÅÍÀÇ ¿ÀºêÁ§Æ® ¸®½ºÆ®¿¡¼­ »èÁ¦ if( pSector ) { RC::eSECTOR_REULT result = pSector->LeaveObject( pObject ); if( result != RC::RC_SECTOR_SUCCESS ) { SUNLOG( eCRITICAL_LOG, "[Field::LeaveField] RemoveObject Fail![%d] ", result ); return FALSE; } pSector->UpdateReferenceCount( pObject, FALSE ); } // ÁÖº¯ ¼½Å͸¸ ó¸®ÇÑ´Ù. Center´Â ¾Õ ·ÎÁ÷¿¡¼­ Á¦°ÅµÇ¾úÀ½. FOREACH_ARRAY( const SECTOR_IDX sector_idx, grid.Grid, SectorGrid3x3::GridArray ) { if( INVALID_SECTOR_INDEX == sector_idx ) continue; Sector* const pSector = m_SectorGrid.GetSector( sector_idx ); //if( IsUsingViewPort() ) // ±âÁ¸ ·ÎÁ÷¿¡ ÀÇÇϸé, view_port¸¦ »ç¿ëÇÏÁö ¾Ê´Â °æ¿ì Àüü ¼½Å͸¦ ó¸®ÇÏ´Â ÇüÅ¿´´Ù. // ¿Ö Àüü ¼½Å͸¦ ´Ù ó¸®Çß¾ú´ÂÁö¸¦ ŸÀüÇØ º¼ °Í. // ÀÏ´Ü °¡´É¼ºÀº OldSector󸮻óÀÇ ¹®Á¦°¡ ÀÖÀ» ¼ö ÀÖ´Ù. pSector->OnLeaveThisToNeighbor( pObject ); pSector->UpdateReferenceCount( pObject, FALSE ); } return TRUE; } VOID Field::ChangeSector( Object* pObject ) { if( !IsValidState(pObject) ) { SUNLOG( eCRITICAL_LOG, "[EnterField]´¦ÓÚ´íÎó״̬." ); return; } const SECTOR_IDX old_index = pObject->GetOldSectorIndex(); const SECTOR_IDX new_index = pObject->GetSectorIndex(); SectorGrid3x3_ChangeSector grids; if( FALSE == m_SectorGrid.ChangeSector( old_index, new_index, grids ) ) { SUNLOG( eCRITICAL_LOG, "["__FUNCTION__"] - Irony State!! [OI:CI] = [%4d:%4d]", old_index, new_index ); return; } Sector* const pOldSector = GetSector( old_index ); if( pOldSector ) // ÀÌÀü ¼½ÅÍ¿¡¼­ ij¸¯ÅÍ Á¦°Å pOldSector->Remove(pObject); //ASSERT( new_index == grids.CurrentSectors[SectorGrid3x3::CENTER] ); Sector* const pNewSector = GetSector( new_index ); if( pNewSector ) // »õ·Î¿î ¼½ÅÍ¿¡ ij¸¯ÅÍ Ãß°¡ pNewSector->AddObject( pObject ); // ¿ÏÀüÈ÷ ¶°³ª´Â ¼½ÅÍ Ã³¸® SectorGrid3x3& rLeave = grids.LeaveSectors; FOREACH_ARRAY( const SECTOR_IDX sector_idx, rLeave.Grid, SectorGrid3x3::GridArray ) { if( sector_idx == INVALID_SECTOR_INDEX ) continue; Sector* const pSector = GetSector( sector_idx ); // if( IsUsingViewPort() ) // - À̹ø¿¡µµ ¸¶Âù°¡Áö´Ù. Enter, Leave½Ã ¸ù¶¥ ó¸®Çϰí ÀÖ´Ù... ¿ØÁö ºÒ¾ÈÇØÁø´Ù. ¿Ö ÀÌ·¸°Ô Çß¾úÁö? pSector->OnLeaveThisToNeighbor( pObject ); // ij¸¯ÅͰ¡ ¶°³µÀ½À» ¼½ÅÍ¿¡ ¾Ë·ÁÁØ´Ù. pSector->OnLeaveNeighborToThis( pObject ); // ¼½ÅÍÀÇ Á¤º¸¸¦ ¶°³ª´Â ij¸¯ÅͷκÎÅÍ Á¦°ÅÇÑ´Ù. pSector->UpdateReferenceCount( pObject, FALSE ); } // ½Å±Ô·Î µîÀåÇÏ´Â ¼½ÅÍ Ã³¸® SectorGrid3x3& rEnter = grids.EnterSectors; FOREACH_ARRAY( const SECTOR_IDX sector_idx, rEnter.Grid, SectorGrid3x3::GridArray ) { if( sector_idx == INVALID_SECTOR_INDEX ) continue; Sector* const pSector = GetSector( sector_idx ); // if( IsUsingViewPort() ) // - À̹ø¿¡µµ ¸¶Âù°¡Áö´Ù. Enter, Leave½Ã ¸ù¶¥ ó¸®Çϰí ÀÖ´Ù... ¿ØÁö ºÒ¾ÈÇØÁø´Ù. ¿Ö ÀÌ·¸°Ô Çß¾úÁö? pSector->OnEnterThisToNeighbor( pObject ); // »õ·Î¿î ij¸¯ÅͰ¡ µîÀåÇßÀ½À» ¼½ÅÍ¿¡ ¾Ë·ÁÁØ´Ù. pSector->OnEnterNeighborToThis( pObject ); // ¼½ÅÍÀÇ Á¤º¸¸¦ µîÀå ij¸¯ÅÍ¿¡°Ô ¾Ë·ÁÁØ´Ù. pSector->UpdateReferenceCount( pObject, TRUE ); SpawnSector( sector_idx, pObject ); } } BOOL Field::CorrectMovableDestPath(Character* pCharacter, const WzVector* pwvDest, WzVector* corrected_dest) { // implemented by _NA001385_20090924_DOMINATION_FINDPATH_ATTACK const DWORD ERRCODE_INVALID_USAGE = 100; // CHANGES: f110303.1L, added new argument to control result pos. WzVector working_vector; WzVector* result_dest = &working_vector; if (corrected_dest == NULL) { working_vector = *pwvDest; }; if (corrected_dest != NULL) { if (corrected_dest != pwvDest) { *corrected_dest = *pwvDest; } result_dest = corrected_dest; }; ////////////////////////////////////////////////////////////////////////// // FlowControl flow; FLOWCONTROL_START() { //IfFailThenBreak(pwvDest, ERRCODE_INVALID_USAGE); static const SERVER_COMMON_OPTION& stServerOptionInfo = ServerOptionParserEx::Instance()->GetServerOption(); static const WORD maxDistance = stServerOptionInfo.m_wFINDPATH_MAX_DISTANCE; static const FLOAT fAcceptalble_lenQ2 = (FLOAT)(maxDistance * maxDistance); WORD cur_tile_attr = 0; FLOAT fZdiff = 0; //static const WORD jumpLimit = stServerOptionInfo.m_fFINDPATH_JUMPLIMIT; const INT iTileNo = m_pMovingPlanner->GetTileToStand(*result_dest, \ &fZdiff, stServerOptionInfo.m_fFINDPATH_JUMPLIMIT, 100.0f, &cur_tile_attr); if( iTileNo < 0 ) return FALSE; result_dest->z -= fZdiff; const WORD filtered_attr = (PTA_NO_WALK | PTA_PLAYER_FALLDOWN_TILE); const ENUM_FINDPATH_RESULT path_result = m_pMovingPlanner->PathPlan_MoveCheck(pCharacter, *result_dest, iTileNo, filtered_attr, MAX_TILE_NODE_CNT_IN_DOMINATION); if (path_result == EFR_FAILURE || path_result == EFR_SAME_POSITION) return FALSE; return TRUE; } FLOWCONTROL_END; SUNLOG( eCRITICAL_LOG, "["__FUNCTION__"Unexpected Status Check-it now! [Err:%u]", flow.GetErrorCode() ); return FALSE; } BOOL Field::FindPath(Character* pCharacter, WzVector* pwvDest, eCHAR_STATE_TYPE eException) { // (CHANGES) (091229) (WAVERIX) code-arrangement for NPC moving control // (NOTE) (080925) (WAVERIX) // - µÎ ¹øÂ°·Î °í·Á »çÇ×ÀÌ ¸¹Àº ·ÎÁ÷ÀÌ µÇ¾î ¹ö·È´Ù. ÀÏ´Ü ±âÁ¸ ·ÎÁ÷ ÀçÁ¤¸® ÈÄ Ãß°¡ Àû¿ëÇÏ´Â ¹æ½ÄÀ» ÃëÇϱâ·Î ÇÑ´Ù. // Normal status´Â ±×³É ¸®ÅÏ const DWORD ERRCODE_INVALID_USAGE = 100; ////////////////////////////////////////////////////////////////////////// // FlowControl flow; FLOWCONTROL_START() { IfFailThenBreak(pCharacter && pwvDest, ERRCODE_INVALID_USAGE); // ij¸¯ÅͰ¡ À̵¿°¡´ÉÇÑ »óÅÂÀÎÁö üũ // can_move can_move_e // 0 0 0 // 0 1 1 // 1 0(X) 1(not_process) // 1 1(X) 1(not_process) BOOLEAN can_move = !!pCharacter->CanMove(); BOOLEAN can_move_e = can_move ? can_move : !!pCharacter->CanMove(eException); // ¼­¹ö °­Á¦ À̵¿ÀÏ °æ¿ìµµ Æ÷ÇÔ if ((can_move | can_move_e) == 0) return false; // À̵¿°¡´ÉÇÑ ÁÂÇ¥ÀÎÁö üũ if (m_pFieldInfo->IsValidCoordinates(pwvDest) == false) return false; const WORD disable_attr = PTA_NO_WALK | PTA_PLAYER_FALLDOWN_TILE; // (CHANGES) add current tile check if (nsAI::PlanEventObject::AcceptableTarget(pCharacter, 0, 0) == false) // no check safety return false; //const int cur_tile = pCharacter->PlanEvent->GetTile(); //if (cur_tile < 0) // return false; //const WORD cur_tile_attr = m_pMovingPlanner->GetAttribute(cur_tile); //// (NOTE) À̵¿ ºÒ°¡ ŸÀÏ À§¿¡ Á¸ÀçÇϰí ÀÖÀ» ¼ö ÀÖ´Ù. //if (disable_attr & cur_tile_attr) // return false; static const SERVER_COMMON_OPTION& stServerOptionInfo = ServerOptionParserEx::Instance()->GetServerOption(); static const float fAcceptalble_lenQ2 = (float)(stServerOptionInfo.m_wFINDPATH_MAX_DISTANCE * stServerOptionInfo.m_wFINDPATH_MAX_DISTANCE); ////////////////////////////////////////////////////////////////////////// // ´ÙÀ½ ·ÎÁ÷ºÎÅÍ´Â time slicingµîµîÀ» °í·ÁÇØ¾ß ÇÑ´Ù. // TODO(WAVERIX) WORD dest_tile_attr = 0; float fZdiff = 0; const INT dest_tile = m_pMovingPlanner->GetTileToStand(*pwvDest, &fZdiff, stServerOptionInfo.m_fFINDPATH_JUMPLIMIT, 100.0f, &dest_tile_attr); if (dest_tile < 0) return false; // °¥ ¼ö ¾ø´Â °÷ ¶Ç´Â °¡¼­´Â ¾ÈµÇ´Â °Í ½ºÅµ ó¸® // TODO(WAVERIX) °í·Á»çÇ×ÀÌ ¸¹´Ù. // Çö ½ÃÁ¡(080925) fear»óŶó¸é, ³«»çŸÀϷεµ µµ¸ÁÄ¡µµ·Ï ÇÏÀÚ. const WORD filtered_attr = (can_move_e > can_move) ? PTA_NO_WALK : disable_attr; if (filtered_attr & dest_tile_attr) return false; pwvDest->z -= fZdiff; // ±âÁ¸ ·ÎÁ÷... 󸮻ó (PTA_ONLY_JUMP) ÀÌ»óÇÑ ºÎºÐÀÌ ÀÖ´Ù. // ÀÏ´Ü º¯È¯ ÀÛ¾÷ÇÏ´Â ¸ñÀû¿¡ ¸Â°Ô º¯°æÇϱâÀü ÀÌ ºÎºÐÀ» ÇØ°áÇϱâ·Î ÇÑ´Ù. const BOOLEAN isNPC = pCharacter->IsEqualObjectKind(NPC_OBJECT); // (Old Comment) ÇöÀç ±æÃ£±â ¿£Áø¿¡ ¹®Á¦ ¶§¹®¿¡ ³Ê¹« ¸Õ°Å¸®´Â ±æÃ£±â ½Ãµµ¸¦ ÇÏÁö ¾Ê´Â´Ù. if (isNPC) { const float fLengthQ2 = Math_VectorLength2(*pwvDest, *pCharacter->GetPosPtr()); if (fLengthQ2 > fAcceptalble_lenQ2) return false; } const ENUM_FINDPATH_RESULT path_result = m_pMovingPlanner->PathPlan_FindPath(pCharacter, *pwvDest, dest_tile, filtered_attr, stServerOptionInfo.m_wFINDPATH_MAX_NODE_COUNT); if (path_result == EFR_FAILURE || path_result == EFR_SAME_POSITION) { return false; } return true; } FLOWCONTROL_END; SUNLOG(eCRITICAL_LOG, "["__FUNCTION__"Unexpected Status Check-it now! [Err:%u]", flow.GetErrorCode()); return false; } BOOL Field::FindPathThrust(Character* pCharacter, WzVector* pwvMoveDistance, BOOL bForcedMove) { // (CHANGES) (091229) (WAVERIX) code-arrangement for NPC moving control // (NOTE) (080925) (WAVERIX) // - Á¦ÀÏ °í·Á »çÇ×ÀÌ ¸¹Àº ·ÎÁ÷ÀÌ µÇ¾î ¹ö·È´Ù. ÀÏ´Ü ±âÁ¸ ·ÎÁ÷ ÀçÁ¤¸® ÈÄ Ãß°¡ Àû¿ëÇÏ´Â ¹æ½ÄÀ» ÃëÇϱâ·Î ÇÑ´Ù. ////////////////////////////////////////////////////////////////////////// // FlowControl flow; FLOWCONTROL_START() { // ij¸¯ÅͰ¡ À̵¿°¡´ÉÇÑ »óÅÂÀÎÁö üũ if ((bForcedMove || pCharacter->CanMove()) == false) return false; // (CHANGES) add current tile check if (nsAI::PlanEventObject::AcceptableTarget(pCharacter, 0, 0) == false) // no check safety return false; //const int cur_tile = pCharacter->PlanEvent->GetTile(); //if (cur_tile < 0) // return false; //const WORD cur_tile_attr = m_pMovingPlanner->GetAttribute(cur_tile); //// (NOTE) À̵¿ ºÒ°¡ ŸÀÏ À§¿¡ Á¸ÀçÇϰí ÀÖÀ» ¼ö ÀÖ´Ù. //if ((PTA_NO_WALK | PTA_PLAYER_FALLDOWN_TILE) & cur_tile_attr) // return false; // À̵¿°¡´ÉÇÑ ÁÂÇ¥ÀÎÁö üũ const WzVector& rCurPos = *pCharacter->GetPosPtr(); WzVector wvDestPos = rCurPos; wvDestPos += *pwvMoveDistance; // TODO(WAVERIX) °í·Á»çÇ×ÀÌ ¸¹´Ù. if (!IsMovableCoordinates(&wvDestPos)) return false; // °¥ ¼ö ¾ø´Â °÷ ¶Ç´Â °¡¼­´Â ¾ÈµÇ´Â °Í ½ºÅµ ó¸® const WORD disable_attr = (PTA_NO_WALK);//| PTA_PLAYER_FALLDOWN_TILE); // Çö ½ÃÁ¡(080925) fear»óŶó¸é, ³«»çŸÀϷεµ µµ¸ÁÄ¡µµ·Ï ÇÏÀÚ. const WORD filtered_attr = (!bForcedMove) ? PTA_NO_WALK : disable_attr; //if (filtered_attr & cur_tile_attr) // return false; const ENUM_FINDPATH_RESULT path_result = \ m_pMovingPlanner->PathPlan_Thrust(pCharacter, pwvMoveDistance, filtered_attr); if (path_result == EFR_FAILURE || path_result == EFR_SAME_POSITION) { return false; } return true; } FLOWCONTROL_END; return false; } bool Field::GetRandomPosInAround(const WzVector* query_position, int iDist, // TODO: f110321.2L, changes to more valuable usage WzVector& result_position, int number_of_max_retry) { // CHANGES: f080925.x, temporary changes // CHANGES: f110321.2L, the renewal logic has more correct z-axis value than the custom logic result FieldInfo* field_info = this->GetFieldInfo(); // NOTE: first, check whether the position stand on valid grid sector if (field_info->IsValidCoordinates(query_position) == false) { return false; }; // WzVector working_position = *query_position; FiltersForMovableCoordinates coord_check_filter = { 0, }; coord_check_filter.modified_position = &working_position; // for (int loop = number_of_max_retry; loop >= 0; --loop) { RandomRangeVector(&working_position, iDist); if (this->IsMovableCoordinates(&working_position, &coord_check_filter)) { result_position = working_position; // CHANGES: f110322.1L, fixed return true; } } return false; } BOOL Field::GetRandomPosInAroundCheckPath( Character* pCharacter, WORD wMaxNodeCount, const WzVector* pOrgPos, INT iDist, WzVector & vResultPos, int iLoop ) { // TODO: do changes related to f110321.2L // implemented _NA001385_20090924_DOMINATION_~~ vResultPos = *pOrgPos; for( int i = 0; i < iLoop; i++ ) { RandomRangeVector( &vResultPos, iDist ); if (IsMovableCoordinates(&vResultPos) && CorrectMovableDestPath(pCharacter, &vResultPos, &vResultPos)) return TRUE; } return FALSE; } BOOL Field::GetRandomPos( WzVector& wzVec, int iLoop ) { const WORD cant_move_tile_attr = PTA_PICK|PTA_ONLY_JUMP|PTA_NO_WALK; const INT max_tile_count = m_pMovingPlanner->GetNumPathTile(); for( INT loop=iLoop ; loop ; --loop ) { const INT iTileNo = rand()%max_tile_count; const WORD tile_attr = m_pMovingPlanner->GetAttribute( iTileNo ); if( tile_attr & cant_move_tile_attr ) continue; wzVec = m_pMovingPlanner->GetRandomPosInTile( iTileNo ); return TRUE; } SUNLOG( eCRITICAL_LOG, "[Field::GetRandomPos] Can't Find RandomPoint(Too Many Loof)!!" ); return FALSE; } WzVector Field::GetRandomStartingVector( BYTE byClass ) { WzVector wzVec; DWORD TileIndex; nsAI::MovingPlanner* const pMovingPlanner = GetMovingPlanner(); for( int i = 0; i < 50; i++ ) { TileIndex = m_pFieldInfo->GetRandomStartingTileIndex( byClass ); wzVec = pMovingPlanner->GetRandomPosInTile( TileIndex ); if( IsMovableCoordinates( &wzVec ) ) return wzVec; } SUNLOG( eCRITICAL_LOG, "[Field::GetRandomStartingVector] Can't Find RandomStartingPoint!!" ); SetVector( &wzVec, 0, 0, 0 ); return wzVec; } BOOL Field::GetAreaRandomStartingVector( WzID id, WzVector& wzVec ) { const DWORD ERRCODE_CANT_FIND_AREA = 100; const DWORD ERRCODE_NOT_DEFINED_BVTYPE = 110; const DWORD ERRCODE_OTHER = 120; ////////////////////////////////////////////////////////////////////////// // FlowControl flow; FLOWCONTROL_START() { WzSpecialArea* const pArea = m_pFieldInfo->GetAreaInfo( id ); IfFailThenBreak(pArea, ERRCODE_CANT_FIND_AREA); const ENUM_BVTYPE bv_type = pArea->m_wbvRegion.m_eBvType; switch( bv_type ) { case BVT_AABB: { //const BvAABB& rAABB = pArea->m_wbvRegion.m_aabb; const WzVector& rMinPos = pArea->m_wbvRegion.m_aabb.m_wvMin; const WzVector& rMaxPos = pArea->m_wbvRegion.m_aabb.m_wvMax; wzVec.z = rMaxPos.z; // 30¹ø ½Ãµµ¶ó... ¾ÈµÇ´Â °ÍÀº ¾ÈµÇ´Â °ÅÁö¸¸¼­µÎ... for( INT loop=30 ; loop ; --loop ) { wzVec.x = (float)dRandom( rMinPos.x, rMaxPos.x ); wzVec.y = (float)dRandom( rMinPos.y, rMaxPos.y ); if( IsMovableCoordinates( &wzVec ) ) return TRUE; } } break; case BVT_PATH_TILE_INDEX: { const DWORD area_tile_count = pArea->m_wbvRegion.m_BvPathTileIndex.m_nCount; const DWORD* const area_tiles = pArea->m_wbvRegion.m_BvPathTileIndex.m_pdwData; IfFailThenBreak(area_tile_count, ERRCODE_OTHER); nsAI::MovingPlanner* const pMovingPlanner = GetMovingPlanner(); // 30¹ø ½Ãµµ¶ó... ¾ÈµÇ´Â °ÍÀº ¾ÈµÇ´Â °ÅÁö¸¸¼­µÎ... for( INT loop=30 ; loop ; --loop ) { const DWORD selected_tile = (rand() % area_tile_count); wzVec = pMovingPlanner->GetRandomPosInTile( area_tiles[selected_tile] ); if( IsMovableCoordinates( &wzVec ) ) return TRUE; } SetFailFc( "loop limit", ERRCODE_OTHER ); } break; } // ¿©±â¿¡ µµ´ÞÇÏ´Â °ÍÀº ¿¡·¯ ¹ß»ýÇÑ °æ¿ì // return FALSE; } FLOWCONTROL_END; ////////////////////////////////////////////////////////////////////////// // switch( flow.GetErrorCode() ) { case ERRCODE_CANT_FIND_AREA: { TCHAR pszAreaID[8] = { 0, }; WzIDToString( pszAreaID, id ); pszAreaID[4] = '\0'; SUNLOG( eCRITICAL_LOG , "[Field::GetAreaRandomStartingVector][FIELDCODE:%u][AreaID:%s]ûÓг¡¾°." , m_pFieldInfo->GetFieldCode(), pszAreaID ); wzVec = GetRandomStartingVector(); } return FALSE; default: SetVector( &wzVec, 0, 0, 0 ); break; } return FALSE; } BOOL Field::RandomAreaPos( WzVector & vRandomPos, DWORD dwAreaID ) { WzSpecialArea *pBaseAreaInfo = GetFieldInfo()->GetAreaInfo( dwAreaID ); if( !pBaseAreaInfo ) { SUNLOG( eFULL_LOG, "[RandomAreaPos] MoveArea(%u)Info doesn't exist!", dwAreaID ); return FALSE; } if( pBaseAreaInfo ->m_wbvRegion.m_eBvType == BVT_PATH_TILE_INDEX ) { DWORD dwAreaTileCnt = pBaseAreaInfo->m_wbvRegion.m_BvPathTileIndex.m_nCount; if( dwAreaTileCnt ) { DWORD *pdwTileIndex = pBaseAreaInfo->m_wbvRegion.m_BvPathTileIndex.m_pdwData; DWORD dwSelectedTile = rand() % dwAreaTileCnt; vRandomPos = m_pMovingPlanner->GetRandomPosInTile( pdwTileIndex[dwSelectedTile] ); return TRUE; } } else if( pBaseAreaInfo ->m_wbvRegion.m_eBvType == BVT_AABB ) { WzVector vMinPos = pBaseAreaInfo->m_wbvRegion.m_aabb.m_wvMin; WzVector vMaxPos = pBaseAreaInfo->m_wbvRegion.m_aabb.m_wvMax; vRandomPos.z = vMaxPos.z; // 10¹ø±îÁö¸¸ ½ÃµµÇÑ´Ù. for( int i = 0; i < 10; ++i ) { vRandomPos.x = (float)dRandom( vMinPos.x, vMaxPos.x ); vRandomPos.y = (float)dRandom( vMinPos.y, vMaxPos.y ); if( IsMovableCoordinates( &vRandomPos ) ) { return TRUE; } } } else { SUNLOG( eCRITICAL_LOG, "[Field::RandomAreaPos] AreaType is Invalid!!" ); } return FALSE; } //{__NA_0_20090720_GUILD_RENDER_INFO_MODIFY //GetSectorGrid3x3 VOID Field::FirstGuildMemberEnter( Player* pPlayer ) { if( !IsValidState(pPlayer) ) { SUNLOG( eCRITICAL_LOG, "[EnterField]´¦ÓÚ´íÎó״̬." ); return; } const SECTOR_IDX idxSector = pPlayer->GetSectorIndex(); SectorGrid3x3 OUT grid; if( FALSE == m_SectorGrid.GetAroundSectors(idxSector, &grid) ) return; //.// Center const Sector* const pSector = m_SectorGrid.GetSector( idxSector ); grid.Grid[ SectorGrid3x3::CENTER ] = INVALID_SECTOR_INDEX; // Center Á¦°Å pPlayer->OnSendAllPlayersGuildRenderInfoToNeighbor(*pSector); pPlayer->OnSendAllPlayersGuildRenderInfo(*pSector); //.// Around FOREACH_ARRAY( const SECTOR_IDX sector_idx, grid.Grid, SectorGrid3x3::GridArray ) { if( INVALID_SECTOR_INDEX == sector_idx ) continue; const Sector* const pSector = m_SectorGrid.GetSector( sector_idx ); pPlayer->OnSendAllPlayersGuildRenderInfoToNeighbor(*pSector); pPlayer->OnSendAllPlayersGuildRenderInfo(*pSector); } } //}