forked from metin2/server
2077 lines
44 KiB
C++
2077 lines
44 KiB
C++
#include "stdafx.h"
|
||
#include "utils.h"
|
||
#include "config.h"
|
||
#include "char.h"
|
||
#include "desc.h"
|
||
#include "sectree_manager.h"
|
||
#include "packet.h"
|
||
#include "protocol.h"
|
||
#include "log.h"
|
||
#include "skill.h"
|
||
#include "unique_item.h"
|
||
#include "profiler.h"
|
||
#include "marriage.h"
|
||
#include "item_addon.h"
|
||
#include "dev_log.h"
|
||
#include "locale_service.h"
|
||
#include "item.h"
|
||
#include "item_manager.h"
|
||
#include "affect.h"
|
||
#include "DragonSoul.h"
|
||
#include "buff_on_attributes.h"
|
||
#include "belt_inventory_helper.h"
|
||
#include <common/VnumHelper.h>
|
||
|
||
CItem::CItem(DWORD dwVnum)
|
||
: m_dwVnum(dwVnum), m_bWindow(0), m_dwID(0), m_bEquipped(false), m_dwVID(0), m_wCell(0), m_dwCount(0), m_lFlag(0), m_dwLastOwnerPID(0),
|
||
m_bExchanging(false), m_pkDestroyEvent(NULL), m_pkUniqueExpireEvent(NULL), m_pkTimerBasedOnWearExpireEvent(NULL), m_pkRealTimeExpireEvent(NULL),
|
||
m_pkExpireEvent(NULL),
|
||
m_pkAccessorySocketExpireEvent(NULL), m_pkOwnershipEvent(NULL), m_dwOwnershipPID(0), m_bSkipSave(false), m_isLocked(false),
|
||
m_dwMaskVnum(0), m_dwSIGVnum (0)
|
||
{
|
||
memset( &m_alSockets, 0, sizeof(m_alSockets) );
|
||
memset( &m_aAttr, 0, sizeof(m_aAttr) );
|
||
}
|
||
|
||
CItem::~CItem()
|
||
{
|
||
Destroy();
|
||
}
|
||
|
||
void CItem::Initialize()
|
||
{
|
||
CEntity::Initialize(ENTITY_ITEM);
|
||
|
||
m_bWindow = RESERVED_WINDOW;
|
||
m_pOwner = NULL;
|
||
m_dwID = 0;
|
||
m_bEquipped = false;
|
||
m_dwVID = m_wCell = m_dwCount = m_lFlag = 0;
|
||
m_pProto = NULL;
|
||
m_bExchanging = false;
|
||
memset(&m_alSockets, 0, sizeof(m_alSockets));
|
||
memset(&m_aAttr, 0, sizeof(m_aAttr));
|
||
|
||
m_pkDestroyEvent = NULL;
|
||
m_pkOwnershipEvent = NULL;
|
||
m_dwOwnershipPID = 0;
|
||
m_pkUniqueExpireEvent = NULL;
|
||
m_pkTimerBasedOnWearExpireEvent = NULL;
|
||
m_pkRealTimeExpireEvent = NULL;
|
||
|
||
m_pkAccessorySocketExpireEvent = NULL;
|
||
|
||
m_bSkipSave = false;
|
||
m_dwLastOwnerPID = 0;
|
||
}
|
||
|
||
void CItem::Destroy()
|
||
{
|
||
event_cancel(&m_pkDestroyEvent);
|
||
event_cancel(&m_pkOwnershipEvent);
|
||
event_cancel(&m_pkUniqueExpireEvent);
|
||
event_cancel(&m_pkTimerBasedOnWearExpireEvent);
|
||
event_cancel(&m_pkRealTimeExpireEvent);
|
||
event_cancel(&m_pkAccessorySocketExpireEvent);
|
||
|
||
CEntity::Destroy();
|
||
|
||
if (GetSectree())
|
||
GetSectree()->RemoveEntity(this);
|
||
}
|
||
|
||
EVENTFUNC(item_destroy_event)
|
||
{
|
||
item_event_info* info = dynamic_cast<item_event_info*>( event->info );
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "item_destroy_event> <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPITEM pkItem = info->item;
|
||
|
||
if (pkItem->GetOwner())
|
||
sys_err("item_destroy_event: Owner exist. (item %s owner %s)", pkItem->GetName(), pkItem->GetOwner()->GetName());
|
||
|
||
pkItem->SetDestroyEvent(NULL);
|
||
M2_DESTROY_ITEM(pkItem);
|
||
return 0;
|
||
}
|
||
|
||
void CItem::SetDestroyEvent(LPEVENT pkEvent)
|
||
{
|
||
m_pkDestroyEvent = pkEvent;
|
||
}
|
||
|
||
void CItem::StartDestroyEvent(int iSec)
|
||
{
|
||
if (m_pkDestroyEvent)
|
||
return;
|
||
|
||
item_event_info* info = AllocEventInfo<item_event_info>();
|
||
info->item = this;
|
||
|
||
SetDestroyEvent(event_create(item_destroy_event, info, PASSES_PER_SEC(iSec)));
|
||
}
|
||
|
||
void CItem::EncodeInsertPacket(LPENTITY ent)
|
||
{
|
||
LPDESC d;
|
||
|
||
if (!(d = ent->GetDesc()))
|
||
return;
|
||
|
||
const PIXEL_POSITION & c_pos = GetXYZ();
|
||
|
||
struct packet_item_ground_add pack;
|
||
|
||
pack.bHeader = HEADER_GC_ITEM_GROUND_ADD;
|
||
pack.x = c_pos.x;
|
||
pack.y = c_pos.y;
|
||
pack.z = c_pos.z;
|
||
pack.dwVnum = GetVnum();
|
||
pack.dwVID = m_dwVID;
|
||
//pack.count = m_dwCount;
|
||
|
||
d->Packet(&pack, sizeof(pack));
|
||
|
||
if (m_pkOwnershipEvent != NULL)
|
||
{
|
||
item_event_info * info = dynamic_cast<item_event_info *>(m_pkOwnershipEvent->info);
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "CItem::EncodeInsertPacket> <Factor> Null pointer" );
|
||
return;
|
||
}
|
||
|
||
TPacketGCItemOwnership p;
|
||
|
||
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
|
||
p.dwVID = m_dwVID;
|
||
strncpy(p.szName, info->szOwnerName, sizeof(p.szName));
|
||
|
||
d->Packet(&p, sizeof(TPacketGCItemOwnership));
|
||
}
|
||
}
|
||
|
||
void CItem::EncodeRemovePacket(LPENTITY ent)
|
||
{
|
||
LPDESC d;
|
||
|
||
if (!(d = ent->GetDesc()))
|
||
return;
|
||
|
||
struct packet_item_ground_del pack;
|
||
|
||
pack.bHeader = HEADER_GC_ITEM_GROUND_DEL;
|
||
pack.dwVID = m_dwVID;
|
||
|
||
d->Packet(&pack, sizeof(pack));
|
||
sys_log(2, "Item::EncodeRemovePacket %s to %s", GetName(), ((LPCHARACTER) ent)->GetName());
|
||
}
|
||
|
||
void CItem::SetProto(const TItemTable * table)
|
||
{
|
||
assert(table != NULL);
|
||
m_pProto = table;
|
||
SetFlag(m_pProto->dwFlags);
|
||
}
|
||
|
||
void CItem::UsePacketEncode(LPCHARACTER ch, LPCHARACTER victim, struct packet_item_use *packet)
|
||
{
|
||
if (!GetVnum())
|
||
return;
|
||
|
||
packet->header = HEADER_GC_ITEM_USE;
|
||
packet->ch_vid = ch->GetVID();
|
||
packet->victim_vid = victim->GetVID();
|
||
packet->Cell = TItemPos(GetWindow(), m_wCell);
|
||
packet->vnum = GetVnum();
|
||
}
|
||
|
||
void CItem::RemoveFlag(int bit)
|
||
{
|
||
REMOVE_BIT(m_lFlag, bit);
|
||
}
|
||
|
||
void CItem::AddFlag(int bit)
|
||
{
|
||
SET_BIT(m_lFlag, bit);
|
||
}
|
||
|
||
void CItem::UpdatePacket()
|
||
{
|
||
if (!m_pOwner || !m_pOwner->GetDesc())
|
||
return;
|
||
|
||
TPacketGCItemUpdate pack;
|
||
|
||
pack.header = HEADER_GC_ITEM_UPDATE;
|
||
pack.Cell = TItemPos(GetWindow(), m_wCell);
|
||
pack.count = m_dwCount;
|
||
|
||
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
|
||
pack.alSockets[i] = m_alSockets[i];
|
||
|
||
memcpy(pack.aAttr, GetAttributes(), sizeof(pack.aAttr));
|
||
|
||
sys_log(2, "UpdatePacket %s -> %s", GetName(), m_pOwner->GetName());
|
||
m_pOwner->GetDesc()->Packet(&pack, sizeof(pack));
|
||
}
|
||
|
||
DWORD CItem::GetCount()
|
||
{
|
||
if (GetType() == ITEM_ELK) return MIN(m_dwCount, INT_MAX);
|
||
else
|
||
{
|
||
return MIN(m_dwCount, 200);
|
||
}
|
||
}
|
||
|
||
bool CItem::SetCount(DWORD count)
|
||
{
|
||
if (GetType() == ITEM_ELK)
|
||
{
|
||
m_dwCount = MIN(count, INT_MAX);
|
||
}
|
||
else
|
||
{
|
||
m_dwCount = MIN(count, ITEM_MAX_COUNT);
|
||
}
|
||
|
||
if (count == 0 && m_pOwner)
|
||
{
|
||
if (GetSubType() == USE_ABILITY_UP || GetSubType() == USE_POTION || GetVnum() == 70020)
|
||
{
|
||
LPCHARACTER pOwner = GetOwner();
|
||
WORD wCell = GetCell();
|
||
|
||
RemoveFromCharacter();
|
||
|
||
if (!IsDragonSoul())
|
||
{
|
||
LPITEM pItem = pOwner->FindSpecifyItem(GetVnum());
|
||
|
||
if (NULL != pItem)
|
||
{
|
||
pOwner->ChainQuickslotItem(pItem, QUICKSLOT_TYPE_ITEM, wCell);
|
||
}
|
||
else
|
||
{
|
||
pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 255);
|
||
}
|
||
}
|
||
|
||
M2_DESTROY_ITEM(this);
|
||
}
|
||
else
|
||
{
|
||
if (!IsDragonSoul())
|
||
{
|
||
m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 255);
|
||
}
|
||
M2_DESTROY_ITEM(RemoveFromCharacter());
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
UpdatePacket();
|
||
|
||
Save();
|
||
return true;
|
||
}
|
||
|
||
LPITEM CItem::RemoveFromCharacter()
|
||
{
|
||
if (!m_pOwner)
|
||
{
|
||
sys_err("Item::RemoveFromCharacter owner null");
|
||
return (this);
|
||
}
|
||
|
||
LPCHARACTER pOwner = m_pOwner;
|
||
|
||
if (m_bEquipped) // <20><><EFBFBD><EFBFBD><EFBFBD>Ǿ<EFBFBD><C7BE>°<EFBFBD>?
|
||
{
|
||
Unequip();
|
||
//pOwner->UpdatePacket();
|
||
|
||
SetWindow(RESERVED_WINDOW);
|
||
Save();
|
||
return (this);
|
||
}
|
||
else
|
||
{
|
||
if (GetWindow() != SAFEBOX && GetWindow() != MALL)
|
||
{
|
||
if (IsDragonSoul())
|
||
{
|
||
if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
|
||
sys_err("CItem::RemoveFromCharacter: pos >= DRAGON_SOUL_INVENTORY_MAX_NUM");
|
||
else
|
||
pOwner->SetItem(TItemPos(m_bWindow, m_wCell), NULL);
|
||
}
|
||
else
|
||
{
|
||
TItemPos cell(INVENTORY, m_wCell);
|
||
|
||
if (false == cell.IsDefaultInventoryPosition() && false == cell.IsBeltInventoryPosition()) // <20>ƴϸ<C6B4> <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>?
|
||
sys_err("CItem::RemoveFromCharacter: Invalid Item Position");
|
||
else
|
||
{
|
||
pOwner->SetItem(cell, NULL);
|
||
}
|
||
}
|
||
}
|
||
|
||
m_pOwner = NULL;
|
||
m_wCell = 0;
|
||
|
||
SetWindow(RESERVED_WINDOW);
|
||
Save();
|
||
return (this);
|
||
}
|
||
}
|
||
|
||
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell)
|
||
{
|
||
assert(GetSectree() == NULL);
|
||
assert(m_pOwner == NULL);
|
||
WORD pos = Cell.cell;
|
||
BYTE window_type = Cell.window_type;
|
||
|
||
if (INVENTORY == window_type)
|
||
{
|
||
if (m_wCell >= INVENTORY_MAX_NUM && BELT_INVENTORY_SLOT_START > m_wCell)
|
||
{
|
||
sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
|
||
return false;
|
||
}
|
||
}
|
||
else if (DRAGON_SOUL_INVENTORY == window_type)
|
||
{
|
||
if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
|
||
{
|
||
sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if (ch->GetDesc())
|
||
m_dwLastOwnerPID = ch->GetPlayerID();
|
||
|
||
event_cancel(&m_pkDestroyEvent);
|
||
|
||
ch->SetItem(TItemPos(window_type, pos), this);
|
||
m_pOwner = ch;
|
||
|
||
Save();
|
||
return true;
|
||
}
|
||
|
||
LPITEM CItem::RemoveFromGround()
|
||
{
|
||
if (GetSectree())
|
||
{
|
||
SetOwnership(NULL);
|
||
|
||
GetSectree()->RemoveEntity(this);
|
||
|
||
ViewCleanup();
|
||
|
||
Save();
|
||
}
|
||
|
||
return (this);
|
||
}
|
||
|
||
bool CItem::AddToGround(int lMapIndex, const PIXEL_POSITION & pos, bool skipOwnerCheck)
|
||
{
|
||
if (0 == lMapIndex)
|
||
{
|
||
sys_err("wrong map index argument: %d", lMapIndex);
|
||
return false;
|
||
}
|
||
|
||
if (GetSectree())
|
||
{
|
||
sys_err("sectree already assigned");
|
||
return false;
|
||
}
|
||
|
||
if (!skipOwnerCheck && m_pOwner)
|
||
{
|
||
sys_err("owner pointer not null");
|
||
return false;
|
||
}
|
||
|
||
LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, pos.x, pos.y);
|
||
|
||
if (!tree)
|
||
{
|
||
sys_err("cannot find sectree by %dx%d", pos.x, pos.y);
|
||
return false;
|
||
}
|
||
|
||
//tree->Touch();
|
||
|
||
SetWindow(GROUND);
|
||
SetXYZ(pos.x, pos.y, pos.z);
|
||
tree->InsertEntity(this);
|
||
UpdateSectree();
|
||
Save();
|
||
return true;
|
||
}
|
||
|
||
bool CItem::DistanceValid(LPCHARACTER ch)
|
||
{
|
||
if (!GetSectree())
|
||
return false;
|
||
|
||
int iDist = DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY());
|
||
|
||
if (iDist > 300)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CItem::CanUsedBy(LPCHARACTER ch)
|
||
{
|
||
// Anti flag check
|
||
switch (ch->GetJob())
|
||
{
|
||
case JOB_WARRIOR:
|
||
if (GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR)
|
||
return false;
|
||
break;
|
||
|
||
case JOB_ASSASSIN:
|
||
if (GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN)
|
||
return false;
|
||
break;
|
||
|
||
case JOB_SHAMAN:
|
||
if (GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN)
|
||
return false;
|
||
break;
|
||
|
||
case JOB_SURA:
|
||
if (GetAntiFlag() & ITEM_ANTIFLAG_SURA)
|
||
return false;
|
||
break;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
|
||
{
|
||
// <20>ڽ<EFBFBD><DABD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(ITEM_COSTUME)<29><> WearFlag <20><><EFBFBD> <20><>. (sub type<70><65><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> wear flag <20><> <20>ʿ䰡 <20>ֳ<EFBFBD>..)
|
||
// <20><>ȥ<EFBFBD><C8A5>(ITEM_DS, ITEM_SPECIAL_DS)<29><> SUB_TYPE<50><45><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>. <20>ű<EFBFBD> <20><><EFBFBD><EFBFBD>, <20><>Ʈ<EFBFBD><C6AE> ITEM_TYPE<50><45><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> -_-
|
||
if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
|
||
return -1;
|
||
|
||
// <20><>ȥ<EFBFBD><C8A5> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> WEAR<41><52> ó<><C3B3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>(WEAR<41><52> <20>ִ<EFBFBD> 32<33><32><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ѵ<EFBFBD> <20><>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD> <20>߰<EFBFBD><DFB0>ϸ<EFBFBD> 32<33><32> <20>Ѵ´<D1B4>.)
|
||
// <20>κ<EFBFBD><CEBA>丮<EFBFBD><E4B8AE> Ư<><C6AF> <20><>ġ((INVENTORY_MAX_NUM + WEAR_MAX_NUM)<29><><EFBFBD><EFBFBD> (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)<29><><EFBFBD><EFBFBD>)<29><>
|
||
// <20><>ȥ<EFBFBD><C8A5> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>.
|
||
// return <20><> <20><><EFBFBD><EFBFBD>, INVENTORY_MAX_NUM<55><4D> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,
|
||
// <20><><EFBFBD><EFBFBD> WearCell<6C><6C> INVENTORY_MAX_NUM<55><4D> <20><><EFBFBD><EFBFBD> return <20>ϱ<EFBFBD> <20><><EFBFBD><EFBFBD>.
|
||
if (GetType() == ITEM_DS || GetType() == ITEM_SPECIAL_DS)
|
||
{
|
||
if (iCandidateCell < 0)
|
||
{
|
||
return WEAR_MAX_NUM + GetSubType();
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < DRAGON_SOUL_DECK_MAX_NUM; i++)
|
||
{
|
||
if (WEAR_MAX_NUM + i * DS_SLOT_MAX + GetSubType() == iCandidateCell)
|
||
{
|
||
return iCandidateCell;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
}
|
||
else if (GetType() == ITEM_COSTUME)
|
||
{
|
||
if (GetSubType() == COSTUME_BODY)
|
||
return WEAR_COSTUME_BODY;
|
||
else if (GetSubType() == COSTUME_HAIR)
|
||
return WEAR_COSTUME_HAIR;
|
||
}
|
||
else if (GetType() == ITEM_RING)
|
||
{
|
||
if (ch->GetWear(WEAR_RING1))
|
||
return WEAR_RING2;
|
||
else
|
||
return WEAR_RING1;
|
||
}
|
||
else if (GetType() == ITEM_BELT)
|
||
return WEAR_BELT;
|
||
else if (GetWearFlag() & WEARABLE_BODY)
|
||
return WEAR_BODY;
|
||
else if (GetWearFlag() & WEARABLE_HEAD)
|
||
return WEAR_HEAD;
|
||
else if (GetWearFlag() & WEARABLE_FOOTS)
|
||
return WEAR_FOOTS;
|
||
else if (GetWearFlag() & WEARABLE_WRIST)
|
||
return WEAR_WRIST;
|
||
else if (GetWearFlag() & WEARABLE_WEAPON)
|
||
return WEAR_WEAPON;
|
||
else if (GetWearFlag() & WEARABLE_SHIELD)
|
||
return WEAR_SHIELD;
|
||
else if (GetWearFlag() & WEARABLE_NECK)
|
||
return WEAR_NECK;
|
||
else if (GetWearFlag() & WEARABLE_EAR)
|
||
return WEAR_EAR;
|
||
else if (GetWearFlag() & WEARABLE_ARROW)
|
||
return WEAR_ARROW;
|
||
else if (GetWearFlag() & WEARABLE_UNIQUE)
|
||
{
|
||
if (ch->GetWear(WEAR_UNIQUE1))
|
||
return WEAR_UNIQUE2;
|
||
else
|
||
return WEAR_UNIQUE1;
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>°<EFBFBD><C2B0><EFBFBD><EFBFBD><EFBFBD> <20>ѹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ?E<><45> <20><><EFBFBD><EFBFBD>.
|
||
else if (GetWearFlag() & WEARABLE_ABILITY)
|
||
{
|
||
if (!ch->GetWear(WEAR_ABILITY1))
|
||
{
|
||
return WEAR_ABILITY1;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY2))
|
||
{
|
||
return WEAR_ABILITY2;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY3))
|
||
{
|
||
return WEAR_ABILITY3;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY4))
|
||
{
|
||
return WEAR_ABILITY4;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY5))
|
||
{
|
||
return WEAR_ABILITY5;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY6))
|
||
{
|
||
return WEAR_ABILITY6;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY7))
|
||
{
|
||
return WEAR_ABILITY7;
|
||
}
|
||
else if (!ch->GetWear(WEAR_ABILITY8))
|
||
{
|
||
return WEAR_ABILITY8;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
void CItem::ModifyPoints(bool bAdd)
|
||
{
|
||
int accessoryGrade;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ʸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ų<EFBFBD><C5B2>.
|
||
if (false == IsAccessoryForSocket())
|
||
{
|
||
if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD><D3BC><EFBFBD>ȭ<EFBFBD><C8AD> <20><><EFBFBD><EFBFBD><EFBFBD>Ǵ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4> (ARMOR_WRIST ARMOR_NECK ARMOR_EAR)
|
||
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
|
||
{
|
||
DWORD dwVnum;
|
||
|
||
if ((dwVnum = GetSocket(i)) <= 2)
|
||
continue;
|
||
|
||
TItemTable * p = ITEM_MANAGER::instance().GetTable(dwVnum);
|
||
|
||
if (!p)
|
||
{
|
||
sys_err("cannot find table by vnum %u", dwVnum);
|
||
continue;
|
||
}
|
||
|
||
if (ITEM_METIN == p->bType)
|
||
{
|
||
//m_pOwner->ApplyPoint(p->alValues[0], bAdd ? p->alValues[1] : -p->alValues[1]);
|
||
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
|
||
{
|
||
if (p->aApplies[i].bType == APPLY_NONE)
|
||
continue;
|
||
|
||
if (p->aApplies[i].bType == APPLY_SKILL)
|
||
m_pOwner->ApplyPoint(p->aApplies[i].bType, bAdd ? p->aApplies[i].lValue : p->aApplies[i].lValue ^ 0x00800000);
|
||
else
|
||
m_pOwner->ApplyPoint(p->aApplies[i].bType, bAdd ? p->aApplies[i].lValue : -p->aApplies[i].lValue);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
accessoryGrade = 0;
|
||
}
|
||
else
|
||
{
|
||
accessoryGrade = MIN(GetAccessorySocketGrade(), ITEM_ACCESSORY_SOCKET_MAX_NUM);
|
||
}
|
||
|
||
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
|
||
{
|
||
if (m_pProto->aApplies[i].bType == APPLY_NONE)
|
||
continue;
|
||
|
||
int value = m_pProto->aApplies[i].lValue;
|
||
|
||
if (m_pProto->aApplies[i].bType == APPLY_SKILL)
|
||
{
|
||
m_pOwner->ApplyPoint(m_pProto->aApplies[i].bType, bAdd ? value : value ^ 0x00800000);
|
||
}
|
||
else
|
||
{
|
||
if (0 != accessoryGrade)
|
||
value += MAX(accessoryGrade, value * aiAccessorySocketEffectivePct[accessoryGrade] / 100);
|
||
|
||
m_pOwner->ApplyPoint(m_pProto->aApplies[i].bType, bAdd ? value : -value);
|
||
}
|
||
}
|
||
// <20>ʽ´<CABD><C2B4><EFBFBD> <20><><EFBFBD><EFBFBD>, <20>ҷ<EFBFBD><D2B7><EFBFBD> <20><><EFBFBD><EFBFBD>, <20>ູ<EFBFBD><E0BAB9> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ϵ<EFBFBD> <20>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD><D3BC><EFBFBD> <20>ο<EFBFBD><CEBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,
|
||
// <20><> <20>κ<EFBFBD><CEBA><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> special item group <20><><EFBFBD>̺<EFBFBD><CCBA><EFBFBD><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD><D3BC><EFBFBD> <20>ο<EFBFBD><CEBF>ϵ<EFBFBD><CFB5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD>.
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ϵ<EFBFBD> <20>ڵ<EFBFBD><DAB5>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>־ Ư<><C6AF>ó<EFBFBD><C3B3> <20>س<EFBFBD><D8B3>´<EFBFBD>.
|
||
// <20><> <20><><EFBFBD><EFBFBD><EFBFBD>۵<EFBFBD><DBB5><EFBFBD> <20><><EFBFBD><EFBFBD>, <20>ؿ<EFBFBD> ITEM_UNIQUE<55><45> <20><><EFBFBD><EFBFBD> ó<><C3B3><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD><D3BC><EFBFBD> <20>ο<EFBFBD><CEBF>DZ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>ۿ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD> attribute<74><65> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʰ<EFBFBD> <20>Ѿ<D1BE><EEB0A3>.
|
||
if (true == CItemVnumHelper::IsRamadanMoonRing(GetVnum()) || true == CItemVnumHelper::IsHalloweenCandy(GetVnum())
|
||
|| true == CItemVnumHelper::IsHappinessRing(GetVnum()) || true == CItemVnumHelper::IsLovePendant(GetVnum()))
|
||
{
|
||
// Do not anything.
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
|
||
{
|
||
if (GetAttributeType(i))
|
||
{
|
||
const TPlayerItemAttribute& ia = GetAttribute(i);
|
||
|
||
if (ia.bType == APPLY_SKILL)
|
||
m_pOwner->ApplyPoint(ia.bType, bAdd ? ia.sValue : ia.sValue ^ 0x00800000);
|
||
else
|
||
m_pOwner->ApplyPoint(ia.bType, bAdd ? ia.sValue : -ia.sValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
switch (m_pProto->bType)
|
||
{
|
||
case ITEM_PICK:
|
||
case ITEM_ROD:
|
||
{
|
||
if (bAdd)
|
||
{
|
||
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
|
||
m_pOwner->SetPart(PART_WEAPON, GetVnum());
|
||
}
|
||
else
|
||
{
|
||
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
|
||
m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON));
|
||
}
|
||
}
|
||
break;
|
||
|
||
case ITEM_WEAPON:
|
||
{
|
||
if (bAdd)
|
||
{
|
||
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
|
||
m_pOwner->SetPart(PART_WEAPON, GetVnum());
|
||
}
|
||
else
|
||
{
|
||
if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
|
||
m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON));
|
||
}
|
||
}
|
||
break;
|
||
|
||
case ITEM_ARMOR:
|
||
{
|
||
// <20>ڽ<EFBFBD><DABD><EFBFBD> body<64><79> <20><EFBFBD><D4B0>ִٸ<D6B4> armor<6F><72> <20><><EFBFBD><EFBFBD> <20>Դ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>־<EFBFBD><D6BE><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ָ<EFBFBD> <20><> <20><>.
|
||
if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
|
||
break;
|
||
|
||
if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD)
|
||
{
|
||
if (bAdd)
|
||
{
|
||
if (GetProto()->bSubType == ARMOR_BODY)
|
||
m_pOwner->SetPart(PART_MAIN, GetVnum());
|
||
}
|
||
else
|
||
{
|
||
if (GetProto()->bSubType == ARMOR_BODY)
|
||
m_pOwner->SetPart(PART_MAIN, m_pOwner->GetOriginalPart(PART_MAIN));
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
// <20>ڽ<EFBFBD><DABD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ծ<EFBFBD><D4BE><EFBFBD> <20><> ij<><C4B3><EFBFBD><EFBFBD> parts <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD> <20><>Ÿ<EFBFBD>ϴ<EFBFBD><CFB4><EFBFBD> <20>߰<EFBFBD><DFB0><EFBFBD>..
|
||
case ITEM_COSTUME:
|
||
{
|
||
DWORD toSetValue = this->GetVnum();
|
||
EParts toSetPart = PART_MAX_NUM;
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20>ڽ<EFBFBD><DABD><EFBFBD>
|
||
if (GetSubType() == COSTUME_BODY)
|
||
{
|
||
toSetPart = PART_MAIN;
|
||
|
||
if (false == bAdd)
|
||
{
|
||
// <20>ڽ<EFBFBD><DABD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD> <20>־<EFBFBD><D6BE>ٸ<EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> look <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> <20>ʾҴٸ<D2B4> default look
|
||
const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
|
||
toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
|
||
}
|
||
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20>ڽ<EFBFBD><DABD><EFBFBD>
|
||
else if (GetSubType() == COSTUME_HAIR)
|
||
{
|
||
toSetPart = PART_HAIR;
|
||
|
||
// <20>ڽ<EFBFBD><DABD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> shape<70><65><EFBFBD><EFBFBD> item proto<74><6F> value3<65><33> <20><><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD> <20><>. Ư<><C6AF><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>(ARMOR_BODY)<29><> shape<70><65><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> value3<65><33> <20>־ <20><><EFBFBD> <20><><EFBFBD><EFBFBD> value3<65><33><EFBFBD><EFBFBD> <20><>.
|
||
// [NOTE] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> vnum<75><6D> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> shape(value3)<29><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.. <20><><EFBFBD><EFBFBD> <20>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD><D7B7><EFBFBD> <20>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD><EFBFBD>...
|
||
toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
|
||
}
|
||
|
||
if (PART_MAX_NUM != toSetPart)
|
||
{
|
||
m_pOwner->SetPart((BYTE)toSetPart, toSetValue);
|
||
m_pOwner->UpdatePacket();
|
||
}
|
||
}
|
||
break;
|
||
case ITEM_UNIQUE:
|
||
{
|
||
if (0 != GetSIGVnum())
|
||
{
|
||
const CSpecialItemGroup* pItemGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(GetSIGVnum());
|
||
if (NULL == pItemGroup)
|
||
break;
|
||
DWORD dwAttrVnum = pItemGroup->GetAttrVnum(GetVnum());
|
||
const CSpecialAttrGroup* pAttrGroup = ITEM_MANAGER::instance().GetSpecialAttrGroup(dwAttrVnum);
|
||
if (NULL == pAttrGroup)
|
||
break;
|
||
for (itertype (pAttrGroup->m_vecAttrs) it = pAttrGroup->m_vecAttrs.begin(); it != pAttrGroup->m_vecAttrs.end(); it++)
|
||
{
|
||
m_pOwner->ApplyPoint(it->apply_type, bAdd ? it->apply_value : -it->apply_value);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
bool CItem::IsEquipable() const
|
||
{
|
||
switch (this->GetType())
|
||
{
|
||
case ITEM_COSTUME:
|
||
case ITEM_ARMOR:
|
||
case ITEM_WEAPON:
|
||
case ITEM_ROD:
|
||
case ITEM_PICK:
|
||
case ITEM_UNIQUE:
|
||
case ITEM_DS:
|
||
case ITEM_SPECIAL_DS:
|
||
case ITEM_RING:
|
||
case ITEM_BELT:
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// return false on error state
|
||
bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
|
||
{
|
||
if (!ch)
|
||
{
|
||
sys_err("EquipTo: nil character");
|
||
return false;
|
||
}
|
||
|
||
// <20><>ȥ<EFBFBD><C8A5> <20><><EFBFBD><EFBFBD> index<65><78> WEAR_MAX_NUM <20><><EFBFBD><EFBFBD> ŭ.
|
||
if (IsDragonSoul())
|
||
{
|
||
if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
|
||
{
|
||
sys_err("EquipTo: invalid dragon soul cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetSubType(), bWearCell - WEAR_MAX_NUM);
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (bWearCell >= WEAR_MAX_NUM)
|
||
{
|
||
sys_err("EquipTo: invalid wear cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetWearFlag(), bWearCell);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if (ch->GetWear(bWearCell))
|
||
{
|
||
sys_err("EquipTo: item already exist (this: #%d %s cell: %d %s)", GetOriginalVnum(), GetName(), bWearCell, ch->GetWear(bWearCell)->GetName());
|
||
return false;
|
||
}
|
||
|
||
if (GetOwner())
|
||
RemoveFromCharacter();
|
||
|
||
ch->SetWear(bWearCell, this); // <20><><EFBFBD>⼭ <20><>Ŷ <20><><EFBFBD><EFBFBD>
|
||
|
||
m_pOwner = ch;
|
||
m_bEquipped = true;
|
||
m_wCell = INVENTORY_MAX_NUM + bWearCell;
|
||
|
||
DWORD dwImmuneFlag = 0;
|
||
|
||
for (int i = 0; i < WEAR_MAX_NUM; ++i)
|
||
if (m_pOwner->GetWear(i))
|
||
SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
|
||
|
||
m_pOwner->SetImmuneFlag(dwImmuneFlag);
|
||
|
||
if (IsDragonSoul())
|
||
{
|
||
DSManager::instance().ActivateDragonSoul(this);
|
||
}
|
||
else
|
||
{
|
||
ModifyPoints(true);
|
||
StartUniqueExpireEvent();
|
||
if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
|
||
StartTimerBasedOnWearExpireEvent();
|
||
|
||
// ACCESSORY_REFINE
|
||
StartAccessorySocketExpireEvent();
|
||
// END_OF_ACCESSORY_REFINE
|
||
}
|
||
|
||
ch->BuffOnAttr_AddBuffsFromItem(this);
|
||
|
||
m_pOwner->ComputeBattlePoints();
|
||
|
||
m_pOwner->UpdatePacket();
|
||
|
||
Save();
|
||
|
||
return (true);
|
||
}
|
||
|
||
bool CItem::Unequip()
|
||
{
|
||
if (!m_pOwner || GetCell() < INVENTORY_MAX_NUM)
|
||
{
|
||
// ITEM_OWNER_INVALID_PTR_BUG
|
||
sys_err("%s %u m_pOwner %p, GetCell %d",
|
||
GetName(), GetID(), get_pointer(m_pOwner), GetCell());
|
||
// END_OF_ITEM_OWNER_INVALID_PTR_BUG
|
||
return false;
|
||
}
|
||
|
||
if (this != m_pOwner->GetWear(GetCell() - INVENTORY_MAX_NUM))
|
||
{
|
||
sys_err("m_pOwner->GetWear() != this");
|
||
return false;
|
||
}
|
||
|
||
//<2F>ű<EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>Ž<EFBFBD> ó<><C3B3>
|
||
if (IsRideItem())
|
||
ClearMountAttributeAndAffect();
|
||
|
||
if (IsDragonSoul())
|
||
{
|
||
DSManager::instance().DeactivateDragonSoul(this);
|
||
}
|
||
else
|
||
{
|
||
ModifyPoints(false);
|
||
}
|
||
|
||
StopUniqueExpireEvent();
|
||
|
||
if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
|
||
StopTimerBasedOnWearExpireEvent();
|
||
|
||
// ACCESSORY_REFINE
|
||
StopAccessorySocketExpireEvent();
|
||
// END_OF_ACCESSORY_REFINE
|
||
|
||
|
||
m_pOwner->BuffOnAttr_RemoveBuffsFromItem(this);
|
||
|
||
m_pOwner->SetWear(GetCell() - INVENTORY_MAX_NUM, NULL);
|
||
|
||
DWORD dwImmuneFlag = 0;
|
||
|
||
for (int i = 0; i < WEAR_MAX_NUM; ++i)
|
||
if (m_pOwner->GetWear(i))
|
||
SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
|
||
|
||
m_pOwner->SetImmuneFlag(dwImmuneFlag);
|
||
|
||
m_pOwner->ComputeBattlePoints();
|
||
|
||
m_pOwner->UpdatePacket();
|
||
|
||
m_pOwner = NULL;
|
||
m_wCell = 0;
|
||
m_bEquipped = false;
|
||
|
||
return true;
|
||
}
|
||
|
||
int CItem::GetValue(DWORD idx)
|
||
{
|
||
assert(idx < ITEM_VALUES_MAX_NUM);
|
||
return GetProto()->alValues[idx];
|
||
}
|
||
|
||
void CItem::SetExchanging(bool bOn)
|
||
{
|
||
m_bExchanging = bOn;
|
||
}
|
||
|
||
void CItem::Save()
|
||
{
|
||
if (m_bSkipSave)
|
||
return;
|
||
|
||
ITEM_MANAGER::instance().DelayedSave(this);
|
||
}
|
||
|
||
bool CItem::CreateSocket(BYTE bSlot, BYTE bGold)
|
||
{
|
||
assert(bSlot < ITEM_SOCKET_MAX_NUM);
|
||
|
||
if (m_alSockets[bSlot] != 0)
|
||
{
|
||
sys_err("Item::CreateSocket : socket already exist %s %d", GetName(), bSlot);
|
||
return false;
|
||
}
|
||
|
||
if (bGold)
|
||
m_alSockets[bSlot] = 2;
|
||
else
|
||
m_alSockets[bSlot] = 1;
|
||
|
||
UpdatePacket();
|
||
|
||
Save();
|
||
return true;
|
||
}
|
||
|
||
void CItem::SetSockets(const LONG * c_al)
|
||
{
|
||
memcpy(m_alSockets, c_al, sizeof(m_alSockets));
|
||
Save();
|
||
}
|
||
|
||
void CItem::SetSocket(int i, int v, bool bLog)
|
||
{
|
||
assert(i < ITEM_SOCKET_MAX_NUM);
|
||
m_alSockets[i] = v;
|
||
UpdatePacket();
|
||
Save();
|
||
if (bLog)
|
||
LogManager::instance().ItemLog(i, v, 0, GetID(), "SET_SOCKET", "", "", GetOriginalVnum());
|
||
}
|
||
|
||
int CItem::GetGold()
|
||
{
|
||
if (IS_SET(GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
|
||
{
|
||
if (GetProto()->dwGold == 0)
|
||
return GetCount();
|
||
else
|
||
return GetCount() / GetProto()->dwGold;
|
||
}
|
||
else
|
||
return GetProto()->dwGold;
|
||
}
|
||
|
||
int CItem::GetShopBuyPrice()
|
||
{
|
||
return GetProto()->dwShopBuyPrice;
|
||
}
|
||
|
||
bool CItem::IsOwnership(LPCHARACTER ch)
|
||
{
|
||
if (!m_pkOwnershipEvent)
|
||
return true;
|
||
|
||
return m_dwOwnershipPID == ch->GetPlayerID() ? true : false;
|
||
}
|
||
|
||
EVENTFUNC(ownership_event)
|
||
{
|
||
item_event_info* info = dynamic_cast<item_event_info*>( event->info );
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "ownership_event> <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPITEM pkItem = info->item;
|
||
|
||
pkItem->SetOwnershipEvent(NULL);
|
||
|
||
TPacketGCItemOwnership p;
|
||
|
||
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
|
||
p.dwVID = pkItem->GetVID();
|
||
p.szName[0] = '\0';
|
||
|
||
pkItem->PacketAround(&p, sizeof(p));
|
||
return 0;
|
||
}
|
||
|
||
void CItem::SetOwnershipEvent(LPEVENT pkEvent)
|
||
{
|
||
m_pkOwnershipEvent = pkEvent;
|
||
}
|
||
|
||
void CItem::SetOwnership(LPCHARACTER ch, int iSec)
|
||
{
|
||
if (!ch)
|
||
{
|
||
if (m_pkOwnershipEvent)
|
||
{
|
||
event_cancel(&m_pkOwnershipEvent);
|
||
m_dwOwnershipPID = 0;
|
||
|
||
TPacketGCItemOwnership p;
|
||
|
||
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
|
||
p.dwVID = m_dwVID;
|
||
p.szName[0] = '\0';
|
||
|
||
PacketAround(&p, sizeof(p));
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (m_pkOwnershipEvent)
|
||
return;
|
||
|
||
if (true == LC_IsEurope())
|
||
{
|
||
if (iSec <= 10)
|
||
iSec = 30;
|
||
}
|
||
|
||
m_dwOwnershipPID = ch->GetPlayerID();
|
||
|
||
item_event_info* info = AllocEventInfo<item_event_info>();
|
||
strncpy(info->szOwnerName, ch->GetName(), sizeof(info->szOwnerName));
|
||
info->item = this;
|
||
|
||
SetOwnershipEvent(event_create(ownership_event, info, PASSES_PER_SEC(iSec)));
|
||
|
||
TPacketGCItemOwnership p;
|
||
|
||
p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
|
||
p.dwVID = m_dwVID;
|
||
strncpy(p.szName, ch->GetName(), sizeof(p.szName));
|
||
|
||
PacketAround(&p, sizeof(p));
|
||
}
|
||
|
||
int CItem::GetSocketCount()
|
||
{
|
||
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
|
||
{
|
||
if (GetSocket(i) == 0)
|
||
return i;
|
||
}
|
||
return ITEM_SOCKET_MAX_NUM;
|
||
}
|
||
|
||
bool CItem::AddSocket()
|
||
{
|
||
int count = GetSocketCount();
|
||
if (count == ITEM_SOCKET_MAX_NUM)
|
||
return false;
|
||
m_alSockets[count] = 1;
|
||
return true;
|
||
}
|
||
|
||
void CItem::AlterToSocketItem(int iSocketCount)
|
||
{
|
||
if (iSocketCount >= ITEM_SOCKET_MAX_NUM)
|
||
{
|
||
sys_log(0, "Invalid Socket Count %d, set to maximum", ITEM_SOCKET_MAX_NUM);
|
||
iSocketCount = ITEM_SOCKET_MAX_NUM;
|
||
}
|
||
|
||
for (int i = 0; i < iSocketCount; ++i)
|
||
SetSocket(i, 1);
|
||
}
|
||
|
||
void CItem::AlterToMagicItem()
|
||
{
|
||
int idx = GetAttributeSetIndex();
|
||
|
||
if (idx < 0)
|
||
return;
|
||
|
||
// Appeariance Second Third
|
||
// Weapon 50 20 5
|
||
// Armor 30 10 2
|
||
// Acc 20 10 1
|
||
|
||
int iSecondPct;
|
||
int iThirdPct;
|
||
|
||
if (g_iUseLocale)
|
||
{
|
||
switch (GetType())
|
||
{
|
||
case ITEM_WEAPON:
|
||
iSecondPct = 20;
|
||
iThirdPct = 5;
|
||
break;
|
||
|
||
case ITEM_ARMOR:
|
||
case ITEM_COSTUME:
|
||
if (GetSubType() == ARMOR_BODY)
|
||
{
|
||
iSecondPct = 10;
|
||
iThirdPct = 2;
|
||
}
|
||
else
|
||
{
|
||
iSecondPct = 10;
|
||
iThirdPct = 1;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch (GetType())
|
||
{
|
||
case ITEM_WEAPON:
|
||
iSecondPct = 30;
|
||
iThirdPct = 15;
|
||
break;
|
||
|
||
case ITEM_ARMOR:
|
||
case ITEM_COSTUME:
|
||
if (GetSubType() == ARMOR_BODY)
|
||
{
|
||
iSecondPct = 20;
|
||
iThirdPct = 10;
|
||
}
|
||
else
|
||
{
|
||
iSecondPct = 10;
|
||
iThirdPct = 5;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 100% Ȯ<><C8AE><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD> <20>ϳ<EFBFBD>
|
||
PutAttribute(aiItemMagicAttributePercentHigh);
|
||
|
||
if (number(1, 100) <= iSecondPct)
|
||
PutAttribute(aiItemMagicAttributePercentLow);
|
||
|
||
if (number(1, 100) <= iThirdPct)
|
||
PutAttribute(aiItemMagicAttributePercentLow);
|
||
}
|
||
|
||
DWORD CItem::GetRefineFromVnum()
|
||
{
|
||
return ITEM_MANAGER::instance().GetRefineFromVnum(GetVnum());
|
||
}
|
||
|
||
int CItem::GetRefineLevel()
|
||
{
|
||
const char* name = GetBaseName();
|
||
char* p = const_cast<char*>(strrchr(name, '+'));
|
||
|
||
if (!p)
|
||
return 0;
|
||
|
||
int rtn = 0;
|
||
str_to_number(rtn, p+1);
|
||
|
||
const char* locale_name = GetName();
|
||
p = const_cast<char*>(strrchr(locale_name, '+'));
|
||
|
||
if (p)
|
||
{
|
||
int locale_rtn = 0;
|
||
str_to_number(locale_rtn, p+1);
|
||
if (locale_rtn != rtn)
|
||
{
|
||
sys_err("refine_level_based_on_NAME(%d) is not equal to refine_level_based_on_LOCALE_NAME(%d).", rtn, locale_rtn);
|
||
}
|
||
}
|
||
|
||
return rtn;
|
||
}
|
||
|
||
bool CItem::IsPolymorphItem()
|
||
{
|
||
return GetType() == ITEM_POLYMORPH;
|
||
}
|
||
|
||
EVENTFUNC(unique_expire_event)
|
||
{
|
||
item_event_info* info = dynamic_cast<item_event_info*>( event->info );
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "unique_expire_event> <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPITEM pkItem = info->item;
|
||
|
||
if (pkItem->GetValue(2) == 0)
|
||
{
|
||
if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= 1)
|
||
{
|
||
sys_log(0, "UNIQUE_ITEM: expire %s %u", pkItem->GetName(), pkItem->GetID());
|
||
pkItem->SetUniqueExpireEvent(NULL);
|
||
ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
pkItem->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - 1);
|
||
return PASSES_PER_SEC(60);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
time_t cur = get_global_time();
|
||
|
||
if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= cur)
|
||
{
|
||
pkItem->SetUniqueExpireEvent(NULL);
|
||
ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD><C3B0><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>۵<EFBFBD><DBB5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ<EFBFBD> <20><><EFBFBD>װ<EFBFBD> <20>־<EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD>
|
||
// by rtsummit
|
||
if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur < 600)
|
||
return PASSES_PER_SEC(pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur);
|
||
else
|
||
return PASSES_PER_SEC(600);
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20>ð<EFBFBD> <20>ĺ<EFBFBD><C4BA><EFBFBD>
|
||
// timer<65><72> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ƴ϶<C6B4>,
|
||
// timer<65><72> <20><>ȭ<EFBFBD><C8AD> <20><><EFBFBD><EFBFBD> timer<65><72> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ð<EFBFBD> <20><>ŭ <20>ð<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
EVENTFUNC(timer_based_on_wear_expire_event)
|
||
{
|
||
item_event_info* info = dynamic_cast<item_event_info*>( event->info );
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "expire_event <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPITEM pkItem = info->item;
|
||
int remain_time = pkItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) - processing_time/passes_per_sec;
|
||
if (remain_time <= 0)
|
||
{
|
||
sys_log(0, "ITEM EXPIRED : expired %s %u", pkItem->GetName(), pkItem->GetID());
|
||
pkItem->SetTimerBasedOnWearExpireEvent(NULL);
|
||
pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, 0);
|
||
|
||
// <20>ϴ<EFBFBD> timer based on wear <20><>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD> <20>ð<EFBFBD> <20><> <20>Ǿ<EFBFBD><C7BE>ٰ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
||
if (pkItem->IsDragonSoul())
|
||
{
|
||
DSManager::instance().DeactivateDragonSoul(pkItem);
|
||
}
|
||
else
|
||
{
|
||
ITEM_MANAGER::instance().RemoveItem(pkItem, "TIMER_BASED_ON_WEAR_EXPIRE");
|
||
}
|
||
return 0;
|
||
}
|
||
pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
|
||
return PASSES_PER_SEC (MIN (60, remain_time));
|
||
}
|
||
|
||
void CItem::SetUniqueExpireEvent(LPEVENT pkEvent)
|
||
{
|
||
m_pkUniqueExpireEvent = pkEvent;
|
||
}
|
||
|
||
void CItem::SetTimerBasedOnWearExpireEvent(LPEVENT pkEvent)
|
||
{
|
||
m_pkTimerBasedOnWearExpireEvent = pkEvent;
|
||
}
|
||
|
||
EVENTFUNC(real_time_expire_event)
|
||
{
|
||
const item_vid_event_info* info = reinterpret_cast<const item_vid_event_info*>(event->info);
|
||
|
||
if (NULL == info)
|
||
return 0;
|
||
|
||
const LPITEM item = ITEM_MANAGER::instance().FindByVID( info->item_vid );
|
||
|
||
if (NULL == item)
|
||
return 0;
|
||
|
||
const time_t current = get_global_time();
|
||
|
||
if (current > item->GetSocket(0)) {
|
||
if(item->IsNewMountItem())
|
||
if (item->GetSocket(2) != 0)
|
||
item->ClearMountAttributeAndAffect();
|
||
|
||
ITEM_MANAGER::instance().RemoveItem(item, "REAL_TIME_EXPIRE");
|
||
|
||
return 0;
|
||
}
|
||
|
||
return PASSES_PER_SEC(1);
|
||
}
|
||
|
||
void CItem::StartRealTimeExpireEvent()
|
||
{
|
||
if (m_pkRealTimeExpireEvent)
|
||
return;
|
||
for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
|
||
{
|
||
if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType || LIMIT_REAL_TIME_START_FIRST_USE == GetProto()->aLimits[i].bType)
|
||
{
|
||
item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
|
||
info->item_vid = GetVID();
|
||
|
||
m_pkRealTimeExpireEvent = event_create( real_time_expire_event, info, PASSES_PER_SEC(1));
|
||
|
||
sys_log(0, "REAL_TIME_EXPIRE: StartRealTimeExpireEvent");
|
||
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
bool CItem::IsRealTimeItem()
|
||
{
|
||
if(!GetProto())
|
||
return false;
|
||
for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
|
||
{
|
||
if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void CItem::StartUniqueExpireEvent()
|
||
{
|
||
if (GetType() != ITEM_UNIQUE)
|
||
return;
|
||
|
||
if (m_pkUniqueExpireEvent)
|
||
return;
|
||
|
||
//<2F>Ⱓ<EFBFBD><E2B0A3> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD><C3B0><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>
|
||
if (IsRealTimeItem())
|
||
return;
|
||
|
||
// HARD CODING
|
||
if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
|
||
m_pOwner->ShowAlignment(false);
|
||
|
||
int iSec = GetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME);
|
||
|
||
if (iSec == 0)
|
||
iSec = 60;
|
||
else
|
||
iSec = MIN(iSec, 60);
|
||
|
||
SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, 0);
|
||
|
||
item_event_info* info = AllocEventInfo<item_event_info>();
|
||
info->item = this;
|
||
|
||
SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec)));
|
||
}
|
||
|
||
// <20>ð<EFBFBD> <20>ĺ<EFBFBD><C4BA><EFBFBD>
|
||
// timer_based_on_wear_expire_event <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
void CItem::StartTimerBasedOnWearExpireEvent()
|
||
{
|
||
if (m_pkTimerBasedOnWearExpireEvent)
|
||
return;
|
||
|
||
//<2F>Ⱓ<EFBFBD><E2B0A3> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD><C3B0><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>
|
||
if (IsRealTimeItem())
|
||
return;
|
||
|
||
if (-1 == GetProto()->cLimitTimerBasedOnWearIndex)
|
||
return;
|
||
|
||
int iSec = GetSocket(0);
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD><C3B0><EFBFBD> <20>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>...
|
||
if (0 != iSec)
|
||
{
|
||
iSec %= 60;
|
||
if (0 == iSec)
|
||
iSec = 60;
|
||
}
|
||
|
||
item_event_info* info = AllocEventInfo<item_event_info>();
|
||
info->item = this;
|
||
|
||
SetTimerBasedOnWearExpireEvent(event_create(timer_based_on_wear_expire_event, info, PASSES_PER_SEC(iSec)));
|
||
}
|
||
|
||
void CItem::StopUniqueExpireEvent()
|
||
{
|
||
if (!m_pkUniqueExpireEvent)
|
||
return;
|
||
|
||
if (GetValue(2) != 0) // <20><><EFBFBD>ӽð<D3BD><C3B0><EFBFBD> <20>̿<EFBFBD><CCBF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> UniqueExpireEvent<6E><74> <20>ߴ<EFBFBD><DFB4><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
||
return;
|
||
|
||
// HARD CODING
|
||
if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
|
||
m_pOwner->ShowAlignment(true);
|
||
|
||
SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, event_time(m_pkUniqueExpireEvent) / passes_per_sec);
|
||
event_cancel(&m_pkUniqueExpireEvent);
|
||
|
||
ITEM_MANAGER::instance().SaveSingleItem(this);
|
||
}
|
||
|
||
void CItem::StopTimerBasedOnWearExpireEvent()
|
||
{
|
||
if (!m_pkTimerBasedOnWearExpireEvent)
|
||
return;
|
||
|
||
int remain_time = GetSocket(ITEM_SOCKET_REMAIN_SEC) - event_processing_time(m_pkTimerBasedOnWearExpireEvent) / passes_per_sec;
|
||
|
||
SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
|
||
event_cancel(&m_pkTimerBasedOnWearExpireEvent);
|
||
|
||
ITEM_MANAGER::instance().SaveSingleItem(this);
|
||
}
|
||
|
||
void CItem::ApplyAddon(int iAddonType)
|
||
{
|
||
CItemAddonManager::instance().ApplyAddonTo(iAddonType, this);
|
||
}
|
||
|
||
int CItem::GetSpecialGroup() const
|
||
{
|
||
return ITEM_MANAGER::instance().GetSpecialGroupFromItem(GetVnum());
|
||
}
|
||
|
||
//
|
||
// <20>Ǽ<EFBFBD><C7BC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ó<><C3B3>.
|
||
//
|
||
bool CItem::IsAccessoryForSocket()
|
||
{
|
||
return (m_pProto->bType == ITEM_ARMOR && (m_pProto->bSubType == ARMOR_WRIST || m_pProto->bSubType == ARMOR_NECK || m_pProto->bSubType == ARMOR_EAR)) ||
|
||
(m_pProto->bType == ITEM_BELT); // 2013<31><33> 2<><32> <20><><EFBFBD><EFBFBD> <20>߰<EFBFBD><DFB0><EFBFBD> '<27><>Ʈ' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ȹ<EFBFBD><C8B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ǽ<EFBFBD><C7BC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD> <20>״<EFBFBD><D7B4><EFBFBD> <20>̿<EFBFBD><CCBF><EFBFBD><EFBFBD>ڰ<EFBFBD> <20><>.
|
||
}
|
||
|
||
void CItem::SetAccessorySocketGrade(int iGrade)
|
||
{
|
||
SetSocket(0, MINMAX(0, iGrade, GetAccessorySocketMaxGrade()));
|
||
|
||
int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
|
||
|
||
//if (test_server)
|
||
// iDownTime /= 60;
|
||
|
||
SetAccessorySocketDownGradeTime(iDownTime);
|
||
}
|
||
|
||
void CItem::SetAccessorySocketMaxGrade(int iMaxGrade)
|
||
{
|
||
SetSocket(1, MINMAX(0, iMaxGrade, ITEM_ACCESSORY_SOCKET_MAX_NUM));
|
||
}
|
||
|
||
void CItem::SetAccessorySocketDownGradeTime(DWORD time)
|
||
{
|
||
SetSocket(2, time);
|
||
|
||
if (test_server && GetOwner())
|
||
GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s<><73><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD> %d"), GetName(), time);
|
||
}
|
||
|
||
EVENTFUNC(accessory_socket_expire_event)
|
||
{
|
||
item_vid_event_info* info = dynamic_cast<item_vid_event_info*>( event->info );
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "accessory_socket_expire_event> <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPITEM item = ITEM_MANAGER::instance().FindByVID(info->item_vid);
|
||
|
||
if (item->GetAccessorySocketDownGradeTime() <= 1)
|
||
{
|
||
degrade:
|
||
item->SetAccessorySocketExpireEvent(NULL);
|
||
item->AccessorySocketDegrade();
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
int iTime = item->GetAccessorySocketDownGradeTime() - 60;
|
||
|
||
if (iTime <= 1)
|
||
goto degrade;
|
||
|
||
item->SetAccessorySocketDownGradeTime(iTime);
|
||
|
||
if (iTime > 60)
|
||
return PASSES_PER_SEC(60);
|
||
else
|
||
return PASSES_PER_SEC(iTime);
|
||
}
|
||
}
|
||
|
||
void CItem::StartAccessorySocketExpireEvent()
|
||
{
|
||
if (!IsAccessoryForSocket())
|
||
return;
|
||
|
||
if (m_pkAccessorySocketExpireEvent)
|
||
return;
|
||
|
||
if (GetAccessorySocketMaxGrade() == 0)
|
||
return;
|
||
|
||
if (GetAccessorySocketGrade() == 0)
|
||
return;
|
||
|
||
int iSec = GetAccessorySocketDownGradeTime();
|
||
SetAccessorySocketExpireEvent(NULL);
|
||
|
||
if (iSec <= 1)
|
||
iSec = 5;
|
||
else
|
||
iSec = MIN(iSec, 60);
|
||
|
||
item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
|
||
info->item_vid = GetVID();
|
||
|
||
SetAccessorySocketExpireEvent(event_create(accessory_socket_expire_event, info, PASSES_PER_SEC(iSec)));
|
||
}
|
||
|
||
void CItem::StopAccessorySocketExpireEvent()
|
||
{
|
||
if (!m_pkAccessorySocketExpireEvent)
|
||
return;
|
||
|
||
if (!IsAccessoryForSocket())
|
||
return;
|
||
|
||
int new_time = GetAccessorySocketDownGradeTime() - (60 - event_time(m_pkAccessorySocketExpireEvent) / passes_per_sec);
|
||
|
||
event_cancel(&m_pkAccessorySocketExpireEvent);
|
||
|
||
if (new_time <= 1)
|
||
{
|
||
AccessorySocketDegrade();
|
||
}
|
||
else
|
||
{
|
||
SetAccessorySocketDownGradeTime(new_time);
|
||
}
|
||
}
|
||
|
||
bool CItem::IsRideItem()
|
||
{
|
||
if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_RIDE == GetSubType())
|
||
return true;
|
||
if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_MOUNT_RIDE == GetSubType())
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
bool CItem::IsRamadanRing()
|
||
{
|
||
if (GetVnum() == UNIQUE_ITEM_RAMADAN_RING)
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
void CItem::ClearMountAttributeAndAffect()
|
||
{
|
||
LPCHARACTER ch = GetOwner();
|
||
|
||
ch->RemoveAffect(AFFECT_MOUNT);
|
||
ch->RemoveAffect(AFFECT_MOUNT_BONUS);
|
||
|
||
ch->MountVnum(0);
|
||
|
||
ch->PointChange(POINT_ST, 0);
|
||
ch->PointChange(POINT_DX, 0);
|
||
ch->PointChange(POINT_HT, 0);
|
||
ch->PointChange(POINT_IQ, 0);
|
||
}
|
||
|
||
// fixme
|
||
// <20>̰<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ⱦ<EFBFBD><C8BE><EFBFBD>... <20>ٵ<EFBFBD> Ȥ<>ó<EFBFBD> <20>; <20><><EFBFBD>ܵ<EFBFBD>.
|
||
// by rtsummit
|
||
bool CItem::IsNewMountItem()
|
||
{
|
||
switch(GetVnum())
|
||
{
|
||
case 76000: case 76001: case 76002: case 76003:
|
||
case 76004: case 76005: case 76006: case 76007:
|
||
case 76008: case 76009: case 76010: case 76011:
|
||
case 76012: case 76013: case 76014:
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void CItem::SetAccessorySocketExpireEvent(LPEVENT pkEvent)
|
||
{
|
||
m_pkAccessorySocketExpireEvent = pkEvent;
|
||
}
|
||
|
||
void CItem::AccessorySocketDegrade()
|
||
{
|
||
if (GetAccessorySocketGrade() > 0)
|
||
{
|
||
LPCHARACTER ch = GetOwner();
|
||
|
||
if (ch)
|
||
{
|
||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s<><73> <20><><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>."), GetName());
|
||
}
|
||
|
||
ModifyPoints(false);
|
||
SetAccessorySocketGrade(GetAccessorySocketGrade()-1);
|
||
ModifyPoints(true);
|
||
|
||
int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
|
||
|
||
if (test_server)
|
||
iDownTime /= 60;
|
||
|
||
SetAccessorySocketDownGradeTime(iDownTime);
|
||
|
||
if (iDownTime)
|
||
StartAccessorySocketExpireEvent();
|
||
}
|
||
}
|
||
|
||
// ring<6E><67> item<65><6D> <20><><EFBFBD><EFBFBD> <20><> <20>ִ<EFBFBD><D6B4><EFBFBD> <20><><EFBFBD>θ<EFBFBD> üũ<C3BC>ؼ<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
static const bool CanPutIntoRing(LPITEM ring, LPITEM item)
|
||
{
|
||
const DWORD vnum = item->GetVnum();
|
||
return false;
|
||
}
|
||
|
||
bool CItem::CanPutInto(LPITEM item)
|
||
{
|
||
if (item->GetType() == ITEM_BELT)
|
||
return this->GetSubType() == USE_PUT_INTO_BELT_SOCKET;
|
||
|
||
else if(item->GetType() == ITEM_RING)
|
||
return CanPutIntoRing(item, this);
|
||
|
||
else if (item->GetType() != ITEM_ARMOR)
|
||
return false;
|
||
|
||
DWORD vnum = item->GetVnum();
|
||
|
||
struct JewelAccessoryInfo
|
||
{
|
||
DWORD jewel;
|
||
DWORD wrist;
|
||
DWORD neck;
|
||
DWORD ear;
|
||
};
|
||
const static JewelAccessoryInfo infos[] = {
|
||
{ 50634, 14420, 16220, 17220 },
|
||
{ 50635, 14500, 16500, 17500 },
|
||
{ 50636, 14520, 16520, 17520 },
|
||
{ 50637, 14540, 16540, 17540 },
|
||
{ 50638, 14560, 16560, 17560 },
|
||
};
|
||
|
||
DWORD item_type = (item->GetVnum() / 10) * 10;
|
||
for (int i = 0; i < sizeof(infos) / sizeof(infos[0]); i++)
|
||
{
|
||
const JewelAccessoryInfo& info = infos[i];
|
||
switch(item->GetSubType())
|
||
{
|
||
case ARMOR_WRIST:
|
||
if (info.wrist == item_type)
|
||
{
|
||
if (info.jewel == GetVnum())
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
break;
|
||
case ARMOR_NECK:
|
||
if (info.neck == item_type)
|
||
{
|
||
if (info.jewel == GetVnum())
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
break;
|
||
case ARMOR_EAR:
|
||
if (info.ear == item_type)
|
||
{
|
||
if (info.jewel == GetVnum())
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (item->GetSubType() == ARMOR_WRIST)
|
||
vnum -= 14000;
|
||
else if (item->GetSubType() == ARMOR_NECK)
|
||
vnum -= 16000;
|
||
else if (item->GetSubType() == ARMOR_EAR)
|
||
vnum -= 17000;
|
||
else
|
||
return false;
|
||
|
||
DWORD type = vnum / 20;
|
||
|
||
if (type < 0 || type > 11)
|
||
{
|
||
type = (vnum - 170) / 20;
|
||
|
||
if (50623 + type != GetVnum())
|
||
return false;
|
||
else
|
||
return true;
|
||
}
|
||
else if (item->GetVnum() >= 16210 && item->GetVnum() <= 16219)
|
||
{
|
||
if (50625 != GetVnum())
|
||
return false;
|
||
else
|
||
return true;
|
||
}
|
||
else if (item->GetVnum() >= 16230 && item->GetVnum() <= 16239)
|
||
{
|
||
if (50626 != GetVnum())
|
||
return false;
|
||
else
|
||
return true;
|
||
}
|
||
|
||
return 50623 + type == GetVnum();
|
||
}
|
||
|
||
// PC_BANG_ITEM_ADD
|
||
bool CItem::IsPCBangItem()
|
||
{
|
||
for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
|
||
{
|
||
if (m_pProto->aLimits[i].bType == LIMIT_PCBANG)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
// END_PC_BANG_ITEM_ADD
|
||
|
||
bool CItem::CheckItemUseLevel(int nLevel)
|
||
{
|
||
for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
|
||
{
|
||
if (this->m_pProto->aLimits[i].bType == LIMIT_LEVEL)
|
||
{
|
||
if (this->m_pProto->aLimits[i].lValue > nLevel) return false;
|
||
else return true;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
int CItem::FindApplyValue(BYTE bApplyType)
|
||
{
|
||
if (m_pProto == NULL)
|
||
return 0;
|
||
|
||
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
|
||
{
|
||
if (m_pProto->aApplies[i].bType == bApplyType)
|
||
return m_pProto->aApplies[i].lValue;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
void CItem::CopySocketTo(LPITEM pItem)
|
||
{
|
||
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
|
||
{
|
||
pItem->m_alSockets[i] = m_alSockets[i];
|
||
}
|
||
}
|
||
|
||
int CItem::GetAccessorySocketGrade()
|
||
{
|
||
return MINMAX(0, GetSocket(0), GetAccessorySocketMaxGrade());
|
||
}
|
||
|
||
int CItem::GetAccessorySocketMaxGrade()
|
||
{
|
||
return MINMAX(0, GetSocket(1), ITEM_ACCESSORY_SOCKET_MAX_NUM);
|
||
}
|
||
|
||
int CItem::GetAccessorySocketDownGradeTime()
|
||
{
|
||
return MINMAX(0, GetSocket(2), aiAccessorySocketDegradeTime[GetAccessorySocketGrade()]);
|
||
}
|
||
|
||
void CItem::AttrLog()
|
||
{
|
||
const char * pszIP = NULL;
|
||
|
||
if (GetOwner() && GetOwner()->GetDesc())
|
||
pszIP = GetOwner()->GetDesc()->GetHostName();
|
||
|
||
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
|
||
{
|
||
if (m_alSockets[i])
|
||
{
|
||
LogManager::instance().ItemLog(i, m_alSockets[i], 0, GetID(), "INFO_SOCKET", "", pszIP ? pszIP : "", GetOriginalVnum());
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i<ITEM_ATTRIBUTE_MAX_NUM; ++i)
|
||
{
|
||
int type = m_aAttr[i].bType;
|
||
int value = m_aAttr[i].sValue;
|
||
|
||
if (type)
|
||
LogManager::instance().ItemLog(i, type, value, GetID(), "INFO_ATTR", "", pszIP ? pszIP : "", GetOriginalVnum());
|
||
}
|
||
}
|
||
|
||
int CItem::GetLevelLimit()
|
||
{
|
||
for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
|
||
{
|
||
if (this->m_pProto->aLimits[i].bType == LIMIT_LEVEL)
|
||
{
|
||
return this->m_pProto->aLimits[i].lValue;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
bool CItem::OnAfterCreatedItem()
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD>̶<EFBFBD><CCB6><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ߴٸ<DFB4>, <20><> <20><><EFBFBD>Ŀ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾƵ<CABE> <20>ð<EFBFBD><C3B0><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ǵ<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
|
||
{
|
||
// Socket1<74><31> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> Ƚ<><C8BD><EFBFBD><EFBFBD> <20><><EFBFBD>ϵǾ<CFB5> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD>̶<EFBFBD><CCB6><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Ÿ<≯Ӹ<CCB8> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
||
if (0 != GetSocket(1))
|
||
{
|
||
StartRealTimeExpireEvent();
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
#ifdef __AUCTION__
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// window<6F><77> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
|
||
bool CItem::MoveToAuction()
|
||
{
|
||
LPCHARACTER owner = GetOwner();
|
||
if (owner == NULL)
|
||
{
|
||
sys_err ("Item those owner is not exist cannot regist in auction");
|
||
return false;
|
||
}
|
||
|
||
if (GetWindow() == AUCTION)
|
||
{
|
||
sys_err ("Item is already in auction.");
|
||
}
|
||
|
||
SetWindow(AUCTION);
|
||
owner->SetItem(m_bCell, NULL);
|
||
Save();
|
||
ITEM_MANAGER::instance().FlushDelayedSave(this);
|
||
|
||
return true;
|
||
}
|
||
|
||
void CItem::CopyToRawData (TPlayerItem* new_item)
|
||
{
|
||
if (new_item != NULL)
|
||
return;
|
||
|
||
new_item->id = m_dwID;
|
||
new_item->window = m_bWindow;
|
||
new_item->pos = m_bCell;
|
||
new_item->count = m_dwCount;
|
||
|
||
new_item->vnum = GetVnum();
|
||
memcpy (new_item->alSockets, m_alSockets, sizeof (m_alSockets));
|
||
memcpy (new_item->aAttr, m_aAttr, sizeof (m_aAttr));
|
||
|
||
new_item->owner = m_pOwner->GetPlayerID();
|
||
}
|
||
#endif
|
||
|
||
bool CItem::IsDragonSoul()
|
||
{
|
||
return GetType() == ITEM_DS;
|
||
}
|
||
|
||
int CItem::GiveMoreTime_Per(float fPercent)
|
||
{
|
||
if (IsDragonSoul())
|
||
{
|
||
DWORD duration = DSManager::instance().GetDuration(this);
|
||
int remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
|
||
int given_time = fPercent * duration / 100;
|
||
if (remain_sec == duration)
|
||
return false;
|
||
if ((given_time + remain_sec) >= duration)
|
||
{
|
||
SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
|
||
return duration - remain_sec;
|
||
}
|
||
else
|
||
{
|
||
SetSocket(ITEM_SOCKET_REMAIN_SEC, given_time + remain_sec);
|
||
return given_time;
|
||
}
|
||
}
|
||
// <20>켱 <20><>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD> <20><><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD> <20>ϵ<EFBFBD><CFB5><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
int CItem::GiveMoreTime_Fix(DWORD dwTime)
|
||
{
|
||
if (IsDragonSoul())
|
||
{
|
||
DWORD duration = DSManager::instance().GetDuration(this);
|
||
int remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
|
||
if (remain_sec == duration)
|
||
return false;
|
||
if ((dwTime + remain_sec) >= duration)
|
||
{
|
||
SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
|
||
return duration - remain_sec;
|
||
}
|
||
else
|
||
{
|
||
SetSocket(ITEM_SOCKET_REMAIN_SEC, dwTime + remain_sec);
|
||
return dwTime;
|
||
}
|
||
}
|
||
// <20>켱 <20><>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD> <20><><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD> <20>ϵ<EFBFBD><CFB5><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
|
||
int CItem::GetDuration()
|
||
{
|
||
if(!GetProto())
|
||
return -1;
|
||
|
||
for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
|
||
{
|
||
if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType)
|
||
return GetProto()->aLimits[i].lValue;
|
||
}
|
||
|
||
if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
|
||
return GetProto()->aLimits[GetProto()->cLimitTimerBasedOnWearIndex].lValue;
|
||
|
||
return -1;
|
||
}
|
||
|
||
bool CItem::IsSameSpecialGroup(const LPITEM item) const
|
||
{
|
||
// <20><><EFBFBD><EFBFBD> VNUM<55><4D> <20><><EFBFBD>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><EFBFBD><D7B7><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if (this->GetVnum() == item->GetVnum())
|
||
return true;
|
||
|
||
if (GetSpecialGroup() && (item->GetSpecialGroup() == GetSpecialGroup()))
|
||
return true;
|
||
|
||
return false;
|
||
} |