Jump to content

Sash absorbing 100%


Recommended Posts

Hey, i have problem with Sash.

Its absorbing the 100% of the 1/5 and 6/7 Bonus.

Like in this Thread. But i dont know what/how to change in item.cpp maybe you can help me.

Is it here?

                        attrVal = int(float(attrVal) / 100.0f * float(GetSocket(0)));// <= 0 ? 1 : int(float(attrVal) / 100.0f * float(GetSocket(0)));

item.cpp full:

Spoiler

#include "stdafx.h"
#include "utils.h"
#include "config.h"
#include "char.h"
#include "desc.h"
#include "sectree_manager.h"
#include "packet.h"
#include "mob_manager.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"
#ifdef SHOP_SEARCH
#include "shop_search.h"
#endif
#include "../../common/VnumHelper.h"
#include "../../common/CommonDefines.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_pkExpireEvent(NULL), m_pkUniqueExpireEvent(NULL),
    m_pkTimerBasedOnWearExpireEvent(NULL), m_pkRealTimeExpireEvent(NULL),
       m_pkAccessorySocketExpireEvent(NULL), m_pkOwnershipEvent(NULL), m_dwOwnershipPID(0), m_bSkipSave(false), m_isLocked(false),
    m_dwMaskVnum(0), m_dwSIGVnum (0)
#ifdef __CHANGE_LOOK_SYSTEM__
    , m_dwLook(0)
#endif
{
    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;
#ifdef OFFLINE_SHOP
    m_dwRealID = 0;
#endif
    m_bSkipSave = false;
    m_dwLastOwnerPID = 0;
#ifdef __CHANGE_LOOK_SYSTEM__
    m_dwLook = 0;
#endif
}

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;
#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
    for (size_t i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
        pack.alSockets = GetSocket(i);

    thecore_memcpy(pack.aAttrs, GetAttributes(), sizeof(pack.aAttrs));
#endif

    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;
        strlcpy(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);
}

#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
const char * CItem::GetName()
{
    static char szItemName[128];
    memset(szItemName, 0, sizeof(szItemName));
    if (GetProto())
    {
        int len = 0;
        switch (GetType())
        {
            case ITEM_POLYMORPH:
            {
                const DWORD dwMobVnum = GetSocket(0);
                const CMob* pMob = CMobManager::instance().Get(dwMobVnum);
                if (pMob)
                    len = snprintf(szItemName, sizeof(szItemName), "%s", pMob->m_table.szLocaleName);

                break;
            }
            case ITEM_SKILLBOOK:
            case ITEM_SKILLFORGET:
            {
                const DWORD dwSkillVnum = (GetVnum() == ITEM_SKILLBOOK_VNUM || GetVnum() == ITEM_SKILLFORGET_VNUM) ? GetSocket(0) : 0;
                const CSkillProto* pSkill = (dwSkillVnum != 0) ? CSkillManager::instance().Get(dwSkillVnum) : NULL;
                if (pSkill)
                    len = snprintf(szItemName, sizeof(szItemName), "%s", pSkill->szName);

                break;
            }
        }
        len += snprintf(szItemName + len, sizeof(szItemName) - len, (len>0)?" %s":"%s", GetProto()->szLocaleName);
    }

    return szItemName;
}
#endif

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(long bit)
{
    REMOVE_BIT(m_lFlag, bit);
}

void CItem::AddFlag(long 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);
#ifdef __CHANGE_LOOK_SYSTEM__
    pack.dwVnum = m_dwLook;
#endif
    pack.count    = m_dwCount;

    for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
        pack.alSockets = m_alSockets;

    thecore_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, g_bItemCountLimit);
    }
}

bool CItem::SetCount(DWORD count)
{
    if (GetType() == ITEM_ELK)
    {
        m_dwCount = MIN(count, INT_MAX);
    }
    else
    {
        m_dwCount = MIN(count, g_bItemCountLimit);
    }

    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
                {
#ifdef ENABLE_5_INVENTORY
                    pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 750);                
#else
                    pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 255);
#endif
                }
            }

            M2_DESTROY_ITEM(this);
        }
        else
        {
            if (!IsDragonSoul())
            {
#ifdef ENABLE_5_INVENTORY
                m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 750);                
#else
                m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 255);
#endif
            }
            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)    
    {
        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())
                    sys_err("CItem::RemoveFromCharacter: Invalid Item Position");
                else
                {
                    pOwner->SetItem(cell, NULL);
                }
            }
        }

        m_pOwner = NULL;
        m_wCell = 0;

        SetWindow(RESERVED_WINDOW);
#ifdef OFFLINE_SHOP
        if(!GetRealID())
#endif
        Save();
        return (this);
    }
}

#ifdef __HIGHLIGHT_SYSTEM__
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell, bool isHighLight)
#else
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell)
#endif
{
    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);

#ifdef __HIGHLIGHT_SYSTEM__
    ch->SetItem(TItemPos(window_type, pos), this, isHighLight);
#else
    ch->SetItem(TItemPos(window_type, pos), this);
#endif
    m_pOwner = ch;

    Save();
    return true;
}

LPITEM CItem::RemoveFromGround()
{
    if (GetSectree())
    {
        SetOwnership(NULL);

        GetSectree()->RemoveEntity(this);

        ViewCleanup();

        Save();
    }

    return (this);
}

bool CItem::AddToGround(long 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;
#ifdef ENABLE_WOLFMAN_CHARACTER
        case JOB_WOLFMAN:
            if (GetAntiFlag() & ITEM_ANTIFLAG_WOLFMAN)
                return false;
            break;
#endif
    }

    return true;
}
int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
{
    // 코스츔 아이템(ITEM_COSTUME)은 WearFlag 없어도 됨. (sub type으로 착용위치 구분. 귀찮게 또 wear flag 줄 필요가 있나..)
    // 용혼석(ITEM_DS, ITEM_SPECIAL_DS)도  SUB_TYPE으로 구분. 신규 반지, 벨트는 ITEM_TYPE으로 구분 -_-
#ifdef SHININGSYSTEM
    if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType() && ITEM_SHINING != GetType())
        return -1;
#else    
    if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
        return -1;
#endif
    // 용혼석 슬롯을 WEAR로 처리할 수가 없어서(WEAR는 최대 32개까지 가능한데 용혼석을 추가하면 32가 넘는다.)
    // 인벤토리의 특정 위치((INVENTORY_MAX_NUM + WEAR_MAX_NUM)부터 (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)까지)를
    // 용혼석 슬롯으로 정함.
    // return 할 때에, INVENTORY_MAX_NUM을 뺀 이유는,
    // 본래 WearCell이 INVENTORY_MAX_NUM를 빼고 return 하기 때문.
    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;
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
        else if (GetSubType() == COSTUME_MOUNT)
            return WEAR_COSTUME_MOUNT;
#endif
#ifdef __COSTUME_ACCE__
        else if (GetSubType() == COSTUME_ACCE)
            return WEAR_COSTUME_ACCE;
#endif
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
        else if (GetSubType() == COSTUME_WEAPON)
            return WEAR_COSTUME_WEAPON;
#endif
    }
#if !defined(ENABLE_MOUNT_COSTUME_SYSTEM) && !defined(__COSTUME_ACCE__)
    else if (GetType() == ITEM_RING)
    {
        if (ch->GetWear(WEAR_RING1))
            return WEAR_RING2;
        else
            return WEAR_RING1;
    }
#endif
    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;
    }
#ifdef SHININGSYSTEM
    else if (GetType() == ITEM_SHINING)
    {
        if (GetSubType() == SHINING_WEAPON) {
            for (int i = WEAR_SHINING_WEAPON_1; i <= WEAR_SHINING_WEAPON_3; i++)
            {
                if (!ch->GetWear(i))
                    return i;
            }
            return WEAR_SHINING_WEAPON_1;
        }
        else if (GetSubType() == SHINING_ARMOR) {
            if (ch->GetWear(WEAR_SHINING_ARMOR_1))
                return WEAR_SHINING_ARMOR_2;
            else
                return WEAR_SHINING_ARMOR_1;
        }
        else if (GetSubType() == SHINING_SPECIAL) {
            return WEAR_SHINING_SPECIAL;
        }
    }
#endif
    // 수집 퀘스트를 위한 아이템이 박히는곳으로 한번 박히면 절대 E수 없다.
    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;

    // 무기와 갑옷만 소켓을 적용시킨다.
    if (false == IsAccessoryForSocket())
    {
        if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
        {
            // 소켓이 속성강화에 사용되는 경우 적용하지 않는다 (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.bType == APPLY_NONE)
                            continue;

                        if (p->aApplies.bType == APPLY_SKILL)
                            m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? p->aApplies.lValue : p->aApplies.lValue ^ 0x00800000);
                        else
                            m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? p->aApplies.lValue : -p->aApplies.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.bType == APPLY_NONE)
            continue;

        long value = m_pProto->aApplies.lValue;

        if (m_pProto->aApplies.bType == APPLY_SKILL)
        {
            m_pOwner->ApplyPoint(m_pProto->aApplies.bType, bAdd ? value : value ^ 0x00800000);
        }
        else
        {
            if (0 != accessoryGrade)
                value += MAX(accessoryGrade, value * aiAccessorySocketEffectivePct[accessoryGrade] / 100);

            m_pOwner->ApplyPoint(m_pProto->aApplies.bType, bAdd ? value : -value);
        }
    }
    // 초승달의 반지, 할로윈 사탕, 행복의 반지, 영원한 사랑의 펜던트의 경우
    // 기존의 하드 코딩으로 강제로 속성을 부여했지만,
    // 그 부분을 제거하고 special item group 테이블에서 속성을 부여하도록 변경하였다.
    // 하지만 하드 코딩되어있을 때 생성된 아이템이 남아있을 수도 있어서 특수처리 해놓는다.
    // 이 아이템들의 경우, 밑에 ITEM_UNIQUE일 때의 처리로 속성이 부여되기 때문에,
    // 아이템에 박혀있는 attribute는 적용하지 않고 넘어간다.
