376 lines
10 KiB
C++
376 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include "Durability.h"
|
|
#include "SPlayerInfoMgr.h"
|
|
#include "SGameSystem.h"
|
|
#include "SkillBaseFile.h"
|
|
#include "SInventoryMgr.h"
|
|
#include "SItemDB.h"
|
|
//#include "SGameMessageUI.h"
|
|
#include "SStringDB.h"
|
|
#include "sgame.h"
|
|
#include "SGameManager.h"
|
|
#include "SSummonSlotMgr.h"
|
|
|
|
|
|
extern SGameSystem * g_pCurrentGameSystem;
|
|
|
|
#define MSG(pMessage) g_pCurrentGameSystem->GetGame()->GetGameManager()->ProcMsgAtStatic(pMessage)
|
|
|
|
|
|
namespace
|
|
{
|
|
const short g_nGauge = 12; // 게이지 개수. 11개인데 c_EquipSetNames의 순서에서 망토(cloak) 이 중간에 끼여있는 관계로 12개로 한다.
|
|
};
|
|
|
|
void SRepairItemInfo::Set( ItemBaseEx_info * _pItemBase, SInventorySlot * pSlot )
|
|
{
|
|
if( _pItemBase )
|
|
{
|
|
if( pSlot->getMaxEtherealDurability() > 0)
|
|
{
|
|
maxEthereal = pSlot->getMaxEtherealDurability(); // 최대내구도.
|
|
crrEthereal = pSlot->GetEtherealDurability(); // 현재내구도.
|
|
|
|
if( crrEthereal == 0 )
|
|
percent = 0.0f;
|
|
else if( crrEthereal > 0 )
|
|
{
|
|
lossValue = maxEthereal - crrEthereal; // 손실 내구도값.
|
|
percent = ( ( float )crrEthereal / ( float )maxEthereal ) * 100.0f; // 현재 내구도 %.
|
|
}
|
|
|
|
EtherealPerOne = (float)maxEthereal / 100.0f; // 1% 당 ethereal 량.
|
|
}
|
|
else
|
|
Clear();
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
bool GetBiggerPercent( SRepairItemInfo & p1, SRepairItemInfo & p2 )
|
|
{
|
|
return p1.percent > p2.percent;
|
|
}
|
|
|
|
bool GetsmallerPercent( SRepairItemInfo & p1, SRepairItemInfo & p2 )
|
|
{
|
|
return p1.percent < p2.percent;
|
|
}
|
|
|
|
|
|
SDurability::SDurability(bool bChar)
|
|
{
|
|
bCharacter = bChar;
|
|
}
|
|
|
|
bool IsRepair( SInventorySlot * pSlot )
|
|
{
|
|
if( pSlot == NULL )
|
|
return false;
|
|
|
|
const ItemBaseEx_info * pItemBase = GetItemDB().GetItemData( pSlot->GetItemCode() );
|
|
if(pItemBase)
|
|
{
|
|
if( pSlot->getMaxEtherealDurability() > 0) // 상급아이템.
|
|
{
|
|
// 내구도가 소모된 아이템.
|
|
int maxEthereal = pSlot->getMaxEtherealDurability();
|
|
int crrEthereal = pSlot->GetEtherealDurability();
|
|
|
|
if( crrEthereal < maxEthereal && crrEthereal > 0 )
|
|
{
|
|
if( ( (float)maxEthereal / 10000.0f ) - ( (float)crrEthereal / 10000.0f ) >= 1.0f )
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool checkEthereal(SPlayerInfoMgr* pPlayerInfoMgr, int& nCurrentEthereal)
|
|
{
|
|
if( pPlayerInfoMgr == NULL )
|
|
return false;
|
|
|
|
if( pPlayerInfoMgr->GetEtherealStoneDurability() <= 0 )
|
|
{
|
|
MSG( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::_MSGBOXID::MSGBOX_GENERAL, S( 7908 ), true ) ); return false;
|
|
}
|
|
|
|
nCurrentEthereal = pPlayerInfoMgr->GetEtherealStoneDurability(); // 현재 에테리얼충전량.
|
|
if( nCurrentEthereal < 1 )
|
|
{
|
|
MSG( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::_MSGBOXID::MSGBOX_GENERAL, S( 733 ), true ) ); return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool checkCharItems( SPlayerInfoMgr* pPlayerInfoMgr, SInventoryMgr* pInventoryMgr, std::vector< SRepairItemInfo >* pVector )
|
|
{
|
|
if( pPlayerInfoMgr == NULL || pVector == NULL )
|
|
return false;
|
|
|
|
int oldWearType = 0;
|
|
int nSize = g_nGauge + 2; // 교체장비 추가.
|
|
SInventorySlot* pSlot = NULL;
|
|
for( int nWearType = 0; nWearType < nSize; ++nWearType )
|
|
{
|
|
SRepairItemInfo aRepairInfo;
|
|
|
|
if( nWearType >= g_nGauge ) // 교체무기.
|
|
{
|
|
oldWearType = nWearType;
|
|
nWearType += ( ItemBase::ItemWearType::WEAR_SWAP_WEAPON - ItemBase::ItemWearType::WEAR_EAR - 1 );
|
|
}
|
|
|
|
if (nWearType == 7) // 망토 제외.
|
|
pSlot = pInventoryMgr->GetItemInfo( ItemBase::WEAR_SECOND_EAR );
|
|
else
|
|
pSlot = pInventoryMgr->GetItemInfo( nWearType );
|
|
|
|
if( pSlot ) // 장비중.
|
|
{
|
|
if( IsRepair( pSlot ) ) // 수리해야 할 내구도가 소모된 아이템.
|
|
{
|
|
ItemBaseEx_info * pItemBase = const_cast< ItemBaseEx_info * >( GetItemDB().GetItemData( pSlot->GetItemCode() ) );
|
|
|
|
aRepairInfo.Set( pItemBase, pSlot );
|
|
|
|
pVector->push_back( aRepairInfo );
|
|
}
|
|
}
|
|
|
|
if( oldWearType > 0 )
|
|
nWearType = oldWearType;
|
|
}
|
|
|
|
/// 보스카드 체크
|
|
for (int beltIndex = 0; beltIndex < 6; ++beltIndex)
|
|
{
|
|
AR_HANDLE hItem = pInventoryMgr->GetBeltSlot(beltIndex);
|
|
if( !hItem )
|
|
continue ;
|
|
|
|
pSlot = pInventoryMgr->GetItemInfo(hItem);
|
|
if( pSlot && GetItemDB().GetGroup(pSlot->GetItemCode()) == ItemBase::GROUP_BOSSCARD )
|
|
{
|
|
if( IsRepair( pSlot ) )
|
|
{
|
|
ItemBaseEx_info * pItemBase = const_cast< ItemBaseEx_info * >( GetItemDB().GetItemData( pSlot->GetItemCode() ) );
|
|
|
|
SRepairItemInfo aRepairInfo;
|
|
aRepairInfo.Set( pItemBase, pSlot );
|
|
pVector->push_back( aRepairInfo );
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool checkCreatureItems( SPlayerInfoMgr* pPlayerInfoMgr, SCreatureSlotMgr* pCreatureSlotMgr, SInventoryMgr* pInventoryMgr, std::vector< SRepairItemInfo >* pVector )
|
|
{
|
|
if( pPlayerInfoMgr == NULL || pCreatureSlotMgr == NULL || pVector == NULL )
|
|
return false;
|
|
|
|
float fRate = 0.0f;
|
|
AR_HANDLE hCreture = pCreatureSlotMgr->GetSelectedCreature();
|
|
if( hCreture )
|
|
{
|
|
int nCount = SCreatureSlotMgr::MAX_CREATURE_SLOT - 1; // 크리처 아이템 슬롯 5개
|
|
for( int i = 0; i < nCount; i++ )
|
|
{
|
|
AR_HANDLE hItem = pCreatureSlotMgr->GetCreatureItem( hCreture, i );
|
|
if( hItem == NULL )
|
|
continue;
|
|
|
|
SInventorySlot* pSlot = pInventoryMgr->GetItemInfo( hItem );
|
|
if( pSlot )
|
|
{
|
|
if( IsRepair( pSlot ) )
|
|
{
|
|
ItemBaseEx_info * pItemBase = const_cast< ItemBaseEx_info * >( GetItemDB().GetItemData( pSlot->GetItemCode() ) );
|
|
|
|
SRepairItemInfo aRepairInfo;
|
|
aRepairInfo.Set( pItemBase, pSlot );
|
|
pVector->push_back( aRepairInfo );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
float SDurability::calculate(SPlayerInfoMgr* pPlayerInfoMgr, SInventoryMgr* pInventoryMgr, SCreatureSlotMgr* pCreatureSlotMgr)
|
|
{
|
|
if( pPlayerInfoMgr == NULL || pInventoryMgr == NULL )
|
|
return 0.0f;
|
|
|
|
int crrEthereal = 0;
|
|
if( false == checkEthereal(pPlayerInfoMgr, crrEthereal) )
|
|
return 0.0f;
|
|
|
|
crrEthereal *= 10000;
|
|
|
|
m_arrRepairInfo.clear();
|
|
|
|
if( bCharacter )
|
|
{
|
|
if( false == checkCharItems(pPlayerInfoMgr, pInventoryMgr, &m_arrRepairInfo) ) // 캐릭터
|
|
return 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if( false == checkCreatureItems(pPlayerInfoMgr, pCreatureSlotMgr, pInventoryMgr, &m_arrRepairInfo) ) // 크리처
|
|
return 0.0f;
|
|
}
|
|
|
|
if( m_arrRepairInfo.empty() ) // 수리할 아이템이 없다.
|
|
{
|
|
MSG( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::_MSGBOXID::MSGBOX_GENERAL, S( 732 ), true ) ); return 0.0f;
|
|
}
|
|
|
|
float sendPercent = 0.0f; // 서버에 전송할 충전 %.
|
|
|
|
// 전체충전 가능검사.
|
|
int needValue = 0; // 개별 충전필요량.
|
|
int needTotalValue = 0; // 총 충전 필요량.
|
|
int size = m_arrRepairInfo.size();
|
|
for( int i=0; i<size; ++i )
|
|
{
|
|
SRepairItemInfo & aInfo = m_arrRepairInfo[ i ];
|
|
needValue = ( 100.0f - aInfo.percent ) * (float)aInfo.EtherealPerOne; // 필요 에테리얼 량.
|
|
needTotalValue += needValue; // 필요 에테리얼 총량.
|
|
}
|
|
|
|
if( needTotalValue <= crrEthereal ) // 충전가능.
|
|
return 100.0f;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 전체충전이 불가능하다. 균등분배시작.
|
|
|
|
// 현재 내구도 % 로 내림차순 정렬.
|
|
sort( m_arrRepairInfo.begin(), m_arrRepairInfo.end(), GetBiggerPercent );
|
|
|
|
struct SRepair
|
|
{
|
|
int index;
|
|
int needEthereal;
|
|
SRepair( int _index, int _needEthereal ) : index( _index ), needEthereal( _needEthereal ) {}
|
|
};
|
|
std::vector< SRepair > arrNeedEthereal; // 필요 에테리얼 량.
|
|
|
|
float bigPercent = 0.0f;
|
|
size = m_arrRepairInfo.size();
|
|
for( int i=0; i<size-1; ++i )
|
|
{
|
|
needTotalValue = 0;
|
|
arrNeedEthereal.clear();
|
|
|
|
SRepairItemInfo & aBig = m_arrRepairInfo[ i ];
|
|
|
|
// 최대치(%) 에 맞추기위해 필요한 에테리얼량 계산.
|
|
needTotalValue = 0;
|
|
for( int k=i+1; k<size; ++k )
|
|
{
|
|
SRepairItemInfo & aInfo = m_arrRepairInfo[ k ];
|
|
needValue = ( aBig.percent - aInfo.percent ) * (float)aInfo.EtherealPerOne; // 필요 에테리얼 량.
|
|
needTotalValue += needValue; // 필요 에테리얼 총량.
|
|
|
|
arrNeedEthereal.push_back( SRepair( k, needValue ) );
|
|
}
|
|
|
|
if( ( needTotalValue + 10000 ) <= crrEthereal ) // 충전가능.
|
|
{
|
|
bigPercent = aBig.percent;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( bigPercent == 0.0f )
|
|
{
|
|
MSG( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::_MSGBOXID::MSGBOX_GENERAL, S( 733 ), true ) ); return 0.0f;
|
|
}
|
|
|
|
int rest = crrEthereal - needTotalValue;
|
|
if( rest == 0 )
|
|
{
|
|
sendPercent = bigPercent;
|
|
}
|
|
else if( rest > 0 )
|
|
{
|
|
rest = crrEthereal;// - needTotalValue;
|
|
|
|
int needValue = 0;
|
|
|
|
// % 만큼 에테리얼을 채운다.
|
|
//size = m_arrRepairInfo.size();
|
|
size = arrNeedEthereal.size();
|
|
for( int x=0; x<size; ++x )
|
|
{
|
|
SRepair & aRepair = arrNeedEthereal[ x ];
|
|
needValue = aRepair.needEthereal;
|
|
|
|
SRepairItemInfo & aInfo = m_arrRepairInfo[ aRepair.index ];
|
|
|
|
if( needValue > 0 )
|
|
{
|
|
rest -= needValue; // 나머지 에테리얼 감소.
|
|
aInfo.crrEthereal += needValue;
|
|
|
|
// 현재 % 다시 계산.
|
|
aInfo.percent = (float)aInfo.crrEthereal / (float)aInfo.maxEthereal;
|
|
}
|
|
}
|
|
|
|
// 오름차순 정렬.
|
|
std::vector< SRepairItemInfo > arrRepairInfoSmall( m_arrRepairInfo.begin(), m_arrRepairInfo.end() );
|
|
sort( arrRepairInfoSmall.begin(), arrRepairInfoSmall.end(), GetsmallerPercent );
|
|
|
|
float smallPercent = arrRepairInfoSmall[ 0 ].percent; // 가장 작은 내구도 %.
|
|
|
|
size = arrRepairInfoSmall.size();
|
|
|
|
bool bLoop = true;
|
|
while( bLoop )
|
|
{
|
|
for( int x=0; x<size; ++x )
|
|
{
|
|
SRepairItemInfo & aSmall = arrRepairInfoSmall[ x ];
|
|
|
|
// 1% 당 필요 에테리얼량이 가장작은 것도 채울수가 없다.
|
|
if( rest < aSmall.EtherealPerOne )
|
|
{
|
|
sendPercent = aSmall.percent * 100.0f;
|
|
|
|
// 필요 에테리얼량이 가장작은 0번째의 1%도 충전불가하다면 현재에테리얼량이 부족한것이다.
|
|
if( x == 0 || ( ( aSmall.percent-smallPercent ) < 0.01f ) )
|
|
{
|
|
MSG( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::_MSGBOXID::MSGBOX_GENERAL, S( 733 ), true ) );
|
|
arrRepairInfoSmall.clear();
|
|
return 0.0f;
|
|
}
|
|
bLoop = false;
|
|
break;
|
|
}
|
|
|
|
// 1% 채워본다.
|
|
aSmall.crrEthereal += aSmall.EtherealPerOne;
|
|
rest -= aSmall.EtherealPerOne;
|
|
|
|
// 현재 % 다시 계산.
|
|
aSmall.percent = (float)aSmall.crrEthereal / (float)aSmall.maxEthereal;
|
|
}
|
|
}
|
|
arrRepairInfoSmall.clear();
|
|
}
|
|
|
|
arrNeedEthereal.clear();
|
|
|
|
m_arrRepairInfo.clear();
|
|
|
|
return sendPercent;
|
|
}
|