Files
Leviathan/Client/Game/game/Utility/Durability.cpp
T
2026-06-01 12:46:52 +02:00

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;
}