#ifdef __COSTUME_ACCE__
    if (ITEM_COSTUME == GetType() && COSTUME_ACCE == GetSubType())
    {
        TItemTable * p = ITEM_MANAGER::instance().GetTable(GetSocket(1));

        if (p) {

            for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
            {
                if (p->aApplies.bType == APPLY_NONE)
                    continue;

                int value = p->aApplies.lValue;

                if (value < 0)
                    value = 1;
                else
                    value = int(float(value) / 100.0f * float(GetSocket(0))) <= 0 ? 1 : int(float(value) / 100.0f * float(GetSocket(0)));

                if (p->aApplies.bType == APPLY_SKILL)
                {
                    m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? value : value ^ 0x00800000);
                }
                else
                {
                    m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? value : -value);
                }
            }
        }
    }
#endif
    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);
                short attrVal = ia.sValue;
#ifdef __COSTUME_ACCE__
                if (ITEM_COSTUME == GetType() && COSTUME_ACCE == GetSubType())
                {
                    if (attrVal < 0)
                        attrVal = 1;
                    else
                        attrVal = int(float(attrVal) / 100.0f * float(GetSocket(0)));// <= 0 ? 1 : int(float(attrVal) / 100.0f * float(GetSocket(0)));
                }
#endif
                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, 0);
                }
            }
            break;

        case ITEM_WEAPON:
            {
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
                if (0 != m_pOwner->GetWear(WEAR_COSTUME_WEAPON))
                    break;
#endif

                if (bAdd)
                {
#ifdef __CHANGE_LOOK_SYSTEM__
                    if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
                        m_pOwner->SetPart(PART_WEAPON, GetItemLook() > 0 ? GetItemLook() : GetVnum());
#else
                    if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
                        m_pOwner->SetPart(PART_WEAPON, GetVnum());
#endif
                }
                else
                {
                    if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
                        m_pOwner->SetPart(PART_WEAPON, 0);
                }
            }
            break;

        case ITEM_ARMOR:
            {
                // 코스츔 body를 입고있다면 armor는 벗던 입던 상관 없이 비주얼에 영향을 주면 안 됨.
                if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
                    break;

                if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD)
                {
                    if (bAdd)
                    {
#ifdef __CHANGE_LOOK_SYSTEM__
                        if (GetProto()->bSubType == ARMOR_BODY)
                            m_pOwner->SetPart(PART_MAIN, GetItemLook() > 0 ? GetItemLook() : GetVnum());
#else
                        if (GetProto()->bSubType == ARMOR_BODY)
                            m_pOwner->SetPart(PART_MAIN, GetVnum());
#endif
                    }
                    else
                    {
                        if (GetProto()->bSubType == ARMOR_BODY)
                            m_pOwner->SetPart(PART_MAIN, m_pOwner->GetOriginalPart(PART_MAIN));
                    }
                }
            }
            break;

        // 코스츔 아이템 입었을 때 캐릭터 parts 정보 세팅. 기존 스타일대로 추가함..
        case ITEM_COSTUME:
            {
                DWORD toSetValue = this->GetVnum();
                EParts toSetPart = PART_MAX_NUM;

                // 갑옷 코스츔
                if (GetSubType() == COSTUME_BODY)
                {
                    toSetPart = PART_MAIN;

                    if (false == bAdd)
                    {
                        // 코스츔 갑옷을 벗었을 때 원래 갑옷을 입고 있었다면 그 갑옷으로 look 세팅, 입지 않았다면 default look
#ifdef __CHANGE_LOOK_SYSTEM__
                        CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
#else
                        const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
#endif
#ifdef __CHANGE_LOOK_SYSTEM__
                        toSetValue = (NULL != pArmor) ? pArmor->GetItemLook() > 0 ? pArmor->GetItemLook() : pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
#else
                        toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
#endif
                    }

                }

                // 헤어 코스츔
                else if (GetSubType() == COSTUME_HAIR)
                {
                    toSetPart = PART_HAIR;

                    // 코스츔 헤어는 shape값을 item proto의 value3에 세팅하도록 함. 특별한 이유는 없고 기존 갑옷(ARMOR_BODY)의 shape값이 프로토의 value3에 있어서 헤어도 같이 value3으로 함.
                    // [NOTE] 갑옷은 아이템 vnum을 보내고 헤어는 shape(value3)값을 보내는 이유는.. 기존 시스템이 그렇게 되어있음...
                    toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
                }

#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
                else if (GetSubType() == COSTUME_MOUNT)
                {
                    // not need to do a thing in here
                }
#endif

#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
                else if (GetSubType() == COSTUME_WEAPON)
                {
                    toSetPart = PART_WEAPON;
                    if (false == bAdd)
                    {
#ifdef __CHANGE_LOOK_SYSTEM__
                        CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
#else
                        const CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
#endif            
#ifdef __CHANGE_LOOK_SYSTEM__
                        toSetValue = (NULL != pWeapon) ? pWeapon->GetItemLook() > 0 ? pWeapon->GetItemLook() : pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
#else
                        toSetValue = (NULL != pWeapon) ? pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
#endif
                    }
                }
#endif
#ifdef __COSTUME_ACCE__
                else if (GetSubType() == COSTUME_ACCE) {
                    toSetPart = PART_ACCE;
                    toSetValue = (true == bAdd) ? this->GetVnum() : 0;
                }
#endif

                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:
#ifdef SHININGSYSTEM
    case ITEM_SHINING:
#endif
        return true;
    }

    return false;
}

#define ENABLE_IMMUNE_FIX
// return false on error state
#ifdef ENABLE_5_INVENTORY
bool CItem::EquipTo(LPCHARACTER ch, WORD bWearCell)
#else
bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
#endif
{
    if (!ch)
    {
        sys_err("EquipTo: nil character");
        return false;
    }

    // 용혼석 슬롯 index는 WEAR_MAX_NUM 보다 큼.
    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); // 여기서 패킷 나감

    m_pOwner = ch;
    m_bEquipped = true;
    m_wCell    = INVENTORY_MAX_NUM + bWearCell;

#ifndef ENABLE_IMMUNE_FIX
    DWORD dwImmuneFlag = 0;

    for (int i = 0; i < WEAR_MAX_NUM; ++i)
    {
        if (m_pOwner->GetWear(i))
        {
            // m_pOwner->ChatPacket(CHAT_TYPE_INFO, "unequip immuneflag(%u)", m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); // always 0
            SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
        }
    }

    m_pOwner->SetImmuneFlag(dwImmuneFlag);
#endif

    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;
    }

    //신규 말 아이템 제거시 처리
    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);

#ifndef ENABLE_IMMUNE_FIX
    DWORD dwImmuneFlag = 0;

    for (int i = 0; i < WEAR_MAX_NUM; ++i)
    {
        if (m_pOwner->GetWear(i))
        {
            // m_pOwner->ChatPacket(CHAT_TYPE_INFO, "unequip immuneflag(%u)", m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); // always 0
            SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
        }
    }

    m_pOwner->SetImmuneFlag(dwImmuneFlag);
#endif

    m_pOwner->ComputeBattlePoints();

    m_pOwner->UpdatePacket();

    m_pOwner = NULL;
    m_wCell = 0;
    m_bEquipped    = false;

    return true;
}

long 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)
{
    thecore_memcpy(m_alSockets, c_al, sizeof(m_alSockets));
    Save();
}

void CItem::SetSocket(int i, long v, bool bLog)
{
    assert(i < ITEM_SOCKET_MAX_NUM);
    m_alSockets = v;
    UpdatePacket();
    Save();
    if (bLog)
    {
#ifdef ENABLE_NEWSTUFF
        if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
        LogManager::instance().ItemLog(i, v, 0, GetID(), "SET_SOCKET", "", "", GetOriginalVnum());
    }
}

