Files
2022-10-26 12:25:11 +08:00

1108 lines
37 KiB
C++

#include "stdafx.h"
#include "./ItemManager.h"
#include <PublicMath.h>
#include "InventorySlotContainer.h"
#include "EquipmentSlotContainer.h"
#include "SlotManager.h"
#include "DropManager.h"
#include "FunctionalRestrictManager.h"
#include "AchievementManager.h"
#include "ItemExpDistributor.h"
#include "Item.h"
#include "GameParty/NewGamePartyManager.h"
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
#include "NotificationInfoParser.h"
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
//
//==================================================================================================
//==================================================================================================
//==================================================================================================
// ItemManager
//
ItemManager::ItemManager()
: player_(NULL)
, slot_manager_(NULL)
, slot_containers_(NULL)
, current_special_transaction_(ItemManager::TransactionClosure::eTransType_None)
, item_switch_handle_(NULL)
{
item_update_timer_.SetTimer(3 * 1000);
}
ItemManager::~ItemManager()
{
Release();
}
VOID
ItemManager::Release()
{
// m_SerialCodeCheck.RemoveAll();
SALE_ITEM_DEQ::iterator iter;
for(iter = saled_item_list_.begin(); iter != saled_item_list_.end(); ++iter)
{
RepurchaseSlot& slot = *iter;
SAFE_DELETE(slot.m_itemSlot);
}
saled_item_list_.clear();
SAFE_DELETE(item_switch_handle_);
}
void ItemManager::Init(SlotManager* slot_manager)
{
player_ = slot_manager->player_;
slot_containers_ = slot_manager->slot_container_list_;
slot_manager_ = slot_manager;
// CHANGES: f091202.x, WOPS:5334, 可在锁定状态下清除物品的特殊处理(PK掉落)
current_special_transaction_ = TransactionClosure::eTransType_None; // ref) eLOG_ITEM
// CHANGES: f110404.2L, this object has not release routine.
new (&durability_impl_) nsSlot::DurabilityImpl(this);
new (&item_move_impl_) nsSlot::ItemMoveImpl(this);
new (&trading_impl_) nsSlot::ItemTradingImpl(this);
new (&updater_impl_) nsSlot::ItemManagerUpdateImpl(this);
serial_check_table_.clear();
expiration_item_table_.clear();
saled_item_list_.clear();
saled_item_list_.resize(MAX_REPURCHASE_ITEM_NUM, RepurchaseSlot());
}
//==================================================================================================
//== basic check routines
//==================================================================================================
bool ItemManager::IsEmpty(SLOTIDX slot_index, POSTYPE pos_in_slots)
{
ASSERT(slot_index < SI_MAX && slot_index != SI_SKILL);
return slot_manager_->IsEmpty(slot_index, pos_in_slots);
}
SCItemSlotContainer* ItemManager::GetItemSlotContainer(const SLOTIDX slot_index) const
{
const ulong kAcceptablContainers = (1 << SI_INVENTORY)
| (1 << SI_EQUIPMENT)
| (1 << SI_WAREHOUSE)
| (1 << SI_GUILDWAREHOUSE);
if (bool in_range = (((1 << slot_index) & kAcceptablContainers) != 0)) {
SCItemSlotContainer* selected_container =
static_cast<SCItemSlotContainer*>(slot_manager_->GetSlotContainer(slot_index));
// 帮会仓库容器可能没有在列表中
return selected_container;
}
return NULL;
}
bool ItemManager::ValidPos(
const SLOTIDX slot_index, const POSTYPE pos_in_slots, const bool check_empty) const
{
const ulong kPreventContainers = (1 << SI_SKILL)
| (1 << SI_STYLE) // removed by _NA002217_100728_EP2_PERK_SYSTEM_
| (1 << SI_QUICK);
if (bool is_prevent = (((1 << slot_index) & kPreventContainers) != 0)) {
return false;
}
return slot_manager_->ValidPos(slot_index, pos_in_slots, check_empty);
}
bool ItemManager::ValidContainer(SLOTIDX slot_index)
{
return slot_manager_->ValidContainer(slot_index);
}
bool ItemManager::ValidState() const
{
return slot_manager_->ValidState();
}
bool ItemManager::IsRestrictFunction(eFUNCTIONALRESTRICT_TYPE type) const
{
switch (type)
{
case eFUNCTIONALRESTRICT_ENCHANT:
case eFUNCTIONALRESTRICT_RANKUP:
case eFUNCTIONALRESTRICT_ADDSOCKET:
case eFUNCTIONALRESTRICT_FILLSOCKET:
case eFUNCTIONALRESTRICT_EXTRACTSOCKET:
case eFUNCTIONALRESTRICT_COMPOSE:
case eFUNCTIONALRESTRICT_CRYSTALIZE:
case eFUNCTIONALRESTRICT_USE_EXTRASTONE:
case eFUNCTIONALRESTRICT_USE_WAREHOUSE:
//case eFUNCTIONALRESTRICT_USE_TRADE:
//case eFUNCTIONALRESTRICT_USE_VENDOR:
case eFUNCTIONALRESTRICT_REPAIR_ITEM:
case eFUNCTIONALRESTRICT_SELL_ITEM:
case eFUNCTIONALRESTRICT_BUY_ITEM:
case eFUNCTIONALRESTRICT_EXCHANGE_ITEM:
if (g_pGameServer->GetServerType() == BATTLE_SERVER)
{ // 是黑客玩家!!!!需要制剂措施!
return false;
}
break;
}
return g_FunctionalRestrictMgr.IsRestrictFunction(type);
}
void ItemManager::BindGuildWarehouseContainer(
CGuildWarehouseSlotContainer* guild_warehouse_container)
{
// TODO: waverix, added acceptable slotcontainer filter
slot_manager_->BindGuildWarehouseContainer(guild_warehouse_container);
}
void ItemManager::UnbindGuildWarehouseContainer()
{
// TODO: waverix, added acceptable slotcontainer filter
slot_manager_->UnbindGuildWarehouseContainer();
}
//==================================================================================================
//== 项更新例程的根。ItemManagerUpdateImpl中的实际处理工作
//==================================================================================================
void ItemManager::Update()
{
updater_impl_._UpdateExpirationItem();
updater_impl_._UpdateEtcItem();
#ifdef _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
updater_impl_.UpdateImmediatelyUseItem();
#endif // _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
}
//==================================================================================================
//==================================================================================================
//==================================================================================================
#ifdef _NA_002289_20110322_EQUIPMENTS_CALCULATOR_CHANGES_FOR_IMPROVEMENT
void ItemManager::UpdateItemAttributes(bool recalced_equip_items,
bool recalced_inven_option_items)
{
if (recalced_equip_items == false && recalced_inven_option_items == false) {
assert(!"check! unexpected command");
return;
};
ns_object::ChangedValuesNotifier notifier(player_);
if (recalced_equip_items)
{
CEquipmentSlotContainer* const equip_container =
static_cast<CEquipmentSlotContainer*>(GetItemSlotContainer(SI_EQUIPMENT));
equip_container->CheckupActiveEquipItemAll();
};
if (recalced_inven_option_items) {
CInventorySlotContainer* const inventory =
static_cast<CInventorySlotContainer*>(GetItemSlotContainer(SI_INVENTORY));
inventory->UpdateAttr();
};
}
// CHANGES: f110422.2L, 刷新CEquipmentSlotContainer::设备存在_
void ItemManager::RefreshEquipItemsCache()
{
CEquipmentSlotContainer* const equip_container =
static_cast<CEquipmentSlotContainer*>(GetItemSlotContainer(SI_EQUIPMENT));
equip_container->RefreshEquipItemsCache();
}
//==================================================================================================
#else //if !defined(_NA_002289_20110322_EQUIPMENTS_CALCULATOR_CHANGES_FOR_IMPROVEMENT)
//==================================================================================================
void ItemManager::UpdateAttrInventory() // 只对Inventory进行UpdateAtter
{
CInventorySlotContainer* const inventory =
static_cast<CInventorySlotContainer*>(GetItemSlotContainer(SI_INVENTORY));
inventory->UpdateAttr();
}
void ItemManager::UpdateAttrForEquipItem()
{
DWORD maxHP = player_->GetMaxHP();
DWORD maxMP = player_->GetMaxMP();
DWORD maxSD = player_->GetMaxSD();
CEquipmentSlotContainer* const equip_container =
static_cast<CEquipmentSlotContainer*>(GetItemSlotContainer(SI_EQUIPMENT));
equip_container->CheckupActiveEquipItemAll();
if (maxHP != player_->GetMaxHP()) {
player_->NotifyChangedStatus(PlayerStatEvent::eFlag_ChangedHP);
};
if (maxMP != player_->GetMaxMP()) {
player_->NotifyChangedStatus(PlayerStatEvent::eFlag_ChangedMP);
};
if (maxSD != player_->GetMaxSD()) {
player_->NotifyChangedStatus(PlayerStatEvent::eFlag_ChangedSD);
}
}
#endif //_NA_002289_20110322_EQUIPMENTS_CALCULATOR_CHANGES_FOR_IMPROVEMENT
//==================================================================================================
RC::eITEM_RESULT
ItemManager::DropMoney( MONEY Money )
{
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
if( Money > player_->GetMoney() )
{
return RC::RC_ITEM_HAVENOTMONEY;
}
WzVector wvCurPos = player_->GetRandomPosInAround(2);
if( !g_DropManager.DropMoneyToField( player_->GetField(), &wvCurPos, 0, 0, Money ) )
{
return RC::RC_ITEM_ERRORDROPMONEY;
}
// player_->SetMoney( player_->GetMoney() - Money );
player_->MinusMoney( Money ); // 用SetMoney花钱的部分全部换成MinusMoney()中
return RC::RC_ITEM_SUCCESS;
}
RC::eITEM_RESULT
ItemManager::Drop( SLOTIDX atIndex, POSTYPE atPos, DWORD dwOwnerKey )
{
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
if( !ValidPos( atIndex, atPos ) )
return RC::RC_ITEM_INVALIDPOS;
SCSlotContainer * pAtContainer = GetItemSlotContainer( atIndex );
SCItemSlot & rSlot = (SCItemSlot &)pAtContainer->GetSlot(atPos);
// (CHANGES) protect invalid item operation
// (NOTE) 首先只检查from.
const nsSlot::ItemRuleInfo& from_item_rule_info = rSlot.GetItemRuleInfo();
if(from_item_rule_info.is_valid_item == 0)
return RC::RC_ITEM_INVALIDPOS;
// 不可掉落?
if (rSlot.IsPossessionItem() && rSlot.GetIdentifyPossession() && (!rSlot.IsDestroyItem())) {
return RC::RC_ITEM_CANNOT_DROP_ITEM;
}
if (rSlot.CanTradeSell(eITEM_TRADESELL_DROP) == false) {
return RC::RC_ITEM_CANNOT_DROP_ITEM;
}
SCItemSlot DropItemSlotOut;
if( !pAtContainer->DeleteSlot( atPos, &DropItemSlotOut ) )
return RC::RC_ITEM_CANNNOT_DROPSTATE;
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
PlayerSpaInfo* spa_info = player_->GetPlayerSpaInfo();
spa_info->CheckAndResetSpaTicket(atPos);
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
WzVector wvCurPos = player_->GetRandomPosInAround(2);
if( !g_DropManager.DropItemToField( player_->GetField(), &wvCurPos, dwOwnerKey, 0, DropItemSlotOut, 0 ) )
{
pAtContainer->InsertSlot( atPos, DropItemSlotOut );
return RC::RC_ITEM_INVALIDPOSFORDROPITEM;
}
// 游戏日志
GAMELOG->LogItem( ITEM_DROP, player_, &DropItemSlotOut, 0, DropItemSlotOut.GetNum() );
return RC::RC_ITEM_SUCCESS;
}
RC::eITEM_RESULT
ItemManager::Pick( POSTYPE NumberOfItems, SCItemSlot & rItemSlot, INVENTORY_TOTAL_INFO * OUT pTotalInfo )
{
DURATYPE Num = rItemSlot.GetNum();
rItemSlot.SetNum(1);
RC::eITEM_RESULT rt = Obtain( rItemSlot, NumberOfItems*Num, pTotalInfo );
if( rt == RC::RC_ITEM_SUCCESS )
{
// 物品捡取日志
GAMELOG->LogItem( ITEM_PICK, player_, &rItemSlot, 0, NumberOfItems*Num );
#ifdef _NA_001990_ACSYSTEM_ADD
const BASE_ITEMINFO* const pInfo = rItemSlot.GetItemInfo();
if(pInfo->m_wACCode)
{
player_->GetACManager()->ProcessItemObtain(pInfo->m_Code, pInfo->m_wACCode,
pInfo->m_byACReferenceID, NumberOfItems*Num);
}
#endif
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
if (rItemSlot.GetSerial() == 0 &&
NotificationInfoParser::Instance()->IsNotificationItem(
rItemSlot, eNotificationDrop) == true)
{
MSG_DG_NOTIFICATION_ITEM_SYN msg;
msg.info.SetInfo(player_->GetCharName(),
(player_->GetGameZonePtr() != NULL) ? player_->GetGameZonePtr()->GetMapCode() : 0,
GetTickCount(), eNotificationDrop, rItemSlot.GetItemCode());
g_pGameServer->SendToSessionType(GAME_DBPROXY, &msg, sizeof(MSG_DG_NOTIFICATION_ITEM_SYN));
}
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
}
return rt;
}
//选择了GameField中的单品。
//将物品放入库存的空余空间或临时库存中。
//重叠的项目重叠处理,发送ACK。
//不重叠的项目不同步地从DBP那里获得麦片,发送ACK.
RC::eITEM_RESULT
ItemManager::Pick( DWORD dwItemObjectKey, INVENTORY_TOTAL_INFO * OUT pTotalInfo )
{
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
if( !ValidContainer(SI_INVENTORY) )
return RC::RC_ITEM_INVALIDSTATE;
GameField *pField = player_->GetField();
if( !pField || !pField->IsReady() )
return RC::RC_ITEM_INVALIDSTATE;
// CHANGES: f100503.3L, 更改接口用法
// f110415.6L, 使用方法查找简单的更改。邻里关系的内在过程
// 对每个项目都有一个对象搜索算法.
Item* pItem = NULL;
;{
Object* object = pField->FindObject(ITEM_OBJECT, dwItemObjectKey);
if (object && object->IsEqualObjectKind(ITEM_OBJECT) &&
object->IsDeleteReserved() == false)
{
pItem = static_cast<Item*>(object);
}
};
#if SUN_CODE_BACKUP
Item* pItem = pField->SearchNeighborItem(player_->GetSectorIndex(), dwItemObjectKey);
#endif
if( !pItem)
{
return RC::RC_ITEM_NOTEXISTITEMATFIELD;
}
// 确认是否可以提供该物品
RC::eITEM_RESULT rt = CanPick( pItem );
if( rt != RC::RC_ITEM_SUCCESS )
{
return rt;
}
SCItemSlot ItemSlot = pItem->GetItemSlot();
DURATYPE num = 1;
//#ifdef _DEBUG
// 测试用
// switch( rItemSlot.GetItemInfo()->m_ChargeSubType )
// {
// case eCHARGE_SUB_FIXED_AMOUNT:
// case eCHARGE_SUB_FIXED_AMOUNT_EX:
// case eCHARGE_SUB_FIXED_QUANTITY:
// {
// // 30盒利侩
// rItemSlot.SetDateTime( 30*60 );
// }break;
// }
//#endif
rt = Pick( num, ItemSlot, pTotalInfo );
if( rt == RC::RC_ITEM_SUCCESS )
{
// 初次获得怪物的道具时,也会分配给周边队员.
if( pItem->GetFromMonsterKey() != 0 )
{
g_ItemExpDistributor.DistributeItem( pItem, player_ );
}
pField->DestroyObject( pItem );
}
return rt;
}
#ifdef _NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
//可以代替队员的道具
RC::eITEM_RESULT
ItemManager::PickParty( DWORD dwItemObjectKey, const SERVER_COMMON_OPTION& ServerOption )
{
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
if( !ValidContainer(SI_INVENTORY) )
return RC::RC_ITEM_INVALIDSTATE;
GameField *pField = player_->GetField();
if( !pField || !pField->IsReady() )
return RC::RC_ITEM_INVALIDSTATE;
// CHANGES: f100503.3L, 更改接口用法
// f110415.6L, 使用方法查找简单的更改。邻里关系的内在过程
// 对每个项目都有一个对象搜索算法.
Item* pItem = NULL;
;{
Object* object = pField->FindObject(ITEM_OBJECT, dwItemObjectKey);
if (object && object->IsEqualObjectKind(ITEM_OBJECT) &&
object->IsDeleteReserved() == false)
{
pItem = static_cast<Item*>(object);
}
};
if( !pItem)
{
return RC::RC_ITEM_NOTEXISTITEMATFIELD;
}
// 确认是否可以提供该物品
RC::eITEM_RESULT rt = CanPick( pItem );
if( rt != RC::RC_ITEM_SUCCESS )
{
return rt;
}
//
Player* item_owner = player_;
#ifdef _NA_003033_20110831_DICECAST_ITEM_ROUTING
;{
NewGamePartyManager* party_manager = NewGamePartyManager::Instance();
DWORD item_owner_key = pItem->GetOwnerPlayerKey();
if (pItem->IsEqualObjectKind(ITEM_OBJECT))
{
// 物品的所有权在队员处时
WORD party_key = player_->GetPartyState().GetPartyKey();
if(Player* party_member = party_manager->FindMemberPlayer(party_key, item_owner_key))
{
eITEM_DISTRIBUTION_TYPE party_type = \
static_cast<eITEM_DISTRIBUTION_TYPE>(party_manager->GetDistributionType(party_key));
if( party_type != eITEM_DISTRIBUTION_DEFAULT &&
party_type != eITEM_DISTRIBUTION_DICE_AND_DEFAULT )
{
item_owner = party_member; // 可以代替队员的道具进行路由.
}
//
if( pItem->GetItemSlot().GetDiceCastType() )
{
MSG_CG_PARTY_DICECAST_RESULT_CMD msg;
{
msg.item_object_key = 0;
msg.winner_key = 0;
memset(msg.result, 0, sizeof(msg.result));
};
DWORD winner_key = party_manager->GetDiceCastDistributionMember(player_, party_key, msg.result);
Player* winner_player = party_manager->FindMemberPlayer(party_key, winner_key);
if(winner_player)
{
// 告知骰子结果
msg.item_object_key = pItem->GetObjectKey();
msg.item_code = pItem->GetItemSlot().GetItemInfo()->m_Code;
msg.winner_key = winner_key;
party_manager->SendPacketAllMember(party_key, &msg, sizeof(msg));
// 掷骰子一次的道具转换为普通道具.
pItem->GetItemSlot().SetDiceCastType(FALSE);
// 物品的所有权由骰子结果第一的玩家持有.
pItem->SetOwnerPlayerKey(winner_key);
item_owner = winner_player;
}
}
}
}
};
#else
if (pItem->IsEqualObjectKind(ITEM_OBJECT) && (player_->GetObjectKey() != pItem->GetOwnerPlayerKey()))
{
WORD PartyKey = player_->GetPartyState().GetPartyKey();
if( PartyKey )
{
if(NewGamePartyManager::Instance()->GetDistributionType(PartyKey) != eITEM_DISTRIBUTION_DEFAULT)
{
Player *pMember = NewGamePartyManager::Instance()->FindMemberPlayer( PartyKey, pItem->GetOwnerPlayerKey() );
if( pMember )
{
item_owner = pMember; // 可以代替队员的道具进行调整。arycoat 2011.6.28#2946道具获得方式变更
}
}
}
}
#endif //_NA_003033_20110831_DICECAST_ITEM_ROUTING
MSG_CG_ITEM_PICK_ACK msgACK;
// NOTE: f110715.1L, 复制是因为“Pick”操作有SCItemSlot修改的副作用
SCItemSlot ItemSlot = pItem->GetItemSlot();
DURATYPE num = 1;
if(item_owner == player_) {
rt = Pick(num, ItemSlot, &msgACK.m_ItemInfo);
}
else {
if( item_owner->IsDead() )
return RC::RC_ITEM_DEAD_OWNER;
GameField* pOwnerField = item_owner->GetField();
GameField* pMemberField = player_->GetField();
if ((pOwnerField == NULL) || (pMemberField == NULL) || (pOwnerField != pMemberField)) {
return RC::RC_ITEM_DEAD_OWNER;
};
//
rt = item_owner->GetItemManager()->Pick(num, ItemSlot, &msgACK.m_ItemInfo);
}
if( rt == RC::RC_ITEM_SUCCESS )
{
// 初次获得怪物的道具时,也会分配给周边队员.
if( pItem->GetFromMonsterKey() != 0 )
{
g_ItemExpDistributor.DistributeItem( pItem, item_owner );
}
pField->DestroyObject( pItem );
//
item_owner->SendPacket(&msgACK, msgACK.GetSize());
const sPOLICY_CHARACTER& rPolicyment = item_owner->Policyment;
const BOOLEAN isBrdApply = !(rPolicyment.FIELD & rPolicyment.PCC_IN_SSQ_FIELD_PLAYER);
if(isBrdApply) {
// 物品习得告知周围.
MSG_CG_ITEM_PICK_BRD msgBRD;
msgBRD.m_dwObjKey = item_owner->GetObjectKey();
msgBRD.m_ItemCode = msgACK.m_ItemInfo.m_Slot[0].m_Stream.Part.wCode;
if(ServerOption.m_bItemPickUpMsgBrd != 0) {
item_owner->SendPacketAround(&msgBRD, sizeof(msgBRD), FALSE);
}
if(ServerOption.m_bItemPickUpPartyMsgBrd != 0) {
WORD party_key = item_owner->GetPartyState().GetPartyKey();
if(party_key != 0) {
NewGamePartyManager* pPartyManager = NewGamePartyManager::Instance();
pPartyManager->SendPacketAllMember(party_key, &msgBRD, sizeof(msgBRD));
}
}
}
}
return rt;
}
#endif //_NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
RC::eITEM_RESULT
ItemManager::CanPick( Item *pItem )
{
if(pItem->IsDeleteReserved())
return RC::RC_ITEM_NOTEXISTITEMATFIELD;
if( player_->GetGMStateInfo().m_TransOn )
return RC::RC_ITEM_CANNOT_PICKUP_OBSERVER;
// 当前客户端为7m
// 玩家和Item的距离远就捡不到.
WzVector posOfItem;
WzVector posOfPlayer;
pItem->GetPos( &posOfItem );
player_->GetPos( &posOfPlayer );
float fItemLen = Math_Vector3DLength( posOfPlayer, posOfItem );
if( DISTANCE_SPACE_GET_ITEM < fItemLen )
{
return RC::RC_ITEM_CANT_PICKABLE_BY_LENGTH;
}
// 确认所有权.
if( pItem->GetOwnerPlayerKey() )
{
WORD PartyKey = player_->GetPartyState().GetPartyKey();
if( PartyKey )
{
Player *pMember = NewGamePartyManager::Instance()->FindMemberPlayer( PartyKey, pItem->GetOwnerPlayerKey() );
// 检查物品的所有权者是否是同一队伍的原因
if( !pMember )
{
return RC::RC_ITEM_DONOT_HAVE_OWNERSHIP;
}
#ifdef _NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
BOOL bPartyMemberCanPickItem = FALSE;
if(pItem->IsEqualObjectKind(ITEM_OBJECT))
{
// 可以代替队员的道具进行调整。arycoat 2011.6.28#2946道具获得方式变更
bPartyMemberCanPickItem = TRUE;
#if SUN_CODE_BACKUP
const BASE_ITEMINFO* ItemInfo = pItem->GetItemSlot().GetItemInfo();
if(ItemInfo)
{
const eITEMTYPE type = static_cast<eITEMTYPE>(ItemInfo->m_wType);
if (type == eITEMTYPE_QUEST ||
type == eITEMTYPE_AC ||
type == eITEMTYPE_EVENT_FIELD_PARTY_ALL_MEMBER_PICK_UP)
{
bPartyMemberCanPickItem = TRUE;
}
}
#endif //SUN_CODE_BACKUP
}
#endif //_NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
// changed rule by _NA_0_20101206_PARTY_ITEM_DISTRIBUTE_CHANGE
//--------------------------------------------------------------------------------------
// CHANGES: f110413.2L, 解决版本控制问题
// 因为包含下面代码块的嵌套宏是模糊的.
// 海姆可由所有队员获得. - arycoat 2011.03.24
const bool result_of_money_distribute_method = !pItem->IsEqualObjectKind(MONEY_OBJECT);
#ifdef _NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
const bool result_of_item_routing_method = (bPartyMemberCanPickItem == false);
#else
const bool result_of_item_routing_method = true;
#endif
if ((result_of_money_distribute_method) &&
(result_of_item_routing_method) &&
(NewGamePartyManager::Instance()->GetDistributionType(PartyKey) !=
eITEM_DISTRIBUTION_DEFAULT))
{
if (player_->GetObjectKey() != pItem->GetOwnerPlayerKey()) {
return RC::RC_ITEM_DONOT_HAVE_OWNERSHIP;
}
}
//--------------------------------------------------------------------------------------
}
else // if PartyKey is zero...
{
if( player_->GetObjectKey() != pItem->GetOwnerPlayerKey() )
{
return RC::RC_ITEM_DONOT_HAVE_OWNERSHIP;
}
}
}
//道具不存在捡的几率。
//如果有分开的单品,只能捡不捡.
if( pItem->GetFromMonsterKey() != 0 )
{
BOOL bItemPicUp = player_->GetFatigueManager()->GetItemPickUp();
if( bItemPicUp == 0 )
return RC::RC_ITEM_OVER_PLAYING_TIME;
}
return RC::RC_ITEM_SUCCESS;
}
RC::eITEM_RESULT ItemManager::Combine(const SLOTIDX from_slot_type,
const POSTYPE from_slot_position,
const SLOTIDX to_slot_type,
const POSTYPE to_slot_position,
DURATYPE& INOUT combine_quantity)
{
if (IsRestrictFunction(eFUNCTIONALRESTRICT_COMBINE_ITEM))
{
return RC::RC_ITEM_UNUSABLE_FUNCTION;
}
if (!ValidState())
{
return RC::RC_ITEM_INVALIDSTATE;
}
if (!ValidPos(from_slot_type, from_slot_position))
{
return RC::RC_ITEM_INVALIDPOS;
}
if (!ValidPos(to_slot_type, to_slot_position))
{
return RC::RC_ITEM_INVALIDPOS;
}
// 非库存不可combine.
// 仓库尽可能的。...
if ((from_slot_type != SI_INVENTORY && from_slot_type != SI_WAREHOUSE) ||
(to_slot_type != SI_INVENTORY && to_slot_type != SI_WAREHOUSE))
{
return RC::RC_ITEM_INVALIDSTATE;
}
// 各种例外处理
if (from_slot_type == to_slot_type && from_slot_position == to_slot_position)
{
return RC::RC_ITEM_INVALIDPOS;
}
SCSlotContainer* const from_item_slot_container = GetItemSlotContainer(from_slot_type);
SCSlotContainer* const to_item_slot_container = GetItemSlotContainer(to_slot_type);
SCItemSlot& from_item_slot =
static_cast<SCItemSlot&>(from_item_slot_container->GetSlot(from_slot_position));
SCItemSlot& to_item_slot =
static_cast<SCItemSlot&>(to_item_slot_container->GetSlot(to_slot_position));
if (from_item_slot.GetItemCode() != to_item_slot.GetItemCode())
{
return RC::RC_ITEM_ITEMCODENOTEQUAL;
}
if (from_item_slot.GetMaxNum() <= 1) // || (from_item_slot.GetItemInfo() && from_item_slot.GetItemInfo()->m_wType != eITEMTYPE_WASTE ) )
{
return RC::RC_ITEM_ITEMCODENOTEQUAL;
}
// NOTE: f100909.1L, 另一个项目\
//即使已标记项的项代码等于未标记项的项代码.
if (from_item_slot.GetOptionTag().value != to_item_slot.GetOptionTag().value) {
return RC::RC_ITEM_ITEMCODENOTEQUAL;
};
const WORD number_of_max_combine = from_item_slot.GetMaxNum();
if (number_of_max_combine > 0x270F)//物品叠加最大值 9999 by:十里坡剑神 2021-06-04
{
return RC::RC_ITEM_INVALIDSTATE;
}
// 检查请求的数量是否实际存在.
if (combine_quantity > from_item_slot.GetNum())
{
SUNLOG(eCRITICAL_LOG,
_T("|%s |要移动的数量比实际存在的数量多。|出发槽=%d,出发槽数量=%d,移动个数=%d,角色名称=%s |"),
__FUNCTION__,
from_slot_position,
from_item_slot.GetNum(),
combine_quantity,
player_->GetCharName());
return RC::RC_ITEM_INVALIDSTATE;
}
const bool is_divide_combine = (combine_quantity > 0 && combine_quantity != from_item_slot.GetNum());
const WORD number_of_combine =
(is_divide_combine ? combine_quantity : from_item_slot.GetNum()) + to_item_slot.GetNum();
// 如果把物品分割后合并的话
if (is_divide_combine)
{
DURATYPE new_combine_quantity = combine_quantity;
// 合七个数超过最大重叠个数的话。
if (number_of_combine > number_of_max_combine)
{
// 最多叠加个数.
new_combine_quantity = number_of_max_combine - to_item_slot.GetNum();
}
// 记录日志.
GAMELOG->LogItemEx(ITEM_COMBINE,
player_,
to_item_slot,
from_item_slot,
0,
new_combine_quantity);
// 更新个数.
from_item_slot_container->UpdateSlot(from_slot_position, -new_combine_quantity);
to_item_slot_container->UpdateSlot(to_slot_position, new_combine_quantity);
// 设置变更的个数.
combine_quantity = to_item_slot.GetNum();
}
// 如果不是分割的话,就用和以前一样的方式合并.
else
{
if (number_of_combine > number_of_max_combine)
{
GAMELOG->LogItemEx(ITEM_COMBINE,
player_,
to_item_slot,
from_item_slot,
0,
static_cast<BYTE>(number_of_max_combine));
// to from 俺荐 函版茄促.
from_item_slot_container->UpdateSlot(from_slot_position, number_of_combine - number_of_max_combine - from_item_slot.GetNum());
// to slot 俺荐 函版茄促.
to_item_slot_container->UpdateSlot(to_slot_position, number_of_max_combine - to_item_slot.GetNum());
}
else
{
GAMELOG->LogItemEx(ITEM_COMBINE,
player_,
to_item_slot,
from_item_slot,
0,
static_cast<BYTE>(number_of_combine));
// from slot 瘤款促.
from_item_slot_container->DeleteSlot(from_slot_position, NULL);
// to slot 俺荐 函版茄促.
to_item_slot_container->UpdateSlot(to_slot_position, number_of_combine - to_item_slot.GetNum());
}
}
return RC::RC_ITEM_SUCCESS;
}
RC::eITEM_RESULT
ItemManager::Divide( POSTYPE fromPos, POSTYPE toPos, DURATYPE fromNum, DURATYPE toNum )
{
if( IsRestrictFunction( eFUNCTIONALRESTRICT_DIVIDE_ITEM ) )
return RC::RC_ITEM_UNUSABLE_FUNCTION;
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
if( !ValidPos( SI_INVENTORY, fromPos ) )
return RC::RC_ITEM_INVALIDPOS;
if( !ValidPos( SI_INVENTORY, toPos, FALSE ) )
return RC::RC_ITEM_INVALIDPOS;
if( fromPos == toPos )
return RC::RC_ITEM_INVALIDPOS;
SCSlotContainer * pAtContainer = GetItemSlotContainer( SI_INVENTORY );
if( !pAtContainer->IsEmpty(toPos) )
return RC::RC_ITEM_INVALIDPOS;
SCItemSlot & rFromSlot = static_cast<SCItemSlot &>(pAtContainer->GetSlot( fromPos ));
if( fromNum == 0 || toNum == 0 ||
rFromSlot.GetNum() != (fromNum+toNum) )
return RC::RC_ITEM_INVALID_VALUE;
pAtContainer->UpdateSlot( rFromSlot.GetPos(), -toNum );
// toPos俊绰 矫府倔 惯鞭 贸府 -----------------------
SCItemSlot slot;
slot.Copy(rFromSlot);
slot.SetNum(toNum);
slot.SetSerial(TEMP_DBSERIAL_VALUE);
pAtContainer->InsertSlot( toPos, slot );
//pAtContainer->SetLock( toPos, TRUE );
//MSG_DG_ITEM_SERIAL_SYN msg;
//msg.m_dwKey = player_->GetUserKey();
//msg.m_SlotIdx = SI_INVENTORY;
//msg.m_ItemPos = toPos;
//player_->SendToGameDBPServer( &msg, sizeof(msg) );
//// --------------------------------------------------
GAMELOG->LogItemEx( ITEM_DIVIDE, player_, rFromSlot, slot, 0, fromNum );
return RC::RC_ITEM_SUCCESS;
}
RC::eITEM_RESULT
ItemManager::Delete( POSTYPE atPos )
{
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
if( !ValidPos( SI_INVENTORY, atPos ) )
return RC::RC_ITEM_INVALIDPOS;
SCSlotContainer * pAtContainer = GetItemSlotContainer( SI_INVENTORY );
SCItemSlot & rItemSlot = (SCItemSlot &)pAtContainer->GetSlot( atPos );
// BASE_ITEMINFO * pInfo = rItemSlot.GetItemInfo();
// (CHANGES) change to more generic code 'IsPetLocked' & 'IsRiderLocked' ...
if(rItemSlot.IsUserBlocked())
return RC::RC_ITEM_CANNOT_DESTROY_ITEM;
if( rItemSlot.GetLaxLock()->IsLock() )
return RC::RC_ITEM_CANNOT_DESTROY_ITEM;
// 昏力啊瓷牢 酒捞袍父 昏力且 荐 乐促.
if (rItemSlot.CanTradeSell(eITEM_TRADESELL_DELETE) == false) {
return RC::RC_ITEM_CANNOT_DESTROY_ITEM;
}
// 酒捞袍 昏力 肺弊
GAMELOG->LogItem( ITEM_DELETE, player_, &rItemSlot, 0, rItemSlot.GetNum() );
pAtContainer->DeleteSlot( atPos, NULL );
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
PlayerSpaInfo* spa_info = player_->GetPlayerSpaInfo();
spa_info->CheckAndResetSpaTicket(atPos);
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
return RC::RC_ITEM_SUCCESS;
}
RC::eITEM_RESULT // ref) eLOG_ITEM
ItemManager::Delete( SLOTIDX fromIndex, POSTYPE atPos, POSTYPE num, int iLogType )
{
// 捞霖籍 : 东户内靛 荐沥 官恩!!!
if( !player_ )
return RC::RC_ITEM_INVALIDSTATE;
// (BUGFIX) (091202) (WOPS:5334) 牢亥泪陛 惑怕俊辑 酒捞袍 力芭 啊瓷茄 漂荐 贸府(PK靛而)
TransactionClosure transaction(this, TransactionClosure::eTransType_PKDrop);
// (CHANGES) (091209) (WAVERIX) 昏力 啊瓷 浇吩捞 公搬己捞 焊厘登瘤 臼绰促, all version supported
#if WAVERIX_CODE_RENEWAL
if(ValidPos(fromIndex, atPos, true) == false)
return RC::RC_ITEM_INVALIDPOS;
SCSlotContainer* pAtContainer = GetItemSlotContainer(fromIndex);
const SCItemSlot& rItemSlot = static_cast<SCItemSlot&>(pAtContainer->GetSlot(atPos));
if(rItemSlot.IsContainValidItem() == false)
return RC::RC_ITEM_INVALIDPOS;
const BASE_ITEMINFO* pItemInfo = rItemSlot.GetItemInfo(); // available instance in this function
// 昏力啊瓷牢 酒捞袍父 昏力且 荐 乐促.
if (rItemSlot.CanTradeSell(eITEM_TRADESELL_DELETE) == false) {
return RC::RC_ITEM_CANNOT_DESTROY_ITEM;
}
// 俺荐父怒 乐绰瘤 眉农
DURATYPE duplicated_num = rItemSlot.GetNum();
if(duplicated_num < num) {
return RC::RC_ITEM_CANNOT_DELETE_FOR_SHORT_COUNT;
}
else if(duplicated_num == num) {
// (BUGFIX) (WAVERIX) 酒捞袍 昏力 贸府矫 秦寸 浇吩篮 檬扁拳 等促.
// 肋给等 沥焊甫 扁废窍绰 巩力 荐沥窍扁 困秦 鉴辑 焊沥
GAMELOG->LogItem(iLogType, player_, &rItemSlot, 0, num);
pAtContainer->DeleteSlot(atPos, NULL);
}
else {//duplicated_num > num
pAtContainer->UpdateSlot(atPos, -num);
GAMELOG->LogItem(iLogType, player_, &rItemSlot, 0, num);
}
return RC::RC_ITEM_SUCCESS;
#else //---------------------------------------------------------------------------
if( !ValidPos( fromIndex, atPos ) )
return RC::RC_ITEM_INVALIDPOS;
SCSlotContainer * pAtContainer = GetItemSlotContainer( fromIndex );
SCItemSlot & rItemSlot = (SCItemSlot &)pAtContainer->GetSlot( atPos );
// 昏力啊瓷牢 酒捞袍父 昏力且 荐 乐促.
if( rItemSlot.GetItemInfo()->m_wTradeSellType & eITEM_TRADESELL_DELETE )
return RC::RC_ITEM_CANNOT_DESTROY_ITEM;
// 俺荐父怒 乐绰瘤 眉农
if( rItemSlot.GetNum() < num )
return RC::RC_ITEM_CANNOT_DELETE_FOR_SHORT_COUNT;
else if( rItemSlot.GetNum() == num )
pAtContainer->DeleteSlot(atPos, NULL);
else
{
pAtContainer->UpdateSlot( rItemSlot.GetPos(), -num );
}
// 酒捞袍 昏力 肺弊
GAMELOG->LogItem( iLogType, player_, &rItemSlot, 0, num );
return RC::RC_ITEM_SUCCESS;
#endif //!WAVERIX_CODE_RENEWAL
}
// 捞巴篮 泅犁 荤侩窍瘤 臼绰 窃荐 (菊栏肺绰?)
RC::eITEM_RESULT
ItemManager::Lose( SLOTCODE ItemCode, BOOL bAllOfItem )
{
if( !ValidState() )
return RC::RC_ITEM_INVALIDSTATE;
SCSlotContainer * pInventory = GetItemSlotContainer( SI_INVENTORY );
for(POSTYPE i = 0 ; i < pInventory->GetMaxSlotNum() ; ++i )
{
if( pInventory->IsEmpty(i) ) continue;
const SCItemSlot & rSlot = static_cast<SCItemSlot&>(pInventory->GetSlot(i));
if( rSlot.GetItemCode() != ItemCode ) continue;
pInventory->DeleteSlot(i, NULL);
// 菩哦 焊晨 < 函版登菌栏骨肺 老窜 林籍贸府
//MSG_CG_ITEM_LOSE_ACK msg;
//msg.m_ItemPos = i;
//player_->SendPacket( &msg, sizeof(msg) );
if( bAllOfItem ) return RC::RC_ITEM_SUCCESS;
}
return RC::RC_ITEM_SUCCESS;
}
// 荤侩惑 林狼痢!!!
// 馆靛矫 己傍窍绰 牢磊蔼父阑 持绢具 茄促.
// 溜, 蜡瓤己 眉农甫 茄 牢磊父 持绢具 茄促.
VOID
ItemManager::Lose( SCSlotContainer * pContainer, POSTYPE pos, int num )
{
SCItemSlot & rSlotItem = (SCItemSlot &)pContainer->GetSlot(pos);
if( rSlotItem.GetNum() > num )
{
pContainer->UpdateSlot( rSlotItem.GetPos(), -num );
}
else
{
BOOL rt = pContainer->DeleteSlot( rSlotItem.GetPos(), NULL );
ASSERT( rt && "泅犁 浇吩 牧抛捞呈俊辑 昏力且 荐 绝绰 酒捞袍涝聪促.\n" );
}
}
//==================================================================================================
//==================================================================================================
//==================================================================================================
VOID
ItemManager::SendSetItemBrd( BOOL bFullOption )
{
if( !player_ ) return;
MSG_CG_ITEM_SETITEM_CHANGE_BRD Brd;
Brd.m_PlayerKey = (PLAYERKEY)player_->GetObjectKey();
Brd.m_bFull = bFullOption;
player_->SendPacketAround( &Brd, sizeof(Brd), FALSE );
}
RC::eBATTLE_GROUND_RESULT ItemManager::GetPlayerItemScore(DWORD* OUT item_score)
{
CEquipmentSlotContainer* const equip_container =
static_cast<CEquipmentSlotContainer* const>(GetItemSlotContainer(SI_EQUIPMENT));
if (equip_container == NULL) {
return RC::RC_BATTLE_GROUND_RESERVATION_FAIL;
}
const ns_formula::EquipSlotsManageInfo* const equip_manage_info = \
equip_container->GetEquipmentManageInfo();
if (equip_manage_info == NULL)
{
return RC::RC_BATTLE_GROUND_RESERVATION_FAIL;
}
const ns_formula::EquipSlotsManageInfo::ItemScoreInfo& item_score_info = \
equip_manage_info->item_score_info;
*item_score = item_score_info.GetTotalScore();
return RC::RC_BATTLE_GROUND_RESERVATION_SUCCESS;
}
//==================================================================================================
//==================================================================================================
//==================================================================================================