Files
git 9cb257e7ae Add GameClients drops and keep current 1602 source work.
CN1602 is the local client. KR is the official tree with unpacked Data, System, and Sound. Packed .wpk files stay off git.
2026-08-30 23:24:31 +03:00

910 lines
29 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Field.cpp: implementation of the Field class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <float.h>
#include <Global.h>
#include <NPCInfoParser.h>
#include <ServerOptionParser.h>
#include <ServerOptionParserEx.h>
#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;
//////////////////////////////////////////////////////////////////////////
// <LOGIC CONTROL>
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<GameField*>( 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<GameField*>(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;
};
//////////////////////////////////////////////////////////////////////////
// <LOGIC CONTROL>
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;
//////////////////////////////////////////////////////////////////////////
// <LOGIC CONTROL>
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)
// - ???? ???? ?????? ???? ?????? ??? ?????. ??? ???? ???? ?????? ?? ??? ??????? ????? ?????? ???.
//////////////////////////////////////////////////////////////////////////
// <LOGIC CONTROL>
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;
//////////////////////////////////////////////////////////////////////////
// <LOGIC CONTROL>
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;
//////////////////////////////////////////////////////////////////////////
// <ERROR CONTROL>
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);
}
}
//}