Files
Sun1602/Server/GameServer/CrystallizeImplement.cpp
T
2022-10-26 12:25:11 +08:00

432 lines
15 KiB
C++

#include "StdAfx.h"
#include ".\CrystallizeImplement.h"
#include <ItemCrystalizeListParser.h>
#include "StatisticsManager.h"
#include "ExtraNPCManager.h"
#include <SCItemSlotContainer.h>
#include ".\ItemManager.h"
#include ".\ChaoState.h"
#include ".\Player.h"
CrystallizeImplement::CrystallizeImplement( void )
{
}
CrystallizeImplement::~CrystallizeImplement( void )
{
}
VOID CrystallizeImplement::OnFailed( DWORD dwResult )
{
MSG_CG_ITEM_CRYSTALIZE_NAK Message;
Message.m_byErrorCode = (BYTE)dwResult;
m_pPlayer->SendPacket( &Message, sizeof(Message) );
}
VOID CrystallizeImplement::OnImplement( MSG_BASE* pRecvMessage )
{
MSG_CG_ITEM_CRYSTALIZE_SYN* pRecvMsg = (MSG_CG_ITEM_CRYSTALIZE_SYN*)pRecvMessage;
ItemManager* item_manager = m_pPlayer->GetItemManager();
SCSlotContainer* inventory = item_manager->GetItemSlotContainer(SI_INVENTORY);
SCItemSlot& rTargetItem = (SCItemSlot &)inventory->GetSlot( pRecvMsg->m_TargetPos );
static CrystallizeImplement::sOutput Output;
RC::eITEM_RESULT Result = Crystallize( rTargetItem, Output );
if( Result != RC::RC_ITEM_SUCCESS )
{
OnFailed( Result );
return;
}
if( Output.TotalCount > 0 )
{
MSG_CG_ITEM_CRYSTALIZE_SUCCESS_ACK Message;
RC::eITEM_RESULT Result = item_manager->ObtainAllKindOfItem(Output.TotalCount,
Output.ObtainCodeArray,
Output.ObtainCountArray,
&Message.m_ItemInfo);
if( Result == RC::RC_ITEM_SUCCESS )
{
// 결정화 성공 로그
GAMELOG->LogCrystalizeSuccess(m_pPlayer,
rTargetItem,
Output.TotalCount,
Output.ObtainCodeArray,
Output.ObtainCountArray);
g_StatisticsManager.PlusStatisticType(eSTATISTIC_CRYSTALIZE_COUNT, 1);
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
DeleteTargetItem(rTargetItem);
#else
inventory->DeleteSlot(pRecvMsg->m_TargetPos, NULL);
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE
Message.m_Money = m_pPlayer->GetMoney();
m_pPlayer->SendPacket( &Message, Message.GetSize() );
}
else
{
OnFailed( Result );
}
}
else
{
// 결정화 실패 로그
GAMELOG->LogItem( ITEM_CRYSTALIZE_FAILED, m_pPlayer, &rTargetItem );
g_StatisticsManager.PlusStatisticType( eSTATISTIC_CRYSTALIZE_COUNT, 1 );
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
DeleteTargetItem(rTargetItem);
#else
inventory->DeleteSlot(pRecvMsg->m_TargetPos, NULL);
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE
MSG_CG_ITEM_CRYSTALIZE_FAILED_ACK Message;
Message.m_Money = m_pPlayer->GetMoney();
m_pPlayer->SendPacket( &Message, sizeof(Message) );
}
}
BOOL CrystallizeImplement::OnCheck( MSG_BASE* pRecvMsg, DWORD& OUT dwResult )
{
MSG_CG_ITEM_CRYSTALIZE_SYN* pMessage = (MSG_CG_ITEM_CRYSTALIZE_SYN *)pRecvMsg;
dwResult = RC::RC_ITEM_SUCCESS;
ItemManager* item_manager = m_pPlayer->GetItemManager();
ASSERT(item_manager);
if (item_manager == NULL)
{
dwResult = RC::RC_ITEM_FAILED;
return FALSE;
}
SCSlotContainer* inventory = item_manager->GetItemSlotContainer(SI_INVENTORY);
ASSERT(inventory);
if (inventory == NULL)
{
dwResult = RC::RC_ITEM_FAILED;
return FALSE;
}
if( !m_pPlayer->GetField() )
{
dwResult = RC::RC_ITEM_UNABLE_FUNCTION_FOR_CUR_ZONE;
return FALSE;
}
if( item_manager->IsRestrictFunction( eFUNCTIONALRESTRICT_CRYSTALIZE ) )
{
dwResult = RC::RC_ITEM_UNUSABLE_FUNCTION;
return FALSE;
}
#ifdef __NA_676_PK_SYSTEM_IMPROVEMENT
if( !m_pPlayer->GetChaoState().CanUseFuction( CHAO_USE_CRYSTALIZE ) )
{
dwResult = RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
return FALSE;
}
#else //__NA_676_PK_SYSTEM_IMPROVEMENT
if( m_pPlayer->GetChaoState().IsChaoState() )
{
dwResult = RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
return FALSE;
}
#endif //__NA_676_PK_SYSTEM_IMPROVEMENT
if( m_pPlayer->GetBehave() == PLAYER_BEHAVE_UNEXPECTED_WAITING )
{
dwResult = RC::RC_ITEM_INVALIDSTATEOFPLAYER;
return FALSE;
}
if( !m_pPlayer->GetWarehouseInventoryProtector().INVENTORY().IsUsable() )
{
dwResult = RC::RC_ITEM_INVENTORY_NEED_PASSWORD;
return FALSE;
}
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
#else
if( m_pPlayer->GetLevel() < LIMIT_LEVEL_CRYSTALIZE )
{
dwResult = RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
return FALSE;
}
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE
if( !item_manager->ValidState() )
{
dwResult = RC::RC_ITEM_INVALIDSTATE;
return FALSE;
}
if( !item_manager->ValidPos( SI_INVENTORY, pMessage->m_TargetPos ) )
{
dwResult = RC::RC_ITEM_INVALIDPOS;
return FALSE;
}
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
#else
if( !g_ExtraNPCManager.IsLengthCanUseNPC( pMessage->m_NPCCode, m_pPlayer, eNPC_TYPE_ITEM_MIX ) )
{
dwResult = RC::RC_ITEM_LENGTH_CANNOT_USE_NPC;
return FALSE;
}
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE
return TRUE;
}
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
RC::eITEM_RESULT CrystallizeImplement::Crystallize( SCItemSlot& rTargetItem, CrystallizeImplement::sOutput& OUT Output )
{
BYTE TotalCount = 0;
SLOTCODE* ObtainCodeArray = Output.ObtainCodeArray;
DURATYPE* ObtainCountArray = Output.ObtainCountArray;
//정렬용
STLX_MAP<SLOTCODE, DWORD> created_materials; // 먼저, 만들어진 재료들을 이곳에 담는다.
STLX_MAP<SLOTCODE, DWORD>::iterator miter;
// Check Validity---------------------------------------------------------------------------
const BASE_ITEMINFO* const pItemInfo = rTargetItem.GetItemInfo();
FASSERT( pItemInfo );
if( !pItemInfo )
return RC::RC_ITEM_INVALID_VALUE;
#ifdef _NA_008124_20150313_AWAKENING_SYSTEM
SLOTCODE CrystallizeCode = ItemCrystalizeListParser::Instance()->GetCrystalizeCode( rTargetItem, rTargetItem.GetEnchant() );
#else
SLOTCODE CrystallizeCode = ItemCrystalizeListParser::Instance()->GetCrystalizeCode( rTargetItem );
#endif // _NA_008124_20150313_AWAKENING_SYSTEM
sITEM_CRYSTALIZE_LIST* pListInfo = ItemCrystalizeListParser::Instance()->GetCrystalizeListInfo( CrystallizeCode );
if( !pListInfo )
{
SUNLOG( eCRITICAL_LOG, "CrystallizeImplement::Crystallize() Can't Find Crystallize List Information [Code : %d]", CrystallizeCode );
return RC::RC_ITEM_INVALID_VALUE;
}
if( pListInfo->m_ItemType != pItemInfo->m_wType )
return RC::RC_ITEM_INVALID_VALUE;
if (rTargetItem.CanUseMixture(MIXTURE_CRYSTALIZE) == false) {
return RC::RC_ITEM_NOT_MIXTURE;
}
//------------------------------------------------------------------------------------------
// Count Materials, 생성될 결정체들을 우선 구한다
DWORD seed = 1;
DWORD ObtainCount = 0;
SLOTCODE material_code = 0;
for( int count = 0 ; count < sITEM_CRYSTALIZE_LIST::MAX_MATERIALS ; ++count )
{
material_code = pListInfo->m_pResult[count].m_MaterialCode;
// 결정체 획득 확률
seed = random( 1, 100 );
if( seed > pListInfo->m_pResult[count].m_ResultRatio )
continue;
if( material_code == 0 )
continue;
// 생성될 결정체 개수 계산
ObtainCount = pListInfo->m_pResult[count].m_MaterialCount;
#ifdef _NA_008124_20150313_AWAKENING_SYSTEM
SLOTCODE temp_crystallize_code = ItemCrystalizeListParser::Instance()->GetCrystalizeCode( rTargetItem, 0 );
sITEM_CRYSTALIZE_LIST* list_info = ItemCrystalizeListParser::Instance()->GetCrystalizeListInfo( temp_crystallize_code );
if( !list_info )
{
continue;
}
ObtainCount += (list_info->m_pResult[count].m_MaterialCount * rTargetItem.GetAwakening());
#endif // _NA_008124_20150313_AWAKENING_SYSTEM
// 결정체의 금액이 0 이 아닌 경우 아이템의 상점 구입 가격/ MaterialMoney로 추가되는 결정체의 갯수가 결정된다.
if( 0 != pListInfo->m_pResult[count].m_MaterialMoney )
{
ObtainCount += (rTargetItem.GetPriceForBuy() / pListInfo->m_pResult[count].m_MaterialMoney);
}
miter = created_materials.find(material_code);
if (miter == created_materials.end()) {
created_materials[material_code] = ObtainCount;
}
else /* if (miter != created_materials.end())*/ {
miter->second += ObtainCount;
}
}
//created_materials의 재료들을 적당하게 output의 배열에 담아준다--------------------------------
for (miter = created_materials.begin(); miter != created_materials.end(); ++miter)
{
SLOTCODE material_code = miter->first;
DWORD material_count = miter->second;
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다. 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
// 또한 최대 가질 수 있는 결정체의 갯수를 총 2개의 슬롯으로 제한 시킨다.
material_count = min( material_count, UCHAR_MAX*2 );
while( material_count > UCHAR_MAX )
{
ObtainCodeArray[TotalCount] = material_code;
ObtainCountArray[TotalCount] = UCHAR_MAX;
material_count -= UCHAR_MAX;
++TotalCount;
}
if( material_count > 0 )
{
ObtainCodeArray[TotalCount] = material_code;
ObtainCountArray[TotalCount] = (BYTE)material_count;
++TotalCount;
}
}
Output.TotalCount = TotalCount;
ASSERT( TotalCount <= MAX_INVENTORY_SLOT_NUM );
if( TotalCount > MAX_INVENTORY_SLOT_NUM )
{
SUNLOG( eCRITICAL_LOG, "CrystallizeImplement::Crystallize() Crystallize Overflow to Max Slot Count" );
return RC::RC_ITEM_FAILED;
}
return RC::RC_ITEM_SUCCESS;
}
VOID CrystallizeImplement::DeleteTargetItem( SCItemSlot& rTargetItem )
{
ItemManager* item_manager = m_pPlayer->GetItemManager();
SCSlotContainer* inventory = item_manager->GetItemSlotContainer(SI_INVENTORY);
MSG_CG_ITEM_LOSE_ACK delete_msg;
delete_msg.m_ItemInfo.Clear();
DURATYPE item_count = delete_msg.m_ItemInfo.m_Count;
delete_msg.m_ItemInfo.m_Slot[item_count].m_Num = rTargetItem.GetNum();
delete_msg.m_ItemInfo.m_Slot[item_count].m_Pos = rTargetItem.GetPos();
++delete_msg.m_ItemInfo.m_Count;
inventory->DeleteSlot(rTargetItem.GetPos(), NULL);
m_pPlayer->SendPacket( &delete_msg, sizeof(delete_msg) );
}
#else
RC::eITEM_RESULT CrystallizeImplement::Crystallize( SCItemSlot& rTargetItem, CrystallizeImplement::sOutput& OUT Output )
{
const BASE_ITEMINFO* const pItemInfo = rTargetItem.GetItemInfo();
FASSERT( pItemInfo );
if( !pItemInfo )
return RC::RC_ITEM_INVALID_VALUE;
SLOTCODE CrystallizeCode = ItemCrystalizeListParser::Instance()->GetCrystalizeCode( rTargetItem );
sITEM_CRYSTALIZE_LIST* pListInfo = ItemCrystalizeListParser::Instance()->GetCrystalizeListInfo( CrystallizeCode );
if( !pListInfo )
{
SUNLOG( eCRITICAL_LOG, "CrystallizeImplement::Crystallize() Can't Find Crystallize List Information [Code : %d]", CrystallizeCode );
return RC::RC_ITEM_INVALID_VALUE;
}
if( pListInfo->m_ItemType != pItemInfo->m_wType )
return RC::RC_ITEM_INVALID_VALUE;
if (rTargetItem.CanUseMixture(MIXTURE_CRYSTALIZE) == false) {
return RC::RC_ITEM_NOT_MIXTURE;
}
// 일반적인 아이템인 경우 1레벨 0랭크 E인챈트인 무기는 분해 불가능
if( pItemInfo->m_wSubType == eITEMSUBTYPE_GENERAL )
{
if( pItemInfo->m_LV == 1 && rTargetItem.GetRank() == RANK_E && rTargetItem.GetEnchant() == 0 )
return RC::RC_ITEM_INVALID_VALUE;
}
// 기본적으로 pListInfo->m_ItemLevel = 0값을 가지며, 악세사리의 경우 1, 2의 Level값을 가진다.
if( pListInfo->m_ItemLevel && ( pItemInfo->m_LV != pListInfo->m_ItemLevel ) )
return RC::RC_ITEM_INVALID_VALUE;
if( pListInfo->m_EnchantLv != rTargetItem.GetEnchant() )
return RC::RC_ITEM_INVALID_VALUE;
POSTYPE TotalCount = 0;
DWORD seed = 1;
int i = 0;
MONEY ObtainCount = 0;
SLOTCODE* ObtainCodeArray = Output.ObtainCodeArray;
POSTYPE* ObtainCountArray = Output.ObtainCountArray;
// 1차 결정체 획득 확률
for( i = 0 ; i < sITEM_CRYSTALIZE_LIST::MAX_RESULT ; ++i )
{
seed = random( 1, 100 );
if( seed > pListInfo->m_pResult[i].m_ResultRatio )
continue;
if( pListInfo->m_pResult[i].m_MaterialCode == 0 )
continue;
ObtainCount = pListInfo->m_pResult[i].m_MaterialCount;
// 결정체의 금액이 0 이 아닌 경우 아이템의 상점 구입 가격/ MaterialMoney로 추가되는 결정체의 갯수가 결정된다.
if( 0 != pListInfo->m_pResult[i].m_MaterialMoney )
{
ObtainCount += (rTargetItem.GetPriceForBuy() / pListInfo->m_pResult[i].m_MaterialMoney);
}
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다. 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
// 또한 최대 가질 수 있는 결정체의 갯수를 총 2개의 슬롯으로 제한 시킨다.
ObtainCount = min( ObtainCount, UCHAR_MAX*2 );
while( ObtainCount > UCHAR_MAX )
{
ObtainCodeArray[TotalCount] = pListInfo->m_pResult[i].m_MaterialCode;
ObtainCountArray[TotalCount] = UCHAR_MAX;
ObtainCount -= UCHAR_MAX;
++TotalCount;
}
if( ObtainCount > 0 )
{
ObtainCodeArray[TotalCount] = pListInfo->m_pResult[i].m_MaterialCode;
ObtainCountArray[TotalCount] = (POSTYPE)ObtainCount;
++TotalCount;
}
}
// 랜덤 결정체 획득 확률
for( i = 0 ; i < sITEM_CRYSTALIZE_LIST::MAX_RANDOMRESULT ; ++i )
{
seed = (DWORD)dRandom( 1, pListInfo->m_pRandomResult[i].m_RandomStandardRatio );
if( seed > pListInfo->m_pRandomResult[i].m_RandomRatio )
continue;
if( pListInfo->m_pRandomResult[i].m_MaterialCode == 0 )
continue;
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다. 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
// 또한 최대 가질 수 있는 결정체의 갯수를 총 1개의 슬롯으로 제한 시킨다.
ObtainCount = min( pListInfo->m_pRandomResult[i].m_MaterialCount, UCHAR_MAX );
if( ObtainCount > 0 )
{
ObtainCodeArray[TotalCount] = pListInfo->m_pRandomResult[i].m_MaterialCode;
ObtainCountArray[TotalCount] = (POSTYPE)ObtainCount;
++TotalCount;
}
}
Output.TotalCount = TotalCount;
ASSERT( TotalCount <= MAX_INVENTORY_SLOT_NUM );
if( TotalCount > MAX_INVENTORY_SLOT_NUM )
{
SUNLOG( eCRITICAL_LOG, "CrystallizeImplement::Crystallize() Crystallize Overflow to Max Slot Count" );
return RC::RC_ITEM_FAILED;
}
return RC::RC_ITEM_SUCCESS;
}
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE