565 lines
17 KiB
C++
565 lines
17 KiB
C++
|
|
#include "stdafx.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <mmo/ArTime.h>
|
|
|
|
#include "StructEventItemManager.h"
|
|
#include "GameDBUtil.h"
|
|
#include "DB_Commands.h"
|
|
|
|
|
|
struct dbEventItemDropInfo : public CADORecordBinding
|
|
{
|
|
BEGIN_ADO_BINDING(dbEventItemDropInfo)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(1, adInteger, sid, sizeof(sid), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(2, adInteger, code, sizeof(code), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(3, adInteger, remain_time, sizeof(remain_time), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(4, adInteger, duration, sizeof(duration), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(5, adInteger, count, sizeof(count), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(6, adInteger, total_count, sizeof(total_count), FALSE)
|
|
END_ADO_BINDING()
|
|
|
|
int sid;
|
|
int code;
|
|
int remain_time;
|
|
int duration;
|
|
int count;
|
|
int total_count;
|
|
};
|
|
|
|
struct dbEventItemSupplyInfo : public CADORecordBinding
|
|
{
|
|
BEGIN_ADO_BINDING(dbEventItemSupplyInfo)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(1, adInteger, sid, sizeof(sid), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(2, adInteger, code, sizeof(code), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(3, adInteger, min_count, sizeof(min_count), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(4, adInteger, max_count, sizeof(max_count), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(5, adInteger, flag, sizeof(flag), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(6, adDBTimeStamp, start_time, sizeof(start_time), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(7, adDBTimeStamp, end_time, sizeof(end_time), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(8, adInteger, left_count, sizeof(left_count), FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(9, adInteger, total_count, sizeof(total_count), FALSE)
|
|
END_ADO_BINDING()
|
|
|
|
int sid;
|
|
int code;
|
|
int min_count;
|
|
int max_count;
|
|
int flag;
|
|
DBTIMESTAMP start_time;
|
|
DBTIMESTAMP end_time;
|
|
int left_count;
|
|
int total_count;
|
|
};
|
|
|
|
struct dbEventDungeonDroprateInfo : public CADORecordBinding
|
|
{
|
|
BEGIN_ADO_BINDING(dbEventDungeonDroprateInfo)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(1, adInteger, dungeon_id, sizeof(dungeon_id), FALSE)
|
|
ADO_NUMERIC_ENTRY2(2, adDecimal, drop_rate, 10, 4, FALSE)
|
|
ADO_VARIABLE_LENGTH_ENTRY4(3, adDBTimeStamp, end_time, sizeof(end_time), FALSE)
|
|
END_ADO_BINDING()
|
|
|
|
int dungeon_id;
|
|
_decimal_variant drop_rate;
|
|
DBTIMESTAMP end_time;
|
|
};
|
|
|
|
StructEventItemManager & StructEventItemManager::GetInstance()
|
|
{
|
|
static StructEventItemManager _inst;
|
|
return _inst;
|
|
}
|
|
|
|
bool StructEventItemManager::Init()
|
|
{
|
|
LoadEventItemDropInfo();
|
|
LoadEventItemSupplyInfo();
|
|
LoadEventDungeonDroprateInfo();
|
|
|
|
// 불러들인 게 있으면 시작하자. (이벤트 시작도 안했는데 true로 체크되어 몹 죽을때마다 검사되는 거 방지.)
|
|
if( !m_vEventItemDropInfo.empty() )
|
|
m_bStartEventDrop = true;
|
|
if( !m_vEventItemSupplyInfo.empty() )
|
|
m_bStartEventSupply = true;
|
|
if( !m_vEventDungeonDroprateInfo.empty() )
|
|
m_bDungeonDropRateEvent = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool StructEventItemManager::DeInit()
|
|
{
|
|
while( !m_lQueryList.empty() )
|
|
{
|
|
Sleep( 100 );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void StructEventItemManager::onEndQuery()
|
|
{
|
|
THREAD_SYNCRONIZE( m_QueryLock );
|
|
|
|
m_lQueryList.pop_front();
|
|
|
|
if( !m_lQueryList.empty() )
|
|
{
|
|
DB().Push( m_lQueryList.front() );
|
|
}
|
|
}
|
|
|
|
void StructEventItemManager::Push( GameDBManager::DBProc* pWork )
|
|
{
|
|
THREAD_SYNCRONIZE( m_QueryLock );
|
|
|
|
if( m_lQueryList.empty() )
|
|
{
|
|
DB().Push( pWork );
|
|
}
|
|
|
|
m_lQueryList.push_back( pWork );
|
|
}
|
|
|
|
float StructEventItemManager::GetEventDungeonDropRate( int nDungeonID )
|
|
{
|
|
THREAD_SYNCHRONIZE( m_DropRateLock );
|
|
|
|
std::vector< EVENT_DUNGEON_DROPRATE_INFO >::iterator it = m_vEventDungeonDroprateInfo.begin();
|
|
for( ; it != m_vEventDungeonDroprateInfo.end() ; ++it )
|
|
{
|
|
if( nDungeonID != (*it).m_nDungeonID )
|
|
continue;
|
|
|
|
if( (*it).m_tEndTime < time( NULL ) )
|
|
{
|
|
m_vEventDungeonDroprateInfo.erase( it );
|
|
break;
|
|
}
|
|
|
|
return (*it).m_fDropRate;
|
|
}
|
|
return 1.0f;
|
|
}
|
|
|
|
void StructEventItemManager::LoadEventDungeonDroprateInfo()
|
|
{
|
|
THREAD_SYNCHRONIZE( m_DropRateLock );
|
|
|
|
m_vEventDungeonDroprateInfo.clear();
|
|
_ConnectionPtr ConnPtr = NULL;
|
|
InitUserDbConnection( ConnPtr );
|
|
|
|
_RecordsetPtr pRS = NULL;
|
|
|
|
pRS.CreateInstance( __uuidof(Recordset) );
|
|
|
|
pRS->Open("SELECT * FROM dbo.EventDungeonDropRate ORDER BY end_time DESC",
|
|
_variant_t((IDispatch *)ConnPtr,true),
|
|
adOpenForwardOnly, adLockReadOnly, adCmdText);
|
|
|
|
dbEventDungeonDroprateInfo emprs;
|
|
IADORecordBinding *picRs = NULL; // Interface Pointer declared.
|
|
|
|
pRS->QueryInterface( __uuidof(IADORecordBinding),(LPVOID*)&picRs );
|
|
picRs->BindToRecordset( &emprs );
|
|
|
|
while( pRS->State != adStateClosed && !pRS->EndOfFile )
|
|
{
|
|
struct tm tmEndTime;
|
|
tmEndTime.tm_year = emprs.end_time.year - 1900;
|
|
tmEndTime.tm_mon = emprs.end_time.month - 1;
|
|
tmEndTime.tm_mday = emprs.end_time.day;
|
|
tmEndTime.tm_hour = emprs.end_time.hour;
|
|
tmEndTime.tm_min = emprs.end_time.minute;
|
|
tmEndTime.tm_sec = emprs.end_time.second;
|
|
tmEndTime.tm_isdst = -1;
|
|
time_t tEndTime = mktime( &tmEndTime );
|
|
|
|
StructEventItemManager::RegisterEventDungeonDroprateInfo( emprs.dungeon_id, emprs.drop_rate.getFloat(), tEndTime );
|
|
|
|
pRS->MoveNext();
|
|
}
|
|
|
|
}
|
|
|
|
void StructEventItemManager::LoadEventItemDropInfo()
|
|
{
|
|
AR_TIME t = GetArTime();
|
|
|
|
m_vEventItemDropInfo.clear();
|
|
|
|
_ConnectionPtr ConnPtr = NULL;
|
|
InitUserDbConnection( ConnPtr );
|
|
|
|
_RecordsetPtr pRS = NULL;
|
|
|
|
pRS.CreateInstance( __uuidof(Recordset) );
|
|
|
|
pRS->Open("SELECT * FROM dbo.EventItemDropInfo ORDER BY CAST( duration AS FLOAT ) / total_count DESC",
|
|
_variant_t((IDispatch *)ConnPtr,true),
|
|
adOpenForwardOnly, adLockReadOnly, adCmdText);
|
|
|
|
dbEventItemDropInfo emprs;
|
|
IADORecordBinding *picRs = NULL; // Interface Pointer declared.
|
|
|
|
pRS->QueryInterface( __uuidof(IADORecordBinding),(LPVOID*)&picRs );
|
|
picRs->BindToRecordset( &emprs );
|
|
|
|
while( pRS->State != adStateClosed && !pRS->EndOfFile )
|
|
{
|
|
StructEventItemManager::RegisterEventItemDropInfo( emprs.sid, emprs.code, emprs.remain_time * 100, emprs.duration * 100, emprs.count, emprs.total_count );
|
|
|
|
pRS->MoveNext();
|
|
}
|
|
|
|
// 드랍 개수 보관 벡터도 초기화.
|
|
m_vEventItemDropPicker.clear();
|
|
for( size_t i = 0 ; i < m_vEventItemDropInfo.size() ; ++i )
|
|
{
|
|
m_vEventItemDropPicker.push_back( 0 );
|
|
}
|
|
}
|
|
|
|
void StructEventItemManager::RegisterEventDungeonDroprateInfo( int dungeon_id, float drop_rate, time_t end_time )
|
|
{
|
|
THREAD_SYNCHRONIZE( m_DropRateLock );
|
|
|
|
if( time( NULL ) < end_time )
|
|
{
|
|
m_vEventDungeonDroprateInfo.push_back( EVENT_DUNGEON_DROPRATE_INFO( dungeon_id, drop_rate, end_time ) );
|
|
}
|
|
}
|
|
|
|
void StructEventItemManager::RegisterEventItemDropInfo( int sid, ItemBase::ItemCode code, AR_TIME remain_time, AR_TIME duration, int count, int total_count )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
AR_TIME t = GetArTime();
|
|
|
|
if( remain_time > duration )
|
|
remain_time = duration;
|
|
|
|
std::vector< EVENT_ITEM_DROP_INFO >::iterator it;
|
|
|
|
for( it = m_vEventItemDropInfo.begin(); it != m_vEventItemDropInfo.end(); ++it )
|
|
{
|
|
if( (*it).sid == sid )
|
|
{
|
|
(*it) = EVENT_ITEM_DROP_INFO( sid, code, 1, 1, -1, t + remain_time, duration, count, total_count );
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_vEventItemDropInfo.push_back( EVENT_ITEM_DROP_INFO( sid, code, 1, 1, -1, t + remain_time, duration, count, total_count ) );
|
|
}
|
|
|
|
ItemBase::ItemCode StructEventItemManager::GetActiveDrop( AR_TIME t, float fDropRatePenalty )
|
|
{
|
|
if( !m_bStartEventDrop || m_vEventItemDropInfo.size() == 0 || fDropRatePenalty == 0.0f )
|
|
return 0;
|
|
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
__int64 total_goal_count = 0;
|
|
__int64 total_remain_count = 0;
|
|
int i = 0;
|
|
for( std::vector< EVENT_ITEM_DROP_INFO >::iterator it = m_vEventItemDropInfo.begin() ; it != m_vEventItemDropInfo.end() ; ++it, ++i )
|
|
{
|
|
if( (*it).left_count < 1 || (*it).total_count < 1 ) continue;
|
|
|
|
int remain_time = 0;
|
|
float ratio = 0.0f;
|
|
|
|
if( (*it).end_time > t )
|
|
{
|
|
remain_time = (*it).end_time - t;
|
|
// 이벤트 기간에 대한 비율, 0에 가까울 수록 이벤트 초반 / 1에 가까울 수록 이벤트 후반
|
|
ratio = 1.0f - ( float( remain_time ) / float( (*it).duration ) );
|
|
}
|
|
|
|
// 현재 시간대에서 풀어야 할 수량
|
|
__int64 goal_count = ratio * (*it).total_count;
|
|
// 현재 떨어진 양을 감안하여 풀릴 수 있는 수량
|
|
__int64 remain_count = goal_count - ( (*it).total_count - (*it).left_count );
|
|
|
|
if( remain_count < 1 || goal_count < 1 )
|
|
continue;
|
|
|
|
total_remain_count += remain_count;
|
|
total_goal_count += goal_count;
|
|
m_vEventItemDropPicker[ i ] = remain_count;
|
|
}
|
|
|
|
if( total_remain_count < 1 || total_goal_count < 1 )
|
|
return 0;
|
|
|
|
// 드랍 확률은 [현재 시간 기준으로 남은 양] / [현재 시간 기준으로 풀려야 할 양]
|
|
__int64 probability = ( total_remain_count * fDropRatePenalty ) / total_goal_count * 1000000;
|
|
if( XRandom() % 1000000 < probability )
|
|
{
|
|
// 드랍 확률 통과. 이제는 무슨 아이템을 드랍시킬 지 결정.
|
|
int nPick = XRandom() % total_remain_count;
|
|
|
|
size_t i = 0;
|
|
for( ; i < m_vEventItemDropPicker.size() ; ++i )
|
|
{
|
|
nPick -= m_vEventItemDropPicker[ i ];
|
|
if( nPick < 0 )
|
|
break;
|
|
}
|
|
--m_vEventItemDropInfo[ i ].left_count;
|
|
|
|
Push( new DB_UpdateEventItemDropInfo(
|
|
m_vEventItemDropInfo[ i ].sid,
|
|
( m_vEventItemDropInfo[ i ].end_time > t ) ? ( ( m_vEventItemDropInfo[ i ].end_time - t ) / 100 ) : 0,
|
|
(int)(m_vEventItemDropInfo[ i ].duration / 100),
|
|
m_vEventItemDropInfo[ i ].left_count,
|
|
m_vEventItemDropInfo[ i ].total_count ) );
|
|
|
|
return m_vEventItemDropInfo[ i ].code;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void StructEventItemManager::LoadEventItemSupplyInfo()
|
|
{
|
|
m_vEventItemSupplyInfo.clear();
|
|
|
|
_ConnectionPtr ConnPtr = NULL;
|
|
InitUserDbConnection( ConnPtr );
|
|
|
|
_RecordsetPtr pRS = NULL;
|
|
|
|
pRS.CreateInstance( __uuidof(Recordset) );
|
|
|
|
pRS->Open("EventItemSupplyInfo",
|
|
_variant_t((IDispatch *)ConnPtr,true),
|
|
adOpenForwardOnly, adLockReadOnly, adCmdTable);
|
|
|
|
dbEventItemSupplyInfo emprs;
|
|
IADORecordBinding *picRs = NULL; // Interface Pointer declared.
|
|
|
|
pRS->QueryInterface( __uuidof(IADORecordBinding),(LPVOID*)&picRs );
|
|
picRs->BindToRecordset( &emprs );
|
|
|
|
while( pRS->State != adStateClosed && !pRS->EndOfFile )
|
|
{
|
|
struct tm tmStartTime;
|
|
tmStartTime.tm_year = emprs.start_time.year - 1900;
|
|
tmStartTime.tm_mon = emprs.start_time.month - 1;
|
|
tmStartTime.tm_mday = emprs.start_time.day;
|
|
tmStartTime.tm_hour = emprs.start_time.hour;
|
|
tmStartTime.tm_min = emprs.start_time.minute;
|
|
tmStartTime.tm_sec = emprs.start_time.second;
|
|
tmStartTime.tm_isdst = -1;
|
|
time_t tStartTime = mktime( &tmStartTime );
|
|
|
|
struct tm tmEndTime;
|
|
tmEndTime.tm_year = emprs.end_time.year - 1900;
|
|
tmEndTime.tm_mon = emprs.end_time.month - 1;
|
|
tmEndTime.tm_mday = emprs.end_time.day;
|
|
tmEndTime.tm_hour = emprs.end_time.hour;
|
|
tmEndTime.tm_min = emprs.end_time.minute;
|
|
tmEndTime.tm_sec = emprs.end_time.second;
|
|
tmEndTime.tm_isdst = -1;
|
|
time_t tEndTime = mktime( &tmEndTime );
|
|
|
|
StructEventItemManager::RegisterEventItemSupplyInfo( emprs.sid, emprs.code, emprs.min_count, emprs.max_count, tStartTime, tStartTime, tEndTime, emprs.left_count, emprs.total_count );
|
|
|
|
pRS->MoveNext();
|
|
}
|
|
}
|
|
|
|
void StructEventItemManager::RegisterEventItemSupplyInfo( const int & sid, const ItemBase::ItemCode & code, const int & min_count, const int & max_count, const int & flag, const time_t & start_time, const time_t & end_time, const int & left_count, const int & total_count )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
std::vector< EVENT_ITEM_SUPPLY_INFO >::iterator it;
|
|
|
|
for( it = m_vEventItemSupplyInfo.begin() ; it != m_vEventItemSupplyInfo.end() ; ++it )
|
|
{
|
|
if( (*it).sid == sid )
|
|
{
|
|
(*it) = EVENT_ITEM_SUPPLY_INFO( sid, code, min_count, max_count, flag, start_time, end_time, left_count, total_count );
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_vEventItemSupplyInfo.push_back( EVENT_ITEM_SUPPLY_INFO( sid, code, min_count, max_count, flag, start_time, end_time, left_count, total_count ) );
|
|
}
|
|
|
|
void StructEventItemManager::SetActiveSupply( const ItemBase::ItemCode & code, const int & min_count, const int & max_count, const int & flag )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
m_ReservedActiveSupply = EVENT_ITEM_INFO( code, min_count, max_count, flag );
|
|
}
|
|
|
|
const EVENT_ITEM_INFO StructEventItemManager::GetActiveSupply( const time_t & t )
|
|
{
|
|
EVENT_ITEM_INFO ActiveSupply( 0, 0, 0, 0 );
|
|
|
|
if( !m_bStartEventSupply )
|
|
return ActiveSupply;
|
|
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
// 예약된 드랍이 있다면 드랍
|
|
if( m_ReservedActiveSupply.code )
|
|
{
|
|
ActiveSupply = m_ReservedActiveSupply;
|
|
m_ReservedActiveSupply.code = 0;
|
|
}
|
|
else
|
|
{
|
|
for( std::vector< EVENT_ITEM_SUPPLY_INFO >::iterator it = m_vEventItemSupplyInfo.begin() ; it != m_vEventItemSupplyInfo.end() ; ++it )
|
|
{
|
|
// 남은 수량이 없거나 아직 시작되지 않은 이벤트는 제낌
|
|
if( (*it).left_count < 1 || (*it).start_time > t ) continue;
|
|
|
|
bool bWinning = false;
|
|
if( (*it).end_time > t )
|
|
{
|
|
// 이벤트 종료 시점 이전: 당첨 체크
|
|
time_t tSecPerOneSupply = ( (*it).end_time - (*it).start_time ) / ( (*it).total_count + 1 );
|
|
time_t tThisSupplyTime = (*it).start_time + ( tSecPerOneSupply * ( (*it).total_count - (*it).left_count + 1 ) );
|
|
tThisSupplyTime += tSecPerOneSupply * ( ( XRandom( 50, 150 ) - 100 ) / 100 );
|
|
if( tThisSupplyTime <= t )
|
|
{
|
|
bWinning = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 이벤트 종료 시점 이후: 100% 당첨
|
|
bWinning = true;
|
|
}
|
|
|
|
if( bWinning )
|
|
{
|
|
ActiveSupply = (*it);
|
|
--(*it).left_count;
|
|
Push( new DB_UpdateEventItemSupplyInfo( (*it).sid, (*it).left_count ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return ActiveSupply;
|
|
}
|
|
|
|
void StructEventItemManager::InsertEventDrop( StructPlayer *pPlayer, ItemBase::ItemCode code, int count, int minute )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
AR_TIME base_time = GetArTime();
|
|
int last_sid = 0; int remain_time, duration = 0;
|
|
|
|
std::vector< EVENT_ITEM_DROP_INFO >::iterator it;
|
|
|
|
for( it = m_vEventItemDropInfo.begin(); it != m_vEventItemDropInfo.end(); ++it )
|
|
{
|
|
if( (*it).sid > last_sid ) last_sid = (*it).sid;
|
|
}
|
|
int sid = last_sid + 1;
|
|
|
|
StructEventItemManager::RegisterEventItemDropInfo( sid, code, 6000 * minute, 6000 * minute, count, count );
|
|
|
|
for( it = m_vEventItemDropInfo.begin(); it != m_vEventItemDropInfo.end(); ++it )
|
|
{
|
|
if ( (*it).sid == sid )
|
|
{
|
|
duration = (*it).duration / 100;
|
|
remain_time = ( (*it).end_time - base_time) / 100;
|
|
if ( remain_time < 0 ) remain_time = 0;
|
|
Push( new DB_InsertEventItemDropInfo( (*it).sid, (*it).code, remain_time, duration, (*it).left_count, (*it).total_count ) );
|
|
}
|
|
}
|
|
|
|
m_vEventItemDropPicker.clear();
|
|
for( size_t i = 0 ; i < m_vEventItemDropInfo.size() ; ++i )
|
|
{
|
|
m_vEventItemDropPicker.push_back( 0 );
|
|
}
|
|
|
|
if ( pPlayer ) SendChatMessage( false, CHAT_NOTICE, "@SYSTEM", pPlayer, "Inserted." );
|
|
|
|
StructEventItemManager::ShowEventDrop( pPlayer );
|
|
}
|
|
|
|
void StructEventItemManager::ShowEventDrop( StructPlayer *pPlayer )
|
|
{
|
|
if ( !pPlayer ) return;
|
|
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
char szBuf[255];
|
|
s_sprintf( szBuf, _countof( szBuf ), "<#FF00FF>Total:%d Start:%d", m_vEventItemDropInfo.size(), ( m_bStartEventDrop ? 1 : 0 ) );
|
|
|
|
SendChatMessage( false, CHAT_NOTICE, "@SYSTEM", pPlayer, szBuf );
|
|
|
|
std::vector< EVENT_ITEM_DROP_INFO >::iterator it;
|
|
int left_count, total_count, hour, day, hour_pr, rate;
|
|
time_t end_time, duration, time_diff;
|
|
signed int order = 0;
|
|
AR_TIME base_time = GetArTime();
|
|
if ( m_vEventItemDropInfo.begin() != m_vEventItemDropInfo.end() )
|
|
{
|
|
for( it = m_vEventItemDropInfo.begin(); it != m_vEventItemDropInfo.end(); ++it, ++order )
|
|
{
|
|
left_count = (*it).left_count;
|
|
total_count = (*it).total_count;
|
|
end_time = (*it).end_time;
|
|
duration = (*it).duration;
|
|
time_diff = (end_time - base_time) / 100;
|
|
hour = time_diff / 60 / 60;
|
|
day = hour / 24;
|
|
hour_pr = hour % 24;
|
|
if ( left_count <= 0
|
|
|| total_count <= 0
|
|
|| end_time < 0
|
|
|| duration <= 0
|
|
|| (rate = (total_count * (1.0 - ((end_time - base_time) / duration))),
|
|
rate <= 0) )
|
|
s_sprintf( szBuf, _countof( szBuf ), "<#FFFF00>%d: %d (%d/%d) %dd %dh %dm", order, (*it).sid, left_count, total_count, day, hour_pr, (time_diff / 60 % 60) );
|
|
else
|
|
s_sprintf( szBuf, _countof( szBuf ), "<#FFFF00>%d: %d (%d/%d) %dd %dh %dm (%d/%d) %.2f%%", order, (*it).sid, left_count, total_count, day, hour_pr, (time_diff / 60 % 60), (total_count - left_count), rate, (float)((1000000 * (rate - (total_count - left_count)) / rate) / 10000.0) );
|
|
SendChatMessage( false, CHAT_NOTICE, "@SYSTEM", pPlayer, szBuf );
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructEventItemManager::UpdateEventDrop( StructPlayer *pPlayer, int no, int count, int minute )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_IntfLock );
|
|
|
|
if ( m_vEventItemDropInfo.begin() == m_vEventItemDropInfo.end() && pPlayer ) SendChatMessage( false, CHAT_NOTICE, "@SYSTEM", pPlayer, "Can't find sid. type //show_event_drop() and check it." );
|
|
else
|
|
{
|
|
int duration, remain_time = 0;
|
|
std::vector< EVENT_ITEM_DROP_INFO >::iterator it;
|
|
for( it = m_vEventItemDropInfo.begin(); it != m_vEventItemDropInfo.end(); ++it )
|
|
{
|
|
if ( (*it).sid == no )
|
|
{
|
|
(*it).left_count += count;
|
|
(*it).total_count+= count;
|
|
(*it).end_time += (6000 * minute);
|
|
(*it).duration += (6000 * minute);
|
|
duration = (*it).duration / 100;
|
|
remain_time = ( (*it).end_time - GetArTime()) / 100;
|
|
if ( remain_time < 0 ) { remain_time = 0; }
|
|
Push( new DB_UpdateEventItemDropInfo( (*it).sid, remain_time, duration, (*it).left_count, (*it).total_count ) );
|
|
}
|
|
}
|
|
if ( pPlayer ) SendChatMessage( false, CHAT_NOTICE, "@SYSTEM", pPlayer, "Updated" );
|
|
StructEventItemManager::ShowEventDrop(pPlayer);
|
|
}
|
|
|
|
}
|
|
|