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

635 lines
26 KiB
C++

#include "stdafx.h"
#include "./ItemManager_ItemFunction.h"
#include "ItemManager.h"
#include "LotteryInfoParser.h"
#include "ItemTypeList.h"
#include "DropRatioInfoList.h"
#include "InventorySlotContainer.h"
#include "AchievementManager.h"
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
#include "NotificationInfoParser.h"
#include "GameZone.h"
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
//==================================================================================================
namespace nsSlot {
;
// NOTE: sub-manager is implemented to decompose ItemManager.
// this object has not extra members and virtual function table except the instance of ItemManager.
BOOST_STATIC_ASSERT(sizeof(nsSlot::ItemFunctionLottery) == sizeof(ItemManager*) * 2);
}; //end of namespace
//==================================================================================================
// CHANGES: f110611.1L, moved from ItemManager_Use.cpp
// 고정 타입 아이템 생성
// 예외조건은 위에서 다 처리하였다.
SCItemSlot* nsSlot::ItemFunctionLottery::MakeItemByLotteryInfo(
const MiniSlotInfo& mini_slot_info, BOOL random, SCItemSlot* const working_slot)
{
static SCItemSlot item_slot_static;
SCItemSlot& making_item_slot = working_slot ? *working_slot : item_slot_static;
making_item_slot.Clear(); // should be first call before a 'SetCode' call
//
bool is_overlapping_item = false;
DWORD number_of_items = 0;
DWORD item_type_index = 0;
SLOTCODE item_code = 0;
//---------------------------------------------------------------------------------------------
if (random)
{
DropRatioInfoList* const drop_parser = DropRatioInfoList::Instance();
DropObj* drop_object = NULL;
for (int retry_count = 5; retry_count > 0; --retry_count)
{
drop_object = drop_parser->PopRandomItemTypeIndex(mini_slot_info.Index);
if (drop_object == NULL || (drop_object->GetType() != DROP_OBJ_ITEM)) {
drop_object = NULL;
continue;
};
break;
}
if (drop_object == NULL)
{
SUNLOG(eCRITICAL_LOG,
_T("|["__FUNCTION__"]|斤口=can't find the drop info (%d)"),
mini_slot_info.Index);
return NULL;
};
// success
DropItemObj* drop_item_obj = static_cast<DropItemObj*>(drop_object);
// WARNING: ... problem point
item_code = static_cast<SLOTCODE>(drop_item_obj->GetItemCode());
making_item_slot.SetCode(item_code);
// a default value of 'GetNum' is 1.
is_overlapping_item = (making_item_slot.IsOverlap() != false);
if (is_overlapping_item) {
number_of_items = drop_item_obj->GetReserved();
item_type_index = 0;
}
else {
number_of_items = 1;
item_type_index = drop_item_obj->GetReserved();
};
// added logic to support _NA_0_20110318_ITEM_EXPIRATION_PERIOD
const BYTE group_code = drop_item_obj->GetGroupCode();
const bool apply_time = ((group_code & (DROP_GROUP::LIMIT_DATE|DROP_GROUP::LIMIT_TIME)) != 0);
if (apply_time)
{
const nsSlot::ItemRuleInfo& drop_item_rule_info = making_item_slot.GetItemRuleInfo();
if (drop_item_rule_info.is_valid_item == 0)
{
SUNLOG(eCRITICAL_LOG, TEXT("[ItemFunctionLottery]drop_item_code|%u|Try to invalid item drop"), item_code);
return NULL;
};
if (making_item_slot.ChangeItemToUsingTimer() == false)
{
SUNLOG(eCRITICAL_LOG, _T("[ItemFunctionLottery]ItemCode|%u|failed apply timer to drop item"),
item_code);
return NULL;
};
DWORD drop_item_reserved = drop_item_obj->GetReserved();
switch (drop_item_rule_info.charge_sub_type)
{
case eCHARGE_SUB_FIXED_AMOUNT:
case eCHARGE_SUB_FIXED_AMOUNT_EX:
case eCHARGE_SUB_FIXED_QUANTITY:
case eCHARGE_SUB_FIXED_AMOUNT_WAIT:
case eCHARGE_SUB_FATE:
case eCHARGE_SUB_COORDINATE_EX:
case eCHARGE_SUB_RIDER_WITH_PART:
case eCHARGE_SUB_RIDER_WITH_PART_NOTIMER:
case eCHARGE_SUB_FIXED_AMOUNT_EX2:
if (group_code & DROP_GROUP::LIMIT_TIME)
{
// 분단위 적용
making_item_slot.SetDateTime(drop_item_reserved * 60);
}
else if (group_code & DROP_GROUP::LIMIT_DATE)
{
//날짜 YYYYMMDDHHMMSS 값을 맞추기 위해 1000000을 곱한다.
DWORD64 d = (DWORD64)drop_item_reserved*1000000;
making_item_slot.SetFixedDateTime(d);
};
// CHANGES: f110603.4L, set default value about drop_item_reserved
drop_item_reserved = 0;
break;
}
}; // apply time
}
else
{
if (0 == mini_slot_info.Index)
{
// 랜덤이 아닐때는 item_code Index는 0이 될 수 없다.
// 스크립트 로드할 때 체크한다. 0이면 크리티컬 에러
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|斤口=invalid input value 'Index(%d)'|"),
mini_slot_info.Index);
return NULL;
}
assert(SAFE_NUMERIC_TYPECAST(DWORD, mini_slot_info.Index, SLOTCODE));
item_code = static_cast<SLOTCODE>(mini_slot_info.Index);
making_item_slot.SetCode(item_code);
//
is_overlapping_item = (making_item_slot.IsOverlap() != false);
if (is_overlapping_item) {
number_of_items = mini_slot_info.ItemTypeIndex;
item_type_index = 0;
}
else {
number_of_items = 1;
item_type_index = mini_slot_info.ItemTypeIndex;
};
};
//---------------------------------------------------------------------------------------------
if (is_overlapping_item)
{
making_item_slot.SetNum(static_cast<DURATYPE>(number_of_items));
}
else if (const ItemType* item_type = ItemTypeList::Instance()->FindItemType(item_type_index))
{
// default : SetNum(1)
const nsSlot::ItemRuleInfo& item_rule_info = making_item_slot.GetItemRuleInfo();
if (item_rule_info.IsEnableEnchant()) {
making_item_slot.SetEnchant(item_type->GetEnchant());
};
//_NA_000251_20100727_SOCKET_SYSTEM
// EP2에서는 아이템 타입 정보의 랭크 항목을 소켓 개수로 사용한다.
const BYTE number_of_socket = item_type->GetRank();
if (number_of_socket != 0 && item_rule_info.IsEnableSocket())
{
if (making_item_slot.CreateSocketItem(number_of_socket, false) == false)
{
SUNLOG(eCRITICAL_LOG,
_T("|%s|소켓 개수 설정에 실패했습니다.|아이템코드 = %u, 소켓개수 = &u"),
__FUNCTION__,
item_code,
number_of_socket);
}
};
nsSlot::ItemTypeChanger::ChangeItemByType(&making_item_slot, item_type->GetItemType());
}
else
{
// is_overlapping_item == false && can't find 'ItemType'
// default item
};
return &making_item_slot;
}
// CHANGES: f110614.3L, logic arrangement, f110611.1L, moved from ItemManager_Use.cpp
//판도라의 상자를 연다.
RC::eITEM_RESULT nsSlot::ItemFunctionLottery::PandoraBoxOpen(
POSTYPE lottery_item_pos, ITEMSTREAMEX* const result_stream)
{
if (root_->player_->GetBehave() != PLAYER_BEHAVE_IDLE_STATE) {
return RC::RC_ITEM_INVALIDSTATE;
};
if (root_->ValidState() == false) {
return RC::RC_ITEM_INVALIDSTATE;
};
if (root_->ValidPos(SI_INVENTORY, lottery_item_pos) == false) {
return RC::RC_ITEM_INVALIDPOS;
};
CInventorySlotContainer* const inventory = \
static_cast<CInventorySlotContainer*>(root_->GetItemSlotContainer(SI_INVENTORY));
SCItemSlot& lottery_item = static_cast<SCItemSlot&>(inventory->GetSlot(lottery_item_pos));
if (const nsSlot::ItemRuleInfo* item_rule_info = &lottery_item.GetItemRuleInfo()) {
if (item_rule_info->is_valid_item == false ||
item_rule_info->is_lottery == false)
{
return RC::RC_ITEM_LOTTO_NOLOTTOITEM;
};
};
#ifdef _NA_0_20110803_LOTTO_ITEM_LEVEL_LIMIT
LEVELTYPE level = lottery_item.GetItemInfo()->m_LimitUseLevel;
if (level != 0 && root_->player_->GetLevel() < level)
return RC::RC_ITEM_CANNOT_USE_PLAYER_LEVEL;
#endif
#ifdef _NA_003740_20210624_ADDBOXKEY
//藤속芎綾篤네-늪뇹털뙤角뤠槨矜狼賈痰篤네돨芎綾 by:枷쟁팃숲 2021-07-23
if(lottery_item.GetItemInfo()->m_BoxKeyIndex!=0)
{
ItemManager* const item_manager = root_->player_->GetItemManager();
const int amount_of_inven = item_manager->ExistItem(SI_INVENTORY, lottery_item.GetItemInfo()->m_BoxKeyIndex, 1);
if(amount_of_inven <1)
{//芎綾篤네꼇닸瞳샀鑒좆꼇뭘 藤속芎綾篤네 by:枷쟁팃숲 2021-07-31
return RC::RC_ITEM_BOXITEM_NOTKEY;
}
}
#endif //_NA_003740_20210624_ADDBOXKEY
SCLottoInfo* const lottery_info = lottery_item.GetLottoInfo();
// #1. check remain slot... pass
//if (inventory->GetEmptySlotNum() < MAX_PANDORA_SLOT_NUM) {
// return RC::RC_ITEM_LOTTO_NEED_EMPTY_SLOT;
//};
// #2. if the lottery item don't identificaiton, do identity
if (lottery_info->IsIdentity() == false)
{
// item_info->m_MaterialCode -> link -> lotteryinfo.lottery_index
const SLOTCODE material_code = lottery_item.GetItemInfo()->m_MaterialCode;
const LotteryIndexGroup* lottery_group = \
LotteryInfoParser::Instance()->GetLotteryIndexGroup(material_code);
if (lottery_group == NULL)
{
SUNLOG(eCRITICAL_LOG, _T("|[%s]|斤口=can't find lottery index(%d)|"),
__FUNCTION__, material_code);
return RC::RC_ITEM_LOTTO_IDENTITY_FAIL;
};
lottery_info->SetLottoIndex(material_code);
if (lottery_info->Identity() == false) {
return RC::RC_ITEM_LOTTO_IDENTITY_FAIL;
};
};
//
if (lottery_item.IsPandoraOpen())
{
SUNLOG(eCRITICAL_LOG, _T("|[%s]|斤口=is it sync problem? open failed|"), __FUNCTION__);
return RC::RC_ITEM_LOTTO_OPEN_FAIL;
};
// success
root_->player_->SetBehave(PLAYER_BEHAVE_DIALOG_OPEN_STATE);
lottery_info->SetOpenStatus(true);
if (result_stream) {
lottery_item.CopyOut(*result_stream);
};
//
return RC::RC_ITEM_LOTTO_OPEN_SUCCESS;
}
// CHANGES: f110614.3L, logic arrangement, f110611.1L, moved from ItemManager_Use.cpp
// 판도라의 상자를 닫을 때.
RC::eITEM_RESULT nsSlot::ItemFunctionLottery::PandoraBoxClose(POSTYPE lottery_item_pos)
{
if (root_->player_->GetBehave() != PLAYER_BEHAVE_DIALOG_OPEN_STATE) {
return RC::RC_ITEM_INVALIDSTATE;
};
if (root_->ValidState() == false) {
return RC::RC_ITEM_INVALIDSTATE;
};
if (root_->ValidPos(SI_INVENTORY, lottery_item_pos, false) == false) {
return RC::RC_ITEM_INVALIDPOS;
};
CInventorySlotContainer* const inventory = \
static_cast<CInventorySlotContainer*>(root_->GetItemSlotContainer(SI_INVENTORY));
SCItemSlot& lottery_item = static_cast<SCItemSlot&>(inventory->GetSlot(lottery_item_pos));
if (lottery_item.GetItemCode() == 0) {
// NOTE: the pointed lottery item can be already deleted when all lottery slot empty.
root_->player_->SetBehave(PLAYER_BEHAVE_IDLE_STATE);
return RC::RC_ITEM_PANDORABOX_CLOSE_SUCCESS;
};
//----------------------------------------------------------------------------------------------
if (const nsSlot::ItemRuleInfo* item_rule_info = &lottery_item.GetItemRuleInfo()) {
if (item_rule_info->is_valid_item == false ||
item_rule_info->is_lottery == false)
{
return RC::RC_ITEM_LOTTO_NOLOTTOITEM;
};
};
SCLottoInfo* const lottery_info = lottery_item.GetLottoInfo();
// NOTE: the state of identification is already processed after the lottery item opened.
// if the below condition is fails, that is the unexpected state.
if (lottery_info->IsIdentity() == false) {
return RC::RC_ITEM_PANDORABOX_CLOSE_FAIL;
};
if (lottery_item.IsPandoraOpen() == false) {
SUNLOG(eCRITICAL_LOG, _T("|[%s]|斤口=is it sync problem? open failed|"), __FUNCTION__);
return RC::RC_ITEM_PANDORABOX_CLOSE_FAIL;
};
// success process
root_->player_->SetBehave(PLAYER_BEHAVE_IDLE_STATE);
lottery_info->SetOpenStatus(false);
return RC::RC_ITEM_PANDORABOX_CLOSE_SUCCESS;
}
// CHANGES: f110613.3L, added the lottery renewal logic
RC::eITEM_RESULT nsSlot::ItemFunctionLottery::ExtractLotteryItems(bool moved_all,
POSTYPE lottery_item_pos, POSTYPE slot_index_in_lottery, const POSTYPE empty_slot_count,
ConcretizationResult* const concretization_result)
{
;{
concretization_result->result_value = concretization_result->eResult_None;
ZeroMemory(concretization_result->changed_lottery_item_stream,
sizeof(*concretization_result->changed_lottery_item_stream));
concretization_result->total_info->m_InvenCount = 0;
concretization_result->total_info->m_TmpInvenCount = 0;
};
//----------------------------------------------------------------------------------------------
if (root_->ValidState() == false) {
return RC::RC_ITEM_INVALIDSTATE;
};
if (root_->ValidPos(SI_INVENTORY, lottery_item_pos, true) == false) {
return RC::RC_ITEM_INVALIDPOS;
};
//----------------------------------------------------------------------------------------------
CInventorySlotContainer* const inventory = static_cast<CInventorySlotContainer*>(
root_->GetItemSlotContainer(SI_INVENTORY));
//----------------------------------------------------------------------------------------------
SCItemSlot& lottery_item = static_cast<SCItemSlot&>(inventory->GetSlot(lottery_item_pos));
#ifdef _NA_003740_20210624_ADDBOXKEY
const BASE_ITEMINFO* iteminfo = lottery_item.GetItemInfo();
if(iteminfo->m_BoxKeyIndex!=0)
{//芎綾篤네俚뙈꼇槨0句봬篤네 藤속芎綾篤네 by:枷쟁팃숲 2021-08-01
ItemManager* item_manager = root_->player_->GetItemManager();
POSTYPE num = static_cast<POSTYPE>(1);
const SLOTCODE itemCode = static_cast<SLOTCODE>(iteminfo->m_BoxKeyIndex);
SCItemSlot deleted_item_slot;
MSG_CG_ITEM_LOSE_ACK ack_msg;
{
RC::eITEM_RESULT result_value = item_manager->DeleteAllKindOfItem( \
1, &itemCode, &num, &(ack_msg.m_ItemInfo), &deleted_item_slot);
if (result_value != RC::RC_ITEM_SUCCESS)
{
SUNLOG(eCRITICAL_LOG,
__FUNCTION__" : 芎綾篤네꼇닸瞳 : %d",
root_->player_->GetCharGuid());
return RC::RC_ITEM_BOXITEM_NOTKEY;
}
GAMELOG->LogItem(ITEM_USE, root_->player_, &deleted_item_slot, 0, num);
}
root_->player_->SendPacket(&ack_msg, ack_msg.GetSize());
}
#endif //_NA_003740_20210624_ADDBOXKEY
if (const nsSlot::ItemRuleInfo* item_rule_info = &lottery_item.GetItemRuleInfo())
{
if (item_rule_info->is_valid_item == false ||
item_rule_info->is_lottery == false)
{
return RC::RC_ITEM_INVALIDSTATE;
}
};
if (lottery_item.IsPandoraOpen() == false) {
return RC::RC_ITEM_LOTTO_NEED_OPEN_STATE;
};
//
SCLottoInfo* const lottery_info = lottery_item.GetLottoInfo();
if (lottery_info->IsIdentity() == false) {
return RC::RC_ITEM_LOTTO_NEED_IDENTYFY_LOTTO_ITEM;
};
if( empty_slot_count < lottery_info->GetCount() )
{
PandoraBoxClose(lottery_item_pos);
return RC::RC_ITEM_HAVENOTSPACE;
}
//----------------------------------------------------------------------------------------------
// lottery_item -> inventory, concretization
RC::eITEM_RESULT result = RC::RC_ITEM_SUCCESS;
if (lottery_info->GetCount() > 0) {
result = this->AcquireItemsFromLottery(\
moved_all, lottery_item, slot_index_in_lottery, concretization_result);
}
else {
// delete
};
//----------------------------------------------------------------------------------------------
if ((result != RC::RC_ITEM_SUCCESS) &&
(result != RC::RC_ITEM_LOTTO_CONCRETIZE_SUCCESS))
{
return result;
};
//
if (lottery_info->GetCount() > 0)
{ // success process, concretization
lottery_item.CopyOut(*concretization_result->changed_lottery_item_stream);
return result;
}
else
{
// NOTE: result process with the lottery item deletion.
// CHANGES: f110610.3L, fixed invalid item logging problem that the item is already deleted.
// Custom comments: 현재 판도라 박스의 아이템 개수가 0이면... 복권을 삭제한다.
SCItemSlot deleted_item_for_log;
bool success = inventory->DeleteSlot(lottery_item_pos, &deleted_item_for_log) != false;
if (FlowControl::FCAssert(success))
{ // success process
concretization_result->result_value |=
concretization_result->eResult_RemoveLotteryItem;
GAMELOG->LogItem(ITEM_DELETE, root_->player_, &deleted_item_for_log);
return result;
};
};
ASSERT(!"we must accomplish to success");
// FAILED process
result = RC::RC_ITEM_FAILED;
if (INVENTORY_TOTAL_INFO* const total_info = concretization_result->total_info)
{
// NOTE: waverix hopes not to enter at this point.
// CHANGES: f110610.3L, fixed deleting only one item
// even though acquired items may grater than one.
const INVENTORY_TOTAL_INFO::SLOT_TYPE* it = total_info->m_Slot,
* const end = &total_info->m_Slot[total_info->m_InvenCount];
for (; it != end; ++it)
{
if (inventory->DeleteSlot(it->m_Pos, NULL) != RC::RC_ITEM_SUCCESS)
{
SLOTCODE item_code = it->m_Stream.Part.wCode;
SUNLOG(eCRITICAL_LOG,
_T("|[%s]|斤口=failed to rollback rewarded item(%d)|CharGuid=%d"),
__FUNCTION__, item_code, root_->player_->GetCharGuid());
};
};
};
return result;
}
//==================================================================================================
namespace nsSlot { namespace internal {
;
struct WorkingLotteryInfoNode
{
POSTYPE slot_index_in_lottery;
const MiniSlotInfo* mini_slot_info;
const SCLottoInfo::MiniSlot* mini_slot; // selected node in SCItemSlot::LottoInfo
};
struct WorkingLotteryItemSlot
{
uint8_t stream[sizeof(SCItemSlot)];
SCItemSlot* CreateInstance() {
return new (stream) SCItemSlot; // SCItemSlot need not to delete instance
};
SCItemSlot* GetInstance() {
return reinterpret_cast<SCItemSlot*>(stream);
};
};
}}; //end of namespace
//==================================================================================================
// CHANGES: f110613.3L, added the lottery renewal logic
RC::eITEM_RESULT nsSlot::ItemFunctionLottery::AcquireItemsFromLottery(
bool moved_all, SCItemSlot& lottery_item, POSTYPE slot_index_in_lottery,
ConcretizationResult* const concretization_result)
{
//
SCLottoInfo* lottery_info = lottery_item.GetLottoInfo();
if (FlowControl::FCAssert(lottery_info->GetCount() > 0) == false) {
return RC::RC_ITEM_SUCCESS; // for the empty lottery item deletion
};
const LotteryIndexGroup* lottery_index_group = NULL;
if (LotteryInfoParser* lottery_parser = LotteryInfoParser::Instance())
{
const uint16_t lottery_index = lottery_info->GetLottoIndex();
lottery_index_group = lottery_parser->GetLotteryIndexGroup(lottery_index);
if (lottery_index_group == NULL)
{
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|斤口=can't find lottery index(%d)|"),
lottery_index);
return RC::RC_ITEM_LOTTO_INVALID_LOTTOSCRIPT_INDEX;
}
};
nsSlot::internal::WorkingLotteryItemSlot working_slots[MAX_PANDORA_SLOT_NUM];
nsSlot::internal::WorkingLotteryInfoNode working_infos[MAX_PANDORA_SLOT_NUM] = { 0, };
int number_of_processing = 0;
if (moved_all)
{
for (uint8_t index = 0; index < _countof(working_infos); ++index)
{
const SCLottoInfo::MiniSlot* const mini_slot = &lottery_info->GetMiniSlot(index);
if (mini_slot->ExistItem == 0) {
continue;
};
// this mini_slot can handle the invalid lotto slot that is filled in zero.
// be basically selected zero index(1st).
const MiniSlotInfo* mini_slot_info =
lottery_index_group->GetMiniSlotInfo(mini_slot->InfoPos);
if (mini_slot_info == NULL) {
continue;
};
nsSlot::internal::WorkingLotteryInfoNode* info_node = &working_infos[number_of_processing];
;{
info_node->slot_index_in_lottery = index;
info_node->mini_slot = mini_slot;
info_node->mini_slot_info = mini_slot_info;
};
SCItemSlot* making_slot = working_slots[number_of_processing].CreateInstance();
making_slot = MakeItemByLotteryInfo(*info_node->mini_slot_info,
info_node->mini_slot->Random, making_slot);
if (making_slot == NULL) {
continue;
};
++number_of_processing;
};
}
else
{
const SCLottoInfo::MiniSlot* const mini_slot = \
&lottery_info->GetMiniSlot(slot_index_in_lottery);
if (mini_slot->ExistItem == 0) {
return RC::RC_ITEM_NOTEXIST_ITEM;
};
const MiniSlotInfo* mini_slot_info =
lottery_index_group->GetMiniSlotInfo(mini_slot->InfoPos);
if (mini_slot_info == NULL) {
return RC::RC_ITEM_NOTEXIST_ITEM;
};
nsSlot::internal::WorkingLotteryInfoNode* info_node = &working_infos[number_of_processing];
;{
info_node->slot_index_in_lottery = slot_index_in_lottery;
info_node->mini_slot = mini_slot;
info_node->mini_slot_info = mini_slot_info;
};
SCItemSlot* making_slot = working_slots[number_of_processing].CreateInstance();
making_slot = MakeItemByLotteryInfo(*info_node->mini_slot_info,
info_node->mini_slot->Random, making_slot);
if (making_slot != NULL) {
++number_of_processing;
};
};
if (number_of_processing == 0) {
return RC::RC_ITEM_NOTEXIST_ITEM;
};
//----------------------------------------------------------------------------------------------
nsSlot::ItemQuery select_suplus_query;
if (nsSlot::ItemQuery::MakeQueryInverseSelect(&select_suplus_query,
root_->player_, SI_INVENTORY) == false)
{
return RC::RC_ITEM_INVALIDSTATE;
};
for (uint8_t index = 0; index < number_of_processing; ++index)
{
SCItemSlot* making_slot = working_slots[index].GetInstance();
//bool is_overlapping_item = (making_slot->IsOverlap() != false);
const KindOfItemTag& lotto_tag = lottery_item.GetOptionTag();
// f100910.1L, f101101.2L, a making_item can inherit an own original tradable attribute
// by 'SetCode' event, though a parent item (it is a pandora box) has't a tradable attribute
if (lotto_tag.value == lotto_tag.Tag_TradeSkip) {
making_slot->CopyFromInheritableOption(lottery_item);
};
DURATYPE obtainable_number_of_items = making_slot->GetNum();
select_suplus_query.AddArg_ItemSlot(*making_slot, obtainable_number_of_items, true);
};
const ItemQuery::QueryInfo& query_info = select_suplus_query.query_info();
if (query_info.number_of_queries == 0) {
return RC::RC_ITEM_NOTEXIST_ITEM;
};
//----------------------------------------------------------------------------------------------
select_suplus_query.ChangeToFindEmptySlotOnlyMode();
const nsSlot::ItemQueryResult result = root_->Query(&select_suplus_query);
if (result.result_of_inverse_select == 0) {
return RC::RC_ITEM_HAVENOTSPACE;
};
for (int i = 0; i < query_info.number_of_queries; ++i)
{
const nsSlot::ItemQuery::QueryInfo::Node& node = query_info.nodes[i];
if (node.number_of_items != node.sum_of_items) {
return RC::RC_ITEM_HAVENOTSPACE;
};
};
for (int i = 0; i < query_info.number_of_queries; ++i)
{
const nsSlot::ItemQuery::QueryInfo::Node& node = query_info.nodes[i];
lottery_info->ClearMiniSlot(working_infos[i].slot_index_in_lottery);
// 판도라의 상자를 이용하여 아이템을 얻은 로그.
GAMELOG->LogItemEx(ITEM_GET_BY_LOTTERY, root_->player_, *node.item_slot, lottery_item);
//_NA_001990_ACSYSTEM_ADD
if (node.item_info->m_wACCode)
{
root_->player_->GetACManager()->ProcessItemObtain(
node.item_info->m_Code, node.item_info->m_wACCode,
node.item_info->m_byACReferenceID, node.number_of_items);
};
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
if (NotificationInfoParser::Instance()->IsNotificationItem(
*node.item_slot, eNotificationBox) == true)
{
MSG_DG_NOTIFICATION_ITEM_SYN msg;
msg.info.SetInfo(root_->player_->GetCharName(),
(root_->player_->GetGameZonePtr() != NULL) ? root_->player_->GetGameZonePtr()->GetMapCode() : 0,
GetTickCount(), eNotificationBox, node.item_slot->GetItemCode());
g_pGameServer->SendToSessionType(GAME_DBPROXY, &msg, sizeof(MSG_DG_NOTIFICATION_ITEM_SYN));
}
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
};
root_->ObtainAllKindOfItemByQuery(select_suplus_query);
select_suplus_query.MakeSerializedStream(concretization_result->total_info);
return RC::RC_ITEM_LOTTO_CONCRETIZE_SUCCESS;
}
//==================================================================================================