#ifdef ENABLE_YANG_LIMIT
long long CItem::GetGold()
#else
int CItem::GetGold()
#endif
{
    if (IS_SET(GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
    {
        if (GetProto()->dwGold == 0)
            return GetCount();
        else
            return GetCount() / GetProto()->dwGold;
    }
    else
        return GetProto()->dwGold;
}

#ifdef ENABLE_YANG_LIMIT
long long CItem::GetShopBuyPrice()
#else
int CItem::GetShopBuyPrice()
#endif
{
    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 (iSec <= 10)
        iSec = 30;

    m_dwOwnershipPID = ch->GetPlayerID();

    item_event_info* info = AllocEventInfo<item_event_info>();
    strlcpy(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;
    strlcpy(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;

    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;
    }

    // 100% 확률로 좋은 속성 하나
    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
        {
            // 게임 내에 시간제 아이템들이 빠릿빠릿하게 사라지지 않는 버그가 있어
            // 수정
            // 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);
        }
    }
}

// 시간 후불제
// timer를 시작할 때에 시간 차감하는 것이 아니라,
// timer가 발화할 때에 timer가 동작한 시간 만큼 시간 차감을 한다.
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);

        // 일단 timer based on wear 용혼석은 시간 다 되었다고 없애지 않는다.
        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))
    {
        switch (item->GetVnum())
        {
            if(item->IsNewMountItem())
            {
                if (item->GetSocket(2) != 0)
                    item->ClearMountAttributeAndAffect();
            }
            break;
        }
#ifdef SHOP_SEARCH
        if (item->GetOwner() && CShopSearchHelper::IsGlass(item->GetVnum()))
            CShopSearchHelper::Close(item->GetVnum(), item->GetOwner());
    
#endif
        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.bType || LIMIT_REAL_TIME_START_FIRST_USE == GetProto()->aLimits.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.bType)
            return true;
    }
    return false;
}

void CItem::StartUniqueExpireEvent()
{
    if (GetType() != ITEM_UNIQUE)
        return;

    if (m_pkUniqueExpireEvent)
        return;

    //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
    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)));
}

// 시간 후불제
// timer_based_on_wear_expire_event 설명 참조
void CItem::StartTimerBasedOnWearExpireEvent()
{
    if (m_pkTimerBasedOnWearExpireEvent)
        return;

    //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
    if (IsRealTimeItem())
        return;

    if (-1 == GetProto()->cLimitTimerBasedOnWearIndex)
        return;

    int iSec = GetSocket(0);

    // 남은 시간을 분단위로 끊기 위해...
    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) // 게임시간제 이외의 아이템은 UniqueExpireEvent를 중단할 수 없다.
        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());
}

//
// 악세서리 소켓 처리.
//
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년 2월 새로 추가된 '벨트' 아이템의 경우 기획팀에서 악세서리 소켓 시스템을 그대로 이용하자고 함.
}

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에서 소켓 빠질때까지 남은 시간 %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;
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
    if (ITEM_COSTUME == GetType() && COSTUME_MOUNT == GetSubType())
        return true;
#endif
    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
// 이거 지금은 안쓴데... 근데 혹시나 싶어서 남겨둠.
// 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에 박혀있던 보석이 사라집니다."), GetName());
        }

        ModifyPoints(false);
        SetAccessorySocketGrade(GetAccessorySocketGrade()-1);
        ModifyPoints(true);

        int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];

        if (test_server)
            iDownTime /= 60;

        SetAccessorySocketDownGradeTime(iDownTime);

        if (iDownTime)
            StartAccessorySocketExpireEvent();
    }
}

// ring에 item을 박을 수 있는지 여부를 체크해서 리턴
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 },
        { 50639, 14570, 16570, 17570 },
    };

    DWORD item_type = (item->GetVnum() / 10) * 10;
    for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++)
    {
        const JewelAccessoryInfo& info = infos;
        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.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.bType == LIMIT_LEVEL)
        {
            if (this->m_pProto->aLimits.lValue > nLevel) return false;
            else return true;
        }
    }
    return true;
}

long CItem::FindApplyValue(BYTE bApplyType)
{
    if (m_pProto == NULL)
        return 0;

    for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
    {
        if (m_pProto->aApplies.bType == bApplyType)
            return m_pProto->aApplies.lValue;
    }

    return 0;
}

void CItem::CopySocketTo(LPITEM pItem)
{
    for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
    {
        pItem->m_alSockets = m_alSockets;
    }
}

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)
        {
#ifdef ENABLE_NEWSTUFF
            if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
            LogManager::instance().ItemLog(i, m_alSockets, 0, GetID(), "INFO_SOCKET", "", pszIP ? pszIP : "", GetOriginalVnum());
        }
    }

    for (int i = 0; i<ITEM_ATTRIBUTE_MAX_NUM; ++i)
    {
        int    type    = m_aAttr.bType;
        int value    = m_aAttr.sValue;

        if (type)
        {
#ifdef ENABLE_NEWSTUFF
            if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
            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.bType == LIMIT_LEVEL)
        {
            return this->m_pProto->aLimits.lValue;
        }
    }
    return 0;
}

bool CItem::OnAfterCreatedItem()
{
    // 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
    if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
    {
        // Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
        if (0 != GetSocket(1))
        {
            StartRealTimeExpireEvent();
        }
    }

    return true;
}


#ifdef __AUCTION__

// 경매장
// window를 경매장으로 한다.

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();
    thecore_memcpy (new_item->alSockets, m_alSockets, sizeof (m_alSockets));
    thecore_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);
        DWORD remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
        DWORD given_time = fPercent * duration / 100u;
        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;
        }
    }
    // 우선 용혼석에 관해서만 하도록 한다.
    else
        return 0;
}

int CItem::GiveMoreTime_Fix(DWORD dwTime)
{
    if (IsDragonSoul())
    {
        DWORD duration = DSManager::instance().GetDuration(this);
        DWORD 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;
        }
    }
    // 우선 용혼석에 관해서만 하도록 한다.
    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.bType)
            return GetProto()->aLimits.lValue;
    }

    if (GetProto()->cLimitTimerBasedOnWearIndex >= 0)
    {
        BYTE cLTBOWI = GetProto()->cLimitTimerBasedOnWearIndex;
        return GetProto()->aLimits[cLTBOWI].lValue;
    }

    return -1;
}

bool CItem::IsSameSpecialGroup(const LPITEM item) const
{
    // 서로 VNUM이 같다면 같은 그룹인 것으로 간주
    if (this->GetVnum() == item->GetVnum())
        return true;

    if (GetSpecialGroup() && (item->GetSpecialGroup() == GetSpecialGroup()))
        return true;

    return false;
}

#ifdef __CHANGE_LOOK_SYSTEM__
void CItem::SetItemLook(DWORD look)
{
    m_dwLook = look;
    UpdatePacket();
    ITEM_MANAGER::instance().SaveSingleItem(this);
    Save();
}
#endif

 

  

item.cpp

Link to comment
Share on other sites

5 hours ago, newhere said:

Hey, i have problem with Sash.

Its absorbing the 100% of the 1/5 and 6/7 Bonus.

Like in this Thread. But i dont know what/how to change in item.cpp maybe you can help me.

Is it here?

                        attrVal = int(float(attrVal) / 100.0f * float(GetSocket(0)));// <= 0 ? 1 : int(float(attrVal) / 100.0f * float(GetSocket(0)));

item.cpp full:

  Reveal hidden contents

#include "stdafx.h"
#include "utils.h"
#include "config.h"
#include "char.h"
#include "desc.h"
#include "sectree_manager.h"
#include "packet.h"
#include "mob_manager.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"
#ifdef SHOP_SEARCH
#include "shop_search.h"
#endif
#include "../../common/VnumHelper.h"
#include "../../common/CommonDefines.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_pkExpireEvent(NULL), m_pkUniqueExpireEvent(NULL),
    m_pkTimerBasedOnWearExpireEvent(NULL), m_pkRealTimeExpireEvent(NULL),
       m_pkAccessorySocketExpireEvent(NULL), m_pkOwnershipEvent(NULL), m_dwOwnershipPID(0), m_bSkipSave(false), m_isLocked(false),
    m_dwMaskVnum(0), m_dwSIGVnum (0)
#ifdef __CHANGE_LOOK_SYSTEM__
    , m_dwLook(0)
#endif
{
    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;
#ifdef OFFLINE_SHOP
    m_dwRealID = 0;
#endif
    m_bSkipSave = false;
    m_dwLastOwnerPID = 0;
#ifdef __CHANGE_LOOK_SYSTEM__
    m_dwLook = 0;
#endif
}

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;
#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
    for (size_t i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
        pack.alSockets = GetSocket(i);

    thecore_memcpy(pack.aAttrs, GetAttributes(), sizeof(pack.aAttrs));
#endif

    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;
        strlcpy(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);
}

#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
const char * CItem::GetName()
{
    static char szItemName[128];
    memset(szItemName, 0, sizeof(szItemName));
    if (GetProto())
    {
        int len = 0;
        switch (GetType())
        {
            case ITEM_POLYMORPH:
            {
                const DWORD dwMobVnum = GetSocket(0);
                const CMob* pMob = CMobManager::instance().Get(dwMobVnum);
                if (pMob)
                    len = snprintf(szItemName, sizeof(szItemName), "%s", pMob->m_table.szLocaleName);

                break;
            }
            case ITEM_SKILLBOOK:
            case ITEM_SKILLFORGET:
            {
                const DWORD dwSkillVnum = (GetVnum() == ITEM_SKILLBOOK_VNUM || GetVnum() == ITEM_SKILLFORGET_VNUM) ? GetSocket(0) : 0;
                const CSkillProto* pSkill = (dwSkillVnum != 0) ? CSkillManager::instance().Get(dwSkillVnum) : NULL;
                if (pSkill)
                    len = snprintf(szItemName, sizeof(szItemName), "%s", pSkill->szName);

                break;
            }
        }
        len += snprintf(szItemName + len, sizeof(szItemName) - len, (len>0)?" %s":"%s", GetProto()->szLocaleName);
    }

    return szItemName;
}
#endif

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(long bit)
{
    REMOVE_BIT(m_lFlag, bit);
}

