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

703 lines
25 KiB
C++

#include "stdafx.h"
#include "./PerkManager.h"
#ifdef _NA002217_100728_EP2_PERK_SYSTEM_
#include "ItemManager.h"
#include <PacketStruct_DG.h>
#include <SkillSystem/PerkInfoParser.h>
#include <SCItemSlot.h>
#include <SCItemSlotContainer.h>
//_NA_001990_ACSYSTEM_ADD
#include "AchievementManager.h"
//==================================================================================================
namespace nsSkill {
;
struct PerkControlMessengerInGame : public nsSkill::IPerkControlMessenger,
public nsSkill::IPerkControlEvent
{
PerkControlMessengerInGame(Player* player)
: player_(player),
attributes_(&player->GetAttr())
{}
//--------------------------------------------------------------
// interfaces nsSkill::IPerkControlMessenger
virtual SCPerkSlotContainer* GetPerkSlotContainer() {
return NULL;
}
virtual Attributes* GetOwnerAttributes() {
return attributes_;
}
virtual nsSkill::IPerkControlEvent* GetPerkControlEvent() {
return this;
}
//--------------------------------------------------------------
// interfaces for nsSkill::IPerkControlEvent
virtual void OnChangeAttributes() {
attributes_->UpdateEx();
}
virtual void OnChangeSlotContainer() {
// nothing to do
}
virtual void OnLevelup() {
// nothing to do
}
//
//_NA_001990_ACSYSTEM_ADD
virtual void OnLevelup(const PerkID& perk_id)
{
if (AchievementManager* achievement = player_->GetACManager()) {
achievement->ProcessPerkLevel(perk_id.group_, perk_id.level_);
};
// CHANGES: f110602.3L
LEVELTYPE prev_level = (perk_id.level_ > 1) ? perk_id.level_ - 1 : perk_id.level_;
GAMELOG->WritePerkLevelUp(player_, perk_id.group_, prev_level, perk_id.level_);
}
Player* player_;
Attributes* attributes_;
};
struct RollbackRequestByFailed
{
RollbackRequestByFailed(const PerkControl* result_info, PerkControl* modify_info_if_failed)
: result_info_(result_info), modify_info_if_failed_(modify_info_if_failed)
{
}
~RollbackRequestByFailed()
{
if (result_info_->result != result_info_->eRet_Success) {
modify_info_if_failed_->Clear();
}
}
//
const PerkControl* result_info_;
PerkControl* modify_info_if_failed_;
};
//--------------------------------------------------------------------------------------------------
PerkManager::PerkManager()
: perk_data_container_(new nsSkill::PerkDataContainer)
{
ZeroMemory(&inter_, sizeof(inter_));
}
PerkManager::~PerkManager()
{
if (perk_data_container_) {
delete perk_data_container_;
}
ZeroMemory(&inter_, sizeof(inter_));
}
void PerkManager::Reuse(Player* player)
{
ZeroMemory(&inter_, sizeof(inter_));
inter_.player = player;
perk_data_container_->Clear();
update_expiration_date_timer_.Stop();
update_status_timer_.Stop();
}
bool PerkManager::CanProcessState(PerkControl* header, PerkControlData* data)
{
GameField* game_field = inter_.player->GetField();
if (game_field == NULL) {
return false;
};
//
ePLAYER_BEHAVE_STATE behave = inter_.player->GetBehave();
//_NA_005026_20120527_CHAOS_ZONE_BATTLE_GROUND
//_NA_000000_20140402_MODIFY_PERKMANAGER_POSSIBLE_TO_USE_WHILE_BATTLE_GROUND_RESERVATION
if (behave != PLAYER_BEHAVE_IDLE_STATE &&
behave != PLAYER_BEHAVE_RESERVATION_BATTLE_GROUND_ZONE )
{
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_UNUSABLE_FUNCTION;
return false;
}
return true;
}
bool PerkManager::CanProcessState()
{
GameField* game_field = inter_.player->GetField();
if (game_field == NULL) {
return false;
};
//
ePLAYER_BEHAVE_STATE behave = inter_.player->GetBehave();
//_NA_005026_20120527_CHAOS_ZONE_BATTLE_GROUND
//_NA_000000_20140402_MODIFY_PERKMANAGER_POSSIBLE_TO_USE_WHILE_BATTLE_GROUND_RESERVATION
if (behave != PLAYER_BEHAVE_IDLE_STATE &&
behave != PLAYER_BEHAVE_RESERVATION_BATTLE_GROUND_ZONE )
{
return false;
}
return true;
}
// NOTE: the perk system experience rule, add only battle experience value.
bool PerkManager::AddExp(int acquired_exp)
{
if (acquired_exp == 0) {
return false;
};
inter_.acquired_experience += acquired_exp;
return true;
}
void PerkManager::Update(const util::ServerTimeInfoPerFrame* time_info_per_frame)
{
GameField* game_field = inter_.player->GetField();
if (game_field == NULL) {
// to support client synchronization
return;
};
if (update_expiration_date_timer_.IsExpired()) {
UpdateExpirationDate(time_info_per_frame);
}
//if (inter_.acquired_experience)
if (update_status_timer_.IsExpired()) {
UpdateStatus(time_info_per_frame);
}
}
bool PerkManager::UpdateExpirationDate(const util::ServerTimeInfoPerFrame* time_info_per_frame)
{
//
PerkDataContainer::InterData* const inter_data = &perk_data_container_->inter_;
const DWORD64& curr_time_wz = time_info_per_frame->wz_yyyymmddhhmmss_;
const PerkDataNode** cash_it = inter_data->cash_slots_,
** cash_end = &inter_data->cash_slots_[_countof(inter_data->cash_slots_)];
const PerkDataNode* cash_node = NULL;
for ( ; cash_it != cash_end; ++cash_it)
{
// NOTE: one deletion per one time
if (*cash_it == NULL) {
continue;
};
cash_node = *cash_it;
if (curr_time_wz <= cash_node->exp_) {
continue;
}
// expired perk
break;
}
const bool need_deletion = (cash_it != cash_end && cash_node);
if (need_deletion == false) {
return true;
}
// delete operation
MSG_CG_SKILL_PERK_CONTROL_CMD msg_deletion;
//
const PerkID deletion_perk_id = cash_node->perk_id_;
PerkControlMessengerInGame perk_messenger(inter_.player);
const bool success_deletion = perk_data_container_->RequestDeletion(&msg_deletion.header,
deletion_perk_id,
&perk_messenger);
if (success_deletion == false) {
return true;
}
;{ // send a deletion operation to the DB proxy server
MSG_DG_CHARINFO_SKILL_PERK_CONTROL_CMD msg_cmd;
PerkControl* req_header = &msg_cmd.header;
req_header->Clear();
req_header->request = req_header->eReq_DeleteS2S;
req_header->char_guid = inter_.player->GetCharGuid();
req_header->args.delete_s2s.perk_uid = deletion_perk_id.uid_;
msg_cmd.data.Clear();
inter_.player->SendToGameDBPServer(&msg_cmd, msg_cmd.GetSize());
};
perk_data_container_->ProcessDelete(msg_deletion.header, &msg_deletion.data, &perk_messenger);
inter_.player->SendPacket(&msg_deletion, msg_deletion.GetSize());
return true;
}
// CHANGES: f101108.3L, to support GM commmand.
bool PerkManager::ChangePerkLevel(int changed_level)
{
GameField* game_field = inter_.player->GetField();
if (game_field == NULL) {
// to support client synchronization
return false;
};
if (changed_level == 0) {
return true;
};
PerkDataContainer::TouchList touch_list;
if (perk_data_container_->ModifyExpOrLevel(changed_level, true, &touch_list) == false) {
return true; // true? false? hummm....
};
// CHANGES: f110602.3L
for (const PerkDataContainer::TouchList::check_type* it = touch_list.touches;
it != &touch_list.touches[_countof(touch_list.touches)];
++it)
{
if (*it != touch_list.Selected) {
continue;
};
const PerkDataContainer::TouchList::ChangedInfo* changed_info = touch_list.changed_infos;
GAMELOG->LogExpPerk(inter_.player, changed_info->perk_group,
changed_info->next_exp, changed_info->prev_exp);
};
return ProcessStatus(touch_list);
}
bool PerkManager::UpdateStatus(const util::ServerTimeInfoPerFrame* time_info_per_frame)
{
__UNUSED(time_info_per_frame);
if (inter_.acquired_experience == 0) {
return true;
};
PerkDataContainer::TouchList touch_list;
if (perk_data_container_->ModifyExpOrLevel(inter_.acquired_experience, false,
&touch_list) == false)
{
return true; // true? false? hummm....
}
// CHANGES: f110602.3L
for (const PerkDataContainer::TouchList::check_type* it = touch_list.touches;
it != &touch_list.touches[_countof(touch_list.touches)];
++it)
{
if (*it != touch_list.Selected) {
continue;
};
const PerkDataContainer::TouchList::ChangedInfo* changed_info = touch_list.changed_infos;
GAMELOG->LogExpPerk(inter_.player, changed_info->perk_group,
changed_info->next_exp, changed_info->prev_exp);
};
return ProcessStatus(touch_list);
}
bool PerkManager::ProcessStatus(const PerkDataContainer::TouchList& touch_list)
{
//
MSG_CG_SKILL_PERK_STATUS_CMD msg_cmd;
PerkControl* const header = &msg_cmd.header;
;{ // init data
header->Clear();
header->request = header->eReq_Status;
};
PerkStatusData* const data = &msg_cmd.data;
data->Clear();
data->data_type = data->eDataType_ExpUpdate;
//
PerkDataContainer::InterData* const inter_data = &perk_data_container_->inter_;
PerkStatusData::StatusList* const status_list = &data->status_list;
PerkStatusData::__Status* dest_it = status_list->nodes_;
//
for (int index = 0; index < _countof(touch_list.touches); ++index)
{
if (touch_list.touches[index] != touch_list.Selected) {
continue;
}
const PerkDataNode* active_node = inter_data->active_slots_[index];
if (active_node == NULL) {
assert(active_node);
continue;
};
;{ // align data
dest_it->index_ = static_cast<uint8_t>(index);
dest_it->level_ = static_cast<uint8_t>(active_node->perk_id_.level_);
dest_it->exp_ = active_node->exp_;
//
++dest_it;
};
};
//
status_list->number_of_nodes_ = static_cast<uint8_t>(dest_it - status_list->nodes_);
inter_.acquired_experience = 0; // flush hit events
if (status_list->number_of_nodes_ == 0) {
// it's possible, if any perk is not registered.
return true;
};
// NOTE: this section process level up events.
// if a client part, it will be processed in ProcessEventMessage.
;{ // NOTE: level up event handling
PerkControlMessengerInGame perk_messenger(inter_.player);
perk_data_container_->ProcessEvent(msg_cmd.header, &msg_cmd.data, &perk_messenger);
};
// last process
inter_.player->SendPacket(&msg_cmd, msg_cmd.GetSize());
//
return true;
}
//==================================================================================================
void PerkManager::StorePerk(const PerkDataList& perk_data_list, DWORD char_key)
{
#ifdef _NA_007743_20141027_ADD_ISVAILD_CHECK
if (obj_util::IsValid(inter_.player) == false)
{
return;
}
#endif // _NA_007743_20141027_ADD_ISVAILD_CHECK
perk_data_container_->set_pass_key(char_key);
PerkControlMessengerInGame perk_messenger(inter_.player);
perk_data_container_->StorePerk(perk_data_list, &perk_messenger);
perk_data_container_->ApplyAttributes(&perk_messenger);
}
void PerkManager::LoadPerk(PerkDataList* perk_data_list)
{
perk_data_container_->LoadPerk(perk_data_list);
}
// CHANGES: f110727.2L, fixed a missing stopped timer resume event
void nsSkill::PerkManager::OnEnterField(GameField* game_field)
{
__TOUCHED(game_field);
update_expiration_date_timer_.SetTimer(kUpdateExpirationDateInterval);
update_status_timer_.SetTimer(kUpdateStatusInterval);
}
PerkManager::eRequestResult
PerkManager::ProcessRequestedMessage(const PerkControl& req_info,
PerkControl* header, PerkControlData* data)
{
header->Clear();
data->Clear();
*header = req_info;
//
bool success = false;
switch (req_info.request)
{
case req_info.eReq_Register:
return ProcessRegister(req_info, header, data);
case req_info.eReq_Plants:
return ProcessPlants(req_info, header, data);
case req_info.eReq_Uproot:
return ProcessUproot(req_info, header, data);
case req_info.eReq_Unregister:
return ProcessUnregister(req_info, header, data);
//-----------------------------
// operations on server
case req_info.eReq_InsertS2S:
{
const PerkControl::Req_InsertS2S& insert_s2s = req_info.args.insert_s2s;
insert_s2s.perk_uid;
// TODO : this logic, currently, is not implemented at this point.
// need more think related to a synchronous or asynchronous flow.
// related the article : eReq_Plants
};
break;
case req_info.eReq_DeleteS2S:
{
const PerkControl::Req_DeleteS2S& delete_s2s = req_info.args.delete_s2s;
delete_s2s.perk_uid;
// TODO : this logic, currently, is not implemented at this point.
// need more think related to a synchronous or asynchronous flow.
// related the article : eReq_Uproot
};
break;
}
//
return this->eReqResult_None;
}
PerkManager::eRequestResult
PerkManager::ProcessRegister(const PerkControl& req_info,
PerkControl* header, PerkControlData* data)
{
if (CanProcessState(header, data) == false) {
return this->eReqResult_ReplyResult;
}
bool success = false;
assert(req_info.request == req_info.eReq_Register);
const PerkControl::Req_Register& regist = req_info.args.regist;
regist.perk_uid;
regist.active_slot_uid;
PerkControlMessengerInGame perk_messenger(inter_.player);
success = perk_data_container_->RequestRegister(\
header, PerkID(regist.perk_uid), PerkID(regist.active_slot_uid), &perk_messenger);
if (success == false) {
return this->eReqResult_ReplyResult;
}
ASSERT(regist.perk_uid == header->args.regist.perk_uid);
ASSERT(regist.active_slot_uid == header->args.regist.active_slot_uid);
//
RollbackRequestByFailed rollback_request(header, &perk_data_container_->inter_.request_info_);
//
success = perk_data_container_->ProcessReplyMessage(*header, data, &perk_messenger);
ASSERT(success);
//
return this->eReqResult_ReplyResult;
}
PerkManager::eRequestResult
PerkManager::ProcessUnregister(const PerkControl& req_info,
PerkControl* header, PerkControlData* data)
{
bool success = false;
assert(req_info.request == req_info.eReq_Unregister);
const PerkControl::Req_Unregister& unregist = req_info.args.unregist;
unregist.perk_uid;
PerkControlMessengerInGame perk_messenger(inter_.player);
success = perk_data_container_->RequestUnregister(\
header, PerkID(unregist.perk_uid), &perk_messenger);
if (success == false) {
return this->eReqResult_ReplyResult;
}
ASSERT(unregist.perk_uid == header->args.unregist.perk_uid);
//
RollbackRequestByFailed rollback_request(header, &perk_data_container_->inter_.request_info_);
//
success = perk_data_container_->ProcessReplyMessage(*header, data, &perk_messenger);
ASSERT(success);
return this->eReqResult_ReplyResult;
}
PerkManager::eRequestResult
PerkManager::ProcessPlants(const PerkControl& req_info,
PerkControl* header, PerkControlData* data)
{
if (CanProcessState(header, data) == false) {
return this->eReqResult_ReplyResult;
}
//
bool success = false;
assert(req_info.request == req_info.eReq_Plants);
// a plant is an action that a cash item is moved to a cash perk slot
const PerkControl::Req_Plants& plants = req_info.args.plants;
plants.from_item_pos;
// check the inventory of a player related to 'plants.from_item_pos'
ItemManager* const item_manager = inter_.player->GetItemManager();
if (item_manager->ValidPos(SI_INVENTORY, plants.from_item_pos, true) == false) {
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALIDPOS;
return this->eReqResult_ReplyResult;
};
//
SCSlotContainer* const inventory = item_manager->GetItemSlotContainer(SI_INVENTORY);
SCItemSlot& plants_item = static_cast<SCItemSlot&>(inventory->GetSlot(plants.from_item_pos));
const BASE_ITEMINFO* plants_item_info = plants_item.GetItemInfo();
if (plants_item.IsContainValidItem() == false ||
plants_item_info->m_wType != eITEMTYPE_PERK_CASH_ITEM)
{
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALID_TYPE;
return this->eReqResult_ReplyResult;
}
if (plants_item.IsLocked() || plants_item.IsBlocked())
{
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALIDPOS;
return this->eReqResult_ReplyResult;
}
//
const SLOTCODE perk_group_code = plants_item_info->m_wSkillCode;
const PerkID perk_id(perk_group_code, 1);
const PerkInfoParser* perk_parser = PerkInfoParser::Instance();
/*
const PerkGroup* perk_group_info = perk_parser->FindPerkGroup(perk_id);
if (perk_group_info == NULL) {
header->result = header->eRet_SkillFailed;
header->result_code = RC::RC_SKILL_CANT_FIND_INFO;
return this->eReqResult_ReplyResult;
}
const PerkInfo* perk_info = perk_group_info->perk_info_array_[0];
*/
const PerkInfo* perk_info = perk_parser->FindPerkInfo(perk_id);
assert(perk_info);
if (perk_info == NULL || perk_info->item_code_ == 0 ||
perk_info->perk_id_.uid_ != perk_id.uid_)
{
header->result = header->eRet_SkillFailed;
header->result_code = RC::RC_SKILL_CANT_FIND_INFO;
return this->eReqResult_ReplyResult;
};
const PerkDataNode* perk_data = perk_data_container_->FindPerkData(perk_id);
if (perk_data != NULL) {
header->result = header->eRet_SkillFailed;
header->result_code = RC::RC_SKILL_ALREADY_EXIST_SKILL;
return this->eReqResult_ReplyResult;
};
// process with data modification
const bool is_enable_timer = plants_item.GetItemRuleInfo().IsEnableTimer();
assert(is_enable_timer);
if (plants_item.IsProgressTime() == false) {
plants_item.FireUp_DateTime();
}
DWORD64 expiration_date = plants_item.GetDateTime();
//
PerkControlMessengerInGame perk_messenger(inter_.player);
success = perk_data_container_->RequestPlants(header, plants.from_item_pos, &perk_messenger);
if (success == false) {
if (header->result == header->eRet_Success) {
header->result = header->eRet_Failed;
header->result_code = header->eRetCode_Unknown;
}
return this->eReqResult_ReplyResult;
}
ASSERT(plants.from_item_pos == header->args.plants.from_item_pos);
//
RollbackRequestByFailed rollback_request(header, &perk_data_container_->inter_.request_info_);
//
;{
// next task: if the result is success, do configure the 'data' variable.
data->data_type = data->eDataType_Plants;
data->plants.perk_uid = perk_id.uid_;
data->plants.expiration_date = expiration_date; // f101228.2L
};
;{ // use a cash perk regist item
SLOTCODE result_item_code = 0;
RC::eITEM_RESULT result = \
item_manager->Use(SI_INVENTORY, plants.from_item_pos, result_item_code);
if (result != RC::RC_ITEM_SUCCESS) {
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALID_TYPE;
return this->eReqResult_ReplyResult;
}
};
//
success = perk_data_container_->ProcessReplyMessage(*header, data, &perk_messenger);
assert(success);
#ifdef SUN_CODE_BACKUP // f101228.2L
;{ // RESOLVED: configure additional data using 'expiration_date'
const nsSkill::PerkDataNode* perk_data_node = perk_data_container_->FindPerkData(perk_id);
nsSkill::PerkDataNode* perk_data_node_edit = \
const_cast<nsSkill::PerkDataNode*>(perk_data_node);
perk_data_node_edit->exp_ = expiration_date;
};
#endif
return this->eReqResult_ReplyResult;
}
PerkManager::eRequestResult
PerkManager::ProcessUproot(const PerkControl& req_info,
PerkControl* header, PerkControlData* data)
{
if (CanProcessState(header, data) == false) {
return this->eReqResult_ReplyResult;
}
//
bool success = false;
assert(req_info.request == req_info.eReq_Uproot);
// an uproot is an action that a cash perk slot is moved to an item on an inventory
const PerkControl::Req_Uproot& uproot = req_info.args.uproot;
uproot.perk_uid;
uproot.to_item_pos;
//
const PerkID uproot_perk_id(uproot.perk_uid);
const PerkInfoParser* const perk_parser = PerkInfoParser::Instance();
const PerkInfo* perk_info = perk_parser->FindPerkInfo(uproot_perk_id);
if (perk_info == NULL) {
header->result = header->eRet_SkillFailed;
header->result_code = RC::RC_SKILL_CANT_FIND_INFO;
return this->eReqResult_ReplyResult;
};
//
if (perk_info->item_code_ == 0) {
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_UNUSABLE_FUNCTION;
return this->eReqResult_ReplyResult;
};
const ItemInfoParser* item_parser = ItemInfoParser::Instance();
const BASE_ITEMINFO* perk_item_info = item_parser->GetItemInfo(perk_info->item_code_);
if (perk_item_info == NULL || perk_item_info->m_wType != eITEMTYPE_PERK_CASH_ITEM) {
header->result = header->eRet_ItemFailed;
header->result_code = (perk_item_info == NULL) ? RC::RC_ITEM_NOINFO
: RC::RC_ITEM_UNUSABLE_FUNCTION;
return this->eReqResult_ReplyResult;
}
// check the inventory of a player related to 'uproot.to_item_pos'
ItemManager* const item_manager = inter_.player->GetItemManager();
if (item_manager->ValidPos(SI_INVENTORY, uproot.to_item_pos, false) == false) {
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALIDPOS;
return this->eReqResult_ReplyResult;
};
//
SCSlotContainer* const inventory = item_manager->GetItemSlotContainer(SI_INVENTORY);
const SCItemSlot& empty_slot = static_cast<SCItemSlot&>(inventory->GetSlot(uproot.to_item_pos));
if (empty_slot.GetItemCode() != 0) { //...maybe implicit resolved by a ValidPos
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALIDPOS;
return this->eReqResult_ReplyResult;
};
if (empty_slot.IsLocked() || empty_slot.IsBlocked()) {
header->result = header->eRet_ItemFailed;
header->result_code = RC::RC_ITEM_INVALIDSTATE;
return this->eReqResult_ReplyResult;
};
//
PerkControlMessengerInGame perk_messenger(inter_.player);
//
success = perk_data_container_->RequestUproot(header, \
uproot_perk_id, uproot.to_item_pos, &perk_messenger);
if (success == false) {
return this->eReqResult_ReplyResult;
}
ASSERT(uproot.perk_uid == header->args.uproot.perk_uid);
ASSERT(uproot.to_item_pos == header->args.uproot.to_item_pos);
//
RollbackRequestByFailed rollback_request(header, &perk_data_container_->inter_.request_info_);
//
// NOTE: r100914.6L, to get the expiration time of a perk node,
// you try to access the low level data container
nsSkill::PerkDataNode* const uprooting_node = \
perk_data_container_->server_data_.uproot.uprooting_node;
const DWORD64 expiration_date = uprooting_node->exp_;
//
// NOTE: send a perk data stream to a DBP & send a delete operation to a DBP
success = perk_data_container_->ProcessReplyMessage(*header, data, &perk_messenger);
assert(success);
//
;{ // send a deletion operation to the DB proxy server
MSG_DG_CHARINFO_SKILL_PERK_CONTROL_CMD msg_cmd;
PerkControl* req_header = &msg_cmd.header;
req_header->Clear();
req_header->request = req_header->eReq_DeleteS2S;
req_header->char_guid = inter_.player->GetCharGuid();
req_header->args.delete_s2s.perk_uid = uproot_perk_id.uid_;
msg_cmd.data.Clear();
inter_.player->SendToGameDBPServer(&msg_cmd, msg_cmd.GetSize());
};
//
SCItemSlot making_perk_item;
making_perk_item.SetCode(perk_item_info->m_Code);
;{
// NOTE: r100914.6L, get and set time information
// if the uprooting node has the expiration date information.
assert(making_perk_item.IsContainValidItem() &&
making_perk_item.GetItemRuleInfo().IsEnableTimer());
making_perk_item.SetFixedDateTime(expiration_date);
making_perk_item.SetProgressTime(true);
};
FlowControl::FCAssert(RC::RC_INSERT_SLOT_SUCCESS ==
inventory->InsertSlot(uproot.to_item_pos, making_perk_item));
assert(&empty_slot == &inventory->GetSlot(uproot.to_item_pos));
SCItemSlot& perk_item_in_inventory = const_cast<SCItemSlot&>(empty_slot);
//
data->data_type = data->eDataType_Uproot;
perk_item_in_inventory.CopyOut(data->uproot.maked_item);
//
return this->eReqResult_ReplyResult;
}
}; //end of namespace
//==================================================================================================
#endif //_NA002217_100728_EP2_PERK_SYSTEM_