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

745 lines
30 KiB
C++

#include "stdafx.h"
#include "ItemManager.h"
#include "SCItemSlot.h"
#include "SCItemSlotContainer.h"
//==================================================================================================
#include "InventorySlotContainer.h"
#include "EquipmentSlotContainer.h"
#include "AppliedItemDependencyChain.h"
#ifdef _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
#include "PacketHandler/Handler_CG_ITEM.h"
#endif // _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
//==================================================================================================
//==================================================================================================
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::ItemManagerUpdateImpl) == sizeof(ItemManager*));
union AbuseSlotNode
{
DWORD composed;
struct
{
POSTYPE pos_in_slots;
SLOTIDX slot_index;
bool exist;
uint8_t __dummy;
};
};
//// result type : WORD
//#define MAKE_ABUSEDATA(a, b) \
// (WORD)(((a & 0xFF) << 8) | (b & 0xFF))
}; //end of namespace
//==================================================================================================
//== item serial key management routines
//==================================================================================================
bool nsSlot::ItemManagerUpdateImpl::IsDupSerialCode(DWORD64 world_serial_key) const
{
typedef ItemManager::ABUSESERIAL_HASH ABUSESERIAL_HASH;
const ABUSESERIAL_HASH& serial_table = root_->serial_check_table_;
ABUSESERIAL_HASH::const_iterator find_it = serial_table.find(world_serial_key);
if (find_it == serial_table.end()) {
return false;
};
AbuseSlotNode abuse_node = { find_it->second };
if (abuse_node.exist == false) {
return false;
};
return true;
}
void nsSlot::ItemManagerUpdateImpl::RemoveSerialCode(
SLOTIDX slot_index, POSTYPE pos_in_slots, DWORD64 world_serial_key)
{
typedef ItemManager::ABUSESERIAL_HASH ABUSESERIAL_HASH;
ABUSESERIAL_HASH* const serial_table = &root_->serial_check_table_;
ABUSESERIAL_HASH::iterator find_it = serial_table->find(world_serial_key);
if (find_it != serial_table->end()) {
find_it->second = 0;
return;
};
// error reporting
SUNLOG(eCRITICAL_LOG, _T("|[C:%u][Slot:%u,Pos:%u]|can't find the serial(%I64u) in table|"),
root_->player_->GetCharGuid(), slot_index, pos_in_slots, world_serial_key);
}
void nsSlot::ItemManagerUpdateImpl::AddSerialCode(
eSERIAL_ACTION serial_action,
SLOTIDX slot_index, POSTYPE pos_in_slots,
DWORD64 world_serial_key)
{
bool is_empty_serial = static_cast<ulong>(world_serial_key & DBSERIAL_MASK_VALUE) ==
TEMP_DBSERIAL_VALUE;
Player* const player = root_->player_;
const DWORD user_guid = player->GetUserGuid();
if (is_empty_serial)
{
SCItemSlotContainer* const item_container = root_->GetItemSlotContainer(slot_index);
assert(item_container);
if (slot_index == SI_INVENTORY ||
slot_index == SI_EQUIPMENT)
{
// 시리얼 발급
item_container->SetLock(pos_in_slots, true);
// request a serial issue to database (proxy)
;{
MSG_DG_ITEM_SERIAL_SYN msg_syn;
msg_syn.m_dwKey = user_guid;
msg_syn.m_SlotIdx = slot_index;
msg_syn.m_ItemPos = pos_in_slots;
g_pGameServer->SendToServer(GAME_DBPROXY, &msg_syn, sizeof(msg_syn));
};
}
else
{
SUNLOG(eCRITICAL_LOG,
_T("|[C:%u][Slot:%u,Pos:%u]|Warnings!! can't request serial issuance|"),
user_guid, slot_index, pos_in_slots);
};
//
SCItemSlot& issue_item_slot =
static_cast<SCItemSlot&>(item_container->GetSlot(pos_in_slots));
ASSERT(issue_item_slot.GetSerial() == TEMP_DBSERIAL_VALUE);
//------------------------------------------------------------
// configure item options
this->SetupPostItemOptionOnSerialIssued(issue_item_slot);
//------------------------------------------------------------
}
else if (IsDupSerialCode(world_serial_key))
{
this->SetupPostItemEventOnDuplicatedSerialIssued(
serial_action, slot_index, pos_in_slots, world_serial_key);
}
else
{
typedef ItemManager::ABUSESERIAL_HASH ABUSESERIAL_HASH;
ABUSESERIAL_HASH& serial_table = root_->serial_check_table_;
AbuseSlotNode abuse_node = { 0, };
abuse_node.pos_in_slots = pos_in_slots;
abuse_node.slot_index = slot_index;
abuse_node.exist = true;
serial_table[world_serial_key] = abuse_node.composed;
}
}
//==================================================================================================
//==================================================================================================
//==================================================================================================
bool nsSlot::ItemManagerUpdateImpl::SetupPostItemOptionOnSerialIssued(
SCItemSlot& issue_item_slot)
{
const nsSlot::ItemRuleInfo& item_rule_info = issue_item_slot.GetItemRuleInfo();
const BASE_ITEMINFO* const item_info = issue_item_slot.GetItemInfo();
__TOUCHED((item_rule_info, item_info));
// NOTE: post item configurations = { limited }
;{
issue_item_slot.CalLimited(); // calculate item using by prefetched limited index
};
// NOTE: post item configurations = { pet }
if (item_rule_info.is_pet)
{
SCPetInfo* pet_info_in_slot = issue_item_slot.GetPetInfo();
pet_info_in_slot->SetFullness(MAX_PET_FULLNESS);
};
//_NA_000251_20100727_SOCKET_SYSTEM
// NOTE: post item configurations = { socket }
;{
// EP2에서 소켓은 엘리트, 럭키, 리미티드, 일반 등의 구분이 아니라 모두 동일한 규칙을 이용하여
// 생성한다. 소켓 생성 로직이 EP2 이전 룰을 따라서 흩어져 있어서 어떤 경로를 사용해서 아이템을
// 생성하더라도 같은 방식으로 소켓을 생성할 수 있도록 이곳으로 옮긴다.
enum { kRamdomSocketNumber = 0 };
issue_item_slot.CreateSocketItem(kRamdomSocketNumber, false);
};
// NOTE: post item configurations = { zard item }
if (issue_item_slot.IsZardItem())
{
// 옵션이 설정되지 않았다면
if (issue_item_slot.GetExtendData() == SocketOptionParser::kInvalidSocketOptionIndex)
{
// 램덤으로 옵션을 설정한다.
const SocketOptionParser* socket_option_parser = SocketOptionParser::Instance();
const SOCKETINDEX zard_option_index =
socket_option_parser->GetRandomZardOption(item_info->m_Code);
if (zard_option_index != SocketOptionParser::kInvalidSocketOptionIndex)
{
issue_item_slot.SetExtendData(zard_option_index);
}
else
{
SUNLOG(eCRITICAL_LOG,
_T("|["__FUNCTION__"]|can't configure zard option")
_T("|CharGuid=%u, Slot:%u, Pos:%u|"),
root_->player_->GetCharGuid(),
issue_item_slot.GetSlotIdx(),
issue_item_slot.GetPos());
}
}
}
#ifdef _NA_003740_20111122_RANDOM_ITEM
const RandomValueTypeGrade::Value type_grade = RandomValueTypeGrade::kGrade1;
if (issue_item_slot.Randomize(type_grade) == true)
{
TCHAR add_info[MAX_ADDINFO_SIZE] = { 0 };
issue_item_slot.RandomOptionToString<_countof(add_info)>(type_grade, add_info);
GAMELOG->LogItem(ITEM_RANDOMIZE_OPTION, root_->player_, &issue_item_slot, 0, 1, NULL, NULL, add_info);
}
#endif
//!~_NA_000000_20130710_CHARGE_SUB_FIXED_AMOUNT_EX2
if (item_rule_info.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX2) {
issue_item_slot.FireUp_DateTime();
}
//~!_NA_000000_20130710_CHARGE_SUB_FIXED_AMOUNT_EX2
//
return true;
};
bool nsSlot::ItemManagerUpdateImpl::SetupPostItemEventOnDuplicatedSerialIssued(
eSERIAL_ACTION serial_action,
const SLOTIDX slot_index, const POSTYPE pos_in_slots,
const DWORD64 world_serial_key)
{
typedef ItemManager::ABUSESERIAL_HASH ABUSESERIAL_HASH;
//
const ABUSESERIAL_HASH& serial_table = root_->serial_check_table_;
const ABUSESERIAL_HASH::const_iterator abuse_node_it = serial_table.find(world_serial_key);
#ifdef _DEBUG
// pre checked
if (abuse_node_it != serial_table.end()) {
AbuseSlotNode abuse_node = { abuse_node_it->second };
ASSERT(abuse_node.exist);
}
#endif
//
Player* const player = root_->player_;
eABUSE_SUB_TYPE abuse_sub_type = eABUSE_SUB_DUPLICATE_ITEM_SERIAL_EXSIT;
if (SCItemSlotContainer* const item_container = root_->GetItemSlotContainer(slot_index))
{
SCItemSlot& blocking_item_slot =
static_cast<SCItemSlot&>(item_container->GetSlot(pos_in_slots));
//
if (blocking_item_slot.IsBlocked() == false)
{
blocking_item_slot.SetBlocked(true);
;{ // notify blocking state to client to synchronize information
MSG_CG_ITEM_BLOCKC_CMD msg_cmd;
msg_cmd.m_SlotIdx = slot_index;
msg_cmd.m_SlotPos = pos_in_slots;
player->SendPacket(&msg_cmd, sizeof(msg_cmd));
};
//
abuse_sub_type = eABUSE_SUB_DUPLICATE_ITEM_SERIAL_GENERATE;
}
};
//
//----------------------------------------------------------------------------------------------
const AbuseSlotNode abuse_node = { abuse_node_it->second };
if (abuse_node.exist &&
abuse_node.slot_index == slot_index &&
abuse_node.pos_in_slots == pos_in_slots)
{
ASSERT(!"unexpected status");
return false;
};
SCItemSlotContainer* const item_container =
root_->GetItemSlotContainer(abuse_node.slot_index);
if (FlowControl::FCAssert(item_container != NULL) == false) {
return false;
};
if (item_container->ValidPos(abuse_node.pos_in_slots) == false)
{
SUNLOG(eCRITICAL_LOG,
_T("|斤口=invalid serial data in serial table|Serial=%I64u, Slot=%d, Pos=%d|"),
world_serial_key, abuse_node.slot_index, abuse_node.pos_in_slots);
}
else
{
SCItemSlot& abuse_source_item_slot =
static_cast<SCItemSlot&>(item_container->GetSlot(abuse_node.pos_in_slots));
if (abuse_source_item_slot.GetItemCode() == 0)
{
SUNLOG(eCRITICAL_LOG,
_T("|斤口=invalid operation, try serial issue to empty slot")
_T("|Serial=%I64u, Slot=%d, Pos=%d|"),
world_serial_key, abuse_node.slot_index, abuse_node.pos_in_slots);
}
else if (abuse_source_item_slot.IsBlocked() == false)
{
// abuse_source_item_slot.IsBlocked() -> Nothing to do
abuse_source_item_slot.SetBlocked(true);
SUNLOG(eCRITICAL_LOG,
_T("|[C:%u][Serial:%I64u][Slot:%u,Pos:%u][Slot:%u,Pos:%u]|blocked|"),
player->GetCharGuid(),
world_serial_key,
slot_index, pos_in_slots,
abuse_node.slot_index, abuse_node.pos_in_slots);
//
abuse_sub_type = eABUSE_SUB_DUPLICATE_ITEM_SERIAL_GENERATE;
;{ // notify blocking state to client to synchronize information
MSG_CG_ITEM_BLOCKC_CMD msg_cmd;
msg_cmd.m_SlotIdx = abuse_node.slot_index;
msg_cmd.m_SlotPos = abuse_node.pos_in_slots;
player->SendPacket(&msg_cmd, sizeof(msg_cmd));
};
GAMELOG->LogItem(ITEM_DUPLICATE_SERIAL, player, &abuse_source_item_slot);
}
};
SECURELOG(SECURELOG_PLAYERINFO(player, eABUSE_DUPLICATE_ITEM_SERIAL, abuse_sub_type),
_T("[eSERIAL_ACTION:%u][Serial:%I64u,Slot:%u,Pos:%u]=[Slot:%u,Pos:%u]"),
(BYTE)serial_action, world_serial_key,
slot_index, pos_in_slots,
abuse_node.slot_index, abuse_node.pos_in_slots);
//
return true;
};
//==================================================================================================
//==================================================================================================
//==================================================================================================
namespace nsSlot {
;
enum {
eTimeExpirationItemTags =
( (1 << eCHARGE_SUB_FIXED_AMOUNT)
| (1 << eCHARGE_SUB_FIXED_AMOUNT_EX)
| (1 << eCHARGE_SUB_FIXED_QUANTITY)
| (1 << eCHARGE_SUB_FIXED_AMOUNT_WAIT)
| (1 << eCHARGE_SUB_FATE)
| (1 << eCHARGE_PC_ROOM)
| (1 << eCHARGE_SUB_COORDINATE_EX)
| (1 << eCHARGE_SUB_RIDER_WITH_PART)
| (1 << eCHARGE_SUB_RIDER_WITH_PART_NOTIMER)
| (1 << eCHARGE_SUB_FIXED_AMOUNT_EX2)
), //eTimeExpirationItemTags
};
}; //end of namespace
inline DWORD
nsSlot::ItemManagerUpdateImpl::GetExpirationItemType(const SCItemSlot& item_slot) const
{
// CHANGES: f110327.1L, changes charge_sub_type access field
// to support various making item with timer
const nsSlot::ItemRuleInfo& item_rule_info = item_slot.GetItemRuleInfo();
const BASE_ITEMINFO* item_info = item_slot.GetItemInfo();
// [1] - ChargeSubType에 의해 기간제 아이템으로 설정되는 경우
// [2] - 이것이 특수 아이템 (X-Mas Event Time Expiration Item)인 경우 기간제로 설정할 필요 있다.
// - Special Event Handler에 의한 기간제 아이템인지 아닌지를 검사한다.
DWORD selector = SELECTED_DEFAULTITEM;
if (item_rule_info.charge_sub_type &&
(nsSlot::eTimeExpirationItemTags & (1 << item_rule_info.charge_sub_type)))
{
selector = item_rule_info.charge_sub_type;
}
else if (item_info->time_expiration_item)
{
selector = SELECTED_TIMEEXPIRATIONITEM;
}
return selector;
}
//==================================================================================================
// (NOTE) 1st : 기간제 아이템 처리 목적
// 2nd : 유료화 관련 아이템
// 3rd : 기간 존재하는 아이템
// 4th : ItemSlot::Update를 호출해야 하는 아이템
// item_slot: slot in container
void nsSlot::ItemManagerUpdateImpl::AddExpirationItem(SCItemSlot& item_slot)
{
if (item_slot.GetSerial() == TEMP_DBSERIAL_VALUE) {
return;
};
// [1] - ChargeSubType에 의해 기간제 아이템으로 설정되는 경우
// [2] - 이것이 특수 아이템 (X-Mas Event Time Expiration Item)인 경우 기간제로 설정할 필요 있다.
// - Special Event Handler에 의한 기간제 아이템인지 아닌지를 검사한다.
const DWORD selector = GetExpirationItemType(item_slot);
if (selector == SELECTED_DEFAULTITEM) {
return;
};
//
// SELECTED_TIMEEXPIRATIONITEM | eCHARGE_SUB_TYPE(with time check)
typedef ItemManager::EXPIRATIONITEM_HASH EXPIRATIONITEM_HASH;
EXPIRATIONITEM_HASH& time_table = root_->expiration_item_table_;
std::pair<EXPIRATIONITEM_HASH::iterator, bool> result = time_table.insert(&item_slot);
ASSERT(result.second);
}
//==================================================================================================
// item_slot: slot in container
void nsSlot::ItemManagerUpdateImpl::RemoveExpirationItem(SCItemSlot& item_slot) // 기간제 아이템 처리 목적 - 유료화 관련 아이템, 또는 아니더라도 기간 존재하는 아이템
{
if (item_slot.GetSerial() == TEMP_DBSERIAL_VALUE) {
return;
};
// [1] - ChargeSubType에 의해 기간제 아이템으로 설정되는 경우
// [2] - 이것이 특수 아이템 (X-Mas Event Time Expiration Item)인 경우 기간제로 설정할 필요 있다.
// - Special Event Handler에 의한 기간제 아이템인지 아닌지를 검사한다.
const DWORD selector = GetExpirationItemType(item_slot);
if (selector == SELECTED_DEFAULTITEM) {
return;
};
//
// SELECTED_TIMEEXPIRATIONITEM | eCHARGE_SUB_TYPE(with time check)
typedef ItemManager::EXPIRATIONITEM_HASH EXPIRATIONITEM_HASH;
EXPIRATIONITEM_HASH& time_table = root_->expiration_item_table_;
time_table.erase(&item_slot);
}
//==================================================================================================
//==================================================================================================
// <_UpdateExpirationItem>
// Update 처리 구조를 변경하기로 하자.
// @History
// - (WAVERIX) (091002) code rearrangement
// delete : __NA_1017_LUCKY_ITEM_IDENTIFY_LOG
// __NA_0_PET_SYSTEM
bool nsSlot::ItemManagerUpdateImpl::_UpdateExpirationItem() // ChargeItem, etc Time Expiration Items
{
if (root_->item_update_timer_.IsExpired() == false) {
return true;
}
//----------------------------------------------------------------------------------------------
static SCItemSlot deleted_slot_s;
// to reduce code address size
SCItemSlot& deleted_slot = deleted_slot_s;
//----------------------------------------------------------------------------------------------
Player* const player = root_->player_;
const bool is_pcroom_user = player->CanApplyPCBangBenefit(true);
//----------------------------------------------------------------------------------------------
// 유료화 아이템의 만료기간 처리
// eCHARGE_SUB_FIXED_AMOUNT < 정액제 : 일정 기간제 (2007-06-07 24:12:30)
// eCHARGE_SUB_FIXED_AMOUNT_EX < 확장정액제 : 착용시 부터 일정 기간 사용 (30시간 -> 2007-06-07 24:12:30)
// eCHARGE_SUB_FIXED_AMOUNT_WAIT< 기한 만료시 일주일 대기, 대기 시간도 지나면 삭제
// eCHARGE_SUB_FIXED_QUANTITY < 정량제 : 사용 기간제 (30시간)
// eCHARGE_SUB_FATE < 럭키 아이템 형식: { 무제한, 시간 제한, 시간 만료시 사용 불가 }
// eCHARGE_SUB_COORDINATE_EX < 이중 타이머: 사용 기간 만료시 삭제 + 등록된 웨이포인트 삭제시 다음 삭제 가능 시점 설정
// eCHARGE_SUB_RIDER_WITH_PART < 연관 타이머:
// - 라이더: 입수 시점부터 일정 기간 사용 후, 사용 불가 형태로 설정
// - 파츠: 장착 시점부터 일정 기간 사용 후, 사용 불가 형태로 설정
// eCHARGE_SUB_RIDER_WITH_PART_NOTIMER < 연관 타이머:
// - 라이더: 기간 없음(eCHARGE_SUB_GENERAL), 장착된 파츠는 기간 존재할 수 있음.
// - 파츠: 기간 없음, 라이더에 장착된 다른 파츠는 기간 존재 가능
// 장착되지 않고 독립적으로 존재시 'eCHARGE_SUB_GENERAL'와 동일
// eCHARGE_SUB_FIXED_AMOUNT_EX2 < 확장정액제2 : 획득시부터 일정기간 사용
typedef ItemManager::EXPIRATIONITEM_HASH EXPIRATIONITEM_HASH;
EXPIRATIONITEM_HASH& item_time_table = root_->expiration_item_table_;
EXPIRATIONITEM_HASH::iterator it = item_time_table.begin(),
end = item_time_table.end();
// (WAVERIX) (WARNING) 한 번에 제거할 것이 있을 경우 하나씩만 제거하는 루틴이다. 주의할 것.
// - 부연: 제거 이벤트가 발생시(한번이라도)에는 루프가 종료된다.
for (; it != end; ++it)
{
SCItemSlot& item_slot = *(*it);
//------------------------------------------------------------------------------------------
// (NOTE) Expiration Item Section
// - 모처럼 slot updater (ISlotUpdaterExpirationItem)를 만들어 놓고 뭔 짓인가?
// 하지만 현재(071202) 너저분 상태의 update를 정리한 후에 작업하기로 하자.
const DWORD selector = GetExpirationItemType(item_slot);
if (selector == SELECTED_TIMEEXPIRATIONITEM)
{
if (AppliedItemDependencyChain* item_chain = AppliedItemDependencyChain::Instance())
{
if (item_chain->IsExpiredItem(item_slot) == false) {
continue;
};
if (DeleteItemOnUpdate(item_slot.GetSlotIdx(), item_slot.GetPos(),
item_slot, RC::RC_ITEM_DELETE_SUCCESS, ITEM_DELETE, &deleted_slot))
{
break;
}
}
continue;
}
//------------------------------------------------------------------------------------------
// (NOTE) Charge Item Section - controlled by 'eCHARGE_SUB_TYPE'
// (WAVERIX) (NOTE) (071201)
// - 골치 아픈 구조... 불필요한 빈번 체크... 수차례 증분 업데이트로 인한 너저분 정도... 정리하자.
// (WAVERIX) (NOTE) (091002)
// - 정리는 수행, 구조 자체가 변경되지는 않았다.
bool update_result = (item_slot.Update(is_pcroom_user) != false);
if (update_result != false) {
continue;
}
//-------------------------------
// delete operation by game rule
// (NOTE) 대기 시간 관련 | 펫 관련 등등 고려할 것들이 몇 가지 존재한다.
// (NOTE) one-time event로 처리된다. 즉, SCItemSlot내부적으로 한 번만 false가 발생하도록 해준다.
// 이 때 이벤트 처리를 완료해야 하며, 되도록 실패가 없는 편이 필요하다.
const SLOTIDX slot_index = item_slot.GetSlotIdx();
const POSTYPE item_pos = item_slot.GetPos();
// case #1
// 일주일 대기시간이 설정된 경우 (eCHARGE_SUB_FIXED_AMOUNT_WAIT)
// 그냥 사용 불가 설정 (eCHARGE_SUB_FATE, eCHARGE_SUB_RIDER_WITH_PART(_NOTIMER))
//
const nsSlot::ItemRuleInfo& item_rule_info = item_slot.GetItemRuleInfo();
if (item_rule_info.is_rider || item_rule_info.is_rider_parts)
{
if (slot_index == SI_INVENTORY) {
IPlayerRiderD& rider = player->Rider;
rider.Command_ItemSync(player, item_slot);
};
ChangeItemOnUpdate(slot_index, item_pos, item_slot,
true, ITEM_CHARGE_EXPIRED);
continue;
}
bool is_wait_after_expired = (item_slot.IsExpiredWaitTime() != false);
if (is_wait_after_expired != false)
{
// old comments: 럭키 아이템은 기간 만료시 로그로... (일반적으로 삭제시 로그 남김)
// old comments: (091002) (ADDIN) Rider|Rider Parts도 그렇게 할까?
// CHANGES: waverix, 장착된 아아템인 경우에만 'UpdateItemAttributes()' 수행한다.
// CHANGES: f110408.3L, moved to the upper position about attributes update toggling
//
ChangeItemOnUpdate(slot_index, item_pos, item_slot,
item_rule_info.is_fate != false, ITEM_CHARGE_EXPIRED);
// CHANGES: f110408.3L, time attribute changed item is controlled by time_table
// on runtime since _NA_0_20110318_ITEM_EXPIRATION_PERIOD applied.
if (slot_index == SI_EQUIPMENT) {
#ifdef _NA_002289_20110322_EQUIPMENTS_CALCULATOR_CHANGES_FOR_IMPROVEMENT
root_->UpdateItemAttributes(true, false);
#else
root_->UpdateAttrForEquipItem();
#endif
}
continue;
}
// case #2
// 일반적인 삭제 - 예외: 국내의 경우는 시간 제한이 없는 Pet|Rider로 유지될 것이다.
// 하지만 해외는 그렇지 않다. 문제는 Rider의 경우는 Parts도 존재한다는 점에서 Pet과는
// 처리 방식 자체가 다르다. 문제가 대단히 복잡해진다. (ex:Parts를 추출할 인벤공간이 없다면?)
// 따라서 Rider삭제는 없도록 해야 할 것이다.
if (is_wait_after_expired == 0) {
// 여기서 erase를 하면, RemoveChargeItem()에서 아이템을 제거 하지 못한다.
// ref: 루프 시작 위치 '(WARNING)' <- 제거 이벤트가 발생시에는 루프가 종료된다.
//-----------------------------------------------------------------------
// check nested event { pet } - 비활성 시에는 소환 해제부터 수행한다.
if (slot_index == SI_INVENTORY &&
item_slot.IsPetItem() && player->m_PetManager.AlreadySummonedPet())
{
player->m_PetManager.ReturnPet(&item_slot, true /*forced*/);
}
// delete operation : default
if (DeleteItemOnUpdate(slot_index, item_pos, item_slot,
RC::RC_ITEM_DELETE_EXPIRED_CHARGE_ITEM, ITEM_CHARGE_EXPIRED,
&deleted_slot))
{
break;
}
}
// (NOTE) 이곳에 걸린다는 것은 위에서 처리 실패인 경우나
// 또는 처리 성공 이후 continue가 없는 경우. 긴 루프인 관계로 구분하기 위해서 선언
assert(update_result == 0);
}; //end 'for'
//
// update attributes by 'last_auto_update'
//
return true;
}
bool nsSlot::ItemManagerUpdateImpl::_UpdateEtcItem()
{
return true;
}
//==================================================================================================
bool nsSlot::ItemManagerUpdateImpl::DeleteItemOnUpdate(
SLOTIDX slot_index, POSTYPE pos_in_slots,
SCItemSlot& item_slot,
uint8_t reason_based_on_item_result,
uint16_t reason_based_on_game_log,
SCItemSlot* const deleted_item_slot)
{
#ifdef _NA_008089_20150225_BUG_EXPIRE_UNEQUIP_BADGE
const BASE_ITEMINFO* item_info = item_slot.GetItemInfo();
if (item_info != NULL &&
(item_info->m_wType == eITEMTYPE_PCBANG || item_info->m_wType == eITEMTYPE_RENDER_EFFECT_ITEM) )
{
CharacterInfoExManager& extrainfo_manager = root_->player_->GetExtraInfoManager();
extrainfo_manager.TurnOnOffToggleItems((eITEMTYPE)item_info->m_wType, false);
}
#endif //_NA_008089_20150225_BUG_EXPIRE_UNEQUIP_BADGE
SCItemSlotContainer* item_container = root_->GetItemSlotContainer(slot_index);
if (item_container->DeleteSlot(pos_in_slots, deleted_item_slot) == false) {
return false;
};
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
PlayerSpaInfo* spa_info = root_->player_->GetPlayerSpaInfo();
spa_info->CheckAndResetSpaTicket(pos_in_slots);
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
MSG_CG_ITEM_DELETE_CMD msg_del_cmd;
msg_del_cmd.m_byReason = reason_based_on_item_result;
msg_del_cmd.m_atIndex = slot_index;
msg_del_cmd.m_atPos = pos_in_slots;
root_->player_->SendPacket(&msg_del_cmd, sizeof(msg_del_cmd));
GAMELOG->LogItem(reason_based_on_game_log, root_->player_, deleted_item_slot);
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|[IDX:%u][POS:%u]|"),
slot_index, pos_in_slots);
//
return true;
}
bool nsSlot::ItemManagerUpdateImpl::ChangeItemOnUpdate(
SLOTIDX slot_index, POSTYPE pos_in_slots,
SCItemSlot& item_slot,
bool enabled_game_logging, uint16_t reason_based_on_game_log)
{
MSG_CG_ITEM_CHANGE_ITEM_INFO_CMD msg_change_cmd;
msg_change_cmd.m_SlotIndex = slot_index;
msg_change_cmd.m_SlotPos = pos_in_slots;
item_slot.CopyOut(msg_change_cmd.m_ItemStream);
root_->player_->SendPacket(&msg_change_cmd, sizeof(msg_change_cmd));
if (enabled_game_logging) {
GAMELOG->LogItem(reason_based_on_game_log, root_->player_, &item_slot);
};
//
return true;
}
#ifdef _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
void nsSlot::ItemManagerUpdateImpl::AddImmediatelyUseItem( SCItemSlot& item_slot )
{
if (item_slot.GetSerial() == TEMP_DBSERIAL_VALUE) {
return;
};
if (IsImmediatelyUseItem(item_slot) == false)
{
return;
}
root_->immediately_use_item_table_.insert(&item_slot).second;
}
void nsSlot::ItemManagerUpdateImpl::RemoveImmediatelyUseItem( SCItemSlot& item_slot )
{
if (item_slot.GetSerial() == TEMP_DBSERIAL_VALUE) {
return;
};
if (IsImmediatelyUseItem(item_slot) == false)
{
return;
}
root_->immediately_use_item_table_.erase(&item_slot);
}
bool nsSlot::ItemManagerUpdateImpl::IsImmediatelyUseItem( SCItemSlot& item_slot )
{
const BASE_ITEMINFO* item_info = item_slot.GetItemInfo();
if (item_info == NULL)
{
return false;
}
return item_info->IsImmediatelyUseItem();
}
bool nsSlot::ItemManagerUpdateImpl::UpdateImmediatelyUseItem()
{
if (root_ == NULL)
{
return false;
}
if (root_->immediately_use_item_table_.empty() == true)
{
return true;
}
std::vector<POSTYPE> delete_list;
for (std::set<SCItemSlot*>::iterator cur_iter = root_->immediately_use_item_table_.begin();
cur_iter != root_->immediately_use_item_table_.end(); ++cur_iter)
{
SCItemSlot& item_slot = *(*cur_iter);
if ( IsImmediatelyUseItem(item_slot) == false )
{
continue;
}
SLOTCODE slot_code = item_slot.GetCode();
MSG_CG_ITEM_USE_SYN msg;
msg.m_dwKey = root_->player_->GetUserKey();
msg.m_atIndex = item_slot.GetSlotIdx();
msg.m_atPos = item_slot.GetPos();
Handler_CG_ITEM::OnCG_ITEM_USE_SYN(root_->player_->GetServerSession(), &msg, sizeof(msg));
const BASE_ITEMINFO* item_info = item_slot.GetItemInfo();
if (item_info == NULL)
{
continue;
}
if (item_info->m_ChargeSubType == eCHARGE_SUB_IMMEDIATELY_USE_AND_DELETE)
{
delete_list.push_back(msg.m_atPos);
}
}
for (std::vector<POSTYPE>::iterator delete_iter = delete_list.begin();
delete_iter != delete_list.end(); ++delete_iter)
{
POSTYPE pos = *delete_iter;
RC::eITEM_RESULT rt = root_->player_->GetItemManager()->Delete(pos);
if (RC::RC_ITEM_SUCCESS == rt)
{
MSG_CG_ITEM_DELETE_CMD CmdMsg;
CmdMsg.m_byReason = RC::RC_ITEM_DELETE_SUCCESS;
CmdMsg.m_atIndex = SI_INVENTORY;
CmdMsg.m_atPos = pos;
root_->player_->SendPacket(&CmdMsg, sizeof(CmdMsg));
}
}
root_->immediately_use_item_table_.clear();
return true;
}
#endif // _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
//==================================================================================================