void CItem::AddFlag(long 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);
#ifdef __CHANGE_LOOK_SYSTEM__
    pack.dwVnum = m_dwLook;
#endif
    pack.count    = m_dwCount;

    for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
        pack.alSockets = m_alSockets;

    thecore_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, g_bItemCountLimit);
    }
}

bool CItem::SetCount(DWORD count)
{
    if (GetType() == ITEM_ELK)
    {
        m_dwCount = MIN(count, INT_MAX);
    }
    else
    {
        m_dwCount = MIN(count, g_bItemCountLimit);
    }

    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
                {
#ifdef ENABLE_5_INVENTORY
                    pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 750);                
#else
                    pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 255);
#endif
                }
            }

            M2_DESTROY_ITEM(this);
        }
        else
        {
            if (!IsDragonSoul())
            {
#ifdef ENABLE_5_INVENTORY
                m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 750);                
#else
                m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 255);
#endif
            }
            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)    
    {
        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())
                    sys_err("CItem::RemoveFromCharacter: Invalid Item Position");
                else
                {
                    pOwner->SetItem(cell, NULL);
                }
            }
        }

        m_pOwner = NULL;
        m_wCell = 0;

        SetWindow(RESERVED_WINDOW);
#ifdef OFFLINE_SHOP
        if(!GetRealID())
#endif
        Save();
        return (this);
    }
}

#ifdef __HIGHLIGHT_SYSTEM__
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell, bool isHighLight)
#else
bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell)
#endif
{
    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);

#ifdef __HIGHLIGHT_SYSTEM__
    ch->SetItem(TItemPos(window_type, pos), this, isHighLight);
#else
    ch->SetItem(TItemPos(window_type, pos), this);
#endif
    m_pOwner = ch;

    Save();
    return true;
}

LPITEM CItem::RemoveFromGround()
{
    if (GetSectree())
    {
        SetOwnership(NULL);

        GetSectree()->RemoveEntity(this);

        ViewCleanup();

        Save();
    }

    return (this);
}

bool CItem::AddToGround(long 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;
#ifdef ENABLE_WOLFMAN_CHARACTER
        case JOB_WOLFMAN:
            if (GetAntiFlag() & ITEM_ANTIFLAG_WOLFMAN)
                return false;
            break;
#endif
    }

    return true;
}
int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
{
    // 코스츔 아이템(ITEM_COSTUME)은 WearFlag 없어도 됨. (sub type으로 착용위치 구분. 귀찮게 또 wear flag 줄 필요가 있나..)
    // 용혼석(ITEM_DS, ITEM_SPECIAL_DS)도  SUB_TYPE으로 구분. 신규 반지, 벨트는 ITEM_TYPE으로 구분 -_-
#ifdef SHININGSYSTEM
    if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType() && ITEM_SHINING != GetType())
        return -1;
#else    
    if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
        return -1;
#endif
    // 용혼석 슬롯을 WEAR로 처리할 수가 없어서(WEAR는 최대 32개까지 가능한데 용혼석을 추가하면 32가 넘는다.)
    // 인벤토리의 특정 위치((INVENTORY_MAX_NUM + WEAR_MAX_NUM)부터 (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)까지)를
    // 용혼석 슬롯으로 정함.
    // return 할 때에, INVENTORY_MAX_NUM을 뺀 이유는,
    // 본래 WearCell이 INVENTORY_MAX_NUM를 빼고 return 하기 때문.
    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;
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
        else if (GetSubType() == COSTUME_MOUNT)
            return WEAR_COSTUME_MOUNT;
#endif
#ifdef __COSTUME_ACCE__
        else if (GetSubType() == COSTUME_ACCE)
            return WEAR_COSTUME_ACCE;
#endif
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
        else if (GetSubType() == COSTUME_WEAPON)
            return WEAR_COSTUME_WEAPON;
#endif
    }
#if !defined(ENABLE_MOUNT_COSTUME_SYSTEM) && !defined(__COSTUME_ACCE__)
    else if (GetType() == ITEM_RING)
    {
        if (ch->GetWear(WEAR_RING1))
            return WEAR_RING2;
        else
            return WEAR_RING1;
    }
#endif
    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;
    }
#ifdef SHININGSYSTEM
    else if (GetType() == ITEM_SHINING)
    {
        if (GetSubType() == SHINING_WEAPON) {
            for (int i = WEAR_SHINING_WEAPON_1; i <= WEAR_SHINING_WEAPON_3; i++)
            {
                if (!ch->GetWear(i))
                    return i;
            }
            return WEAR_SHINING_WEAPON_1;
        }
        else if (GetSubType() == SHINING_ARMOR) {
            if (ch->GetWear(WEAR_SHINING_ARMOR_1))
                return WEAR_SHINING_ARMOR_2;
            else
                return WEAR_SHINING_ARMOR_1;
        }
        else if (GetSubType() == SHINING_SPECIAL) {
            return WEAR_SHINING_SPECIAL;
        }
    }
#endif
    // 수집 퀘스트를 위한 아이템이 박히는곳으로 한번 박히면 절대 E수 없다.
    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;

    // 무기와 갑옷만 소켓을 적용시킨다.
    if (false == IsAccessoryForSocket())
    {
        if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
        {
            // 소켓이 속성강화에 사용되는 경우 적용하지 않는다 (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.bType == APPLY_NONE)
                            continue;

                        if (p->aApplies.bType == APPLY_SKILL)
                            m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? p->aApplies.lValue : p->aApplies.lValue ^ 0x00800000);
                        else
                            m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? p->aApplies.lValue : -p->aApplies.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.bType == APPLY_NONE)
            continue;

        long value = m_pProto->aApplies.lValue;

        if (m_pProto->aApplies.bType == APPLY_SKILL)
        {
            m_pOwner->ApplyPoint(m_pProto->aApplies.bType, bAdd ? value : value ^ 0x00800000);
        }
        else
        {
            if (0 != accessoryGrade)
                value += MAX(accessoryGrade, value * aiAccessorySocketEffectivePct[accessoryGrade] / 100);

            m_pOwner->ApplyPoint(m_pProto->aApplies.bType, bAdd ? value : -value);
        }
    }
    // 초승달의 반지, 할로윈 사탕, 행복의 반지, 영원한 사랑의 펜던트의 경우
    // 기존의 하드 코딩으로 강제로 속성을 부여했지만,
    // 그 부분을 제거하고 special item group 테이블에서 속성을 부여하도록 변경하였다.
    // 하지만 하드 코딩되어있을 때 생성된 아이템이 남아있을 수도 있어서 특수처리 해놓는다.
    // 이 아이템들의 경우, 밑에 ITEM_UNIQUE일 때의 처리로 속성이 부여되기 때문에,
    // 아이템에 박혀있는 attribute는 적용하지 않고 넘어간다.
#ifdef __COSTUME_ACCE__
    if (ITEM_COSTUME == GetType() && COSTUME_ACCE == GetSubType())
    {
        TItemTable * p = ITEM_MANAGER::instance().GetTable(GetSocket(1));

        if (p) {

            for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
            {
                if (p->aApplies.bType == APPLY_NONE)
                    continue;

                int value = p->aApplies.lValue;

                if (value < 0)
                    value = 1;
                else
                    value = int(float(value) / 100.0f * float(GetSocket(0))) <= 0 ? 1 : int(float(value) / 100.0f * float(GetSocket(0)));

                if (p->aApplies.bType == APPLY_SKILL)
                {
                    m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? value : value ^ 0x00800000);
                }
                else
                {
                    m_pOwner->ApplyPoint(p->aApplies.bType, bAdd ? value : -value);
                }
            }
        }
    }
#endif
    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);
                short attrVal = ia.sValue;
#ifdef __COSTUME_ACCE__
                if (ITEM_COSTUME == GetType() && COSTUME_ACCE == GetSubType())
                {
                    if (attrVal < 0)
                        attrVal = 1;
                    else
                        attrVal = int(float(attrVal) / 100.0f * float(GetSocket(0)));// <= 0 ? 1 : int(float(attrVal) / 100.0f * float(GetSocket(0)));
                }
