Jump to content

newhere

Inactive Member
  • Posts

    13
  • Joined

  • Last visited

  • Feedback

    0%

Posts posted by newhere

  1. 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

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

     

  3. 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

  4. 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

  5. Hey, im here

    1- Cause i dont know/find where i can change the position of my closed Questscrolls

    https://metin2.download/picture/r3F9504x09DVmF8K988YXgTtGTP6KMUj/.gif

    for example i would like to have them on top middle...but i dont know the py data for it... :D

    2-i have Gaya on my Serverfiles since beginning. Everything working...but my Client have a display bug

    New Chars start with 999,999 Clientside shown but really they have ZERO ... I checked hole client for datas with"Gaya" "Gem" "999,999".. i think... :D

    image.png.c73b27551e7c59dd20acc84ffeb47928.png

    Would be nice if you can help me :)

×
×
  • 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.