// 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?????? ??“S???? ? ???? ??????????? ???? ??? 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] invalid state", 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) && 0 == pObject->IsEqualObjectKind(MONSTER_OBJECT)) { // Script spawn points can sit on no-walk / off-mesh tiles. // Collection, map NPCs, and monsters are allowed through here; // SpawnMonster still snaps to a nearby walkable tile when needed. FiltersForMovableCoordinates filter = { 0, }; filter.skip_check_tile_attr = true; IfFailThenBreak(IsMovableCoordinates(pwzVec, &filter) && "[EnterField] invalid position vector", 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] invalid state." ); 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] invalid state." ); 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 ) // ???? ??????? ©¦???? ???? pOldSector->Remove(pObject); //ASSERT( new_index == grids.CurrentSectors[SectorGrid3x3::CENTER] ); Sector* const pNewSector = GetSector( new_index ); if( pNewSector ) // ???¥ï? ????? ©¦???? ??? 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 ); // ©¦????? ???????? ????? ??????. pSector->OnLeaveNeighborToThis( pObject ); // ?????? ?????? ?????? ©¦????¥ê??? ???????. 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 ); // ???¥ï? ©¦????? ?????????? ????? ??????. pSector->OnEnterNeighborToThis( pObject ); // ?????? ?????? ???? ©¦??????? ??????. 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); // ©¦????? ????????? ???????? ?? // 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); // ???? ???? ????? ??­P ???? 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() { // ©¦????? ????????? ???????? ?? 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] no scene." , 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] invalid state." ); 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); } } //}