#endif
                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, 0);
                }
            }
            break;

        case ITEM_WEAPON:
            {
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
                if (0 != m_pOwner->GetWear(WEAR_COSTUME_WEAPON))
                    break;
#endif

                if (bAdd)
                {
#ifdef __CHANGE_LOOK_SYSTEM__
                    if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
                        m_pOwner->SetPart(PART_WEAPON, GetItemLook() > 0 ? GetItemLook() : GetVnum());
#else
                    if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
                        m_pOwner->SetPart(PART_WEAPON, GetVnum());
#endif
                }
                else
                {
                    if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
                        m_pOwner->SetPart(PART_WEAPON, 0);
                }
            }
            break;

        case ITEM_ARMOR:
            {
                // 코스츔 body를 입고있다면 armor는 벗던 입던 상관 없이 비주얼에 영향을 주면 안 됨.
                if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
                    break;

                if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD)
                {
                    if (bAdd)
                    {
#ifdef __CHANGE_LOOK_SYSTEM__
                        if (GetProto()->bSubType == ARMOR_BODY)
                            m_pOwner->SetPart(PART_MAIN, GetItemLook() > 0 ? GetItemLook() : GetVnum());
#else
                        if (GetProto()->bSubType == ARMOR_BODY)
                            m_pOwner->SetPart(PART_MAIN, GetVnum());
#endif
                    }
                    else
                    {
                        if (GetProto()->bSubType == ARMOR_BODY)
                            m_pOwner->SetPart(PART_MAIN, m_pOwner->GetOriginalPart(PART_MAIN));
                    }
                }
            }
            break;

        // 코스츔 아이템 입었을 때 캐릭터 parts 정보 세팅. 기존 스타일대로 추가함..
        case ITEM_COSTUME:
            {
                DWORD toSetValue = this->GetVnum();
                EParts toSetPart = PART_MAX_NUM;

                // 갑옷 코스츔
                if (GetSubType() == COSTUME_BODY)
                {
                    toSetPart = PART_MAIN;

                    if (false == bAdd)
                    {
                        // 코스츔 갑옷을 벗었을 때 원래 갑옷을 입고 있었다면 그 갑옷으로 look 세팅, 입지 않았다면 default look
#ifdef __CHANGE_LOOK_SYSTEM__
                        CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
#else
                        const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
#endif
#ifdef __CHANGE_LOOK_SYSTEM__
                        toSetValue = (NULL != pArmor) ? pArmor->GetItemLook() > 0 ? pArmor->GetItemLook() : pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
#else
                        toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
#endif
                    }

                }

                // 헤어 코스츔
                else if (GetSubType() == COSTUME_HAIR)
                {
                    toSetPart = PART_HAIR;

                    // 코스츔 헤어는 shape값을 item proto의 value3에 세팅하도록 함. 특별한 이유는 없고 기존 갑옷(ARMOR_BODY)의 shape값이 프로토의 value3에 있어서 헤어도 같이 value3으로 함.
                    // [NOTE] 갑옷은 아이템 vnum을 보내고 헤어는 shape(value3)값을 보내는 이유는.. 기존 시스템이 그렇게 되어있음...
                    toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
                }

#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
                else if (GetSubType() == COSTUME_MOUNT)
                {
                    // not need to do a thing in here
                }
#endif

#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
                else if (GetSubType() == COSTUME_WEAPON)
                {
                    toSetPart = PART_WEAPON;
                    if (false == bAdd)
                    {
#ifdef __CHANGE_LOOK_SYSTEM__
                        CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
#else
                        const CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
#endif            
#ifdef __CHANGE_LOOK_SYSTEM__
                        toSetValue = (NULL != pWeapon) ? pWeapon->GetItemLook() > 0 ? pWeapon->GetItemLook() : pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
#else
                        toSetValue = (NULL != pWeapon) ? pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
#endif
                    }
                }
#endif
#ifdef __COSTUME_ACCE__
                else if (GetSubType() == COSTUME_ACCE) {
                    toSetPart = PART_ACCE;
                    toSetValue = (true == bAdd) ? this->GetVnum() : 0;
                }
#endif

                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:
#ifdef SHININGSYSTEM
    case ITEM_SHINING:
#endif
        return true;
    }

    return false;
}

#define ENABLE_IMMUNE_FIX
// return false on error state
#ifdef ENABLE_5_INVENTORY
bool CItem::EquipTo(LPCHARACTER ch, WORD bWearCell)
#else
bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
#endif
{
    if (!ch)
    {
        sys_err("EquipTo: nil character");
        return false;
    }

    // 용혼석 슬롯 index는 WEAR_MAX_NUM 보다 큼.
    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); // 여기서 패킷 나감

    m_pOwner = ch;
    m_bEquipped = true;
    m_wCell    = INVENTORY_MAX_NUM + bWearCell;

#ifndef ENABLE_IMMUNE_FIX
    DWORD dwImmuneFlag = 0;

    for (int i = 0; i < WEAR_MAX_NUM; ++i)
    {
        if (m_pOwner->GetWear(i))
        {
            // m_pOwner->ChatPacket(CHAT_TYPE_INFO, "unequip immuneflag(%u)", m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); // always 0
            SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
        }
    }

    m_pOwner->SetImmuneFlag(dwImmuneFlag);
#endif

    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;
    }

    //신규 말 아이템 제거시 처리
    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);

#ifndef ENABLE_IMMUNE_FIX
    DWORD dwImmuneFlag = 0;

    for (int i = 0; i < WEAR_MAX_NUM; ++i)
    {
        if (m_pOwner->GetWear(i))
        {
            // m_pOwner->ChatPacket(CHAT_TYPE_INFO, "unequip immuneflag(%u)", m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag); // always 0
            SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->m_pProto->dwImmuneFlag);
        }
    }

    m_pOwner->SetImmuneFlag(dwImmuneFlag);
#endif

    m_pOwner->ComputeBattlePoints();

    m_pOwner->UpdatePacket();

    m_pOwner = NULL;
    m_wCell = 0;
    m_bEquipped    = false;

    return true;
}

long 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)
{
    thecore_memcpy(m_alSockets, c_al, sizeof(m_alSockets));
    Save();
}

void CItem::SetSocket(int i, long v, bool bLog)
{
    assert(i < ITEM_SOCKET_MAX_NUM);
    m_alSockets = v;
    UpdatePacket();
    Save();
    if (bLog)
    {
#ifdef ENABLE_NEWSTUFF
        if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
        LogManager::instance().ItemLog(i, v, 0, GetID(), "SET_SOCKET", "", "", GetOriginalVnum());
    }
}

#ifdef ENABLE_YANG_LIMIT
long long CItem::GetGold()
#else
int CItem::GetGold()
#endif
{
    if (IS_SET(GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
    {
        if (GetProto()->dwGold == 0)
            return GetCount();
        else
            return GetCount() / GetProto()->dwGold;
    }
    else
        return GetProto()->dwGold;
}

#ifdef ENABLE_YANG_LIMIT
long long CItem::GetShopBuyPrice()
#else
int CItem::GetShopBuyPrice()
#endif
{
    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 (iSec <= 10)
        iSec = 30;

    m_dwOwnershipPID = ch->GetPlayerID();

    item_event_info* info = AllocEventInfo<item_event_info>();
    strlcpy(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;
    strlcpy(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;

    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;
    }

    // 100% 확률로 좋은 속성 하나
    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
        {
            // 게임 내에 시간제 아이템들이 빠릿빠릿하게 사라지지 않는 버그가 있어
            // 수정
            // 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);
        }
    }
}

// 시간 후불제
// timer를 시작할 때에 시간 차감하는 것이 아니라,
// timer가 발화할 때에 timer가 동작한 시간 만큼 시간 차감을 한다.
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);

        // 일단 timer based on wear 용혼석은 시간 다 되었다고 없애지 않는다.
        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))
    {
        switch (item->GetVnum())
        {
            if(item->IsNewMountItem())
            {
                if (item->GetSocket(2) != 0)
                    item->ClearMountAttributeAndAffect();
            }
            break;
        }
#ifdef SHOP_SEARCH
        if (item->GetOwner() && CShopSearchHelper::IsGlass(item->GetVnum()))
            CShopSearchHelper::Close(item->GetVnum(), item->GetOwner());
    
#endif
        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.bType || LIMIT_REAL_TIME_START_FIRST_USE == GetProto()->aLimits.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.bType)
            return true;
    }
    return false;
}

void CItem::StartUniqueExpireEvent()
{
    if (GetType() != ITEM_UNIQUE)
        return;

    if (m_pkUniqueExpireEvent)
        return;

    //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
    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)));
}

// 시간 후불제
// timer_based_on_wear_expire_event 설명 참조
void CItem::StartTimerBasedOnWearExpireEvent()
{
    if (m_pkTimerBasedOnWearExpireEvent)
        return;

    //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
    if (IsRealTimeItem())
        return;

    if (-1 == GetProto()->cLimitTimerBasedOnWearIndex)
        return;

    int iSec = GetSocket(0);

    // 남은 시간을 분단위로 끊기 위해...
    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) // 게임시간제 이외의 아이템은 UniqueExpireEvent를 중단할 수 없다.
        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());
}

//
// 악세서리 소켓 처리.
//
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년 2월 새로 추가된 '벨트' 아이템의 경우 기획팀에서 악세서리 소켓 시스템을 그대로 이용하자고 함.
}

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에서 소켓 빠질때까지 남은 시간 %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;
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
    if (ITEM_COSTUME == GetType() && COSTUME_MOUNT == GetSubType())
        return true;
#endif
    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
// 이거 지금은 안쓴데... 근데 혹시나 싶어서 남겨둠.
// 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에 박혀있던 보석이 사라집니다."), GetName());
        }

        ModifyPoints(false);
        SetAccessorySocketGrade(GetAccessorySocketGrade()-1);
        ModifyPoints(true);

        int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];

        if (test_server)
            iDownTime /= 60;

        SetAccessorySocketDownGradeTime(iDownTime);

        if (iDownTime)
            StartAccessorySocketExpireEvent();
    }
}

// ring에 item을 박을 수 있는지 여부를 체크해서 리턴
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 },
        { 50639, 14570, 16570, 17570 },
    };

    DWORD item_type = (item->GetVnum() / 10) * 10;
    for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++)
    {
        const JewelAccessoryInfo& info = infos;
        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.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.bType == LIMIT_LEVEL)
        {
            if (this->m_pProto->aLimits.lValue > nLevel) return false;
            else return true;
        }
    }
    return true;
}

long CItem::FindApplyValue(BYTE bApplyType)
{
    if (m_pProto == NULL)
        return 0;

    for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
    {
        if (m_pProto->aApplies.bType == bApplyType)
            return m_pProto->aApplies.lValue;
    }

    return 0;
}

void CItem::CopySocketTo(LPITEM pItem)
{
    for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
    {
        pItem->m_alSockets = m_alSockets;
    }
}

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)
        {
#ifdef ENABLE_NEWSTUFF
            if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
            LogManager::instance().ItemLog(i, m_alSockets, 0, GetID(), "INFO_SOCKET", "", pszIP ? pszIP : "", GetOriginalVnum());
        }
    }

    for (int i = 0; i<ITEM_ATTRIBUTE_MAX_NUM; ++i)
    {
        int    type    = m_aAttr.bType;
        int value    = m_aAttr.sValue;

        if (type)
        {
#ifdef ENABLE_NEWSTUFF
            if (g_iDbLogLevel>=LOG_LEVEL_MAX)
#endif
            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.bType == LIMIT_LEVEL)
        {
            return this->m_pProto->aLimits.lValue;
        }
    }
    return 0;
}

bool CItem::OnAfterCreatedItem()
{
    // 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
    if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
    {
        // Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
        if (0 != GetSocket(1))
        {
            StartRealTimeExpireEvent();
        }
    }

    return true;
}


#ifdef __AUCTION__

// 경매장
// window를 경매장으로 한다.

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();
    thecore_memcpy (new_item->alSockets, m_alSockets, sizeof (m_alSockets));
    thecore_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);
        DWORD remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
        DWORD given_time = fPercent * duration / 100u;
        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;
        }
    }
    // 우선 용혼석에 관해서만 하도록 한다.
    else
        return 0;
}

int CItem::GiveMoreTime_Fix(DWORD dwTime)
{
    if (IsDragonSoul())
    {
        DWORD duration = DSManager::instance().GetDuration(this);
        DWORD 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;
        }
    }
    // 우선 용혼석에 관해서만 하도록 한다.
    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.bType)
            return GetProto()->aLimits.lValue;
    }

    if (GetProto()->cLimitTimerBasedOnWearIndex >= 0)
    {
        BYTE cLTBOWI = GetProto()->cLimitTimerBasedOnWearIndex;
        return GetProto()->aLimits[cLTBOWI].lValue;
    }

    return -1;
}

bool CItem::IsSameSpecialGroup(const LPITEM item) const
{
    // 서로 VNUM이 같다면 같은 그룹인 것으로 간주
    if (this->GetVnum() == item->GetVnum())
        return true;

    if (GetSpecialGroup() && (item->GetSpecialGroup() == GetSpecialGroup()))
        return true;

    return false;
}

#ifdef __CHANGE_LOOK_SYSTEM__
void CItem::SetItemLook(DWORD look)
{
    m_dwLook = look;
    UpdatePacket();
    ITEM_MANAGER::instance().SaveSingleItem(this);
    Save();
}
#endif

 

  

item.cpp

I think you must have this files: acce.cpp and acce.h (from game>src, server source), something like that no? If so please show the acce.cpp, either way, add your item_length.h (from common, server source)

  • Love 1

It's all lies

Link to comment
Share on other sites

hey, thanks for your answer.

 

i dont have acce.cpp or acce.h

item_lenght.h

Spoiler

#ifndef __INC_METIN2_ITEM_LENGTH_H__
#define __INC_METIN2_ITEM_LENGTH_H__

#include "CommonDefines.h"

enum EItemMisc
{
    ITEM_NAME_MAX_LEN            = 24,
    ITEM_VALUES_MAX_NUM            = 6,
    ITEM_SMALL_DESCR_MAX_LEN    = 256,
    ITEM_LIMIT_MAX_NUM            = 2,
    ITEM_APPLY_MAX_NUM            = 3,
    ITEM_SOCKET_MAX_NUM            = 3,
    ITEM_MAX_COUNT                = 200,

    ITEM_ATTRIBUTE_NORM_NUM        = 5,
    ITEM_ATTRIBUTE_RARE_NUM        = 2,

    ITEM_ATTRIBUTE_NORM_START    = 0,
    ITEM_ATTRIBUTE_NORM_END        = ITEM_ATTRIBUTE_NORM_START + ITEM_ATTRIBUTE_NORM_NUM,

    ITEM_ATTRIBUTE_RARE_START    = ITEM_ATTRIBUTE_NORM_END,
    ITEM_ATTRIBUTE_RARE_END        = ITEM_ATTRIBUTE_RARE_START + ITEM_ATTRIBUTE_RARE_NUM,

    ITEM_ATTRIBUTE_MAX_NUM        = ITEM_ATTRIBUTE_RARE_END, // 7
    ITEM_ATTRIBUTE_MAX_LEVEL    = 5,
    ITEM_AWARD_WHY_MAX_LEN        = 50,

    REFINE_MATERIAL_MAX_NUM        = 5,

    ITEM_ELK_VNUM                = 50026,
#ifdef __COSTUME_ACCE__
    ITEM_MAX_ACCEDRAIN = 25,
    ITEM_MIN_ACCEDRAIN = 20,
#endif
};

const BYTE ITEM_SOCKET_REMAIN_SEC = 0;
enum EItemValueIdice
{
    ITEM_VALUE_DRAGON_SOUL_POLL_OUT_BONUS_IDX = 0,
    ITEM_VALUE_CHARGING_AMOUNT_IDX = 0,
    ITEM_VALUE_SECONDARY_COIN_UNIT_IDX = 0,
};
enum EItemDragonSoulSockets
{
    ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX = 2,
    ITEM_SOCKET_CHARGING_AMOUNT_IDX = 2,
};
// 헐 이거 미친거 아니야?
// 나중에 소켓 확장하면 어쩌려고 이지랄 -_-;;;
enum EItemUniqueSockets
{
    ITEM_SOCKET_UNIQUE_SAVE_TIME = ITEM_SOCKET_MAX_NUM - 2,
    ITEM_SOCKET_UNIQUE_REMAIN_TIME = ITEM_SOCKET_MAX_NUM - 1
};

enum EItemTypes
{
    ITEM_NONE,              //0
    ITEM_WEAPON,            //1//무기
    ITEM_ARMOR,             //2//갑옷
    ITEM_USE,               //3//아이템 사용
    ITEM_AUTOUSE,           //4
    ITEM_MATERIAL,          //5
    ITEM_SPECIAL,           //6 //스페셜 아이템
    ITEM_TOOL,              //7
    ITEM_LOTTERY,           //8//복권
    ITEM_ELK,               //9//돈
    ITEM_METIN,             //10
    ITEM_CONTAINER,         //11
    ITEM_FISH,              //12//낚시
    ITEM_ROD,               //13
    ITEM_RESOURCE,          //14
    ITEM_CAMPFIRE,          //15
    ITEM_UNIQUE,            //16
    ITEM_SKILLBOOK,         //17
    ITEM_QUEST,             //18
    ITEM_POLYMORPH,         //19
    ITEM_TREASURE_BOX,      //20//보물상자
    ITEM_TREASURE_KEY,      //21//보물상자 열쇠
    ITEM_SKILLFORGET,       //22
    ITEM_GIFTBOX,           //23
    ITEM_PICK,              //24
    ITEM_HAIR,              //25//머리
    ITEM_TOTEM,             //26//토템
    ITEM_BLEND,                //27//생성될때 랜덤하게 속성이 붙는 약물
    ITEM_COSTUME,            //28//코스츔 아이템 (2011년 8월 추가된 코스츔 시스템용 아이템)
    ITEM_DS,                //29 //용혼석
    ITEM_SPECIAL_DS,        //30 // 특수한 용혼석 (DS_SLOT에 착용하는 UNIQUE 아이템이라 생각하면 됨)
    ITEM_EXTRACT,            //31 추출도구.
    ITEM_SECONDARY_COIN,    //32 ?? 명도전??
    ITEM_RING,                //33 반지
    ITEM_BELT,                //34 벨트
#ifdef COMPANION_SYSTEM
    ITEM_COMPANION,
#endif
#ifdef SHININGSYSTEM
    ITEM_SHINING,            //36 벨트
#endif
};

enum EMetinSubTypes
{
    METIN_NORMAL,
    METIN_GOLD,
};

