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

779 lines
22 KiB
C++

#include <toolkit/khash.h>
#include <dump/XException.h>
#include "StructTitleManager.h"
#include "TitleBase.h"
#include "StructTitleCondition.h"
#include "GameRule.h"
#include "StructItem.h"
static std::vector< TitleBaseServer * > s_vTitleBase;
static KHash< size_t, hashPr_mod_int > s_hsTitleID;
static std::vector< TitleCondition * > s_vTitleCondition;
static KHash< size_t, hashPr_mod_int > s_hsTitleCondition;
static std::vector< TitleConditionType * > s_vTitleConditionType;
static KHash< size_t, hashPr_mod_int > s_hsTitleConditionTypeByID;
static KHash< std::pair< size_t, size_t > *, hashPr_mod_int > s_hsTitleConditionTypeByType;
static volatile LONG s_nTitleMaxID;
static volatile LONG s_nTitleConditionMaxID;
StructTitleManager::StructTitleManager()
{
m_pHandler = NULL;
}
StructTitleManager::~StructTitleManager()
{
m_hsTitle.clear();
m_hsTitleCondition.clear();
for( std::vector< StructTitle * >::iterator it = m_vTitle.begin(); it != m_vTitle.end(); ++it )
{
(*it)->FreeTitle();
}
m_vTitle.clear();
for( std::vector< StructTitleCondition * >::iterator it = m_vTitleCondition.begin(); it != m_vTitleCondition.end(); ++it )
{
(*it)->FreeTitleCondition();
}
m_vTitleCondition.clear();
}
void StructTitleManager::AddTitle( StructTitle * pTitle )
{
m_vTitle.push_back( pTitle );
m_hsTitle.add( pTitle->GetCode(), m_vTitle.size() - 1 );
if( pTitle->GetStatus() & StructTitle::TITLE_STATUS_ACHIEVE )
UpdateTitleConditionByTitleAchieve( pTitle->GetCode() );
}
bool StructTitleManager::AddTitleCondition( struct StructTitleCondition * pTitleCondition )
{
m_vTitleCondition.push_back( pTitleCondition );
m_hsTitleCondition.add( pTitleCondition->GetType(), m_vTitleCondition.size() - 1 );
return true;
}
void StructTitleManager::SetTitleMaxID( int nID )
{
if( s_nTitleMaxID )
{
throw XException( "Call SetTitleMaxID twice by a manager." );
}
s_nTitleMaxID = nID;
}
void StructTitleManager::SetTitleConditionMaxID( int nID )
{
if( s_nTitleConditionMaxID )
{
throw XException( "Call SetTitleConditionMaxID twice by a manager." );
}
s_nTitleConditionMaxID = nID;
}
int StructTitleManager::AllocTitleID()
{
return InterlockedIncrement( &s_nTitleMaxID );
}
int StructTitleManager::AllocTitleConditionID()
{
return InterlockedIncrement( &s_nTitleConditionMaxID );
}
TitleBaseServer * StructTitleManager::RegisterTitleBase( TitleBaseServer * base )
{
if( s_hsTitleID.has( base->nID ) )
{
size_t idx;
s_hsTitleID.lookup( base->nID, idx );
s_vTitleBase[idx] = base;
return s_vTitleBase[idx];
}
s_vTitleBase.push_back( base );
s_hsTitleID.add( base->nID, s_vTitleBase.size() - 1 );
return s_vTitleBase.back();
}
TitleCondition * StructTitleManager::RegisterTitleCondition( TitleCondition * base )
{
if( s_hsTitleCondition.has( base->nTitleID ) )
{
size_t idx;
s_hsTitleCondition.lookup( base->nTitleID, idx );
s_vTitleCondition[idx] = base;
return s_vTitleCondition[idx];
}
s_vTitleCondition.push_back( base );
s_hsTitleCondition.add( base->nTitleID, s_vTitleCondition.size() - 1 );
return s_vTitleCondition.back();
}
void StructTitleManager::RegisterTitleConditionType( TitleConditionType * base )
{
static int nLastCategory = 0;
static int nLastCount = 0;
if( nLastCategory != base->nCategory )
{
if( nLastCategory )
{
std::pair< size_t, size_t > * pRange = new std::pair< size_t, size_t >( s_vTitleConditionType.size() - nLastCount, nLastCount );
s_hsTitleConditionTypeByType.add( nLastCategory, pRange );
}
nLastCategory = base->nCategory;
nLastCount = 0;
}
if( !base->nID )
return;
s_vTitleConditionType.push_back( base );
s_hsTitleConditionTypeByID.add( base->nID, s_vTitleConditionType.size() - 1 );
nLastCount++;
}
void StructTitleManager::RelateTitleCondition( const int nTitleConditionTypeID, TitleCondition * pTitleCondition )
{
if( !s_hsTitleConditionTypeByID.has( nTitleConditionTypeID ) )
{
// TitleCondition이 존재하지 않는 TitleConditionType을 참조
assert( 0 );
return;
}
size_t idx;
s_hsTitleConditionTypeByID.lookup( nTitleConditionTypeID, idx );
s_vTitleConditionType[idx]->vRelatedCondition.push_back( pTitleCondition );
}
TitleBaseServer * StructTitleManager::GetTitleBase( int nCode )
{
size_t idx;
if( s_hsTitleID.lookup( nCode, idx ) )
{
return s_vTitleBase[idx];
}
return NULL;
}
bool StructTitleManager::AchieveTitle( int nCode )
{
StructTitle *pTitle = setTitleStruct( nCode );
if( !pTitle )
return false;
if( pTitle->GetStatus() & StructTitle::TITLE_STATUS_ACHIEVE )
return false;
pTitle->SetStatus( pTitle->GetStatus() | StructTitle::TITLE_STATUS_ACHIEVE );
m_pHandler->onTitleAchieved( pTitle );
UpdateTitleConditionByTitleAchieve( pTitle->GetCode() );
return true;
}
bool StructTitleManager::OpenTitle( int nCode )
{
StructTitle *pTitle = setTitleStruct( nCode );
if( !pTitle )
return false;
if( pTitle->GetStatus() & ( StructTitle::TITLE_STATUS_OPEN | StructTitle::TITLE_STATUS_ACHIEVE ) )
return false;
pTitle->SetStatus( pTitle->GetStatus() | StructTitle::TITLE_STATUS_OPEN );
m_pHandler->onTitleOpened( pTitle );
return true;
}
bool StructTitleManager::BookmarkTitle( int nCode )
{
StructTitle *pTitle = setTitleStruct( nCode );
if( !pTitle )
return false;
pTitle->SetStatus( pTitle->GetStatus() ^ StructTitle::TITLE_STATUS_BOOKMARK );
pTitle->SetDBUpdateFlag( true );
m_pHandler->onTitleBookmarked( pTitle );
return true;
}
bool StructTitleManager::SetTitleChecked( int nCode )
{
StructTitle *pTitle = setTitleStruct( nCode );
if( !pTitle )
return false;
pTitle->SetStatus( pTitle->GetStatus() );
pTitle->SetDBUpdateFlag( true );
return true;
}
void StructTitleManager::CheckTitleCondition( TitleConditionType * & pCondition )
{
// 변경된 상태에 따라 호칭 획득 가능 여부를 체크한다.
for( std::vector< TitleCondition * >::const_iterator it = pCondition->vRelatedCondition.begin(); it != pCondition->vRelatedCondition.end(); ++it )
{
time_t t = time( NULL );
TitleBase *pBase = GetTitleBase( (*it)->nTitleID );
if( pBase->bIsPeriodic && ( pBase->tBeginOfPeriod > t || pBase->tEndOfPeriod < t ) )
continue;
bool bOpened = false, bOpen = false, bAchieve = false;
StructTitle *pTitle = getTitleStruct( (*it)->nTitleID );
if( pTitle )
{
bOpen = bOpened = !!( pTitle->GetStatus() & StructTitle::TITLE_STATUS_OPEN );
bAchieve = !!( pTitle->GetStatus() & StructTitle::TITLE_STATUS_ACHIEVE );
}
// 이미 획득했던 호칭의 조건은 검사하지 않는다.
if( bAchieve )
continue;
if( !bOpened )
bOpen = checkTitleCondition( (*it)->vTitleOpenConditionInfo );
if( bOpen )
bAchieve = checkTitleCondition( (*it)->vTitleAchieveConditionInfo );
if( bAchieve )
{
AchieveTitle( (*it)->nTitleID );
continue;
}
if( !bOpened && bOpen )
{
OpenTitle( (*it)->nTitleID );
continue;
}
}
}
void StructTitleManager::CheckTitleConditionByLogin()
{
for( std::vector< TitleConditionType * >::const_iterator it = s_vTitleConditionType.begin(); it != s_vTitleConditionType.end(); ++it )
{
TitleConditionType * pType = (*it);
CheckTitleCondition( pType );
}
}
void StructTitleManager::UpdateRelatedTitleCondition( int nTitleConditionType, int nValue1, int nValue2, int nValue3, const __int64 nCount )
{
// 값이 완전히 동일한 TitleCondition은 단 한 가지 뿐일 것이므로 대상을 찾은 이후 return한다.
size_t nStart, nEnd;
GetRelatedTitleConditionRange( nTitleConditionType, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] == nValue1 &&
pCondition->nValue[1] == nValue2 &&
pCondition->nValue[2] == nValue3 )
{
updateTitleCondition( pCondition, nCount, pCondition->bIsSet, pCondition->bSkipDBUpdate );
return;
}
}
}
void StructTitleManager::UpdateTitleCondition( const int nTitleCondition, const __int64 nCount )
{
size_t nIndex = 0;
if( !s_hsTitleConditionTypeByID.lookup( nTitleCondition, nIndex ) )
return;
TitleConditionType * & pCondition = s_vTitleConditionType[nIndex];
updateTitleCondition( pCondition, nCount, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
void StructTitleManager::UpdateTitleConditionByMonsterKill( const int nMonsterCode, const int nTamingCode )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_MONSTER_KILL_BY_CODE, nMonsterCode, 0, 0, 1 );
UpdateRelatedTitleCondition( TitleConditionType::TYPE_MONSTER_KILL_BY_TAMING_CODE, nTamingCode, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByItemGet( const ItemBase::ItemCode nItemCode, const __int64 & nCount )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_ITEM_GET_BY_CODE, nItemCode, 0, 0, nCount );
}
void StructTitleManager::UpdateTitleConditionByItemEquip( const ItemBase::ItemCode nItemCode, const bool bEquip )
{
// 기획 데이터가 존재하지 않아 현재는 사용하지 않는 유형이다.
UpdateRelatedTitleCondition( TitleConditionType::TYPE_ITEM_EQUIP_BY_CODE, nItemCode, 0, 0, bEquip );
}
void StructTitleManager::UpdateTitleConditionByItemUse( const ItemBase::ItemCode nItemCode )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_ITEM_USE_BY_CODE, nItemCode, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByItemCreateByMixing( const std::vector< std::pair< StructItem *, __int64 > > & vCreatedItem )
{
for( std::vector< std::pair< StructItem *, __int64 > >::const_iterator it = vCreatedItem.begin(); it != vCreatedItem.end(); ++it )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_ITEM_MIX_BY_CODE, (*it).first->GetItemCode(), 0, 0, (*it).second );
}
}
void StructTitleManager::UpdateTitleConditionBySummonTame( const int nTamingCode, const char nRate, const bool bSuccess )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_SUMMON_TAME_BY_CODE, nTamingCode, bSuccess, 0, 1 );
UpdateRelatedTitleCondition( TitleConditionType::TYPE_SUMMON_TAME_BY_RATE, nRate, bSuccess, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionBySummonEnhance( const int nTamingCode, const char nRate, const int nEnhance )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_SUMMON_ENHANCE_BY_CODE, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] == nTamingCode &&
pCondition->nValue[1] <= nEnhance )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
GetRelatedTitleConditionRange( TitleConditionType::TYPE_SUMMON_ENHANCE_BY_RATE, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] == nRate &&
pCondition->nValue[1] <= nEnhance )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionBySummonEquip( const int nTamingCode, const char nRate, const int nEnhance, const int nInc )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_SUMMON_EQUIP_BY_CODE, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] == nTamingCode &&
pCondition->nValue[1] <= nEnhance )
{
updateTitleCondition( pCondition, nInc, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
GetRelatedTitleConditionRange( TitleConditionType::TYPE_SUMMON_EQUIP_BY_RATE, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] == nRate &&
pCondition->nValue[1] <= nEnhance )
{
updateTitleCondition( pCondition, nInc, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionBySummonMount( const int nTamingCode, const bool bMount )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_SUMMON_MOUNT_BY_CODE, nTamingCode, bMount, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionBySummonPutOnBelt( std::vector< int > & vBeltCode )
{
int nMaxCount = 0, nCode = 0, nCount = 0;
std::sort( vBeltCode.begin(), vBeltCode.end() );
for( std::vector< int >::const_iterator it = vBeltCode.begin(); it != vBeltCode.end(); ++it )
{
if( nCode != (*it) )
{
if( nCount > nMaxCount )
nMaxCount = nCount;
nCode = (*it);
nCount = 1;
}
else
++nCount;
}
if( nCount > nMaxCount )
nMaxCount = nCount;
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_SUMMON_PUT_ON_BELT_WITH_SAME_CODE, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] <= nMaxCount )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionBySummonCardGet( const int nTamingCode, const char nRate, const bool bTamedCard, const bool bIsGet )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_ITEM_SUMMON_GET_BY_CODE, nTamingCode, bTamedCard, 0, bIsGet );
UpdateRelatedTitleCondition( TitleConditionType::TYPE_ITEM_SUMMON_GET_BY_RATE, nRate, bTamedCard, 0, bIsGet );
}
void StructTitleManager::UpdateTitleConditionByQuestStart( const int nQuestCode )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_QUEST_START, nQuestCode, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByQuestEnd( const int nQuestCode )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_QUEST_END, nQuestCode, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByDungeonSiegeStart( const int nDungeonID, const bool bIsAttackTeam )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_DUNGEON_SIEGE_START, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( ( !pCondition->nValue[0] || pCondition->nValue[0] == nDungeonID ) &&
!!pCondition->nValue[1] == bIsAttackTeam )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
UpdateRelatedTitleCondition( TitleConditionType::TYPE_DUNGEON_SIEGE_START, nDungeonID, bIsAttackTeam, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByDungeonSiegeEnd( const int nDungeonID, const bool bIsAttackTeam, const bool bResult )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_DUNGEON_SIEGE_END, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( ( !pCondition->nValue[0] || pCondition->nValue[0] == nDungeonID ) &&
!!pCondition->nValue[1] == bIsAttackTeam &&
!!pCondition->nValue[2] == bResult )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionByPKOn( const bool bPKOn )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_CHARACTER_PK_ON, bPKOn, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByPlayerKill( const c_fixed10 & fImmoralPoint )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_CHARACTER_PLAYER_KILL, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] <= fImmoralPoint )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionByImmoralPoint( const c_fixed10 & fImmoralPoint )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_CHARACTER_IMMORAL_POINT, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] <= fImmoralPoint )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionBySkillLevel( const int nSkillID, const int nSkillLevel )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_CHARACTER_SKILL, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] == nSkillID &&
pCondition->nValue[1] <= nSkillLevel )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::UpdateTitleConditionByTitleAchieve( const int nTitleCode )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_CHARACTER_TITLE, nTitleCode, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByPCBangMode( const char nPCBangMode )
{
UpdateRelatedTitleCondition( TitleConditionType::TYPE_CHARACTER_PC_BANG_MODE, nPCBangMode, 0, 0, 1 );
}
void StructTitleManager::UpdateTitleConditionByGold( const StructGold & nGold )
{
size_t nStart, nEnd;
GetRelatedTitleConditionRange( TitleConditionType::TYPE_CHARACTER_GOLD, nStart, nEnd );
for( size_t i = nStart; i < nEnd; i++ )
{
TitleConditionType * & pCondition = s_vTitleConditionType[i];
if( pCondition->nValue[0] <= static_cast< int >( ( nGold / 10000 ).GetRawData() ) )
{
updateTitleCondition( pCondition, 1, pCondition->bIsSet, pCondition->bSkipDBUpdate );
}
}
}
void StructTitleManager::GetRelatedTitleConditionRange( int nTitleConditionType, size_t & nStart, size_t & nEnd )
{
std::pair< size_t, size_t > * pRange = NULL;
s_hsTitleConditionTypeByType.lookup( nTitleConditionType, pRange );
if( !pRange )
{
nStart = nEnd = 0;
return;
}
nStart = pRange->first;
nEnd = pRange->first + pRange->second;
}
const bool StructTitleManager::IsAchievedTitle( int nCode ) const
{
StructTitle * pTitle = getTitleStruct( nCode );
if( !pTitle )
return false;
return !!( pTitle->GetStatus() & StructTitle::TITLE_STATUS_ACHIEVE );
}
const size_t StructTitleManager::DoEachTitle( struct TitleFunctor & _fo )
{
size_t nCount = 0;
for( std::vector< StructTitle * >::iterator it = m_vTitle.begin(); it != m_vTitle.end(); ++it )
{
++nCount;
_fo( *it );
}
return nCount;
}
const size_t StructTitleManager::DoEachTitleCondition( struct TitleConditionFunctor & _fo )
{
size_t nCount = 0;
for( std::vector< StructTitleCondition * >::iterator it = m_vTitleCondition.begin(); it != m_vTitleCondition.end(); ++it )
{
++nCount;
_fo( *it );
}
return nCount;
}
StructTitle * StructTitleManager::getTitleStruct( int nCode ) const
{
size_t idx;
if( m_hsTitle.lookup( nCode, idx ) )
{
return m_vTitle[idx];
}
return NULL;
}
StructTitle * StructTitleManager::setTitleStruct( int nCode )
{
size_t idx;
if( m_hsTitle.lookup( nCode, idx ) )
{
return m_vTitle[idx];
}
else
{
// 존재하지 않는 호청
if( !GetTitleBase( nCode ) )
return NULL;
StructTitle * pTitle = StructTitle::AllocTitle( m_pHandler, StructTitleManager::AllocTitleID(), nCode, 0 );
AddTitle( pTitle );
pTitle->SetDBInsertFlag();
return pTitle;
}
}
StructTitleCondition * StructTitleManager::getTitleCondition( const int nCode ) const
{
size_t idx;
if( m_hsTitleCondition.lookup( nCode, idx ) )
{
return m_vTitleCondition[idx];
}
return NULL;
}
StructTitleCondition * StructTitleManager::setTitleCondition( const int nCode, const __int64 nCount, const bool bIsSet, const bool bSkipDBUpdate, bool & bIsChanged )
{
StructTitleCondition *pTitleCondition = getTitleCondition( nCode );
if( pTitleCondition )
{
if( bIsSet )
{
// 이미 존재하는 동일한 값을 덮어씌우는 경우라면 어떠한 처리도 할 필요가 없다.
if( pTitleCondition->GetCount() == nCount )
{
bIsChanged = false;
return pTitleCondition;
}
pTitleCondition->SetCount( nCount );
}
else
{
pTitleCondition->AddCount( nCount );
}
if( !bSkipDBUpdate )
pTitleCondition->SetDBUpdateFlag();
}
else
{
int nSID = !bSkipDBUpdate ? StructTitleManager::AllocTitleConditionID() : 0;
pTitleCondition = StructTitleCondition::AllocTitleCondition( nSID, nCode, nCount );
m_vTitleCondition.push_back( pTitleCondition );
m_hsTitleCondition.add( nCode, m_vTitleCondition.size() - 1 );
if( !bSkipDBUpdate )
pTitleCondition->SetDBInsertFlag();
}
return pTitleCondition;
}
void StructTitleManager::updateTitleCondition( TitleConditionType * & pCondition, const __int64 nCount, const bool bIsSet, const bool bSkipDBUpdate )
{
// 저장 및 방송
bool bIsChanged = true;
StructTitleCondition * pTitleCondition = setTitleCondition( pCondition->nID, nCount, bIsSet, bSkipDBUpdate, bIsChanged );
if( !bIsChanged )
return;
if( m_pHandler->isReadInfoComplete() )
{
m_pHandler->onConditionChanged( pCondition, pTitleCondition->GetCount() );
CheckTitleCondition( pCondition );
}
}
const bool StructTitleManager::checkTitleCondition( std::vector< TitleCondition::TITLE_CONDITION_INFO > & vTitleConditionInfo ) const
{
if( !vTitleConditionInfo.size() )
return true;
int nMaxGroupID = 0;
bool bGroupChecked[ GameRule::TITLE_CONDITION_MAX_GROUP + 1 ];
memset( bGroupChecked, true, sizeof( bGroupChecked ) );
std::vector< TitleCondition::TITLE_CONDITION_INFO >::const_iterator it;
for( it = vTitleConditionInfo.begin(); it != vTitleConditionInfo.end(); ++it )
{
// 이미 조건 달성이 불가능한 그룹
if( !bGroupChecked[ (*it).nGroupID ] )
continue;
// 뒤쪽에 몰려있는 달성이 불가능한 그룹은 달성 여부를 확인할 필요없으므로 MaxGroupID에 포함시키지 않는다.
nMaxGroupID = (*it).nGroupID;
StructTitleCondition *pTitleCondition = getTitleCondition( (*it).nConditionType );
if( !pTitleCondition || pTitleCondition->GetCount() < (*it).nCount )
{
bGroupChecked[ (*it).nGroupID ] = false;
continue;
}
}
// 하나라도 만족하는 조건이 있다면 달성
for( int i = 1; i <= nMaxGroupID; i++ )
{
if( bGroupChecked[ i ] )
return true;
}
return false;
}