Files
2026-06-01 12:46:52 +02:00

2105 lines
58 KiB
C++

#include "stdafx.h"
#include "SInventoryMgr.h"
//#include <string>
//#include <vector>
#include "SGame.h"
#include "SChatType.h"
#include "SGameMessage.h"
//#include "SGameMessageUI.h"
#include "SkillBaseFile.h"
#include "SItemDB.h"
#include "SStringDB.h"
#include "SUIDefine.h"
#include "SGameInput.h"
#include "SSummonSlotMgr.h"
#include "SUISysMsgDefine.h"
#include "SDebug_Util.h"
#include <toolkit/XStringUtil.h>
#include "SUIUtil.h"
// AziaMafia ++
#include "SCommandSystem.h"
#include "SGameSystem.h"
extern SGameSystem* g_pCurrentGameSystem;
//IsInstanceUnstackable : 중복불가능한가? ( 비정적데이터를 이용하여 )
bool IsInstanceUnstackable( SInventorySlot* pSlot )
{
static SInventoryMgr* pInvenMgr = NULL;
if( pInvenMgr == NULL )
pInvenMgr = static_cast<SInventoryMgr*>(GameUIMgrInstance.GetUIMgr( SGameUIInstance::INVENTORY_MGR ));
return pSlot->GetXFlag().IsOn( ItemInstance::ITEM_FLAG_SUMMON ) || ( pInvenMgr && pInvenMgr->IsEquipCard( pSlot->GetHandle() ) );
}
bool IsInstanceUnstackable( const XFlag<int>& rFlag )
{
return rFlag.IsOn( ItemInstance::ITEM_FLAG_SUMMON );
}
bool IsInstanceUnstackable( const int nFlag )
{
XFlag<int> xFlag;
xFlag.CopyFrom( &nFlag);
return IsInstanceUnstackable( xFlag );
}
const char* GetMaterialSound( int nMaterial )
{
switch( nMaterial )
{
case 0: return "ui_wear_skin01.wav"; break;//피부
case 1: return "ui_wear_leather01.wav"; break;//가죽
case 2: return "ui_wear_wood01.wav"; break;//나무
case 3: return "ui_wear_steel01.wav"; break;//금속
case 4: return "ui_wear_feather01.wav"; break;//깃털
case 5: return "ui_wear_stone01.wav"; break;//돌
case 6: return "ui_wear_bone01.wav"; break;//뼈
case 7: return "ui_wear_acc01.wav"; break;//악세서리
case 8: return "ui_wear_cube01.wav"; break;//큐브
case 9: return "ui_wear_paper01.wav"; break;//종이
case 10: return "ui_wear_shackle01.wav"; break;//쇠사슬
case 11: return "ui_wear_water01.wav"; break;//물
case 12: return "ui_wear_cloth01.wav"; break;//옷감류
case 13: return "ui_wear_powder01.wav"; break;//가루류
default : return "ui_icon_drag.wav";
// case 99: //기타
}
return "ui_icon_drag.wav";
}
//////////////////////////////////////////////////////////////////////////
// shop slot
SShopSlot::SShopSlot()
{
m_nItemCode = 0;
m_nIconID = 0;
m_nPrice = money_t( 0 );
m_nHuntaHolicPoint = money_t( 0 ); // #2.1.2.11.1
m_hNpc = NULL;
}
SShopSlot::~SShopSlot()
{
}
void SShopSlot::SetItemCode( int nItemCode )
{
m_nItemCode = nItemCode;
m_nIconID = GetItemDB().GetIconID(nItemCode);
}
//////////////////////////////////////////////////////////////////////////
//Invetory Slot
SInventorySlot::SInventorySlot()
: m_bIsAppendedDecomposeWnd( false )
{
m_nGetItemCount = count_t( 0 );
m_bIsExistence = false;
m_nIconID = 0;
::memset( &m_ItemInfo, 0, sizeof(m_ItemInfo) );
m_nLastDurabilityCheckPercent = 0;
m_nLastDurabilityValue = 0;
m_bShowDecoration = true; // 꾸미기아이템 보임.
}
SInventorySlot::~SInventorySlot()
{
}
void SInventorySlot::SetItem( TS_ITEM_INFO* pItemInfo )
{
::memcpy( &m_ItemInfo, pItemInfo, sizeof(m_ItemInfo) );
}
// { [sonador][3.1.2] 경매장 구현
const unsigned int SInventorySlot::GetMaxEndurance( TS_ITEM_BASE_INFO* item )
{
const ItemBaseEx_info* pItemBaseInfo( GetItemDB().GetItemData( item->Code ) );
if( NULL == pItemBaseInfo )
return NULL;
if( NULL == item->socket )
return NULL;
int nJewelID( NULL );
unsigned int dwMaxEndurance( NULL );
const ItemBaseEx_info* pJewelInfo( NULL );
const int nJewelSlotCount( pItemBaseInfo->socket + item->random_option.GetAddJewelSocketCount() );
for( int i( 0 ); i < nJewelSlotCount; ++i )
{
nJewelID = item->socket[i];
if( nJewelID )
{
pJewelInfo = GetItemDB().GetItemData( nJewelID );
if( pJewelInfo )
dwMaxEndurance += pJewelInfo->nEndurance;
}
}
return dwMaxEndurance;
}
const int SInventorySlot::GetCrrEndurancePer( TS_ITEM_BASE_INFO* item, unsigned int& rEndurance )
{
const ItemBaseEx_info* pItemBaseInfo( GetItemDB( ).GetItemData( item->Code ) );
if( NULL == pItemBaseInfo )
return SInventorySlot::NONEITEM;
if( NULL == item->socket )
return SInventorySlot::SOKETNULL;
int nJewelID( 0 );
unsigned int dwMaxEndurance( GetMaxEndurance( item ) );
if( dwMaxEndurance )
{
unsigned int dwEndurance = ( item->endurance + 99999 ) / 100000;
dwMaxEndurance = dwMaxEndurance / 100000;
if( dwMaxEndurance == 0 )
rEndurance = 0;
else
rEndurance = dwEndurance * 100 / dwMaxEndurance;
if( rEndurance == 0 && dwEndurance != 0 )
rEndurance = 1;
return SInventorySlot::ENDURANCE_SUCCESS;
}
return SInventorySlot::NONESOKET;
}
const unsigned int SInventorySlot::GetMaxEndurance()
{
return GetMaxEndurance( &m_ItemInfo );
}
const int SInventorySlot::GetCrrEndurancePer( unsigned int& rEndurance )
{
return GetCrrEndurancePer( &m_ItemInfo, rEndurance );
}
// 2010.07.14 - prodongi
int SInventorySlot::getMaxEtherealDurability() const
{
float pEnhanceDurability[30] =
{
1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f,
2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f, 10.f, 10.f, 10.f, 10.f
};
ItemBaseEx_info const* itemBaseInfo = GetItemDB( ).GetItemData(m_ItemInfo.Code);
if (!itemBaseInfo)
return 0;
if (itemBaseInfo->nType == ItemBase::TYPE_ARMOR && GetEnhance() > 0 && GetEnhance() <= 29)
return itemBaseInfo->nEthereal_durability * pEnhanceDurability[ GetEnhance() - 1 ];
return itemBaseInfo->nEthereal_durability;
}
// 2010.07.14 - prodongi
bool SInventorySlot::isExhausted() const
{
if (isExhaustedSummonCard(m_ItemInfo.Code, GetEnhance(), GetEtherealDurability()))
return true;
return ((0 < getMaxEtherealDurability()) && (0 == GetEtherealDurability()));
}
bool SInventorySlot::IsAwakeningItem()
{
for ( int i = 0; i < ItemBase::MAX_AWAKENING_OPTION; i++ )
{
if ( m_ItemInfo.awakenoption.nData[i] != 0 )
return true;
}
return false;
}
void SInventorySlot::SetUpdateCount( count_t nNewCount, bool bDestroy /*= false*/ )
{
if( !bDestroy )
m_nGetItemCount = GetItemCount() > 0 ? (nNewCount - GetItemCount()) : nNewCount;
else
m_nGetItemCount = nNewCount;
}
//-----------------------------------------------------------------------------------------------------------------
// 보석 장착 슬롯 개수 얻기
// 설명 : 기본 ItemResourceDB에 설정된 슬롯 개수 + 랜덤 옵션으로 생성 된 슬롯 개수
//-----------------------------------------------------------------------------------------------------------------
const int SInventorySlot::GetJewelSlotCount()
{
int nJewelSlotCount( NULL );
int nte = m_ItemInfo.Code;
const ItemBaseEx_info* pItemBaseInfo( GetItemDB().GetItemData( GetItemCode() ) );
if( NULL == pItemBaseInfo )
return nJewelSlotCount;
nJewelSlotCount += pItemBaseInfo->socket;
TS_ITEM_BASE_INFO::RANDOM_OPTION* const pRandomOption( GetRandomOption() );
if( NULL == pRandomOption )
return nJewelSlotCount;
nJewelSlotCount += pRandomOption->GetAddJewelSocketCount();
return nJewelSlotCount;
}
//////////////////////////////////////////////////////////////////////////
//Invetory
SInventoryMgr::SInventoryMgr()
: SGameUIMgr() // 2011.03.29 - servantes
, m_pUpdateItemInfo( NULL )
{
Clear();
m_pUpdateItemInfo = new SInventorySlot;
}
SInventoryMgr::~SInventoryMgr()
{
Clear();
}
void SInventoryMgr::Clear()
{
ItemSet(SET_INDEX_01);
for( unsigned int a(0); ItemBase::MAX_ITEM_WEAR>a; a++ )
{
m_itemCode[a] = 0;
m_itemHandle[a] = 0;
}
m_dwTime = 0;
m_dwCheckLendingTime = 0;
m_nCheckCount = 0;
for( int i(0); TS_SC_ITEM_COOL_TIME::MAX_ITEM_COOLTIME_GROUP>i; i++ )
{
m_dwCur_time[i] = 0;
m_dwCool_time[i] = 0;
m_dwRemain_time[i] = 0;
}
m_hCashDragItem = 0;
for( int i(0); c_BeltSlotCnt>i; i++ )
handle_BeltSlot[i] = 0;
m_vLendingItem.clear();
SAFE_DELETE_VECTOR( m_vInventory );
SAFE_DELETE_VECTOR( m_vecShopList );
m_vCashItemList.clear();
m_vEquipCareList.clear();
SAFE_DELETE( m_pUpdateItemInfo );
m_rqItemState = RQ_ITEM_STATE::RQ_ITEM_STATE_NONE; // 아이템 요청 상태.
}
void SInventoryMgr::ResetInfo()
{
Clear();
if( m_pUpdateItemInfo == NULL )
m_pUpdateItemInfo = new SInventorySlot;
}
AR_HANDLE SInventoryMgr::GetItemHandle( int nIndex )
{
if( m_vInventory.empty() ) return NO_HANDLE;
if( (int)m_vInventory.size() <= nIndex ) return NO_HANDLE;
return m_vInventory[nIndex]->GetHandle();
}
AR_HANDLE SInventoryMgr::GetItemHandleForCode( int nItemCode )
{
int nSize = (int)m_vInventory.size();
for( int i(0); i<nSize; ++i )
{
if( m_vInventory[i]->GetItemCode() == nItemCode )
return m_vInventory[i]->GetHandle();
}
return 0;
}
//Update Item Info
void SInventoryMgr::UpdateWear( struct SMSG_ITEM_WEAR* pMsg )
{
for( int i=0; ItemBase::MAX_ITEM_SPARE_WEAR>i; i++ )
{
m_itemCode[i] = pMsg->nItemCode[i];
}
}
void SInventoryMgr::UpdateWearInfo( struct SMSG_ITEM_WEAR_INFO* pMsg, bool bCreature )
{
AR_HANDLE handle = 0;
for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == pMsg->item_handle )
{
//변경된 아이템의 위치 갱신
m_vInventory[i]->SetPosition( pMsg->wear_position );
m_vInventory[i]->SetWearHandle(NULL);
if( bCreature )
{
m_vInventory[i]->SetWearHandle(pMsg->target_handle);
break;
}
if( pMsg->wear_position != -1 )
{
//기존에 있던 넘의 핸들을 얻는다.
handle = m_itemHandle[pMsg->wear_position];
m_itemHandle[pMsg->wear_position] = pMsg->item_handle;
}
else
{
for( unsigned int a(0); ItemBase::MAX_ITEM_WEAR>a; a++ )
{
if( m_itemHandle[a] == pMsg->item_handle )
m_itemHandle[a] = 0;
}
}
break;
}
}
//기존에 들어 있던것의 위치를 없앤다.
if( !handle ) return;
for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == handle )
{
m_vInventory[i]->SetPosition( -1 );
break;
}
}
}
//Item Use
void SInventoryMgr::Rq_UseItem( int nRace, AR_HANDLE item_handle, AR_HANDLE target_handle, AR_HANDLE item_target_handle, const char* lpText/*=NULL*/ )
{
if( m_vInventory.empty() ) return;
for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == item_handle )
{
const ItemBaseEx_info * pItemBase = GetItemDB().GetItemData( m_vInventory[i]->GetItemCode() );
//사용 가능 한가?
if( ItemBase::TYPE_USEABLE == pItemBase->nType )
{
short nCoolTimeGroup = GetItemDB().GetCoolTimeGroup( m_vInventory[i]->GetItemCode() );
if( GetItemMaxCoolTime( (nCoolTimeGroup-1) ) < GetItemCurCoolTime( (nCoolTimeGroup-1) ) )
{
if( nCoolTimeGroup == 1 || //레드 포션
nCoolTimeGroup == 2 || //오렌지 포션
nCoolTimeGroup == 3 || //블루 포션
nCoolTimeGroup == 4 || //신속의 포션
nCoolTimeGroup == 5 || //바람의 포션
nCoolTimeGroup == 6 ) //스펠 포션
{
//포션류만 소리 재생.
if( m_pGame ) m_pGame->StartSound( "ui_click_potion01.wav" );
}
}
/* TS_CS_USE_ITEM use_msg;
//타겟에 사용 할 수 있는가?
if( pItemBase->Flag.IsOn(ItemBase::FLAG_TARGET_USE) )
{
//타겟을 얻음, 타겟에게 사용
use_msg.item_handle = item_handle;
use_msg.target_handle = target_handle;
}
else
{
//자신한테만 사용한다.
use_msg.item_handle = item_handle;
use_msg.target_handle = 0;
}
SetUpdateItemInfo( m_vInventory[i] );
SendMsg( &use_msg );*/
if( pItemBase->CheckFlag(ItemBase::FLAG_TARGET_USE) )
{
//타겟을 얻음, 타겟에게 사용
AR_UNIT nRange = pItemBase->nThrowRange * GameRule::DEFAULT_UNIT_SIZE;
/* SInputUseItem inupt( target_handle, item_handle, nRange, pItemBase->fOptVar1[0] );
if( m_pGame ) m_pGame->AddGameInput( &inupt );*/
SIMSG_UI_ACT_USEITEM msg;
msg.m_hItemUseTargetHandle = item_target_handle;
msg.m_hTargetHandle = target_handle;
msg.m_hItemHandle = item_handle;
msg.m_fUseRange = nRange;
msg.m_nSkillID = pItemBase->dOptVar1[0];
msg.m_bNeedTarget = true;
if( lpText )
msg.m_strParameter = lpText;
ProcMsgAtStatic( &msg );
}
else
{
//자신한테만 사용한다.
/* SInputUseItem inupt( 0, item_handle, 0, 0 );
if( m_pGame ) m_pGame->AddGameInput( &inupt );*/
bool bIsPosition = false;
if( pItemBase->nType == ItemBase::TYPE_USEABLE &&
((int)pItemBase->dOptVar1[0]) == 0 )
{
bIsPosition = true;
}
// 2012. 8. 8 - marine 추가 성능 아이디가 1(hp), 2(mp)인 경우에는 이동을 유지하도록 수정
if( pItemBase->nType == ItemBase::TYPE_USEABLE &&
(((int)pItemBase->nOptType[0]) == 1 || ((int)pItemBase->nOptType[0]) == 2 ) )
{
bIsPosition = true;
}
SIMSG_UI_ACT_USEITEM msg;
msg.m_hItemUseTargetHandle = item_target_handle;
msg.m_hTargetHandle = 0;
msg.m_hItemHandle = item_handle;
msg.m_fUseRange = 0;
msg.m_nSkillID = 0;
msg.m_bIsPosition = bIsPosition;
if( lpText )
msg.m_strParameter = lpText;
ProcMsgAtStatic( &msg );
}
SetUpdateItemInfo( m_vInventory[i] );
}
else
{
bool bUseItem(false);
if( ItemBase::TYPE_USE == pItemBase->nType ) //장착시 사용인 아이템의 경우
{
/* for( int i(0); ItemBase::MAX_ITEM_WEAR>i; i++ )
{
if( m_itemHandle[i] == item_handle ) //장착되있다면
{
bUseItem = true;
break;
}
}
if( ItemBase::GROUP_RIDING == pItemBase->nGroup ||
ItemBase::GROUP_CASH_ITEM == pItemBase->nGroup )
bUseItem = true;*/
// if( bUseItem )
{
SIMSG_UI_ACT_USEITEM msg; //사용
msg.m_hItemUseTargetHandle = item_target_handle;
msg.m_hTargetHandle = target_handle;
msg.m_hItemHandle = item_handle;
msg.m_fUseRange = 0;
msg.m_nSkillID = pItemBase->dOptVar1[0];
msg.m_bNeedTarget = false;
ProcMsgAtStatic( &msg );
return;
}
}
if( m_vInventory[i]->GetItem() == NULL )
{
assert( 0 && "Item Data Error!!!" );
continue;
}
//너무 빨리 장비를 장착하려고하지는 않는가? 2009.07.31 sfreer
{
static AR_TIME lastpuTime = 0;
AR_TIME time = GetSafeTickCount();
if (time < lastpuTime + 200) //200 tick 안에 wearInfo 들어 오면 무시
{
SendGameInterfaceMsg( &SIMSG_UI_DISPLAY_SYS_MSG( SYS_MSG_PUT_ITEM_TOOFAST ) );
return;
}
lastpuTime = time;
}
//장착 레벨이 되는가?
int nItemCode = m_vInventory[i]->GetItemCode();
ItemBase::ItemWearType wearType = GetItemDB().GetWearType( m_vInventory[i]->GetItemCode() );
if( wearType == ItemBase::WEAR_CANTWEAR && nItemCode != 804000 )
{
//아무 것도 안 해...
return; //사용
}
else
{
int nPosition = GetItemDB().GetWearType( m_vInventory[i]->GetItemCode() );
BOOL bPut = FALSE;
unsigned int a = 0;
// 장착여부 검사. 장착되어 있다면 탈착. bintitle. 2010.11.15.
bPut = TRUE;
for( ; ItemBase::MAX_ITEM_WEAR>a; a++ )
{
if( m_itemHandle[a] == item_handle )
{
//탈착
bPut = FALSE;
break;
}
}
// 장착되지 않았다면 양손 여부 검사. bintitle. 2010.11.15.
if( bPut )
{
//장착 할수 있는 종족 인가?
bool bRace = GetItemDB().IsWearablebyRace( nItemCode, nRace );
if( !bRace )
{
SendGameInterfaceMsg( &SIMSG_UI_DISPLAY_SYS_MSG( SYS_MSG_PUT_ITEM_FAIL ) );
_oprint( "Cannot equip due to wrong race... ItemCode: %d, Race: %d\n", nItemCode,nRace );
return; //사용 불가
}
// From ZONE source; dual crossbows
if (pItemBase->nClass == ItemBase::CLASS_ONEHAND_SWORD ||
pItemBase->nClass == ItemBase::CLASS_DAGGER ||
pItemBase->nClass == ItemBase::CLASS_ONEHAND_AXE ||
<<<<<<< HEAD
pItemBase->nClass == ItemBase::CLASS_CROSSBOW) //Double Crossbow
{
CheckWeapon(pItemBase, item_handle, ItemBase::WEAR_WEAPON, ItemBase::WEAR_SHIELD, a, nPosition, bPut);
}
else if( pItemBase->nClass == ItemBase::CLASS_DECO_ONEHAND_SWORD ||
pItemBase->nClass == ItemBase::CLASS_DECO_DAGGER ||
pItemBase->nClass == ItemBase::CLASS_DECO_ONEHAND_AXE ||
pItemBase->nClass == ItemBase::CLASS_DECO_CROSSBOW) //Double Crossbow
=======
pItemBase->nClass == ItemBase::CLASS_CROSSBOW)
{
CheckWeapon(pItemBase, item_handle, ItemBase::WEAR_WEAPON, ItemBase::WEAR_SHIELD, a, nPosition, bPut);
}
else if (pItemBase->nClass == ItemBase::CLASS_DECO_ONEHAND_SWORD ||
pItemBase->nClass == ItemBase::CLASS_DECO_DAGGER ||
pItemBase->nClass == ItemBase::CLASS_DECO_ONEHAND_AXE ||
pItemBase->nClass == ItemBase::CLASS_DECO_CROSSBOW)
>>>>>>> a34328224e914a577b99c79ec6e8ffbcea554a05
{
CheckWeapon(pItemBase, item_handle, ItemBase::WEAR_DECO_WEAPON, ItemBase::WEAR_DECO_SHIELD, a, nPosition, bPut);
}
//양손 장착 가능 무기인가 검사
//if( pItemBase->nClass == ItemBase::CLASS_ONEHAND_SWORD ||
// pItemBase->nClass == ItemBase::CLASS_DAGGER ||
// pItemBase->nClass == ItemBase::CLASS_ONEHAND_AXE ||
//
// // AziaMafia Double Crossbow
// pItemBase->nClass == ItemBase::CLASS_CROSSBOW)
//{
// CheckWeapon(pItemBase, item_handle, ItemBase::WEAR_WEAPON, ItemBase::WEAR_SHIELD, a, nPosition, bPut);
//}
//else if( pItemBase->nClass == ItemBase::CLASS_DECO_ONEHAND_SWORD ||
// pItemBase->nClass == ItemBase::CLASS_DECO_DAGGER ||
// pItemBase->nClass == ItemBase::CLASS_DECO_ONEHAND_AXE ||
//
// // AziaMafia Double Crossbow
// pItemBase->nClass == ItemBase::CLASS_DECO_CROSSBOW)
//{
// CheckWeapon(pItemBase, item_handle, ItemBase::WEAR_DECO_WEAPON, ItemBase::WEAR_DECO_SHIELD, a, nPosition, bPut);
//}
//else
//{
// //Loop 도는 것은 나중에 고치자~
// //이미 장착 되어 있나 판별
// bPut = TRUE;
// for( ; ItemBase::MAX_ITEM_WEAR>a; a++ )
// {
// if( m_itemHandle[a] == item_handle )
// {
// //탈착
// bPut = FALSE;
// break;
// }
// }
//}
} // bintitle. 2010.11.15.
// ( target_handle == 0 가능 );
if( bPut )
{
{
//에테리얼 내구도 체크
SInventorySlot* pSlot = m_vInventory[i];
const ItemBaseEx_info * pItem = GetItemDB().GetItemData( pSlot->GetItemCode() );
if(pItem->nEthereal_durability > 0)
{
if( pSlot->GetEtherealDurability() == 0)
{
SendGameInterfaceMsg( &SIMSG_UI_DISPLAY_SYS_MSG( SYS_MSG_PUT_BROKEN_ITEM ) );
_oprint( "Ethereal durability is 0. ItemCode: %d\n", nItemCode);
return; //사용 불가
}
}
}
if( m_pGame )
{
m_pGame->StartSound( GetMaterialSound( GetItemDB().GetMaterial( m_vInventory[i]->GetItemCode() ) ) );
m_pGame->Rq_PutOnOffItem( target_handle, item_handle, nPosition);
}
//장착
/* TS_CS_PUTON_ITEM msg;
msg.item_handle = item_handle;
msg.target_handle = target_handle;
msg.position = nPosition;
assert( msg.position != 255 && "Data Error~ 장착 Position 이상~" );
SendMsg( &msg );*/
return; //사용
}
else//탈착 시키자
{
if( m_pGame ) m_pGame->Rq_PutOnOffItem( target_handle, 0, a );
/* TS_CS_PUTOFF_ITEM msg;
msg.position = a;//실제 장착위치//GetItemDB().GetWearType( m_vInventory[i]->GetItemCode() );
msg.target_handle = target_handle;
SendMsg( &msg );*/
return; //사용
}
}
}
}
}
}
void SInventoryMgr::CheckWeapon( const ItemBaseEx_info* pItemBase, int item_handle, ItemBase::ItemWearType MainWearType, ItemBase::ItemWearType SubWearType, unsigned int& a, int& nPosition, BOOL& bPut )
{
if( m_itemHandle[MainWearType] == 0)
{
a = MainWearType;
nPosition = MainWearType;
bPut = TRUE;
}
//Sub(Shield)슬롯이 비어있다면 이곳에 장착 하자
else if( m_itemHandle[SubWearType] == 0 )
{
//Main(Weapon)슬롯 무기와 같지 않아야 한다
if( m_itemHandle[MainWearType] != item_handle )
{
<<<<<<< HEAD
//Main(Weapon)슬롯이 한손검이나 데거 혹은 치장무기가 장착돼있어야 한다
ItemBase::ItemClass clss = GetItemDB().GetClassID( m_itemCode[MainWearType] );
if( clss == ItemBase::CLASS_ONEHAND_SWORD || clss == ItemBase::CLASS_DAGGER || clss == ItemBase::CLASS_ONEHAND_AXE ||
clss == ItemBase::CLASS_DECO_ONEHAND_SWORD || clss == ItemBase::CLASS_DECO_DAGGER ||
clss == ItemBase::CLASS_DECO_ONEHAND_AXE || clss == ItemBase::CLASS_CROSSBOW || clss == ItemBase::CLASS_DECO_CROSSBOW) //Double Crossbow
=======
// From ZONE source; dual crossbows
ItemBase::ItemClass clss = GetItemDB().GetClassID(m_itemCode[MainWearType]);
if (clss == ItemBase::CLASS_ONEHAND_SWORD || clss == ItemBase::CLASS_DAGGER || clss == ItemBase::CLASS_ONEHAND_AXE ||
clss == ItemBase::CLASS_DECO_ONEHAND_SWORD || clss == ItemBase::CLASS_DECO_DAGGER ||
clss == ItemBase::CLASS_DECO_ONEHAND_AXE || clss == ItemBase::CLASS_CROSSBOW || clss == ItemBase::CLASS_DECO_CROSSBOW)
>>>>>>> a34328224e914a577b99c79ec6e8ffbcea554a05
{
if (clss == pItemBase->nClass)
nPosition = SubWearType;
}
//Main(Weapon)슬롯이 한손검이나 데거 혹은 치장무기가 장착돼있어야 한다
//ItemBase::ItemClass clss = GetItemDB().GetClassID( m_itemCode[MainWearType] );
//if( clss == ItemBase::CLASS_ONEHAND_SWORD || clss == ItemBase::CLASS_DAGGER || clss == ItemBase::CLASS_ONEHAND_AXE ||
// clss == ItemBase::CLASS_DECO_ONEHAND_SWORD || clss == ItemBase::CLASS_DECO_DAGGER
// || clss == ItemBase::CLASS_DECO_ONEHAND_AXE
// // AziaMafia Double Crossbow
// || clss == ItemBase::CLASS_CROSSBOW
// || clss == ItemBase::CLASS_DECO_CROSSBOW )
//{
// //장착될 아이템과 Main(Weapon)에 장착된 아이템이 같은 클래스여야 한다
// if( clss == pItemBase->nClass )
// nPosition = SubWearType;
//}
bPut = TRUE;
}
else a = MainWearType;
}
else //양손모두 장착돼 있다면
{
//Main(Weapon)슬롯과 같다면 탈착 시킨다
if( m_itemHandle[MainWearType] == item_handle )
a = MainWearType;
//Sub(Shield)슬롯과 같다면 탈착 시킨다
else if( m_itemHandle[SubWearType] == item_handle )
a = SubWearType;
else//새로운 아이템 이면
{
nPosition = MainWearType;
bPut = TRUE;
}
}
}
void SInventoryMgr::AddEquipCard( AR_HANDLE target_handle, AR_HANDLE hItem )
{
for( unsigned int i(0); m_vEquipCareList.size()>i; i++ )
{
if( m_vEquipCareList[i].item_handle == hItem )
return;
}
EQUIP_CARD equip_card;
equip_card.item_handle = hItem;
equip_card.target_handle = target_handle;
m_vEquipCareList.push_back( equip_card );
}
void SInventoryMgr::DelEquipCard( AR_HANDLE target_handle, AR_HANDLE hItem )
{
for( unsigned int i(0); m_vEquipCareList.size()>i; i++ )
{
if( m_vEquipCareList[i].item_handle == hItem )
{
m_vEquipCareList.erase( m_vEquipCareList.begin()+i );
return;
}
}
}
bool SInventoryMgr::IsEquipCard( AR_HANDLE hItem ) const /// 2010.12.29 const 추가
{
for( unsigned int i(0); m_vEquipCareList.size()>i; i++ )
{
if( m_vEquipCareList[i].item_handle == hItem )
{
return true;
}
}
return false;
}
void SInventoryMgr::SetBeltSlotCard( struct SMSG_BELT_SLOT_INFO* pMsg )
{
for( int i(0); c_BeltSlotCnt>i; i++ )
handle_BeltSlot[i] = pMsg->handle[i];
}
bool SInventoryMgr::IsBeltSlotCard( AR_HANDLE hItem ) const /// 2010.12.29 const 추가 - prodongi
{
for( int i(0); c_BeltSlotCnt>i; i++ )
{
if( handle_BeltSlot[i] == hItem )
return true;
}
return false;
}
// 아이템의 장착여부 반환.
bool SInventoryMgr::IsEquip( AR_HANDLE handle )
{
for( int i=0; i<ItemBase::MAX_ITEM_WEAR; ++i )
{
if( m_itemHandle[ i ] == handle )
return true;
}
return false;
}
int SInventoryMgr::GetBeltSlotIndex( AR_HANDLE hItem )
{
for( int i(0); c_BeltSlotCnt>i; i++ )
{
if( handle_BeltSlot[i] == hItem )
return i;
}
return -1;
}
int SInventoryMgr::GetEmptyBeltSlotIndex()
{
for( int i(0); c_BeltSlotCnt>i; i++ )
{
if( handle_BeltSlot[i] == 0 )
return i;
}
return -1;
}
AR_HANDLE SInventoryMgr::GetBeltSlot( int nIndex )
{
if( nIndex >= 0 && nIndex < c_BeltSlotCnt )
return handle_BeltSlot[nIndex];
return 0;
}
// 2010.08.17 - prodongi
//void SInventoryMgr::Rq_BeltCardPut( bool bPutOn, AR_HANDLE hItem )
void SInventoryMgr::Rq_BeltCardPut( bool bPutOn, AR_HANDLE hItem, int putSlot )
{
if( bPutOn )
{
TS_CS_PUTON_CARD msg;
// 2010.08.17 - prodongi
//msg.position = GetEmptyBeltSlotIndex();
msg.position = putSlot;
msg.item_handle = hItem;
SendMsg( &msg );
}
else
{
// 탈착
TS_CS_PUTOFF_CARD msg;
msg.position = GetBeltSlotIndex( hItem );
SendMsg( &msg );
}
}
// creture item
void SInventoryMgr::Rq_CreatureUseItem( AR_HANDLE item_handle, AR_HANDLE target_handle )
{
if( m_vInventory.empty() ) return;
for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == item_handle )
{
SInventorySlot* pItem = m_vInventory[i];
if( pItem->GetPosition() == ItemBase::WEAR_NONE )
{
//장착
TS_CS_PUTON_ITEM msg;
msg.item_handle = item_handle;
msg.target_handle = target_handle;
//msg.position = ItemBase::MAX_ITEM_WEAR; // 서버에서의 max 값을 날린다.. 크리처는 특정 장착 위치가 없다
// 서버에서의 max 값을 날린다.. 크리처는 특정 장착 위치가 없다.
// 2010.10.05. bintitle. 아바타에 SWAP 장비가 추가되어 MAX가 28 개로 늘었다. 하지만 크리쳐는 서버에서 MAX 24 만 인정하므로 24로 변경.
msg.position = ItemBase::MAX_ITEM_SPARE_WEAR;
assert( msg.position != 255 && "Data Error~ 장착 Position 이상~" );
SendMsg( &msg );
return; //사용
}
else
{
// 탈착
TS_CS_PUTOFF_ITEM msg;
msg.position = pItem->GetPosition()%1000;
msg.target_handle = target_handle;
SendMsg( &msg );
return; //사용
}
}
}
}
void SInventoryMgr::SetItemCoolTime( int nIndex, DWORD dwCoolTime )
{
if( nIndex >= 0 && nIndex < TS_SC_ITEM_COOL_TIME::MAX_ITEM_COOLTIME_GROUP )
{
if( m_dwRemain_time[nIndex] == 0 )
{
m_dwRemain_time[nIndex] = dwCoolTime;
m_dwCool_time[nIndex] = dwCoolTime;
m_dwCur_time[nIndex] = m_dwTime;
}
}
}
int SInventoryMgr::GetItemCurCoolTime( int nIndex )
{
if( nIndex >= 0 && nIndex < TS_SC_ITEM_COOL_TIME::MAX_ITEM_COOLTIME_GROUP )
return m_dwTime - m_dwCur_time[nIndex];
return 0;
}
int SInventoryMgr::GetItemMaxCoolTime( int nIndex )
{
if( nIndex >= 0 && nIndex < TS_SC_ITEM_COOL_TIME::MAX_ITEM_COOLTIME_GROUP )
return m_dwCool_time[nIndex];
return 0;
}
void SInventoryMgr::Process( DWORD time )
{
m_dwTime = time;
//아이템 그룹 쿨 타임 처리
for( int i(0); TS_SC_ITEM_COOL_TIME::MAX_ITEM_COOLTIME_GROUP>i; i++ )
{
if( (m_dwRemain_time[i] > 0) && (m_dwTime - m_dwCur_time[i]) >= (DWORD)m_dwRemain_time[i] )
{
m_dwRemain_time[i] = 0;
}
}
//대여 시간 처리
if( m_dwCheckLendingTime == 0 )
{
m_dwCheckLendingTime = m_dwTime;
}
else
{
if( (m_dwTime - m_dwCheckLendingTime) >= CHECK_LENDING_TIME )
{ //대여 아이템 갱신
m_dwCheckLendingTime = m_dwTime;
++m_nCheckCount;
for( unsigned int i(0); m_vLendingItem.size()>i; i++ )
{
SInventorySlot * pInvenSlot = m_vLendingItem[i];
if( pInvenSlot->GetItem()->remain_time > 0 )
--pInvenSlot->GetItem()->remain_time;
}
for ( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if (( m_vInventory[i]->GetItem()->elemental_effect_type != 0 ) &&
( m_vInventory[i]->GetItem()->elemental_effect_remain_time > 0 ))
--m_vInventory[i]->GetItem()->elemental_effect_remain_time;
}
if( m_nCheckCount >= 60 )
{
m_nCheckCount = 0;
ProcMsgAtStatic( &(SIMSG_UI_STATE_UPDATE(SIMSG_TOGGLE_UIWINDOW::UIWINDOW_INVENTORY)) );
}
}
}
}
int SInventoryMgr::GetLendingItemTime( AR_HANDLE item_handle )
{
for( unsigned int i(0); m_vLendingItem.size()>i; i++ )
{
SInventorySlot * pInvenSlot = m_vLendingItem[i];
if( pInvenSlot->GetHandle() == item_handle )
{
return pInvenSlot->GetItem()->remain_time;
}
}
return 0;
}
void SInventoryMgr::_addLendingItem( SInventorySlot* pItemSlot )
{
if( pItemSlot->GetItem()->remain_time > 0 )
{
m_vLendingItem.push_back( pItemSlot );
}
}
void SInventoryMgr::ClearCashItem()
{
m_vCashItemList.clear();
}
void SInventoryMgr::UpdateCashItem( TS_SC_COMMERCIAL_STORAGE_LIST::CommercialItemInfo* pCashItemInfo )
{
for( unsigned int i(0); m_vCashItemList.size()>i; i++ )
{
TS_SC_COMMERCIAL_STORAGE_LIST::CommercialItemInfo* pItemInfo = &m_vCashItemList[i];
if( pItemInfo->commercial_item_uid == pCashItemInfo->commercial_item_uid )
{ //기존것 갱신
pItemInfo->count = pCashItemInfo->count;
return;
}
}
//새로 추가
TS_SC_COMMERCIAL_STORAGE_LIST::CommercialItemInfo newItem;
newItem.commercial_item_uid = pCashItemInfo->commercial_item_uid;
newItem.code = pCashItemInfo->code;
newItem.count = pCashItemInfo->count;
m_vCashItemList.push_back( newItem );
}
//내구도 관련 메시지 체크 하여 출력하는 함수
void SInventoryMgr::CheckDurabilityMsg(SInventorySlot* pSlot)
{
/*if( pSlot->m_nLastDurabilityValue < pSlot->GetEtherealDurability())
pSlot->m_nLastDurabilityCheckPercent = 0;*/
const ItemBaseEx_info * pItem = GetItemDB().GetItemData( pSlot->GetItemCode() );
int CheckPercent = 0;
if(pItem && pSlot->m_nLastDurabilityValue > pSlot->GetEtherealDurability())
{
if(pSlot->getMaxEtherealDurability() > 0 && pItem->nClass != 451)
{
if( pSlot->GetEtherealDurability() == 0)
{
if(pSlot->m_nLastDurabilityCheckPercent == 0 || pSlot->m_nLastDurabilityCheckPercent != 1 )
CheckPercent = 1;
}
else if( pSlot->GetEtherealDurability() <= pSlot->getMaxEtherealDurability()*0.2 )
{
if(pSlot->m_nLastDurabilityCheckPercent == 0 || pSlot->m_nLastDurabilityCheckPercent != 20 )
CheckPercent = 20;
}
else if( pSlot->GetEtherealDurability() <= pSlot->getMaxEtherealDurability()*0.4 )
{
if(pSlot->m_nLastDurabilityCheckPercent == 0 || pSlot->m_nLastDurabilityCheckPercent != 40)
CheckPercent = 40;
}
else if( pSlot->GetEtherealDurability() <= pSlot->getMaxEtherealDurability()*0.6 )
{
if(pSlot->m_nLastDurabilityCheckPercent == 0 || pSlot->m_nLastDurabilityCheckPercent != 60)
CheckPercent = 60;
}
else if( pSlot->GetEtherealDurability() <= pSlot->getMaxEtherealDurability()*0.8 )
{
if(pSlot->m_nLastDurabilityCheckPercent == 0 || pSlot->m_nLastDurabilityCheckPercent != 80)
CheckPercent = 80;
}
if(CheckPercent > 0)
{
pSlot->m_nLastDurabilityCheckPercent = CheckPercent;
std::string basemsg;
if(CheckPercent==1)
basemsg = S(7907);
else if(CheckPercent==20)
basemsg = S(7906);
else
basemsg = S(7905);
XStringUtil::Replace( basemsg, "#@item_name@#", GetStringDB().GetString( pItem->nNameId ) );
//CStringUtil::StringFormat( "%s(%d%%)", basemsg.c_str(), basemsg );
m_pGame->AddChatMessage( basemsg.c_str() );
}
}
}
pSlot->m_nLastDurabilityValue = pSlot->GetEtherealDurability();
}
//Item 추가
int SInventoryMgr::AddItem( TS_ITEM_INFO * pItemInfo )
{
if( pItemInfo == NULL ) return 1;
//기존것 갱신
for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == pItemInfo->handle )
{
/// 2010.12.08 아이템의 영혼력이 바꼈을 때, 오토 메세지 수정 - prodongi
if( m_vInventory[i]->GetEndurance() != 0 && pItemInfo->endurance == 0 )
SendGameInterfaceMsg( &SIMSG_UI_EMPTY_SOULPWER_MSG(pItemInfo->handle, true) );
else
SendGameInterfaceMsg( &SIMSG_UI_EMPTY_SOULPWER_MSG(pItemInfo->handle, false) );
m_vInventory[i]->SetUpdateCount( count_t( pItemInfo->count ) );
m_vInventory[i]->SetItem( pItemInfo );
CheckDurabilityMsg( m_vInventory[i] );
return (int)m_vInventory.size();
}
}
//새것 추가
SInventorySlot * pInvenSlot = new SInventorySlot;
pInvenSlot->SetUpdateCount( count_t( pItemInfo->count ) );
pInvenSlot->SetItem( pItemInfo ); //순서 있음
m_vInventory.push_back( pInvenSlot );
CheckDurabilityMsg( pInvenSlot );
//대여 시간이 있는 것들만 추가됨.
_addLendingItem( pInvenSlot );
if( pInvenSlot->IsEquipItem() && !pInvenSlot->IsStorageItem() && !pInvenSlot->IsSummonEquip() )
{
if( pItemInfo->wear_position < ItemBase::MAX_ITEM_WEAR &&
pItemInfo->wear_position > -1 )
{
m_itemCode[pItemInfo->wear_position] = pItemInfo->Code;
m_itemHandle[pItemInfo->wear_position] = pItemInfo->handle;
}
}
SetUpdateItemInfo( pInvenSlot );
/// 2010.12.08 영혼력이 0 이면 오토 메세지 출력 - prodongi
if (0 == pItemInfo->endurance)
{
unsigned int nEndurancePer;
int nResult = pInvenSlot->GetCrrEndurancePer(nEndurancePer);
if( nResult == SInventorySlot::ENDURANCE_SUCCESS )
{
if (0 == nEndurancePer && IsEndurance(nEndurancePer))
{
SendGameInterfaceMsg( &SIMSG_UI_EMPTY_SOULPWER_MSG(pItemInfo->handle, true) );
}
}
}
return (int)m_vInventory.size();
}
//Item 삭제
int SInventoryMgr::DropItem( AR_HANDLE item_handle )
{
if( m_vInventory.empty() ) return 0;
/*for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == item_handle )
{
delete m_vInventory[i];
m_vInventory.erase( m_vInventory.begin()+i );
return 1;
}
}*/
std::vector<SInventorySlot*>::iterator it = m_vInventory.begin();
while( it != m_vInventory.end() )
{
SInventorySlot* pSlot = (*it);
if( pSlot && pSlot->GetHandle() == item_handle )
{
SetUpdateItemInfo( pSlot );
_delLendingItem( pSlot );
delete pSlot;
_onEraseItem( m_vInventory.erase(it) );
return 1;
}
it++;
}
SetUpdateItemInfo( NULL );
return 0;
}
void SInventoryMgr::_delLendingItem( SInventorySlot* pItemSlot )
{
std::vector<SInventorySlot*>::iterator it = m_vLendingItem.begin();
while( it != m_vLendingItem.end() )
{
SInventorySlot* pSlot = (*it);
if( pSlot && pSlot->GetHandle() == pItemSlot->GetHandle() )
{
m_vLendingItem.erase(it);
return;
}
++it;
}
}
//Item 제거.
int SInventoryMgr::DestroyItem( AR_HANDLE item_handle )
{
// 아이템 파괴상태 일 경우 함수종료.
if( m_vInventory.empty() || m_rqItemState == RQ_ITEM_STATE::RQ_ITEM_STATE_ERASE )
return 0;
// 상태 초기화.
if( m_rqItemState == RQ_ITEM_STATE::RQ_ITEM_STATE_DROP )
m_rqItemState = RQ_ITEM_STATE::RQ_ITEM_STATE_NONE;
/*for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
if( m_vInventory[i]->GetHandle() == item_handle )
{
delete m_vInventory[i];
m_vInventory.erase( m_vInventory.begin()+i );
return 1;
}
}*/
std::vector<SInventorySlot*>::iterator it = m_vInventory.begin();
while( it != m_vInventory.end() )
{
SInventorySlot* pSlot = (*it);
if( pSlot && pSlot->GetHandle() == item_handle )
{
/// 2010.12.08 영혼력 충전 오토메세지 삭제 - prodongi
if (0 == pSlot->GetEndurance())
{
SendGameInterfaceMsg( &SIMSG_UI_EMPTY_SOULPWER_MSG(item_handle, false) );
}
//모두 다 버린다. 버릴 갯수 설정
pSlot->SetUpdateCount( pSlot->GetItemCount(), true );
SetUpdateItemInfo( pSlot );
_delLendingItem( pSlot );
delete pSlot;
_onEraseItem( m_vInventory.erase(it) );
return 1;
}
it++;
}
SetUpdateItemInfo( NULL );
return 0;
}
void SInventoryMgr::_onEraseItem( std::vector<SInventorySlot*>::iterator it )
{
for( ; it != m_vInventory.end() ; ++it )
{
((*it)->GetItem())->index--;
}
}
// 아이템파괴.
int SInventoryMgr::EraseItem( AR_HANDLE handle, __int64 count )
{
// 상태 초기화.
if( m_rqItemState == RQ_ITEM_STATE::RQ_ITEM_STATE_ERASE )
m_rqItemState = RQ_ITEM_STATE::RQ_ITEM_STATE_NONE;
// 0 이면 파괴 실패.
if( handle == 0 )
return 0;
SInventorySlot * pSlot;
int size = m_vInventory.size();
for( std::vector<SInventorySlot*>::iterator it=m_vInventory.begin(); it!=m_vInventory.end(); ++it )
{
pSlot = (*it);
if( pSlot && pSlot->GetHandle() == handle ) // GetItemCode() == itemCode )
{
SendDestroyMsg(count, pSlot->GetItemCode() );
return 1;
}
}
//SetUpdateItemInfo( NULL );
//// 0 이면 파괴 실패.
//if( itemCode == 0 )
// return 0;
//SInventorySlot * pSlot;
//int size = m_vInventory.size();
//for( std::vector<SInventorySlot*>::iterator it=m_vInventory.begin(); it!=m_vInventory.end(); ++it )
//{
// pSlot = (*it);
// if( pSlot && pSlot->GetItemCode() == itemCode )
// {
// if( pSlot->GetItemCount().getAmount() == 0 ) // 0개이하면 제거.
// {
// _delLendingItem( pSlot );
// delete pSlot;
// m_vInventory.erase( it );
// return 1;
// }
// }
//}
return 0;
}
void SInventoryMgr::SendDestroyMsg(int count, int itemCode)
{
// 시스템메세지 출력.
SMSG_CHATTING msg;
msg.nChatType = CHAT_SYSTEM;
msg.szSender = "";
char strCount[10]={0,};
::itoa( count, strCount, 10 );
msg.strText = SStringDB::ParseString( 730, "#@item_name@#", GetStringDB( ).GetString( GetItemDB().GetTextID( itemCode ) ), "#@item_num@#", strCount );
//msg.strText = CStringUtil::StringFormat( "[%s - %d개] 파괴 되었습니다.", GetStringDB( ).GetString( GetItemDB().GetTextID( pSlot->GetItemCode() ) ), count );
this->m_pGame->ProcMsgAtStatic( &msg );
}
int SInventoryMgr::UpdateItemCount( AR_HANDLE item_handle, count_t nItemCount, bool fromDestory /* = false */ )
{
if( m_vInventory.empty() ) return 0;
SInventorySlot * pSlot;
for( unsigned int i(0); m_vInventory.size()>i; i++ )
{
pSlot = m_vInventory[i];
if( pSlot->GetHandle() == item_handle )
{
count_t beforeCount = pSlot->GetItemCount();
pSlot->SetUpdateCount( nItemCount );
pSlot->SetItemCount( nItemCount );
SetUpdateItemInfo( pSlot );
// 0개면 제거.
if( pSlot->GetItemCount().getAmount() < 1 )
{
std::vector<SInventorySlot*>::iterator it = find( m_vInventory.begin(), m_vInventory.end(), pSlot );
if( it != m_vInventory.end() )
{
// 2012. 7. 20 - marine 완전히 파괴된 경우이므로 이전에 업데이트 하기 전의 count를 쓴다.
// EraseItem()에서도 메세지를 넣지만 여기서 삭제되면 핸들이 사라지기때문에 삭제되기전에 메시지를 날린다.
if(fromDestory)
SendDestroyMsg( beforeCount.getAmount(), pSlot->GetItemCode() );
_delLendingItem( pSlot );
delete pSlot;
_onEraseItem( m_vInventory.erase(it) );
return 1;
}
}
return 1;
}
}
SetUpdateItemInfo( NULL );
return 0;
}
SInventorySlot* SInventoryMgr::GetItemInfo( AR_HANDLE hItem )
{
if( hItem == NULL ) return NULL;
if( m_vInventory.empty() ) return NULL;
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetHandle() == hItem )
return m_vInventory[i];
}
return NULL;
}
SInventorySlot* SInventoryMgr::GetItemInfo( int nWearPos )
{
if( nWearPos == -1 ) return NULL;
if( m_vInventory.empty() ) return NULL;
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->IsPlayerEquipItem(nWearPos) )
return m_vInventory[i];
}
return NULL;
}
SInventorySlot* SInventoryMgr::GetItemInfo( ItemInstance::ItemUID itemUID )
{
if( m_vInventory.empty() ) return NULL;
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetUID() == itemUID )
return m_vInventory[i];
}
return NULL;
}
void SInventoryMgr::GetItemInfo( std::vector<SInventorySlot*>& rItemList, ItemBase::ItemCode code, int level, int enhance )
{
if( m_vInventory.empty() ) return;
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
bool bPush(true);
if( m_vInventory[i]->GetItemCode() == code )
{
if( level && m_vInventory[i]->GetLevel() != level )
bPush = false;
if( enhance && m_vInventory[i]->GetEnhance() != enhance )
bPush = false;
if( bPush ) rItemList.push_back(m_vInventory[i]);
}
}
}
SInventorySlot* SInventoryMgr::GetCodeItemInfo( ItemBase::ItemCode code )
{
if( m_vInventory.empty() ) return NULL;
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetItemCode() == code )
{
return m_vInventory[i];
}
}
return NULL;
}
SInventorySlot* SInventoryMgr::GetComparableEquipItemInfo( SInventorySlot* pItem, bool second_equip )
{
if( pItem->IsEquipItem() == false )
{
return GetComparableEquipItemInfo( pItem->GetItemCode(), second_equip );
}
return NULL;
}
SInventorySlot* SInventoryMgr::GetComparableEquipItemInfo( ItemBase::ItemCode code, bool second_equip )
{
SInventorySlot* pEquipItem = NULL;
int wear_pos = GetItemDB().GetWearType( code );
if( wear_pos >= 0 )
{
// 벨트 슬롯은 비교하지 않는다.(너무 많다.)
if( wear_pos == ItemBase::ItemWearType::WEAR_BELT_SLOT )
{
return NULL;
}
// 반지 혹은 무기
if( wear_pos == ItemBase::ItemWearType::WEAR_RING ||
wear_pos == ItemBase::ItemWearType::WEAR_WEAPON ||
wear_pos == ItemBase::ItemWearType::WEAR_TWOHAND )
{
if( second_equip )
{
if( wear_pos == ItemBase::ItemWearType::WEAR_RING )
{
// 두번째 반지
wear_pos = ItemBase::ItemWearType::WEAR_RING + 1;
}
else
{
// 이도류의 경우만. 방패는 제외한다.
wear_pos = ItemBase::ItemWearType::WEAR_SHIELD;
pEquipItem = GetItemInfo( wear_pos );
if( pEquipItem != NULL )
{
if( GetItemDB().GetWearType( pEquipItem->GetItemCode() ) == ItemBase::ItemWearType::WEAR_WEAPON )
{
return pEquipItem;
}
}
return NULL;
}
}
}
else
{
// 반지가 아닌데 두번째 장비를 요구하면 리턴
if( second_equip )
{
return NULL;
}
}
pEquipItem = GetItemInfo( wear_pos );
if( pEquipItem == NULL )
{
// 무기라면(투핸드 원핸드 비교)
if( wear_pos == ItemBase::ItemWearType::WEAR_WEAPON )
{
pEquipItem = GetItemInfo( ItemBase::ItemWearType::WEAR_TWOHAND );
}
else if( wear_pos == ItemBase::ItemWearType::WEAR_TWOHAND )
{
pEquipItem = GetItemInfo( ItemBase::ItemWearType::WEAR_WEAPON );
}
}
}
return pEquipItem;
}
SInventorySlot* SInventoryMgr::GetItemInfoCreatureUID( int nUID )
{
if( m_vInventory.empty() ) return NULL;
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetItem()->socket[0] == nUID )
return m_vInventory[i];
}
return NULL;
}
bool SInventoryMgr::GetInvenDataList2( int nCategory, std::vector< SInventorySlot*>& vecInvenList )
{
//gmpbigsun( 20130904 ) : nCategory에 따라 Type Value를 재설정하고 아이템DB값의 bitset포함여부로 판단한다.
vecInvenList.clear();
int nNewValue = 0;
switch( nCategory )
{
case UI_ITEM_ALL: nNewValue = UI_ITEM_NEW_ALL; break;
case UI_ITEM_EQUIP: nNewValue = UI_ITEM_NEW_1; break;
case UI_ITEM_USE: nNewValue = UI_ITEM_NEW_2; break;
case UI_ITEM_CARD: nNewValue = UI_ITEM_NEW_3; break;
case UI_ITEM_CREATURE: nNewValue = UI_ITEM_NEW_4; break;
case UI_ITEM_EXPEND: nNewValue = UI_ITEM_NEW_5; break;
case UI_ITEM_ETC: nNewValue = UI_ITEM_NEW_6; break;
case UI_ITEM_QUEST: nNewValue = UI_ITEM_NEW_7; break;
case UI_ITEM_CRU: nNewValue = UI_ITEM_NEW_8; break;
case UI_ITEM_COLLECTION: nNewValue = UI_ITEM_NEW_9; break;
case UI_ITEM_CARD2: nNewValue = UI_ITEM_NEW_10; break;
default:
nNewValue = 0;
break;
}
//TODO:
//nNewVlaue 와 DB의 bitset &(and)결과에 의해 결과 리스트를 뽑음.
int nMaxSize = static_cast<int>(m_vInventory.size());
for( int i = 0; i < nMaxSize; ++i )
{
SInventorySlot* pSlot = m_vInventory[i];
if( !pSlot )
continue; //oops
//창고아이템 pass
if( pSlot->IsStorageItem() )
continue;
const ItemBaseEx_info* pItem = GetItemDB().GetItemData( pSlot->GetItemCode() );
if( !pItem )
continue; //oops
if( nNewValue == UI_ITEM_ALL )
{
//AziaMafia All item inventaire
/*
if ( !( pItem->nCategory_Bitset & UI_ITEM_NEW_3 ) &&
!( pItem->nCategory_Bitset & UI_ITEM_NEW_4 ) )
{
vecInvenList.push_back( pSlot );
}
*/
//add item into all
if ((!(pItem->nCategory_Bitset & UI_ITEM_NEW_7) && !(pItem->nCategory_Bitset & UI_ITEM_NEW_4) &&
!(pItem->nCategory_Bitset & UI_ITEM_NEW_3)) || pSlot->GetItemCode() == 800001 //800001 Unit Card
)
{
vecInvenList.push_back(pSlot);
}
}
//Category Creature
else if (UI_ITEM_NEW_4 == nNewValue && (pSlot->GetXFlag().IsOn(ItemInstance::ITEM_FLAG_CARD)
|| pSlot->GetItemCode() == 800000 // Chalk of Restoration
|| pSlot->GetItemCode() == 710001 // Soul Catalyst<Creature enhancement item><ep7>
|| pSlot->GetItemCode() == 710004)) // Advanced Soul Catalyst<Creature enhancement item><ep7>
vecInvenList.push_back(pSlot);
// else if( UI_ITEM_NEW_7 == nNewValue && pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_QUEST ) )
// vecInvenList.push_back( pSlot );
// else if( UI_ITEM_NEW_8 == nNewValue && pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_CASHITEM ) )
// vecInvenList.push_back( pSlot );
else if (UI_ITEM_NEW_10 == nNewValue )
{
SGameAvatarEx* pOwner = g_pCurrentGameSystem->GetLocalPlayer();
if (pOwner && (ItemBase::GROUP_SKILLCARD == pItem->nGroup
|| pSlot->GetItemCode() == 700401 // Cube de Compétence
|| pSlot->GetItemCode() == 700402 // Ancien Cube de Compétence
))
if (isWearableSkillCardItem(pItem, g_pCurrentGameSystem->GetSkillSlotMgr() ) == true )
vecInvenList.push_back(pSlot);
}
else
{
if( pItem->nCategory_Bitset & nNewValue )
vecInvenList.push_back( pSlot );
}
}
return true;
}
/// 2010.11.24 - prodongi
void SInventoryMgr::GetInvenDataList( int nCategory, std::vector<SInventorySlot*>& vecInvenList, SCreatureSlotMgr const& creatureSlotMgr, bool bExceptEquipItem, bool bExceptDontBuyItem )
//void SInventoryMgr::GetInvenDataList( int nCategory, std::vector<SInventorySlot*>& vecInvenList, bool bExceptEquipItem, bool bExceptDontBuyItem )
{
vecInvenList.clear();
int nUseType = (-1);
switch( nCategory )
{
case UI_ITEM_ALL: nUseType = (-1); break;
case UI_ITEM_EQUIP: nUseType = ItemBase::TYPE_ARMOR; break;
case UI_ITEM_CARD: nUseType = ItemBase::TYPE_CARD; break;
case UI_ITEM_EXPEND: nUseType = ItemBase::TYPE_USEABLE; break;
case UI_ITEM_ETC: nUseType = ItemBase::TYPE_ETC; break;
case UI_ITEM_USE: nUseType = ItemBase::TYPE_USE; break;
case UI_ITEM_QUEST: nUseType = 9999; break; //퀘스트는 플래그
case UI_ITEM_CREATURE: nUseType = ItemBase::TYPE_CREATURE; break; //servantes 2010.11.24 크리처 버튼 안 눌러지는 버그 수정
case UI_ITEM_CRU: nUseType = -2; break;
default:
break;
}
if(nUseType == ItemBase::TYPE_CREATURE) //크리처 //servantes 2010.11.24 크리처 버튼 안 눌러지는 버그 수정
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
SInventorySlot* pSlot = m_vInventory[i];
int nGruop = GetItemDB().GetGroup(pSlot->GetItemCode()); //그룹
bool bCARD = pSlot->GetXFlag().IsOn( ItemInstance::ITEM_FLAG_CARD ); //크리처 장비 카드 여부
if( nGruop == ItemBase::GROUP_SUMMONCARD || //크리처 카드
bCARD ) //크리처 장비 카드
{
/// 2010.12.29 - prodongi
//vecInvenList.push_back( pSlot );
const ItemBaseEx_info * item = GetItemDB().GetItemData( pSlot->GetItemCode() );
if (enableSellItem(bExceptEquipItem, bExceptDontBuyItem, pSlot, creatureSlotMgr, item))
{
vecInvenList.push_back( pSlot );
}
}
}
}
else if(nUseType == ItemBase::TYPE_CARD) //카드 //servantes 2010.11.24
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
SInventorySlot* pSlot = m_vInventory[i];
int nGruop = GetItemDB().GetGroup(pSlot->GetItemCode()); //그룹
if( nGruop == ItemBase::GROUP_SKILLCARD || //스킬 카드
nGruop == ItemBase::GROUP_ITEMCARD || //아이템 카드
nGruop == ItemBase::GROUP_SPELLCARD || //스펠 카드
nGruop == ItemBase::GROUP_SUMMONCARD ) //크리처 카드
{
/// 2010.12.29 - prodongi
//vecInvenList.push_back( pSlot );
const ItemBaseEx_info * item = GetItemDB().GetItemData( pSlot->GetItemCode() );
if (enableSellItem(bExceptEquipItem, bExceptDontBuyItem, pSlot, creatureSlotMgr, item))
{
vecInvenList.push_back( pSlot );
}
}
}
}
else if( nUseType != 9999 )
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->IsStorageItem() ) continue;
const ItemBaseEx_info * pItem = GetItemDB().GetItemData( m_vInventory[i]->GetItemCode() );
bool bInsert = false;
if( pItem->nType == nUseType )
{
bInsert = true;
if( nUseType == ItemBase::TYPE_ARMOR )
{ //장비 얻을때, 카드화 아이템 제외
if( m_vInventory[i]->GetXFlag().IsOn( ItemInstance::ITEM_FLAG_CARD ) )
bInsert = false;
}
}
else
{
if( nUseType == ItemBase::TYPE_CARD )
{ //카드 얻을때, 카드화 아이템 포함
if( m_vInventory[i]->GetXFlag().IsOn( ItemInstance::ITEM_FLAG_CARD ) )
bInsert = true;
}
else
{
// 실제적인 기타 ( 각 탭에 매칭되는 타입 이외의 아이템들 )
if( nUseType == -2 )
{
if( pItem->nType != ItemBase::TYPE_ARMOR && pItem->nType != ItemBase::TYPE_USEABLE && pItem->nType != ItemBase::TYPE_ETC
&& pItem->nType != ItemBase::TYPE_CREATURE && pItem->nType != ItemBase::TYPE_CARD )
bInsert = true;
}
}
}
// if usetype == -1 : 모든 리스트, else : 특정 탭에 해당하는 아이템만, 퀘스트 아이템 제외, 상점 매각 불가 제외
//if (nUseType == -1 || bInsert && !pItem->CheckFlag(ItemBase::ITEM_FLAG::FLAG_QUEST))
if( nUseType == -1 || bInsert && !pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_QUEST ) )
{
/// 2010.12.29 - prodongi
/*
// if except equipitem : 비장착된 아이템만 장착된 카드도 제외, else : 창고 아이템만 제외
if( (bExceptEquipItem && (!m_vInventory[i]->IsEquipItem() && !IsEquipCard(m_vInventory[i]->GetHandle())) ) ||
(!bExceptEquipItem && !m_vInventory[i]->IsStorageItem() ) )
{
if( bExceptDontBuyItem )
{ //상점, 매각 불가 아이템은 스킵
if( pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_CANT_SELL ) )
continue;
}
/// 2010.11.15 - prodongi
if (bExceptEquipItem)
{
if (IsBeltSlotCard(m_vInventory[i]->GetHandle()))
continue;
/// 2010.11.24 편성된 크리처 카드 인지 검사 - prodongi
if (creatureSlotMgr.IsExistCreatureCard(m_vInventory[i]->GetHandle()))
continue;
}
vecInvenList.push_back( m_vInventory[i] );
}
*/
if (enableSellItem(bExceptEquipItem, bExceptDontBuyItem, m_vInventory[i], creatureSlotMgr, pItem))
{
vecInvenList.push_back( m_vInventory[i] );
}
}
}
}
else
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->IsStorageItem() ) continue;
const ItemBaseEx_info * pItem = GetItemDB().GetItemData( m_vInventory[i]->GetItemCode() );
if( pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_QUEST ) )
{
if( (bExceptEquipItem && !m_vInventory[i]->IsEquipItem()) || (!bExceptEquipItem && !m_vInventory[i]->IsStorageItem() ) )
vecInvenList.push_back(m_vInventory[i]);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
// shop list
void SInventoryMgr::AddShopItem( SMSG_MARKET* pMsg )
{
SAFE_DELETE_VECTOR( m_vecShopList );
SMSG_MARKET::ItemInfo* pItemInfo = pMsg->pItemInfo;
for( int i = 0; i < pMsg->item_count; i++ )
{
SShopSlot* pSlot = new SShopSlot;
pSlot->SetNpcHandle( pMsg->npc_handle );
pSlot->SetItemCode( pItemInfo->code );
pSlot->SetPrice( money_t( pItemInfo->price ) );
pSlot->SetHuntaHolicPoint( money_t( pItemInfo->huntaholic_point ) ); // #2.1.2.11.1
pSlot->SetArenaPoint(money_t(pItemInfo->arena_point));
pSlot->SetRank( GetItemDB().GetItemRank( pItemInfo->code ) );
m_vecShopList.push_back(pSlot);
pItemInfo++;
}
}
void SInventoryMgr::GetShopDataList( int nCategory, std::vector<SShopSlot*>& vecShopList )
{
vecShopList.clear();
int nUseType = (-1);
switch( nCategory )
{
case UI_ITEM_ALL: nUseType = (-1); break;
case UI_ITEM_EQUIP: nUseType = ItemBase::TYPE_ARMOR; break;
case UI_ITEM_CARD: nUseType = ItemBase::TYPE_CARD; break;
case UI_ITEM_EXPEND: nUseType = ItemBase::TYPE_USEABLE; break;
case UI_ITEM_ETC: nUseType = ItemBase::TYPE_ETC; break;
case UI_ITEM_USE: nUseType = ItemBase::TYPE_USE; break;
case UI_ITEM_QUEST: nUseType = 9999; break; //퀘스트는 플래그로 처리
case UI_ITEM_CRU: nUseType = -2; break;
}
if( nUseType != 9999 )
{
std::vector<SShopSlot*>::iterator it = m_vecShopList.begin();
while( it != m_vecShopList.end() )
{
SShopSlot* pSlot = (*it);
const ItemBaseEx_info * pItem = GetItemDB().GetItemData( pSlot->GetItemCode() );
if( nUseType == -1 || GetItemDB().GetUseType(pSlot->GetItemCode()) == nUseType && !pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_QUEST ) )
vecShopList.push_back(pSlot);
else
{
if( nUseType == -2 && GetItemDB().GetUseType( pSlot->GetItemCode() ) != nUseType && !pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_QUEST ) )
vecShopList.push_back( pSlot );
}
it++;
}
}
else
{
std::vector<SShopSlot*>::iterator it = m_vecShopList.begin();
while( it != m_vecShopList.end() )
{
SShopSlot* pSlot = (*it);
const ItemBaseEx_info * pItem = GetItemDB().GetItemData( pSlot->GetItemCode() );
if( pItem->CheckFlag( ItemBase::ITEM_FLAG::FLAG_QUEST ) )
vecShopList.push_back(pSlot);
it++;
}
}
}
SShopSlot* SInventoryMgr::GetShopItem( int nItemCode )
{
std::vector<SShopSlot*>::iterator it = m_vecShopList.begin();
while( it != m_vecShopList.end() )
{
SShopSlot* pSlot = (*it);
if( pSlot->GetItemCode() == nItemCode )
return pSlot;
it++;
}
return NULL;
}
void SInventoryMgr::SetUpdateItemInfo( SInventorySlot* pSlot )
{
if( pSlot )
{
*m_pUpdateItemInfo = *pSlot;
m_pUpdateItemInfo->SetExistence( true );
}
else
{
m_pUpdateItemInfo->SetExistence( false );
}
}
SInventorySlot* SInventoryMgr::GetUpdateItemInfo( AR_HANDLE handle )
{
if( m_pUpdateItemInfo->GetHandle() == handle )
{
if( m_pUpdateItemInfo->IsExistence() )
return m_pUpdateItemInfo;
else
return NULL;
}
return NULL;
}
bool SInventoryMgr::IsExistItem( int nItemCode )
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetItemCode() == nItemCode )
return true;
}
return false;
}
bool SInventoryMgr::IsExistItem( AR_HANDLE hItem )
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetHandle() == hItem )
return true;
}
return false;
}
bool SInventoryMgr::IsExistItem( AR_HANDLE hItem, count_t nItemCount )
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetHandle() == hItem &&
m_vInventory[i]->GetItemCount() >= nItemCount )
return true;
}
return false;
}
bool SInventoryMgr::IsExistInvenItem( int nItemCode )
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetItemCode() == nItemCode && !m_vInventory[i]->IsStorageItem() )
{
return true;
}
}
return false;
}
bool SInventoryMgr::IsAwakeningItem(SInventorySlot* pSlot)
{
return pSlot->IsAwakeningItem();
}
AR_HANDLE SInventoryMgr::GetFirstFindItem( int nItemCode )
{
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->GetItemCode() == nItemCode )
return m_vInventory[i]->GetHandle();
}
return 0;
}
count_t SInventoryMgr::GetItemCount( int nItemCode )
{
int nSize = (int)m_vInventory.size();
for( int i = 0; i < nSize; ++i )
{
if( m_vInventory[i]->GetItemCode() == nItemCode )
return m_vInventory[i]->GetItemCount();
}
return count_t( 0 );
}
void SInventoryMgr::GetEquipItemList( std::vector<SInventorySlot*>& vecInvenList )
{
vecInvenList.clear();
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->IsEquipItem() && !m_vInventory[i]->IsStorageItem() && !m_vInventory[i]->IsSummonEquip() )
vecInvenList.push_back(m_vInventory[i]);
}
}
// 2010.07.22 - prodongi
void SInventoryMgr::getCreatureEquipItemList( std::vector<SInventorySlot*>& vecInvenList, AR_HANDLE creatureHandle )
{
vecInvenList.clear();
for( int i = 0; i < static_cast<int>(m_vInventory.size()); i++ )
{
if( m_vInventory[i]->IsEquipItem() && !m_vInventory[i]->IsStorageItem() && m_vInventory[i]->IsSummonEquip() )
{
if (m_vInventory[i]->GetWearHandle() == creatureHandle)
vecInvenList.push_back(m_vInventory[i]);
}
}
}
void SInventoryMgr::SortItemList()
{
struct TItemLess
{
//두인자가 같을 경우 무조건 false가 나오도록 해야한다. 흠 false가 바꾸는 것인데...
bool operator () ( SInventorySlot* a, SInventorySlot* b )
{
if( !a || !b ) return true;
TS_ITEM_INFO* pInfo_1 = a->GetItem();
TS_ITEM_INFO* pInfo_2 = b->GetItem();
if( !pInfo_1 || !pInfo_2 ) return true;
return pInfo_1->index < pInfo_2->index;
}
} pred;
std::sort( m_vInventory.begin(), m_vInventory.end(), pred );
}
/// 2010.12.29 - prodongi
bool SInventoryMgr::enableSellItem(bool exceptEquipItem, bool exceptDontBuyItem, SInventorySlot const* slot,
SCreatureSlotMgr const& creatureSlotMgr, ItemBaseEx_info const* item) const
{
// if except equipitem : 비장착된 아이템만 장착된 카드도 제외, else : 창고 아이템만 제외
if( (exceptEquipItem && (!slot->IsEquipItem() && !IsEquipCard(slot->GetHandle())) ) ||
(!exceptEquipItem && !slot->IsStorageItem() ) )
{
if( exceptDontBuyItem )
{ //상점, 매각 불가 아이템은 스킵
if( item && item->CheckFlag( ItemBase::ITEM_FLAG::FLAG_CANT_SELL ) )
return false;
}
/// 2010.11.15 - prodongi
if (exceptEquipItem)
{
if (IsBeltSlotCard(slot->GetHandle()))
return false;
/// 2010.11.24 편성된 크리처 카드 인지 검사 - prodongi
if (creatureSlotMgr.IsExistCreatureCard(slot->GetHandle()))
return false;
}
return true;
}
return false;
}