enum EWeaponSubTypes
{
    WEAPON_SWORD,
    WEAPON_DAGGER,
    WEAPON_BOW,
    WEAPON_TWO_HANDED,
    WEAPON_BELL,
    WEAPON_FAN,
    WEAPON_ARROW,
    WEAPON_MOUNT_SPEAR,
#ifdef ENABLE_WOLFMAN_CHARACTER
    WEAPON_CLAW,
#endif
    WEAPON_NUM_TYPES,
};

enum EArmorSubTypes
{
    ARMOR_BODY,
    ARMOR_HEAD,
    ARMOR_SHIELD,
    ARMOR_WRIST,
    ARMOR_FOOTS,
    ARMOR_NECK,
    ARMOR_EAR,
    ARMOR_NUM_TYPES
};

enum ECostumeSubTypes
{
    COSTUME_BODY = ARMOR_BODY,            // [중요!!] ECostumeSubTypes enum value는  종류별로 EArmorSubTypes의 그것과 같아야 함.
    COSTUME_HAIR = ARMOR_HEAD,            // 이는 코스츔 아이템에 추가 속성을 붙이겠다는 사업부의 요청에 따라서 기존 로직을 활용하기 위함임.
#ifdef __COSTUME_ACCE__
    COSTUME_ACCE,
#endif
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
    COSTUME_MOUNT    = 3,
#endif
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
    COSTUME_WEAPON    = 4,
#endif
    COSTUME_NUM_TYPES,
};
#ifdef __COSTUME_ACCE__
enum {
    ABSORB,
    COMBINE,
};

enum {
    ACCE_SLOT_LEFT,
    ACCE_SLOT_RIGHT,
    ACCE_SLOT_RESULT,
    ACCE_SLOT_MAX_NUM,
};
#endif
enum EDragonSoulSubType
{
    DS_SLOT1,
    DS_SLOT2,
    DS_SLOT3,
    DS_SLOT4,
    DS_SLOT5,
    DS_SLOT6,
    DS_SLOT_MAX,
};

enum EDragonSoulGradeTypes
{
    DRAGON_SOUL_GRADE_NORMAL,
    DRAGON_SOUL_GRADE_BRILLIANT,
    DRAGON_SOUL_GRADE_RARE,
    DRAGON_SOUL_GRADE_ANCIENT,
    DRAGON_SOUL_GRADE_LEGENDARY,
    DRAGON_SOUL_GRADE_MAX,

};

enum EDragonSoulStepTypes
{
    DRAGON_SOUL_STEP_LOWEST,
    DRAGON_SOUL_STEP_LOW,
    DRAGON_SOUL_STEP_MID,
    DRAGON_SOUL_STEP_HIGH,
    DRAGON_SOUL_STEP_HIGHEST,
    DRAGON_SOUL_STEP_MAX,
};
#define DRAGON_SOUL_STRENGTH_MAX 7

enum EDSInventoryMaxNum
{
    DRAGON_SOUL_INVENTORY_MAX_NUM = DS_SLOT_MAX * DRAGON_SOUL_GRADE_MAX * DRAGON_SOUL_BOX_SIZE,
};

#ifdef SHININGSYSTEM
enum EShiningSubTypes
{
    SHINING_WEAPON,
    SHINING_ARMOR,
    SHINING_SPECIAL,
};
#endif

enum EFishSubTypes
{
    FISH_ALIVE,
    FISH_DEAD,
};

enum EResourceSubTypes
{
    RESOURCE_FISHBONE,
    RESOURCE_WATERSTONEPIECE,
    RESOURCE_WATERSTONE,
    RESOURCE_BLOOD_PEARL,
    RESOURCE_BLUE_PEARL,
    RESOURCE_WHITE_PEARL,
    RESOURCE_BUCKET,
    RESOURCE_CRYSTAL,
    RESOURCE_GEM,
    RESOURCE_STONE,
    RESOURCE_METIN,
    RESOURCE_ORE,
};

enum EUniqueSubTypes
{
    UNIQUE_NONE,
    UNIQUE_BOOK,
    UNIQUE_SPECIAL_RIDE,
    UNIQUE_SPECIAL_MOUNT_RIDE,
};

enum EUseSubTypes
{
    USE_POTION,                    // 0
    USE_TALISMAN,
    USE_TUNING,
    USE_MOVE,
    USE_TREASURE_BOX,
    USE_MONEYBAG,
    USE_BAIT,
    USE_ABILITY_UP,
    USE_AFFECT,
    USE_CREATE_STONE,
    USE_SPECIAL,                // 10
    USE_POTION_NODELAY,
    USE_CLEAR,
    USE_INVISIBILITY,
    USE_DETACHMENT,
    USE_BUCKET,
    USE_POTION_CONTINUE,
    USE_CLEAN_SOCKET,
    USE_CHANGE_ATTRIBUTE,
    USE_ADD_ATTRIBUTE,
    USE_ADD_ACCESSORY_SOCKET,    // 20
    USE_PUT_INTO_ACCESSORY_SOCKET,
    USE_ADD_ATTRIBUTE2,
    USE_RECIPE,
    USE_CHANGE_ATTRIBUTE2,
    USE_BIND,
    USE_UNBIND,
    USE_TIME_CHARGE_PER,
    USE_TIME_CHARGE_FIX,                // 28
    USE_PUT_INTO_BELT_SOCKET,            // 29 벨트 소켓에 사용할 수 있는 아이템
    USE_PUT_INTO_RING_SOCKET,            // 30 반지 소켓에 사용할 수 있는 아이템 (유니크 반지 말고, 새로 추가된 반지 슬롯)
    USE_CHANGE_COSTUME_ATTR,            // 31
    USE_RESET_COSTUME_ATTR,                // 32
#ifdef __CHANGE_LOOK_SYSTEM__
    USE_RESET_LOOK_VNUM,
#endif
};

enum EExtractSubTypes
{
    EXTRACT_DRAGON_SOUL,
    EXTRACT_DRAGON_HEART,
};

enum EAutoUseSubTypes
{
    AUTOUSE_POTION,
    AUTOUSE_ABILITY_UP,
    AUTOUSE_BOMB,
    AUTOUSE_GOLD,
    AUTOUSE_MONEYBAG,
    AUTOUSE_TREASURE_BOX
};

enum EMaterialSubTypes
{
    MATERIAL_LEATHER,
    MATERIAL_BLOOD,
    MATERIAL_ROOT,
    MATERIAL_NEEDLE,
    MATERIAL_JEWEL,
    MATERIAL_DS_REFINE_NORMAL,
    MATERIAL_DS_REFINE_BLESSED,
    MATERIAL_DS_REFINE_HOLLY,
};

enum ESpecialSubTypes
{
    SPECIAL_MAP,
    SPECIAL_KEY,
    SPECIAL_DOC,
    SPECIAL_SPIRIT,
};

enum EToolSubTypes
{
    TOOL_FISHING_ROD
};

enum ELotterySubTypes
{
    LOTTERY_TICKET,
    LOTTERY_INSTANT
};

enum EItemFlag
{
    ITEM_FLAG_REFINEABLE        = (1 << 0),
    ITEM_FLAG_SAVE            = (1 << 1),
    ITEM_FLAG_STACKABLE        = (1 << 2),    // 여러개 합칠 수 있음
    ITEM_FLAG_COUNT_PER_1GOLD    = (1 << 3),
    ITEM_FLAG_SLOW_QUERY        = (1 << 4),
    ITEM_FLAG_UNUSED01        = (1 << 5),    // UNUSED
    ITEM_FLAG_UNIQUE        = (1 << 6),
    ITEM_FLAG_MAKECOUNT        = (1 << 7),
    ITEM_FLAG_IRREMOVABLE        = (1 << 8),
    ITEM_FLAG_CONFIRM_WHEN_USE    = (1 << 9),
    ITEM_FLAG_QUEST_USE        = (1 << 10),
    ITEM_FLAG_QUEST_USE_MULTIPLE    = (1 << 11),
    ITEM_FLAG_QUEST_GIVE        = (1 << 12),
    ITEM_FLAG_LOG            = (1 << 13),
    ITEM_FLAG_APPLICABLE        = (1 << 14),
};

enum EItemAntiFlag
{
    ITEM_ANTIFLAG_FEMALE    = (1 << 0), // 여성 사용 불가
    ITEM_ANTIFLAG_MALE        = (1 << 1), // 남성 사용 불가
    ITEM_ANTIFLAG_WARRIOR    = (1 << 2), // 무사 사용 불가
    ITEM_ANTIFLAG_ASSASSIN    = (1 << 3), // 자객 사용 불가
    ITEM_ANTIFLAG_SURA        = (1 << 4), // 수라 사용 불가
    ITEM_ANTIFLAG_SHAMAN    = (1 << 5), // 무당 사용 불가
    ITEM_ANTIFLAG_GET        = (1 << 6), // 집을 수 없음
    ITEM_ANTIFLAG_DROP        = (1 << 7), // 버릴 수 없음
    ITEM_ANTIFLAG_SELL        = (1 << 8), // 팔 수 없음
    ITEM_ANTIFLAG_EMPIRE_A    = (1 << 9), // A 제국 사용 불가
    ITEM_ANTIFLAG_EMPIRE_B    = (1 << 10), // B 제국 사용 불가
    ITEM_ANTIFLAG_EMPIRE_C    = (1 << 11), // C 제국 사용 불가
    ITEM_ANTIFLAG_SAVE        = (1 << 12), // 저장되지 않음
    ITEM_ANTIFLAG_GIVE        = (1 << 13), // 거래 불가
    ITEM_ANTIFLAG_PKDROP    = (1 << 14), // PK시 떨어지지 않음
    ITEM_ANTIFLAG_STACK        = (1 << 15), // 합칠 수 없음
    ITEM_ANTIFLAG_MYSHOP    = (1 << 16), // 개인 상점에 올릴 수 없음
    ITEM_ANTIFLAG_SAFEBOX    = (1 << 17), // 창고에 넣을 수 없음
#ifdef ENABLE_WOLFMAN_CHARACTER
    ITEM_ANTIFLAG_WOLFMAN    = (1 << 18), // 수인족 사용 불가
#endif
};

enum EItemWearableFlag
{
    WEARABLE_BODY    = (1 << 0),
    WEARABLE_HEAD    = (1 << 1),
    WEARABLE_FOOTS    = (1 << 2),
    WEARABLE_WRIST    = (1 << 3),
    WEARABLE_WEAPON    = (1 << 4),
    WEARABLE_NECK    = (1 << 5),
    WEARABLE_EAR    = (1 << 6),
    WEARABLE_UNIQUE    = (1 << 7),
    WEARABLE_SHIELD    = (1 << 8),
    WEARABLE_ARROW    = (1 << 9),
    WEARABLE_HAIR    = (1 << 10),
    WEARABLE_ABILITY        = (1 << 11),
    WEARABLE_COSTUME_BODY    = (1 << 12),
};

enum ELimitTypes
{
    LIMIT_NONE,

    LIMIT_LEVEL,
    LIMIT_STR,
    LIMIT_DEX,
    LIMIT_INT,
    LIMIT_CON,
    LIMIT_PCBANG,

    /// 착용 여부와 상관 없이 실시간으로 시간 차감 (socket0에 소멸 시간이 박힘: unix_timestamp 타입)
    LIMIT_REAL_TIME,

    /// 아이템을 맨 처음 사용(혹은 착용) 한 순간부터 리얼타임 타이머 시작
    /// 최초 사용 전에는 socket0에 사용가능시간(초단위, 0이면 프로토의 limit value값 사용) 값이 쓰여있다가
    /// 아이템 사용시 socket1에 사용 횟수가 박히고 socket0에 unix_timestamp 타입의 소멸시간이 박힘.
    LIMIT_REAL_TIME_START_FIRST_USE,

    /// 아이템을 착용 중일 때만 사용 시간이 차감되는 아이템
    /// socket0에 남은 시간이 초단위로 박힘. (아이템 최초 사용시 해당 값이 0이면 프로토의 limit value값을 socket0에 복사)
    LIMIT_TIMER_BASED_ON_WEAR,

    LIMIT_MAX_NUM
};

enum EAttrAddonTypes
{
    ATTR_ADDON_NONE,
    // positive values are reserved for set
    ATTR_DAMAGE_ADDON = -1,
};

enum ERefineType
{
    REFINE_TYPE_NORMAL,
    REFINE_TYPE_NOT_USED1,
    REFINE_TYPE_SCROLL,
    REFINE_TYPE_HYUNIRON,
    REFINE_TYPE_MONEY_ONLY,
    REFINE_TYPE_MUSIN,
    REFINE_TYPE_BDRAGON,
};

#endif

 

 

item_length.h

Link to comment
Share on other sites

thanks for your answer. but i dont know.

i have like this:  

ITEM_MAX_ACCEDRAIN = 25,

ITEM_MIN_ACCEDRAIN = 20,

References

Spoiler

if ((pBaseItem->GetRefinedVnum() == 0) && (pBaseItem->GetSocket(0) < ITEM_MAX_ACCEDRAIN) && (GetAcceRefineGrade(pBaseItem->GetVnum()) == 4))
            {
                if (pBaseItem->GetSocket(0) < ITEM_MIN_ACCEDRAIN) {
                    ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ACCE_COMBINE_ABSORB_TO_LOW"));
                    return;
                }
                uppMax = true;
                result_vnum = pBaseItem->GetVnum();
            }
            else {
                result_vnum = pBaseItem->GetRefinedVnum();
            }

 

Link to comment
Share on other sites

  • Premium

Item max acce drain is the max perc. you get if you combine two custom sash and item

min max acce drain is the minimum perc. 

Now, you are asking the sash to drain more than 25% of an item and you have ITEM_MAX_ACCEDRAIN = 25,

what you gonna do? 

Link to comment
Share on other sites

8 minutes ago, newhere said:

I have no calculation for 1/5 and 6/7 bonus

they just add to the sash like in the weapon. no function for calculation.

 

so i need to find the item attribute add to sash thing

and write it like

if 25% sash  

  item_attr /100*25

i think.

Show me the functions where the absorptions happens and we can see where's the problem

  • Love 1

It's all lies

Link to comment
Share on other sites

maybe here: if (ABSORB == GetAcceWindowType())

Spoiler

 

if (ABSORB == GetAcceWindowType())
    {

        if (m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT] != WORD_MAX && m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT] != WORD_MAX)
        {
            LPITEM pkAcce = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT]));
            LPITEM pkWeaponToAbsorb = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT]));
            LPITEM pShowItem = ITEM_MANAGER::instance().CreateItem(pkAcce->GetVnum(), 1, 0, false, -1, true);

            pkWeaponToAbsorb->CopyAttributeTo(pShowItem);
            pShowItem->SetSocket(0, pkAcce->GetSocket(0));
            pShowItem->SetSocket(1, pkWeaponToAbsorb->GetVnum());

            TPacketGCAcce pack;
            pack.header = HEADER_GC_ACCE;
            pack.subheader = ACCE_SUBHEADER_GC_SET_ITEM;
            pack.size = sizeof(TPacketGCAcce) + sizeof(TPacketGCItemSet);

            TPacketGCItemSet pack_sub;

            pack_sub.header = 0;
            pack_sub.Cell = TItemPos(ACCEREFINE, (WORD)ACCE_SLOT_RESULT);
            pack_sub.vnum = pShowItem->GetVnum();
            pack_sub.count = (BYTE)pShowItem->GetCount();
            pack_sub.flags = pShowItem->GetFlag();
            pack_sub.anti_flags = pShowItem->GetAntiFlag();

            thecore_memcpy(pack_sub.alSockets, pShowItem->GetSockets(), sizeof(pack_sub.alSockets));
            thecore_memcpy(pack_sub.aAttr, pShowItem->GetAttributes(), sizeof(pack_sub.aAttr));
            GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCAcce));
            GetDesc()->Packet(&pack_sub, sizeof(TPacketGCItemSet));

            M2_DESTROY_ITEM(pShowItem);
        }

 

 

char_item.cpp

Link to comment
Share on other sites

22 minutes ago, newhere said:

maybe here: if (ABSORB == GetAcceWindowType())

  Reveal hidden contents

 

if (ABSORB == GetAcceWindowType())
    {

        if (m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT] != WORD_MAX && m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT] != WORD_MAX)
        {
            LPITEM pkAcce = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_LEFT]));
            LPITEM pkWeaponToAbsorb = GetItem(TItemPos(INVENTORY, m_pointsInstant.pAcceSlots[ACCE_SLOT_RIGHT]));
            LPITEM pShowItem = ITEM_MANAGER::instance().CreateItem(pkAcce->GetVnum(), 1, 0, false, -1, true);

            pkWeaponToAbsorb->CopyAttributeTo(pShowItem);
            pShowItem->SetSocket(0, pkAcce->GetSocket(0));
            pShowItem->SetSocket(1, pkWeaponToAbsorb->GetVnum());

            TPacketGCAcce pack;
            pack.header = HEADER_GC_ACCE;
            pack.subheader = ACCE_SUBHEADER_GC_SET_ITEM;
            pack.size = sizeof(TPacketGCAcce) + sizeof(TPacketGCItemSet);

            TPacketGCItemSet pack_sub;

            pack_sub.header = 0;
            pack_sub.Cell = TItemPos(ACCEREFINE, (WORD)ACCE_SLOT_RESULT);
            pack_sub.vnum = pShowItem->GetVnum();
            pack_sub.count = (BYTE)pShowItem->GetCount();
            pack_sub.flags = pShowItem->GetFlag();
            pack_sub.anti_flags = pShowItem->GetAntiFlag();

            thecore_memcpy(pack_sub.alSockets, pShowItem->GetSockets(), sizeof(pack_sub.alSockets));
            thecore_memcpy(pack_sub.aAttr, pShowItem->GetAttributes(), sizeof(pack_sub.aAttr));
            GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCAcce));
            GetDesc()->Packet(&pack_sub, sizeof(TPacketGCItemSet));

            M2_DESTROY_ITEM(pShowItem);
        }

 

 

char_item.cpp

if you comment this line and absorb a weapon, does the sash gain attributtes or no?

 

comment this and try:
            pkWeaponToAbsorb->CopyAttributeTo(pShowItem);

 

If it does not gain any atribute we can do a workaround, setting the attributes by ourselves

It's all lies

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.