Files
Leviathan/Server/GameServer/Game/GameProc/RandomManager.cpp
T
2026-06-01 12:46:52 +02:00

504 lines
13 KiB
C++

#include "RandomManager.h"
#include <toolkit/ILock.h>
#include "StructMisc.h"
static std::vector<_AWAKEN_INFO> g_vAwakenInfo;
static std::vector<_AWAKEN_PROBABILITIES_INFO> g_vAwakenProbabilitiesInfo;
static std::vector< RandomItemPresetInfo > g_vRandomItemPresetInfo; // 프리셋 정보 벡터
static std::vector< RandomItemOptionGroupInfo > g_vRandomItemOptionInfo; // 옵션 그룹 벡터 (같은 option ID를 공유하는 옵션리스트의 벡터)
static volatile LONG s_nRandomMaxSID;
void RandomManager::CheckValidityForRandomOptionResource()
{
for( std::vector< RandomItemPresetInfo >::iterator it = g_vRandomItemPresetInfo.begin() ; it != g_vRandomItemPresetInfo.end() ; ++it )
{
for( int i = 0 ; i < ItemInstance::MAX_RANDOM_OPTION_NUMBER ; ++ i )
{
if( it->optionID[ i ] )
{
bool bFind = false;
for( std::vector< RandomItemOptionGroupInfo >::iterator inIt = g_vRandomItemOptionInfo.begin() ; inIt != g_vRandomItemOptionInfo.end() ; ++inIt )
{
if( it->optionID[ i ] == inIt->optionID )
{
bFind = true;
break;
}
}
// 프리셋이 가리키는 옵션 ID가 존재하지 않음
if( !bFind )
assert( 0 );
}
}
}
}
void RandomManager::RegisterAwakenInfo( const _AWAKEN_INFO & _AwakenInfo )
{
std::vector<_AWAKEN_INFO>::iterator it;
bool find = false;
for( it = g_vAwakenInfo.begin() ; it != g_vAwakenInfo.end() ; ++it )
{
if( (*it).nSid == _AwakenInfo.nSid )
{
find = true;
(*it).nSid = _AwakenInfo.nSid;
(*it).nType = _AwakenInfo.nType;
s_memcpy( (*it).Level, sizeof( (*it).Level ), _AwakenInfo.Level, sizeof( _AwakenInfo.Level ) );
break;
}
}
if( !find )
{
_AWAKEN_INFO info;
info.nSid = _AwakenInfo.nSid;
info.nType = _AwakenInfo.nType;
s_memcpy( info.Level, sizeof( info.Level ), _AwakenInfo.Level, sizeof( _AwakenInfo.Level ) );
g_vAwakenInfo.push_back( info );
}
};
void RandomManager::RegisterAwakenProbabilitiesInfo( struct _AWAKEN_PROBABILITIES_INFO & _AwakenProbabilities_info )
{
std::vector<_AWAKEN_PROBABILITIES_INFO>::iterator it;
bool find = false;
for( it = g_vAwakenProbabilitiesInfo.begin() ; it != g_vAwakenProbabilitiesInfo.end() ; ++it )
{
if( (*it).nSid == _AwakenProbabilities_info.nSid )
{
find = true;
(*it).nSid = _AwakenProbabilities_info.nSid;
(*it).nLevel = _AwakenProbabilities_info.nLevel;
(*it).fProbabilities = _AwakenProbabilities_info.fProbabilities;
break;
}
}
if( !find )
{
_AWAKEN_PROBABILITIES_INFO info;
info.nSid = _AwakenProbabilities_info.nSid;
info.nLevel = _AwakenProbabilities_info.nLevel;
info.fProbabilities = _AwakenProbabilities_info.fProbabilities;
g_vAwakenProbabilitiesInfo.push_back( info );
}
};
void RandomManager::RegisterRandomItemOptionInfo( struct RandomItemOptionInfo & info )
{
for( std::vector< RandomItemOptionGroupInfo >::iterator it = g_vRandomItemOptionInfo.begin(); it != g_vRandomItemOptionInfo.end(); ++it )
{
if( (*it).optionID == info.optionID )
{
(*it).optionList.push_back( info );
return;
}
}
if(info.minValue2 > info.maxValue2)
{
_cprint("error item random option min/max value [id %d]\n", info.optionID);
}
RandomItemOptionGroupInfo groupInfo;
groupInfo.optionID = info.optionID;
groupInfo.optionList.push_back( info );
g_vRandomItemOptionInfo.push_back( groupInfo );
}
void RandomManager::RegisterRandomItemPresetInfo( struct RandomItemPresetInfo & info )
{
for( std::vector< RandomItemPresetInfo >::iterator it = g_vRandomItemPresetInfo.begin(); it != g_vRandomItemPresetInfo.end(); ++it )
{
if( (*it).presetID == info.presetID )
{
(*it) = info;
return;
}
}
g_vRandomItemPresetInfo.push_back( info );
}
c_fixed10 RandomManager::GetAwakenProbabilitiesInfo( int _nlevel )
{
std::vector<_AWAKEN_PROBABILITIES_INFO>::iterator it;
for( it = g_vAwakenProbabilitiesInfo.begin() ; it != g_vAwakenProbabilitiesInfo.end() ; ++it )
{
if( (*it).nLevel == _nlevel )
{
return (*it).fProbabilities;
}
}
return 0;
}
void RandomManager::GetAwakenProbabilitiesInfo( int *_arProvabilities, int _nCnt )
{
if( _nCnt > g_vAwakenProbabilitiesInfo.size() )
{
// LOG 남기자
return;
}
memset( _arProvabilities, 0, sizeof(int)*_nCnt );
int nCnt = 0;
int nPrevCnt = 0;
std::vector<_AWAKEN_PROBABILITIES_INFO>::iterator it;
for( it = g_vAwakenProbabilitiesInfo.begin() ; it != g_vAwakenProbabilitiesInfo.end() ; ++it )
{
if( nCnt > _nCnt )
{
// LOG 남기자
return;
}
_arProvabilities[ nCnt ] = _arProvabilities[ nPrevCnt ] + ( (*it).fProbabilities * 1000 );
nPrevCnt = nCnt;
nCnt++;
}
}
int RandomManager::GetAwakenInfoValue( int _nLevel, int _nValueType, int & _nBitSet, int & _Type )
{
int nValueType = 0;
switch( _nValueType )
{
case 1: nValueType = StructState::FLAG_STR; break;
case 2: nValueType = StructState::FLAG_VIT; break;
case 3: nValueType = StructState::FLAG_AGI; break;
case 4: nValueType = StructState::FLAG_DEX; break;
case 5: nValueType = StructState::FLAG_INT; break;
case 6: nValueType = StructState::FLAG_MEN; break;
case 7: nValueType = StructState::FLAG_ATTACK_POINT; break;
case 8: nValueType = StructState::FLAG_MAGIC_POINT; break;
case 9: nValueType = StructState::FLAG_DEFENCE; break;
case 10: nValueType = StructState::FLAG_MAGIC_DEFENCE; break;
case 11: nValueType = StructState::FLAG_ATTACK_SPEED; break;
case 12: nValueType = StructState::FLAG_CAST_SPEED; break;
case 13: nValueType = StructState::FLAG_MOVE_SPEED; break;
case 14: nValueType = StructState::FLAG_ACCURACY; break;
case 15: nValueType = StructState::FLAG_MAGIC_ACCURACY; break;
case 16: nValueType = StructState::FLAG_AVOID; break;
case 17: nValueType = StructState::FLAG_MAGIC_RESISTANCE; break;
case 18: nValueType = StructState::FLAG_CRITICAL; break;
case 19: nValueType = StructState::FLAG_CRITICAL_DAMAGE; break;
default:
{
return 0;
}
break;
}
std::vector<_AWAKEN_INFO>::iterator it;
for( it = g_vAwakenInfo.begin() ; it != g_vAwakenInfo.end() ; ++it )
{
if( (*it).Level[ _nLevel ].nValue1 == nValueType )
{
_Type = (*it).nType;
_nBitSet = nValueType;
return (*it).Level[ _nLevel ].nValue2;
}
}
return 0;
}
int RandomManager::GetAwakenValueType( struct StructItem * _pMainMaterial )
{
int nMaxTypeCount = GetMaxAwakenCount();
int nResult = XRandom( 1, nMaxTypeCount - 2 );
if( _pMainMaterial->IsAccessory() )
nResult = XRandom( 1, nMaxTypeCount );
return nResult;
}
int RandomManager::GetMaxAwakenCount()
{
return static_cast< int >( g_vAwakenInfo.size() );
}
bool RandomManager::CheckMaxAwakenOption( const ItemInstance::RANDOM_OPTION * _pAwakenOption, int _nBitSet, int _nType, int _nData )
{
if( NULL == _pAwakenOption || 0 >= _nBitSet || 0 >= _nType )
{
return false;
}
int nAwakenCheckData = 0;
for( int nArrCnt = 0 ; nArrCnt < 5 ; ++nArrCnt )
{
int nAwakenCheckValue = _pAwakenOption->OptionInfo[ nArrCnt ].fValue1;
int nAwakenCheckType = _pAwakenOption->OptionInfo[ nArrCnt ].nType;
if( _nBitSet == nAwakenCheckValue && _nType == nAwakenCheckType )
{
nAwakenCheckData += _pAwakenOption->OptionInfo[ nArrCnt ].fValue2;
}
}
nAwakenCheckData += _nData;
int OneMin = 0, OneMax = 0;
int MultiMin = 0, MultiMax = 0;
if( _nBitSet & StructState::FLAG_STR // 힘
|| _nBitSet & StructState::FLAG_VIT // 체력
|| _nBitSet & StructState::FLAG_AGI // 민첩
|| _nBitSet & StructState::FLAG_DEX // 집중
|| _nBitSet & StructState::FLAG_INT // 지능
|| _nBitSet & StructState::FLAG_MEN ) // 정신
{
OneMin = -50;
OneMax = 50;
MultiMin = -100;
MultiMax = 100;
}
if( _nBitSet & StructState::FLAG_ATTACK_POINT // 물리 공격력
|| _nBitSet & StructState::FLAG_MAGIC_POINT ) // 마법 공격력
{
OneMin = -500;
OneMax = 500;
MultiMin = -1500;
MultiMax = 1500;
}
if( _nBitSet & StructState::FLAG_DEFENCE // 물리 방어력
|| _nBitSet & StructState::FLAG_MAGIC_DEFENCE ) // 마법 방어력
{
OneMin = -200;
OneMax = 200;
MultiMin = -600;
MultiMax = 600;
}
if( _nBitSet & StructState::FLAG_ACCURACY // 명중
|| _nBitSet & StructState::FLAG_AVOID // 회피
|| _nBitSet & StructState::FLAG_MAGIC_ACCURACY // 마법명중
|| _nBitSet & StructState::FLAG_MAGIC_RESISTANCE ) // 마법저항
{
OneMin = -200;
OneMax = 200;
MultiMin = -600;
MultiMax = 600;
}
if( _nBitSet & StructState::FLAG_ATTACK_SPEED // 공격속도
|| _nBitSet & StructState::FLAG_CAST_SPEED // 시전속도
|| _nBitSet & StructState::FLAG_MOVE_SPEED ) // 이동속도
{
OneMin = -20;
OneMax = 20;
MultiMin = -60;
MultiMax = 60;
}
if( _nBitSet & StructState::FLAG_CRITICAL )
{
OneMin = -10;
OneMax = 10;
MultiMin = -30;
MultiMax = 30;
}
if( _nBitSet & StructState::FLAG_CRITICAL_DAMAGE )
{
OneMin = -15;
OneMax = 15;
MultiMin = -40;
MultiMax = 40;
}
// 하나의 인자 값 범위 확인
if( OneMin > _nData || OneMax < _nData )
{
return false;
}
// 누적 인자값 범위 확인
if( MultiMin > nAwakenCheckData || MultiMax < nAwakenCheckData )
{
return false;
}
return true;
}
bool RandomManager::PickRandomOptionByPreset( struct ItemInstance::RANDOM_OPTION * option, int presetID )
{
// 프리셋 ID로 프리셋 찾기
std::vector< RandomItemPresetInfo >::iterator it = g_vRandomItemPresetInfo.begin();
bool bFind = false;
for( ; it != g_vRandomItemPresetInfo.end() ; ++it )
{
if( presetID == it->presetID )
{
bFind = true;
break;
}
}
if( !bFind )
return false;
option->nRandomType = ItemInstance::IDENTIFIED;
int k = 0;
// 찾은 프리셋의 옵션 돌면서 랜덤화시키기
for( int i = 0 ; i < ItemInstance::MAX_RANDOM_OPTION_NUMBER ; ++i )
{
if( !it->optionSucRate[ i ] )
break;
int nRandom = it->optionSucRate[ i ] * 10000;
// 한 옵션당 성공 or 꽝 결정
if( static_cast< int >( XRandom( 1, 1000000 ) ) <= nRandom )
{
bool bDuplicated;
ItemInstance::OPTION_INFO kData;
do
{
bDuplicated = false;
kData = _PickRandomOptionFromOptionID( it->optionID[ i ] );
for( int j = 0 ; j < k ; ++ j )
{
// 중복 체크
if( option->OptionInfo[ j ].nType == kData.nType && option->OptionInfo[ j ].fValue1 == kData.fValue1 )
{
bDuplicated = true;
break;
}
}
}
while( bDuplicated );
option->OptionInfo[ k ].nType = kData.nType;
option->OptionInfo[ k ].fValue1 = kData.fValue1;
option->OptionInfo[ k ].fValue2 = kData.fValue2;
++k;
}
}
return true;
}
bool RandomManager::PickAwakenRandomOptionByPreset(struct ItemInstance::RANDOM_OPTION* option, int presetID)
{
std::vector< RandomItemPresetInfo >::iterator it = g_vRandomItemPresetInfo.begin();
bool bFind = false;
for (; it != g_vRandomItemPresetInfo.end(); ++it)
{
if (presetID == it->presetID)
{
bFind = true;
break;
}
}
if (!bFind)
return false;
option->nRandomType = ItemInstance::AWAKEN;
int k = 0;
for (int i = 0; i < ItemInstance::MAX_RANDOM_OPTION_NUMBER; ++i)
{
if (!it->optionSucRate[i])
break;
int nRandom = it->optionSucRate[i] * 10000;
if (static_cast<int>(XRandom(1, 1000000)) <= nRandom)
{
bool bDuplicated;
ItemInstance::OPTION_INFO kData;
do
{
bDuplicated = false;
kData = _PickRandomOptionFromOptionID(it->optionID[i]);
for (int j = 0; j < k; ++j)
{
if (option->OptionInfo[j].nType == kData.nType && option->OptionInfo[j].fValue1 == kData.fValue1)
{
bDuplicated = true;
break;
}
}
} while (bDuplicated);
option->OptionInfo[k].nType = kData.nType;
option->OptionInfo[k].fValue1 = kData.fValue1;
option->OptionInfo[k].fValue2 = kData.fValue2;
++k;
}
}
return true;
}
ItemInstance::OPTION_INFO RandomManager::_PickRandomOptionFromOptionID( int id )
{
ItemInstance::OPTION_INFO kOption;
::ZeroMemory(&kOption, sizeof(kOption));
for( std::vector< RandomItemOptionGroupInfo >::iterator it = g_vRandomItemOptionInfo.begin(); it != g_vRandomItemOptionInfo.end() ; ++it )
{
if( id == it->optionID )
{
int nSet = XRandom() % static_cast< int >( it->optionList.size() );
RandomItemOptionInfo kInfo = it->optionList[ nSet ];
kOption.nType = kInfo.optionType;
kOption.fValue1 = kInfo.optionValue1;
// XFastNormalRandom 함수는 정수를 반환하므로 소수점 1째 자리까지 표현하기 위해 곱하기 10 나누기 10 처리 해준다.
int min = static_cast< int >( kInfo.minValue2 * 100 ); //10 AziaMafia fix rdm option
int max = static_cast< int >( kInfo.maxValue2 * 100 ); //10
c_fixed10 rate;
rate.set( kInfo.extremeRate * 100 ); //100
if(min > max)
{
max = min;
}
//AziaMafia Change Option Random top Fast
//kOption.fValue2.set( XNormalRandom( min, max, rate ) * 100 );//1000
kOption.fValue2.set( XRandom(min , max ) * 100 );
break;
}
}
return kOption;
}
void RandomManager::SetMaxRandomOptionSID( int nSID )
{
if( s_nRandomMaxSID )
{
throw XException( "Call SetMaxRandomOptionSID twice by a manager" );
}
s_nRandomMaxSID = nSID;
}
int RandomManager::AllocRandomSID()
{
return InterlockedIncrement( &s_nRandomMaxSID ) + 1;
}