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

675 lines
27 KiB
C++

#include "stdafx.h"
#include "./ItemManager.h"
#include "ItemTypeList.h"
#include "ItemCrystalizeListParser.h"
#include "InventorySlotContainer.h"
#include "SlotManager.h"
#include "GameZone.h"
#include "RewardManager.h"
#include "AchievementManager.h"
#include "ChaoState.h"
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
#include "SCItemSlotContainer.h"
#include "SCItemSlot.h"
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
#include "NotificationInfoParser.h"
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
//--------------------------------------------------------------------------------------------------
// @history
// 09/06/25|~~~
// 09/07/16|shogen|enchant facility uniformity|<- 적용하긴 하는 걸까?
// 09/10/22|namka199|rank facility improvement|(WARNING) 인첸트 일원화 작업이 일부 누락된 듯.
// 10/01/28|waverix|code arrangement
// |delete macros '__NA_676_PK_SYSTEM_IMPROVEMENT'
// | '__NA_977_PREVENTION_PARTY_RETURN_ABUSE'
// | '__NA_1339_ENCHANT_RENEWAL_EX'
// | '__NA_1168_ADD_CONTENTS_ADD_LOG'
// | '__BUG_35162_COMPOSE_BUG_BY_FULL_IVEN'
// | '__CN_1194__ELITE_1_5_ITEM'
// | '__MOD_CRYSTALIZE_MAX_CREATE_ITEM_NUM'
// 10/02/23|hukim|remove warnings level 4... etc...
// |(waverix: i think this changes have fragmentary knowledge)
// 10/02/24|waverix|rollback to revision 46727|
// |현웅씨, 다시 한 번 재검토 해보시구랴. 물론 경고를 무시하는 것은 나쁜 거지만,
// warning level 4라는 녀석의 함정에 빠져 무리한 변경을 수행한 걸로 생각됩니다.
//--------------------------------------------------------------------------------------------------
//==================================================================================================
//==================================================================================================
//==================================================================================================
void ItemManager::SendItemChange(SCItemSlot& target_slot)
{
MSG_CG_ITEM_CHANGE_ITEM_INFO_CMD cmdMsg;
cmdMsg.m_SlotIndex = SI_INVENTORY;
cmdMsg.m_SlotPos = target_slot.GetPos();
target_slot.CopyOut(cmdMsg.m_ItemStream);
player_->SendPacket(&cmdMsg, sizeof(cmdMsg));
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
RC::eITEM_RESULT
ItemManager::Compose(SLOTCODE compose_list_code, BYTE making_num,
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
INVENTORY_TOTAL_INFO* OUT inven_total_info, DURATYPE& success_num_out, DURATYPE& byPreventNum)
#else // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
INVENTORY_TOTAL_INFO* OUT inven_total_info, BYTE& success_num_out)
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
{
if (IsRestrictFunction(eFUNCTIONALRESTRICT_COMPOSE)) {
return RC::RC_ITEM_UNUSABLE_FUNCTION;
}
if (player_->GetChaoState().CanUseFuction(CHAO_USE_COMPOSE) == false) {
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
}
if (player_->GetBehave() == PLAYER_BEHAVE_UNEXPECTED_WAITING) {
return RC::RC_ITEM_INVALIDSTATEOFPLAYER;
}
if (ValidState() == false) {
return RC::RC_ITEM_INVALIDSTATE;
}
if (0 == making_num) {
return RC::RC_ITEM_INVALID_VALUE;
}
ItemComposeListParser* compose_list_parser = ItemComposeListParser::Instance();
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
const sITEM_COMPOSE_LIST* compose_list_from_parser = \
compose_list_parser->GetComposeListInfo(compose_list_code);
if (compose_list_from_parser == NULL) {
return RC::RC_ITEM_INVALID_VALUE;
}
sITEM_COMPOSE_LIST temp_compose_list = *compose_list_from_parser;
sITEM_COMPOSE_LIST* compose_list = &temp_compose_list;
//제작 비용 감소 효과 적용
compose_list->m_Money = \
player_->GetAttr().GetValueAppliedAttr(compose_list_from_parser->m_Money, eATTR_CRAFT_COST_RATIO);
#else // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
const sITEM_COMPOSE_LIST* compose_list = \
compose_list_parser->GetComposeListInfo(compose_list_code);
if (compose_list == NULL) {
return RC::RC_ITEM_INVALID_VALUE;
}
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
// 제한 클래스 여부
// if (0 != pListInfo->m_LimitCharClass && pListInfo->m_LimitCharClass == player_->GetCharType())
// return RC::RC_ITEM_COMPOSE_LIMIT_CLASS;
switch (compose_list->m_ItemType)
{
case eITEMTYPE_RING:
case eITEMTYPE_NECKLACE:
if (player_->GetLevel() < LIMIT_LEVEL_ACCESSORY)
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
break;
// 클래스별 특수 악세서리로 변경
case eITEMTYPE_BERSERKER_SACCESSORY:
case eITEMTYPE_DRAGON_SACCESSORY:
case eITEMTYPE_VALKYRIE_SACCESSORY:
case eITEMTYPE_SHADOW_SACCESSORY:
case eITEMTYPE_ELEMENTALIST_SACCESSORY:
case eITEMTYPE_MYSTIC_SPECIAL_ACCESSORY1: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eITEMTYPE_HELLROID_SPECIAL_ACCESSORY1: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eITEMTYPE_WITCHBLADE_SPECIAL_ACCESSORY1:
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eITEMTYPE_ALLCLASS_CHAOSEYE: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
case eITEMTYPE_ELEMENTALIST_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
case eITEMTYPE_BERSERKER_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
case eITEMTYPE_DRAGON_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
case eITEMTYPE_VALKYRIE_SHADOW_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
case eITEMTYPE_MYSTIC_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
case eITEMTYPE_HELLROID_WITCHBLADE_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
if (player_->GetLevel() < LIMIT_LEVEL_SACCESSORY)
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
break;
// (WARNING) it is has not default logic... thinking... miss?
}
// 돈 체크
if (player_->GetMoney() < compose_list->m_Money * making_num) {
return RC::RC_ITEM_HAVENOTMONEY;
}
GameZone* game_zone = player_->GetGameZonePtr();
if (game_zone == NULL) {
return RC::RC_ITEM_COMPOSE_INVALID_LOCATION;
}
// 맵 체크
{
const MAPCODE current_map_code = game_zone->GetMapCode();
int index = 0;
for ( ; index < _countof(compose_list->m_MapCode); ++index)
{
MAPCODE map_code = compose_list->m_MapCode[index];
if (map_code != 0 && map_code == current_map_code) {
break;
}
}
if (index == _countof(compose_list->m_MapCode)) {
return RC::RC_ITEM_COMPOSE_INVALID_LOCATION;
}
};
// 재료 체크
const sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE* materials = compose_list->m_pMaterial;
for (POSTYPE i = 0; i < compose_list->m_byMatCount; ++i)
{
const sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE& material = materials[i];
if (0 == material.m_ItemCode || 0 == material.m_byItemNum) {
continue;
}
ns_functor::ComposeMaterialItemCheck empty_check(\
material.m_ItemCode, material.m_ItemTypeIndex,
material.m_byItemNum * making_num);
if (ForeachSlot(SI_INVENTORY, &empty_check) == false) {
return RC::RC_ITEM_ENCHANT_HAVENOTMETERIALS;
}
}
RC::eITEM_RESULT compose_result = RC::RC_ITEM_COMPOSE_SUCCESS;
//조합 요청 갯수만큼 루풍~
success_num_out = 0;
for (BYTE loop = making_num; loop; --loop)
{ //조합
#ifdef _NA_000000_20130612_RANDOMIZER_CHANGE
RandomManager* const random_manager = player_->GetRandomManager();
int random_result = random_manager->randomizer_compose_.Rand();
int success_ratio = player_->GetAttr().GetCompositeIncRatio();
; success_ratio += compose_list->m_byCreateRatio;
if (random_result <= success_ratio*10) {
++success_num_out;
}
#else
int ratio = random(1, 100);
// CHANGES: f110125.3L, rollback from sun:r51762 because this attribute is a ratio type.
// the solving methodology is to modify script data not access a ratio section.
int success_ratio = player_->GetAttr().GetCompositeIncRatio();
; success_ratio += compose_list->m_byCreateRatio;
// 결과물 아이템 습득
if (ratio <= success_ratio) {
++success_num_out;
}
#endif //_NA_000000_20130612_RANDOMIZER_CHANGE
}
if (success_num_out != 0)
{
// 성공
if (compose_list->m_byResultType == compose_list->RESULTTYPE_ITEMCODE)
{
// 결과물 아이템 습득
// (CHANGES) (100129) (WAVERIX) fix up invalid result, if not success status
// (WARNING) occurred large block code renewal
RC::eITEM_RESULT obtain_result = RC::RC_ITEM_INVALID_VALUE;
if (compose_list->m_Result.m_ItemTypeIndex == 0)
{
obtain_result = Obtain(compose_list->m_Result.m_ItemCode,
compose_list->m_Result.m_byItemNum * success_num_out,
inven_total_info);
}
else
{
ItemTypeList* const item_type_list = ItemTypeList::Instance();
ItemType* item_type = \
item_type_list->FindItemType(compose_list->m_Result.m_ItemTypeIndex);
if (item_type == NULL)
{
SUNLOG(eCRITICAL_LOG, "["__FUNCTION__"]|斤口=can't find index|value=%d",
compose_list->m_Result.m_ItemTypeIndex);
obtain_result = RC::RC_ITEM_INVALID_VALUE;
}
else
{
BYTE enchant = item_type->GetEnchant();
// (CHANGES) (f100525.1L)
BYTE item_type_value = item_type->GetItemType();
BYTE rank = item_type->GetRank();
obtain_result = ObtainAllKindOfItem(1,
&compose_list->m_Result.m_ItemCode, &success_num_out,
&enchant, &item_type_value, &rank, inven_total_info);
}
}
//
if (obtain_result != RC::RC_ITEM_SUCCESS) {
return obtain_result;
}
}
else if (compose_list->m_byResultType == compose_list->RESULTTYPE_REWARDCODE)
{
if (making_num > 1) {
return RC::RC_ITEM_INVALID_VALUE;
}
RC::eREWARD_RESULT reward_result;
reward_result = g_RewardManager.RewardItem(RewardManager::eREWARD_COMPOSE, \
compose_list->m_Result.m_ItemCode, 0, player_, *inven_total_info);
if (reward_result != RC::RC_REWARD_SUCCESS) {
return RC::RC_ITEM_ISNOTEMPTYSLOT;
}
}
else
{
return RC::RC_ITEM_FAILED;
}
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
if (NotificationInfoParser::Instance()->IsNotificationItem(
compose_list->m_Result.m_ItemCode, eNotificationCraft, 0, 0) == true)
{
MSG_DG_NOTIFICATION_ITEM_SYN msg;
msg.info.SetInfo(player_->GetCharName(),
(player_->GetGameZonePtr() != NULL) ? player_->GetGameZonePtr()->GetMapCode() : 0,
GetTickCount(), eNotificationCraft, compose_list->m_Result.m_ItemCode);
g_pGameServer->SendToSessionType(GAME_DBPROXY, &msg, sizeof(MSG_DG_NOTIFICATION_ITEM_SYN));
}
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
//(lst1024) 비정상 조합로그 수정
// (CHANGES) (100131) (WAVERIX) change pointer calculation that \
// slot position array is continuous sequence
POSTYPE total = 0;
#if SUN_CODE_BACKUP
SCSlotContainer* temp_inventory = GetItemSlotContainer(SI_TEMPINVENTORY);
#endif
SCSlotContainer* inventory = GetItemSlotContainer(SI_INVENTORY);
INVENTORY_TOTAL_INFO::SLOT_TYPE* slot = inven_total_info->m_Slot;
for (POSTYPE loop = inven_total_info->m_InvenCount; loop; --loop)
{
SCItemSlot& target_item = static_cast<SCItemSlot&>(inventory->GetSlot(slot->m_Pos));
#ifdef _NA_007257_20140527_GAMELOG_ITEM_COMPOSE_SUCCESS_COUNT
GAMELOG->LogCompose(true, player_, &target_item, 0, NULL, compose_list->m_Money, NULL, success_num_out);
#else
GAMELOG->LogCompose(true, player_, &target_item, 0, NULL, compose_list->m_Money);
#endif //_NA_007257_20140527_GAMELOG_ITEM_COMPOSE_SUCCESS_COUNT
++slot;
}
#if SUN_CODE_BACKUP
for (POSTYPE loop = inven_total_info->m_TmpInvenCount; loop; --loop)
{
SCItemSlot& target_item = static_cast<SCItemSlot&>(temp_inventory->GetSlot(slot->m_Pos));
GAMELOG->LogCompose(true, player_, &target_item, 0, NULL, compose_list->m_Money);
++slot;
}
#endif
// 성공 로그
}
//삭제되는 아이템 시리얼 담을려고...
DBWLDSERIAL item_serial_static[compose_list->MAX_COMPOSE_ITEM_NUM];
// (CHANGES) (WAVERIX) fix up clear stream based on invalid size
// old code: clear size = { sizeof(DWORD) * MAX_COMPOSE_ITEM_NUM }
ZeroMemory(item_serial_static, sizeof(item_serial_static));
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
// 제작 실패 시 재료 소멸 방지 어트리뷰트 적용
int prevent_delete_ratio = player_->GetAttr().GetCraftPreventExtinctionMaterialRatio();
int delete_num = making_num;
int prevent_num = 0;
if (prevent_delete_ratio > 0
&& (making_num - success_num_out) > 0)
{
for (int i = 0; i < making_num - success_num_out; ++i)
{
if (random_percent(prevent_delete_ratio))
{
++prevent_num;
}
}
delete_num -= prevent_num;
byPreventNum = prevent_num;
}
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
// 재료 없애기
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
MSG_CG_ITEM_LOSE_ACK delete_msg;
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
for (POSTYPE i = 0; i < compose_list->m_byMatCount; ++i)
{
const sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE& material = materials[i];
if (0 == material.m_ItemCode || 0 == material.m_byItemNum) {
continue;
}
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
ns_functor::DeleteComposeMaterialItem delete_operator(\
material.m_ItemCode, material.m_ItemTypeIndex,
material.m_byItemNum * delete_num);
#else
ns_functor::DeleteComposeMaterialItem delete_operator(\
material.m_ItemCode, material.m_ItemTypeIndex,
material.m_byItemNum * making_num);
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
BOOL delete_result = DeleteComposeMaterials(&delete_operator, &delete_msg.m_ItemInfo);
#else
BOOL delete_result = ForeachSlot(SI_INVENTORY, &delete_operator);
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
ASSERT(delete_result);
item_serial_static[i] = delete_operator.GetItemSerial();
}
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
player_->SendPacket( &delete_msg, sizeof(delete_msg) );
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
if (success_num_out != 0)
{
GAMELOG->LogCompose(true, player_, NULL,
compose_list->m_byMatCount,
const_cast<sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE*>(materials),
compose_list->m_Money,
item_serial_static, success_num_out);
}
// 실패 로그
// TODO(WAVERIX) (WARNING) 하기 실패 로그 뭐냥? item_serial_static의 연산 부분 문제있다.
assert(making_num >= success_num_out);
BYTE fail_num = making_num - success_num_out;
if (fail_num > 0) {
GAMELOG->LogCompose(false, player_, NULL,
compose_list->m_byMatCount,
const_cast<sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE*>(materials),
compose_list->m_Money,
item_serial_static, fail_num);
}
if (making_num == fail_num) {
compose_result = RC::RC_ITEM_COMPOSE_FAILED;
}
// 돈차감 (CHANGES) change type 'DWORD64'->'MONEY'
MONEY composition_fee = compose_list->m_Money * making_num;
{
player_->MinusMoney(composition_fee);
GAMELOG->LogMoney(MONEY_COMPOSE, player_, composition_fee);
};
g_pGameServer->NotifyHeimConsumption(player_->GetCharGuid(),
eHEIM_CONSUMPTION_COMPOSITION, composition_fee);
//_NA_001990_ACSYSTEM_ADD
if(compose_list->m_byResultType != compose_list->RESULTTYPE_REWARDCODE)
{
const BASE_ITEMINFO* item_info = \
ItemInfoParser::Instance()->GetItemInfo(compose_list->m_Result.m_ItemCode);
if (item_info && item_info->m_wACCode)
{
player_->GetACManager()->ProcessItemObtain(item_info->m_Code, item_info->m_wACCode,
item_info->m_byACReferenceID, compose_list->m_Result.m_byItemNum * success_num_out);
}
}
return compose_result;
}
//--------------------------------------------------------------------------------------------------
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
// ItemManager::Crystalize는 사용하지 않는 함수이다 (CrystallizeImplement를 사용함)
#else
RC::eITEM_RESULT
ItemManager::Crystalize(SLOTCODE crystalize_list_code, POSTYPE target_pos,
INVENTORY_TOTAL_INFO* OUT inven_total_info)
{
if (IsRestrictFunction(eFUNCTIONALRESTRICT_CRYSTALIZE)) {
return RC::RC_ITEM_UNUSABLE_FUNCTION;
}
if (!player_->GetChaoState().CanUseFuction(CHAO_USE_CRYSTALIZE)) {
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
}
if (player_->GetBehave() == PLAYER_BEHAVE_UNEXPECTED_WAITING) {
return RC::RC_ITEM_INVALIDSTATEOFPLAYER;
}
if (player_->GetLevel() < LIMIT_LEVEL_CRYSTALIZE) {
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
}
if (ValidState() == false) {
return RC::RC_ITEM_INVALIDSTATE;
}
if (ValidPos(SI_INVENTORY, target_pos) == false) {
return RC::RC_ITEM_INVALIDPOS;
}
ItemCrystalizeListParser* const crystalize_list_parser = ItemCrystalizeListParser::Instance();
const sITEM_CRYSTALIZE_LIST* crystalize_list = \
crystalize_list_parser->GetCrystalizeListInfo(crystalize_list_code);
if (crystalize_list == NULL) {
return RC::RC_ITEM_INVALID_VALUE;
}
SCSlotContainer* inventory = GetItemSlotContainer(SI_INVENTORY);
SCItemSlot& target_item = static_cast<SCItemSlot&>(inventory->GetSlot(target_pos));
const BASE_ITEMINFO* item_info = target_item.GetItemInfo();
//FASSERT(item_info); remove 'FASSERT', assert(item_info)
if (crystalize_list->m_ItemType != item_info->m_wType) {
return RC::RC_ITEM_INVALID_VALUE;
}
if (target_item.CanUseMixture(MIXTURE_CRYSTALIZE) == false) {
return RC::RC_ITEM_NOT_MIXTURE;
}
// 일반적인 아이템인 경우 1레벨 0랭크 E인챈트인 무기는 분해 불가능
if (item_info->m_wSubType == eITEMSUBTYPE_GENERAL)
{
if (item_info->m_LV == 1 && target_item.GetRank() == RANK_E && target_item.GetEnchant() == 0)
{
return RC::RC_ITEM_INVALID_VALUE;
}
}
// 기본적으로 pListInfo->m_ItemLevel = 0값을 가지며, 악세사리의 경우 1, 2의 Level값을 가진다.
if (crystalize_list->m_ItemLevel && item_info->m_LV != crystalize_list->m_ItemLevel) {
return RC::RC_ITEM_INVALID_VALUE;
}
if (crystalize_list->m_EnchantLv != target_item.GetEnchant()) {
return RC::RC_ITEM_INVALID_VALUE;
}
static SLOTCODE obtain_code_list[MAX_INVENTORY_SLOT_NUM];
static POSTYPE obtain_counts_list[MAX_INVENTORY_SLOT_NUM];
ZeroMemory(obtain_code_list, sizeof(obtain_code_list));
ZeroMemory(obtain_counts_list, sizeof(obtain_counts_list));
// TODO(WAVERIX) (NOTE) #97 하단부 로직이 buffer boundary에 적합한지 정적 분석만으론 확인되지 않았다. 검증할 것.
POSTYPE total_count = 0;
MONEY number_of_obtains = 0;
// 1차 결정체 획득 확률
for (int i = 0; i < crystalize_list->MAX_RESULT; ++i)
{
const sITEM_CRYSTALIZE_LIST::sITEM_FOR_CRYSTALIZE& crystal_result = \
crystalize_list->m_pResult[i];
DWORD seed = random(1, 100);
if (seed > crystal_result.m_ResultRatio) {
continue;
}
if (crystal_result.m_MaterialCode == 0) {
continue;
}
number_of_obtains = crystal_result.m_MaterialCount;
// 결정체의 금액이 0 이 아닌 경우 아이템의 상점 구입 가격/
// MaterialMoney로 추가되는 결정체의 갯수가 결정된다.
if (0 != crystal_result.m_MaterialMoney) {
number_of_obtains += target_item.GetPriceForBuy() / crystal_result.m_MaterialMoney;
}
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다.
// 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
// 또한 최대 가질 수 있는 결정체의 갯수를 총 2개의 슬롯으로 제한 시킨다.
number_of_obtains = min(number_of_obtains, UCHAR_MAX*2);
while(number_of_obtains > UCHAR_MAX)
{
obtain_code_list[total_count] = crystal_result.m_MaterialCode;
obtain_counts_list[total_count] = UCHAR_MAX;
number_of_obtains -= UCHAR_MAX;
++total_count;
}
if (number_of_obtains > 0)
{
obtain_code_list[total_count] = crystal_result.m_MaterialCode;
obtain_counts_list[total_count] = static_cast<POSTYPE>(number_of_obtains);
++total_count;
}
}
// 랜덤 결정체 획득 확률
for (int i = 0; i < crystalize_list->MAX_RANDOMRESULT; ++i)
{
const sITEM_CRYSTALIZE_LIST::sITEM_FOR_RANDOM_CRYSTALIZE& crystal_random_result = \
crystalize_list->m_pRandomResult[i];
DWORD seed = (DWORD)dRandom(1, crystal_random_result.m_RandomStandardRatio);
if (seed > crystal_random_result.m_RandomRatio) {
continue;
}
if (crystal_random_result.m_MaterialCode == 0) {
continue;
}
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다.
// 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
// 또한 최대 가질 수 있는 결정체의 갯수를 총 1개의 슬롯으로 제한 시킨다.
number_of_obtains = min(crystal_random_result.m_MaterialCount, UCHAR_MAX);
if (number_of_obtains > 0)
{
obtain_code_list[total_count] = crystal_random_result.m_MaterialCode;
obtain_counts_list[total_count] = number_of_obtains;
++total_count;
}
}
ASSERT(total_count <= MAX_INVENTORY_SLOT_NUM);
RC::eITEM_RESULT crystalize_result = RC::RC_ITEM_CRYSTALIZE_FAILED;
if (0 == total_count)
{
// 결정화 실패 로그
GAMELOG->LogItem(ITEM_CRYSTALIZE_FAILED, player_, &target_item);
inventory->DeleteSlot(target_pos, NULL);
}
else
{
crystalize_result = ObtainAllKindOfItem(total_count,
obtain_code_list, obtain_counts_list,
inven_total_info);
if (crystalize_result == RC::RC_ITEM_SUCCESS)
{
// 결정화 성공 로그
GAMELOG->LogCrystalizeSuccess(player_, target_item,
total_count, obtain_code_list, obtain_counts_list);
inventory->DeleteSlot(target_pos, NULL);
crystalize_result = RC::RC_ITEM_CRYSTALIZE_SUCCESS;
}
}
return crystalize_result;
}
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
bool Sorting_PairVector(const std::pair<POSTYPE, INT> &fst, const std::pair<POSTYPE, INT> &sec)
{
return (fst.second < sec.second);
}
BOOL ItemManager::DeleteComposeMaterials( ns_functor::DeleteComposeMaterialItem* functor,
INVEN_DELETE_TOTAL_INFO* OUT delete_item_info)
{
SLOTIDX slot_index = SI_INVENTORY;
SCItemSlotContainer* slot_container = static_cast<SCItemSlotContainer*>(slot_manager_->GetSlotContainer(slot_index));
const SLOTCODE item_code = functor->GetItemCode();
BASE_ITEMINFO* item_info = ItemInfoParser::Instance()->GetItemInfo(item_code);
if(item_info == NULL) {
return false;
}
if (item_info->m_wEqPos == eEQUIPCONTAINER_INVALID)
{
// 장비아이템이 아닌 경우
typedef SCItemSlotContainer::SLOT_LINEAR_LIST SLOT_LINEAR_LIST;
const SLOT_LINEAR_LIST& slot_list = slot_container->GetSlotList();
SLOT_LINEAR_LIST::const_iterator it = slot_list.begin();
for ( ; it != slot_list.end(); ++it)
{
const SCItemSlot& item_slot = static_cast<const SCItemSlot&>(*it->slot);
if (item_slot.GetItemCode() == 0) {
continue;
};
if (functor->operator()(slot_container, item_slot, delete_item_info) == false) {
continue;
};
return true;
}
}
else
{
STLX_VECTOR< std::pair<POSTYPE, INT> > found_item;
// 장비아이템인 경우
const DWORD item_type_index = functor->GetItemTypeIndex();
INT minimum_enchant_value = 0;
ItemType* item_type = ItemTypeList::Instance()->FindItemType(item_type_index);
if (item_type != NULL) {
// NULL이면 0 유지
minimum_enchant_value = item_type->GetEnchant();
}
if (FlowControl::FCAssert(slot_container != NULL) == false) {
return false;
};
const POSTYPE max_number_of_slots = slot_container->GetMaxSlotNum();
// 인챈트 조건의 맞으면서 가장 낮은값을 가진 아이템의 좌표를 찾는다
for (POSTYPE pos = 0; pos < max_number_of_slots; ++pos)
{
if (slot_container->IsEmpty(pos)) {
continue;
}
SCItemSlot& slot = static_cast<SCItemSlot&>(slot_container->GetSlot(pos));
if (slot.GetItemCode() == item_code && slot.GetEnchant() >= minimum_enchant_value)
{
// 조건에 맞는 아이템들을 찾아서 vector에 삽입
found_item.push_back(std::make_pair(pos, slot.GetEnchant()));
}
}
sort(found_item.begin(), found_item.end(), Sorting_PairVector);
STLX_VECTOR< std::pair<POSTYPE,INT> >::iterator viter = found_item.begin();
for (viter; viter != found_item.end(); ++viter)
{
POSTYPE targetpos = viter->first;
SCItemSlot& target_slot = static_cast<SCItemSlot&>( slot_container->GetSlot(targetpos) );
if (functor->operator()(slot_container, target_slot, delete_item_info) == true) {
return true;
}
}
}
return false;
}
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION