Guest User

item.cpp

a guest
May 23rd, 2020
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 54.55 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "utils.h"
  3. #include "config.h"
  4. #include "char.h"
  5. #include "desc.h"
  6. #include "sectree_manager.h"
  7. #include "packet.h"
  8. #include "protocol.h"
  9. #include "log.h"
  10. #include "skill.h"
  11. #include "unique_item.h"
  12. #include "profiler.h"
  13. #include "marriage.h"
  14. #include "item_addon.h"
  15. #include "dev_log.h"
  16. #include "locale_service.h"
  17. #include "item.h"
  18. #include "item_manager.h"
  19. #include "affect.h"
  20. #include "DragonSoul.h"
  21. #include "buff_on_attributes.h"
  22. #include "belt_inventory_helper.h"
  23. #include "../../common/VnumHelper.h"
  24. #include "../../common/service.h"
  25.  
  26. CItem::CItem(DWORD dwVnum)
  27.     : m_dwVnum(dwVnum), m_bWindow(0), m_dwID(0), m_bEquipped(false), m_dwVID(0), m_wCell(0), m_dwCount(0),
  28. #ifdef __CHANGELOOK_SYSTEM__
  29.     m_dwTransmutation(0),
  30. #endif
  31.     m_lFlag(0), m_dwLastOwnerPID(0),
  32.     m_bExchanging(false), m_pkDestroyEvent(NULL), m_pkExpireEvent(NULL), m_pkUniqueExpireEvent(NULL), m_pkTimerBasedOnWearExpireEvent(NULL),
  33.     m_pkRealTimeExpireEvent(NULL),
  34.     m_pkAccessorySocketExpireEvent(NULL), m_pkOwnershipEvent(NULL), m_dwOwnershipPID(0), m_bSkipSave(false), m_isLocked(false),
  35.     m_dwMaskVnum(0), m_dwSIGVnum (0)
  36. {
  37.     memset( &m_alSockets, 0, sizeof(m_alSockets) );
  38.     memset( &m_aAttr, 0, sizeof(m_aAttr) );
  39. }
  40.  
  41. CItem::~CItem()
  42. {
  43.     Destroy();
  44. }
  45.  
  46. void CItem::Initialize()
  47. {
  48.     CEntity::Initialize(ENTITY_ITEM);
  49.  
  50.     m_bWindow = RESERVED_WINDOW;
  51.     m_pOwner = NULL;
  52.     m_dwID = 0;
  53.     m_bEquipped = false;
  54.     m_dwVID = m_wCell = m_dwCount = m_lFlag = 0;
  55. #ifdef __CHANGELOOK_SYSTEM__
  56.     m_dwTransmutation = 0;
  57. #endif
  58.     m_pProto = NULL;
  59.     m_bExchanging = false;
  60.     memset(&m_alSockets, 0, sizeof(m_alSockets));
  61.     memset(&m_aAttr, 0, sizeof(m_aAttr));
  62.  
  63.     m_pkDestroyEvent = NULL;
  64.     m_pkOwnershipEvent = NULL;
  65.     m_dwOwnershipPID = 0;
  66.     m_pkUniqueExpireEvent = NULL;
  67.     m_pkTimerBasedOnWearExpireEvent = NULL;
  68.     m_pkRealTimeExpireEvent = NULL;
  69.  
  70.     m_pkAccessorySocketExpireEvent = NULL;
  71.  
  72.     m_bSkipSave = false;
  73.     m_dwLastOwnerPID = 0;
  74. }
  75.  
  76. void CItem::Destroy()
  77. {
  78.     event_cancel(&m_pkDestroyEvent);
  79.     event_cancel(&m_pkOwnershipEvent);
  80.     event_cancel(&m_pkUniqueExpireEvent);
  81.     event_cancel(&m_pkTimerBasedOnWearExpireEvent);
  82.     event_cancel(&m_pkRealTimeExpireEvent);
  83.     event_cancel(&m_pkAccessorySocketExpireEvent);
  84.  
  85.     CEntity::Destroy();
  86.  
  87.     if (GetSectree())
  88.         GetSectree()->RemoveEntity(this);
  89. }
  90.  
  91. EVENTFUNC(item_destroy_event)
  92. {
  93.     item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  94.  
  95.     if ( info == NULL )
  96.     {
  97.         sys_err( "item_destroy_event> <Factor> Null pointer" );
  98.         return 0;
  99.     }
  100.  
  101.     LPITEM pkItem = info->item;
  102.  
  103.     if (pkItem->GetOwner())
  104.         sys_err("item_destroy_event: Owner exist. (item %s owner %s)", pkItem->GetName(), pkItem->GetOwner()->GetName());
  105.  
  106.     pkItem->SetDestroyEvent(NULL);
  107.     M2_DESTROY_ITEM(pkItem);
  108.     return 0;
  109. }
  110.  
  111. void CItem::SetDestroyEvent(LPEVENT pkEvent)
  112. {
  113.     m_pkDestroyEvent = pkEvent;
  114. }
  115.  
  116. void CItem::StartDestroyEvent(int iSec)
  117. {
  118.     if (m_pkDestroyEvent)
  119.         return;
  120.  
  121.     item_event_info* info = AllocEventInfo<item_event_info>();
  122.     info->item = this;
  123.  
  124.     SetDestroyEvent(event_create(item_destroy_event, info, PASSES_PER_SEC(iSec)));
  125. }
  126.  
  127. void CItem::EncodeInsertPacket(LPENTITY ent)
  128. {
  129.     LPDESC d;
  130.  
  131.     if (!(d = ent->GetDesc()))
  132.         return;
  133.  
  134.     const PIXEL_POSITION & c_pos = GetXYZ();
  135.  
  136.     struct packet_item_ground_add pack;
  137.  
  138.     pack.bHeader    = HEADER_GC_ITEM_GROUND_ADD;
  139.     pack.x      = c_pos.x;
  140.     pack.y      = c_pos.y;
  141.     pack.z      = c_pos.z;
  142.     pack.dwVnum     = GetVnum();
  143.     pack.dwVID      = m_dwVID;
  144.     //pack.count    = m_dwCount;
  145.  
  146.     d->Packet(&pack, sizeof(pack));
  147.  
  148.     if (m_pkOwnershipEvent != NULL)
  149.     {
  150.         item_event_info * info = dynamic_cast<item_event_info *>(m_pkOwnershipEvent->info);
  151.  
  152.         if ( info == NULL )
  153.         {
  154.             sys_err( "CItem::EncodeInsertPacket> <Factor> Null pointer" );
  155.             return;
  156.         }
  157.  
  158.         TPacketGCItemOwnership p;
  159.  
  160.         p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
  161.         p.dwVID = m_dwVID;
  162.         strlcpy(p.szName, info->szOwnerName, sizeof(p.szName));
  163.  
  164.         d->Packet(&p, sizeof(TPacketGCItemOwnership));
  165.     }
  166. }
  167.  
  168. void CItem::EncodeRemovePacket(LPENTITY ent)
  169. {
  170.     LPDESC d;
  171.  
  172.     if (!(d = ent->GetDesc()))
  173.         return;
  174.  
  175.     struct packet_item_ground_del pack;
  176.  
  177.     pack.bHeader    = HEADER_GC_ITEM_GROUND_DEL;
  178.     pack.dwVID      = m_dwVID;
  179.  
  180.     d->Packet(&pack, sizeof(pack));
  181.     sys_log(2, "Item::EncodeRemovePacket %s to %s", GetName(), ((LPCHARACTER) ent)->GetName());
  182. }
  183.  
  184. void CItem::SetProto(const TItemTable * table)
  185. {
  186.     assert(table != NULL);
  187.     m_pProto = table;
  188.     SetFlag(m_pProto->dwFlags);
  189. }
  190.  
  191. void CItem::UsePacketEncode(LPCHARACTER ch, LPCHARACTER victim, struct packet_item_use *packet)
  192. {
  193.     if (!GetVnum())
  194.         return;
  195.  
  196.     packet->header  = HEADER_GC_ITEM_USE;
  197.     packet->ch_vid  = ch->GetVID();
  198.     packet->victim_vid  = victim->GetVID();
  199.     packet->Cell = TItemPos(GetWindow(), m_wCell);
  200.     packet->vnum    = GetVnum();
  201. }
  202.  
  203. void CItem::RemoveFlag(long bit)
  204. {
  205.     REMOVE_BIT(m_lFlag, bit);
  206. }
  207.  
  208. void CItem::AddFlag(long bit)
  209. {
  210.     SET_BIT(m_lFlag, bit);
  211. }
  212.  
  213. void CItem::UpdatePacket()
  214. {
  215.     if (!m_pOwner || !m_pOwner->GetDesc())
  216.         return;
  217.  
  218.     TPacketGCItemUpdate pack;
  219.  
  220.     pack.header = HEADER_GC_ITEM_UPDATE;
  221.     pack.Cell = TItemPos(GetWindow(), m_wCell);
  222.     pack.count  = m_dwCount;
  223. #ifdef __CHANGELOOK_SYSTEM__
  224.     pack.transmutation = m_dwTransmutation;
  225. #endif
  226.  
  227.     for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  228.         pack.alSockets[i] = m_alSockets[i];
  229.  
  230.     thecore_memcpy(pack.aAttr, GetAttributes(), sizeof(pack.aAttr));
  231.  
  232.     sys_log(2, "UpdatePacket %s -> %s", GetName(), m_pOwner->GetName());
  233.     m_pOwner->GetDesc()->Packet(&pack, sizeof(pack));
  234. }
  235.  
  236. DWORD CItem::GetCount()
  237. {
  238. #ifdef __ENABLE_CHEQUE_SYSTEM__
  239.     if (GetType() == ITEM_ELK || GetType() == ITEM_CHEQUE) return MIN(m_dwCount, INT_MAX);
  240. #else
  241.     if (GetType() == ITEM_ELK) return MIN(m_dwCount, INT_MAX);
  242. #endif // __ENABLE_CHEQUE_SYSTEM__
  243.     else
  244.     {
  245.         return MIN(m_dwCount, 200);
  246.     }
  247. }
  248.  
  249. bool CItem::SetCount(DWORD count)
  250. {
  251. #ifdef __ENABLE_CHEQUE_SYSTEM__
  252.     if (GetType() == ITEM_ELK || GetType() == ITEM_CHEQUE)
  253. #else
  254.     if (GetType() == ITEM_ELK)
  255. #endif // __ENABLE_CHEQUE_SYSTEM__
  256.     {
  257.         m_dwCount = MIN(count, INT_MAX);
  258.     }
  259.     else
  260.     {
  261.         m_dwCount = MIN(count, ITEM_MAX_COUNT);
  262.     }
  263.  
  264.     if (count == 0 && m_pOwner)
  265.     {
  266.         if (GetSubType() == USE_ABILITY_UP || GetSubType() == USE_POTION || GetVnum() == 70020)
  267.         {
  268.             LPCHARACTER pOwner = GetOwner();
  269.             WORD wCell = GetCell();
  270.  
  271.             RemoveFromCharacter();
  272.  
  273.             if (!IsDragonSoul())
  274.             {
  275.                 LPITEM pItem = pOwner->FindSpecifyItem(GetVnum());
  276.  
  277.                 if (NULL != pItem)
  278.                 {
  279.                     pOwner->ChainQuickslotItem(pItem, QUICKSLOT_TYPE_ITEM, wCell);
  280.                 }
  281.                 else
  282.                 {
  283.                     pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 255);
  284.                 }
  285.             }
  286.  
  287.             M2_DESTROY_ITEM(this);
  288.         }
  289.         else
  290.         {
  291.             if (!IsDragonSoul())
  292.             {
  293.                 m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 255);
  294.             }
  295.             M2_DESTROY_ITEM(RemoveFromCharacter());
  296.         }
  297.  
  298.         return false;
  299.     }
  300.  
  301.     UpdatePacket();
  302.  
  303.     Save();
  304.     return true;
  305. }
  306. #ifdef __CHANGELOOK_SYSTEM__
  307. void CItem::SetTransmutation(DWORD dwVnum, bool bLog)
  308. {
  309.     m_dwTransmutation = dwVnum;
  310.     UpdatePacket();
  311.     Save();
  312. }
  313. #endif
  314. LPITEM CItem::RemoveFromCharacter()
  315. {
  316.     if (!m_pOwner)
  317.     {
  318.         sys_err("Item::RemoveFromCharacter owner null");
  319.         return (this);
  320.     }
  321.  
  322.     LPCHARACTER pOwner = m_pOwner;
  323.  
  324.     if (m_bEquipped)    // 장착되었는가?
  325.     {
  326.         Unequip();
  327.         //pOwner->UpdatePacket();
  328.  
  329.         SetWindow(RESERVED_WINDOW);
  330.         Save();
  331.         return (this);
  332.     }
  333.     else
  334.     {
  335.         if (GetWindow() != SAFEBOX && GetWindow() != MALL)
  336.         {
  337.             if (IsDragonSoul())
  338.             {
  339.                 if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  340.                     sys_err("CItem::RemoveFromCharacter: pos >= DRAGON_SOUL_INVENTORY_MAX_NUM");
  341.                 else
  342.                     pOwner->SetItem(TItemPos(m_bWindow, m_wCell), NULL);
  343.             }
  344.             else
  345.             {
  346.                 TItemPos cell(INVENTORY, m_wCell);
  347.  
  348.                 if (false == cell.IsDefaultInventoryPosition() && false == cell.IsBeltInventoryPosition()) // 아니면 소지품에?
  349.                     sys_err("CItem::RemoveFromCharacter: Invalid Item Position");
  350.                 else
  351.                 {
  352.                     pOwner->SetItem(cell, NULL);
  353.                 }
  354.             }
  355.         }
  356.  
  357.         m_pOwner = NULL;
  358.         m_wCell = 0;
  359.  
  360.         SetWindow(RESERVED_WINDOW);
  361.         Save();
  362.         return (this);
  363.     }
  364. }
  365.  
  366. bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell)
  367. {
  368.     assert(GetSectree() == NULL);
  369.     assert(m_pOwner == NULL);
  370.     WORD pos = Cell.cell;
  371.     BYTE window_type = Cell.window_type;
  372.    
  373.     if (INVENTORY == window_type)
  374.     {
  375.         if (m_wCell >= INVENTORY_MAX_NUM && BELT_INVENTORY_SLOT_START > m_wCell)
  376.         {
  377.             sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
  378.             return false;
  379.         }
  380.     }
  381.     else if (DRAGON_SOUL_INVENTORY == window_type)
  382.     {
  383.         if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  384.         {
  385.             sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
  386.             return false;
  387.         }
  388.     }
  389. #ifdef SLOT_HIGHLIGHT
  390.     bool bWereMine = this->GetLastOwnerPID() == ch->GetPlayerID();
  391. #endif
  392.     if (ch->GetDesc())
  393.         m_dwLastOwnerPID = ch->GetPlayerID();
  394. #ifdef __SASH_SYSTEM__
  395.     if ((GetType() == ITEM_COSTUME) && (GetSubType() == COSTUME_SASH) && (GetSocket(SASH_ABSORPTION_SOCKET) == 0))
  396.     {
  397.         long lVal = GetValue(SASH_GRADE_VALUE_FIELD);
  398.         switch (lVal)
  399.         {
  400.         case 2:
  401.         {
  402.             lVal = SASH_GRADE_2_ABS;
  403.         }
  404.         break;
  405.         case 3:
  406.         {
  407.             lVal = SASH_GRADE_3_ABS;
  408.         }
  409.         break;
  410.         case 4:
  411.         {
  412.             lVal = number(SASH_GRADE_4_ABS_MIN, SASH_GRADE_4_ABS_MAX_COMB);
  413.         }
  414.         break;
  415.         default:
  416.         {
  417.             lVal = SASH_GRADE_1_ABS;
  418.         }
  419.         break;
  420.         }
  421.  
  422.         SetSocket(SASH_ABSORPTION_SOCKET, lVal);
  423.     }
  424. #endif
  425.  
  426.     event_cancel(&m_pkDestroyEvent);
  427. #ifdef SLOT_HIGHLIGHT
  428.     ch->SetItem(TItemPos(window_type, pos), this, bWereMine);
  429. #else
  430.     ch->SetItem(TItemPos(window_type, pos), this);
  431. #endif
  432.     m_pOwner = ch;
  433.  
  434.     Save();
  435.     return true;
  436. }
  437.  
  438. LPITEM CItem::RemoveFromGround()
  439. {
  440.     if (GetSectree())
  441.     {
  442.         SetOwnership(NULL);
  443.        
  444.         GetSectree()->RemoveEntity(this);
  445.        
  446.         ViewCleanup();
  447.  
  448.         Save();
  449.     }
  450.  
  451.     return (this);
  452. }
  453.  
  454. bool CItem::AddToGround(long lMapIndex, const PIXEL_POSITION & pos, bool skipOwnerCheck)
  455. {
  456.     if (0 == lMapIndex)
  457.     {
  458.         sys_err("wrong map index argument: %d", lMapIndex);
  459.         return false;
  460.     }
  461.  
  462.     if (GetSectree())
  463.     {
  464.         sys_err("sectree already assigned");
  465.         return false;
  466.     }
  467.  
  468.     if (!skipOwnerCheck && m_pOwner)
  469.     {
  470.         sys_err("owner pointer not null");
  471.         return false;
  472.     }
  473.  
  474.     LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, pos.x, pos.y);
  475.  
  476.     if (!tree)
  477.     {
  478.         sys_err("cannot find sectree by %dx%d", pos.x, pos.y);
  479.         return false;
  480.     }
  481.  
  482.     //tree->Touch();
  483.  
  484.     SetWindow(GROUND);
  485.     SetXYZ(pos.x, pos.y, pos.z);
  486.     tree->InsertEntity(this);
  487.     UpdateSectree();
  488.     Save();
  489.     return true;
  490. }
  491.  
  492. bool CItem::DistanceValid(LPCHARACTER ch)
  493. {
  494.     if (!GetSectree())
  495.         return false;
  496.  
  497.     int iDist = DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY());
  498.  
  499.     if (iDist > 300)
  500.         return false;
  501.  
  502.     return true;
  503. }
  504.  
  505. bool CItem::CanUsedBy(LPCHARACTER ch)
  506. {
  507.     // Anti flag check
  508.     switch (ch->GetJob())
  509.     {
  510.         case JOB_WARRIOR:
  511.             if (GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR)
  512.                 return false;
  513.             break;
  514.  
  515.         case JOB_ASSASSIN:
  516.             if (GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN)
  517.                 return false;
  518.             break;
  519.  
  520.         case JOB_SHAMAN:
  521.             if (GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN)
  522.                 return false;
  523.             break;
  524.  
  525.         case JOB_SURA:
  526.             if (GetAntiFlag() & ITEM_ANTIFLAG_SURA)
  527.                 return false;
  528.             break;
  529.     }
  530.  
  531.     return true;
  532. }
  533.  
  534. int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
  535. {
  536.     // 코스츔 아이템(ITEM_COSTUME)은 WearFlag 없어도 됨. (sub type으로 착용위치 구분. 귀찮게 또 wear flag 줄 필요가 있나..)
  537.     // 용혼석(ITEM_DS, ITEM_SPECIAL_DS)도  SUB_TYPE으로 구분. 신규 반지, 벨트는 ITEM_TYPE으로 구분 -_-
  538. #ifdef ITEM_TALISMAN_EQUIPMENT
  539.     if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType() && ITEM_ARMOR != GetType())
  540. #else
  541.     if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
  542. #endif
  543.         return -1;
  544.  
  545.     // 용혼석 슬롯을 WEAR로 처리할 수가 없어서(WEAR는 최대 32개까지 가능한데 용혼석을 추가하면 32가 넘는다.)
  546.     // 인벤토리의 특정 위치((INVENTORY_MAX_NUM + WEAR_MAX_NUM)부터 (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)까지)를
  547.     // 용혼석 슬롯으로 정함.
  548.     // return 할 때에, INVENTORY_MAX_NUM을 뺀 이유는,
  549.     // 본래 WearCell이 INVENTORY_MAX_NUM를 빼고 return 하기 때문.
  550.     if (GetType() == ITEM_DS || GetType() == ITEM_SPECIAL_DS)
  551.     {
  552.         if (iCandidateCell < 0)
  553.         {
  554.             return WEAR_MAX_NUM + GetSubType();
  555.         }
  556.         else
  557.         {
  558.             for (int i = 0; i < DRAGON_SOUL_DECK_MAX_NUM; i++)
  559.             {
  560.                 if (WEAR_MAX_NUM + i * DS_SLOT_MAX + GetSubType() == iCandidateCell)
  561.                 {
  562.                     return iCandidateCell;
  563.                 }
  564.             }
  565.             return -1;
  566.         }
  567.     }
  568.     else if (GetType() == ITEM_COSTUME)
  569.     {
  570.         if (GetSubType() == COSTUME_BODY)
  571.             return WEAR_COSTUME_BODY;
  572.         else if (GetSubType() == COSTUME_HAIR)
  573.             return WEAR_COSTUME_HAIR;
  574. #ifdef __SASH_SYSTEM__
  575.         else if (GetSubType() == COSTUME_SASH)
  576.             return WEAR_COSTUME_SASH;
  577. #endif
  578. #ifdef WJ_ENABLE_COSTUME_MOUNT
  579.         else if (GetSubType() == COSTUME_MOUNT)
  580.             return WEAR_COSTUME_MOUNT;
  581. #endif
  582. //#ifdef ENABLE_COSTUME_WEAPON
  583.         else if (GetSubType() == COSTUME_WEAPON_SWORD ||
  584.             GetSubType() == COSTUME_WEAPON_DAGGER ||
  585.             GetSubType() == COSTUME_WEAPON_BOW ||
  586.             GetSubType() == COSTUME_WEAPON_TWO_HANDED ||
  587.             GetSubType() == COSTUME_WEAPON_BELL ||
  588.             GetSubType() == COSTUME_WEAPON_FAN)
  589.             return WEAR_COSTUME_WEAPON;
  590. //#endif
  591.     }
  592.     else if (GetType() == ITEM_RING)
  593.     {
  594.         if (ch->GetWear(WEAR_RING1))
  595.             return WEAR_RING2;
  596.         else
  597.             return WEAR_RING1;
  598.     }
  599.     else if (GetType() == ITEM_BELT)
  600.         return WEAR_BELT;
  601.     else if (GetWearFlag() & WEARABLE_BODY)
  602.         return WEAR_BODY;
  603.     else if (GetWearFlag() & WEARABLE_HEAD)
  604.         return WEAR_HEAD;
  605.     else if (GetWearFlag() & WEARABLE_FOOTS)
  606.         return WEAR_FOOTS;
  607.     else if (GetWearFlag() & WEARABLE_WRIST)
  608.         return WEAR_WRIST;
  609.     else if (GetWearFlag() & WEARABLE_WEAPON)
  610.         return WEAR_WEAPON;
  611.     else if (GetWearFlag() & WEARABLE_SHIELD)
  612.         return WEAR_SHIELD;
  613.     else if (GetWearFlag() & WEARABLE_NECK)
  614.         return WEAR_NECK;
  615.     else if (GetWearFlag() & WEARABLE_EAR)
  616.         return WEAR_EAR;
  617.     else if (GetWearFlag() & WEARABLE_ARROW)
  618.         return WEAR_ARROW;
  619. #ifdef ITEM_TALISMAN_EQUIPMENT
  620.     else if (GetWearFlag() & WEARABLE_PENDANT)
  621.         return WEAR_PENDANT;
  622. #endif
  623.     else if (GetWearFlag() & WEARABLE_UNIQUE)
  624.     {
  625.         if (ch->GetWear(WEAR_UNIQUE1))
  626.             return WEAR_UNIQUE2;
  627.         else
  628.             return WEAR_UNIQUE1;
  629.     }
  630.  
  631.     // 수집 퀘스트를 위한 아이템이 박히는곳으로 한번 박히면 절대 –E수 없다.
  632.     else if (GetWearFlag() & WEARABLE_ABILITY)
  633.     {
  634.         if (!ch->GetWear(WEAR_ABILITY1))
  635.         {
  636.             return WEAR_ABILITY1;
  637.         }
  638.         else if (!ch->GetWear(WEAR_ABILITY2))
  639.         {
  640.             return WEAR_ABILITY2;
  641.         }
  642.         else if (!ch->GetWear(WEAR_ABILITY3))
  643.         {
  644.             return WEAR_ABILITY3;
  645.         }
  646.         else if (!ch->GetWear(WEAR_ABILITY4))
  647.         {
  648.             return WEAR_ABILITY4;
  649.         }
  650.         else if (!ch->GetWear(WEAR_ABILITY5))
  651.         {
  652.             return WEAR_ABILITY5;
  653.         }
  654.         else if (!ch->GetWear(WEAR_ABILITY6))
  655.         {
  656.             return WEAR_ABILITY6;
  657.         }
  658.         else if (!ch->GetWear(WEAR_ABILITY7))
  659.         {
  660.             return WEAR_ABILITY7;
  661.         }
  662.         else if (!ch->GetWear(WEAR_ABILITY8))
  663.         {
  664.             return WEAR_ABILITY8;
  665.         }
  666.         else
  667.         {
  668.             return -1;
  669.         }
  670.     }
  671.     return -1;
  672. }
  673.  
  674. void CItem::ModifyPoints(bool bAdd)
  675. {
  676.     int accessoryGrade;
  677.  
  678.     // 무기와 갑옷만 소켓을 적용시킨다.
  679.     if (false == IsAccessoryForSocket())
  680.     {
  681.         if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
  682.         {
  683.             // 소켓이 속성강화에 사용되는 경우 적용하지 않는다 (ARMOR_WRIST ARMOR_NECK ARMOR_EAR)
  684.             for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  685.             {
  686.                 DWORD dwVnum;
  687.  
  688.                 if ((dwVnum = GetSocket(i)) <= 2)
  689.                     continue;
  690.                 if (IsRealTimeItem() == true)
  691.                     continue;
  692.                 TItemTable * p = ITEM_MANAGER::instance().GetTable(dwVnum);
  693.  
  694.                 if (!p)
  695.                 {
  696.                     sys_err("cannot find table by vnum %u", dwVnum);
  697.                     continue;
  698.                 }
  699.  
  700.                 if (ITEM_METIN == p->bType)
  701.                 {
  702.                     //m_pOwner->ApplyPoint(p->alValues[0], bAdd ? p->alValues[1] : -p->alValues[1]);
  703.                     for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
  704.                     {
  705.                         if (p->aApplies[i].bType == APPLY_NONE)
  706.                             continue;
  707.  
  708.                         if (p->aApplies[i].bType == APPLY_SKILL)
  709.                             m_pOwner->ApplyPoint(p->aApplies[i].bType, bAdd ? p->aApplies[i].lValue : p->aApplies[i].lValue ^ 0x00800000);
  710.                         else
  711.                             m_pOwner->ApplyPoint(p->aApplies[i].bType, bAdd ? p->aApplies[i].lValue : -p->aApplies[i].lValue);
  712.                     }
  713.                 }
  714.             }
  715.         }
  716.  
  717.         accessoryGrade = 0;
  718.     }
  719.     else
  720.     {
  721.         accessoryGrade = MIN(GetAccessorySocketGrade(), ITEM_ACCESSORY_SOCKET_MAX_NUM);
  722.     }
  723. #ifdef __SASH_SYSTEM__
  724.     if ((GetType() == ITEM_COSTUME) && (GetSubType() == COSTUME_SASH) && (GetSocket(SASH_ABSORBED_SOCKET)))
  725.     {
  726.         TItemTable * pkItemAbsorbed = ITEM_MANAGER::instance().GetTable(GetSocket(SASH_ABSORBED_SOCKET));
  727.         if (pkItemAbsorbed)
  728.         {
  729.             if ((pkItemAbsorbed->bType == ITEM_ARMOR) && (pkItemAbsorbed->bSubType == ARMOR_BODY))
  730.             {
  731.                 long lDefGrade = pkItemAbsorbed->alValues[1] + long(pkItemAbsorbed->alValues[5] * 2);
  732.                 double dValue = lDefGrade * GetSocket(SASH_ABSORPTION_SOCKET);
  733.                 dValue = (double)dValue / 100;
  734.                 dValue = (double)dValue + .5;
  735.                 lDefGrade = (long)dValue;
  736.                 if ((pkItemAbsorbed->alValues[1] > 0) && (lDefGrade <= 0) || (pkItemAbsorbed->alValues[5] > 0) && (lDefGrade < 1))
  737.                     lDefGrade += 1;
  738.                 else if ((pkItemAbsorbed->alValues[1] > 0) || (pkItemAbsorbed->alValues[5] > 0))
  739.                     lDefGrade += 1;
  740.  
  741.                 m_pOwner->ApplyPoint(APPLY_DEF_GRADE_BONUS, bAdd ? lDefGrade : -lDefGrade);
  742.  
  743.                 long lDefMagicBonus = pkItemAbsorbed->alValues[0];
  744.                 dValue = lDefMagicBonus * GetSocket(SASH_ABSORPTION_SOCKET);
  745.                 dValue = (double)dValue / 100;
  746.                 dValue = (double)dValue + .5;
  747.                 lDefMagicBonus = (long)dValue;
  748.                 if ((pkItemAbsorbed->alValues[0] > 0) && (lDefMagicBonus < 1))
  749.                     lDefMagicBonus += 1;
  750.                 else if (pkItemAbsorbed->alValues[0] > 0)
  751.                     lDefMagicBonus += 1;
  752.  
  753.                 m_pOwner->ApplyPoint(APPLY_MAGIC_DEF_GRADE, bAdd ? lDefMagicBonus : -lDefMagicBonus);
  754.             }
  755.             else if (pkItemAbsorbed->bType == ITEM_WEAPON)
  756.             {
  757.                 long lAttGrade = pkItemAbsorbed->alValues[4] + pkItemAbsorbed->alValues[5];
  758.                 if (pkItemAbsorbed->alValues[3] > pkItemAbsorbed->alValues[4])
  759.                     lAttGrade = pkItemAbsorbed->alValues[3] + pkItemAbsorbed->alValues[5];
  760.  
  761.                 double dValue = lAttGrade * GetSocket(SASH_ABSORPTION_SOCKET);
  762.                 dValue = (double)dValue / 100;
  763.                 dValue = (double)dValue + .5;
  764.                 lAttGrade = (long)dValue;
  765.                 if (((pkItemAbsorbed->alValues[3] > 0) && (lAttGrade < 1)) || ((pkItemAbsorbed->alValues[4] > 0) && (lAttGrade < 1)))
  766.                     lAttGrade += 1;
  767.                 else if ((pkItemAbsorbed->alValues[3] > 0) || (pkItemAbsorbed->alValues[4] > 0))
  768.                     lAttGrade += 1;
  769.  
  770.                 m_pOwner->ApplyPoint(APPLY_ATT_GRADE_BONUS, bAdd ? lAttGrade : -lAttGrade);
  771.  
  772.                 long lAttMagicGrade = pkItemAbsorbed->alValues[2] + pkItemAbsorbed->alValues[5];
  773.                 if (pkItemAbsorbed->alValues[1] > pkItemAbsorbed->alValues[2])
  774.                     lAttMagicGrade = pkItemAbsorbed->alValues[1] + pkItemAbsorbed->alValues[5];
  775.  
  776.                 dValue = lAttMagicGrade * GetSocket(SASH_ABSORPTION_SOCKET);
  777.                 dValue = (double)dValue / 100;
  778.                 dValue = (double)dValue + .5;
  779.                 lAttMagicGrade = (long)dValue;
  780.                 if (((pkItemAbsorbed->alValues[1] > 0) && (lAttMagicGrade < 1)) || ((pkItemAbsorbed->alValues[2] > 0) && (lAttMagicGrade < 1)))
  781.                     lAttMagicGrade += 1;
  782.                 else if ((pkItemAbsorbed->alValues[1] > 0) || (pkItemAbsorbed->alValues[2] > 0))
  783.                     lAttMagicGrade += 1;
  784.  
  785.                 m_pOwner->ApplyPoint(APPLY_MAGIC_ATT_GRADE, bAdd ? lAttMagicGrade : -lAttMagicGrade);
  786.             }
  787.         }
  788.     }
  789. #endif
  790.  
  791.     for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
  792.     {
  793. #ifdef __SASH_SYSTEM__
  794.         if ((m_pProto->aApplies[i].bType == APPLY_NONE) && (GetType() != ITEM_COSTUME) && (GetSubType() != COSTUME_SASH))
  795. #else
  796.         if (m_pProto->aApplies[i].bType == APPLY_NONE)
  797. #endif
  798.             continue;
  799.  
  800.         BYTE bType = m_pProto->aApplies[i].bType;
  801.         long value = m_pProto->aApplies[i].lValue;
  802. #ifdef __SASH_SYSTEM__
  803.         if ((GetType() == ITEM_COSTUME) && (GetSubType() == COSTUME_SASH))
  804.         {
  805.             TItemTable * pkItemAbsorbed = ITEM_MANAGER::instance().GetTable(GetSocket(SASH_ABSORBED_SOCKET));
  806.             if (pkItemAbsorbed)
  807.             {
  808.                 if (pkItemAbsorbed->aApplies[i].bType == APPLY_NONE)
  809.                     continue;
  810.  
  811.                 bType = pkItemAbsorbed->aApplies[i].bType;
  812.                 value = pkItemAbsorbed->aApplies[i].lValue;
  813.                 if (value < 0)
  814.                     continue;
  815.  
  816.                 double dValue = value * GetSocket(SASH_ABSORPTION_SOCKET);
  817.                 dValue = (double)dValue / 100;
  818.                 dValue = (double)dValue + .5;
  819.                 value = (long)dValue;
  820.                 if ((pkItemAbsorbed->aApplies[i].lValue > 0) && (value <= 0))
  821.                     value += 1;
  822.             }
  823.             else
  824.                 continue;
  825.         }
  826. #endif
  827.  
  828.         if (bType != APPLY_SKILL)
  829.         {
  830.             if (accessoryGrade != 0)
  831.                 value += MAX(accessoryGrade, value * aiAccessorySocketEffectivePct[accessoryGrade] / 100);
  832.  
  833.             m_pOwner->ApplyPoint(bType, bAdd ? value : -value);
  834.         }
  835.         else
  836.             m_pOwner->ApplyPoint(bType, bAdd ? value : value ^ 0x00800000);
  837.     }
  838.     // 초승달의 반지, 할로윈 사탕, 행복의 반지, 영원한 사랑의 펜던트의 경우
  839.     // 기존의 하드 코딩으로 강제로 속성을 부여했지만,
  840.     // 그 부분을 제거하고 special item group 테이블에서 속성을 부여하도록 변경하였다.
  841.     // 하지만 하드 코딩되어있을 때 생성된 아이템이 남아있을 수도 있어서 특수처리 해놓는다.
  842.     // 이 아이템들의 경우, 밑에 ITEM_UNIQUE일 때의 처리로 속성이 부여되기 때문에,
  843.     // 아이템에 박혀있는 attribute는 적용하지 않고 넘어간다.
  844.     if (true == CItemVnumHelper::IsRamadanMoonRing(GetVnum()) || true == CItemVnumHelper::IsHalloweenCandy(GetVnum())
  845.         || true == CItemVnumHelper::IsHappinessRing(GetVnum()) || true == CItemVnumHelper::IsLovePendant(GetVnum()))
  846.     {
  847.         // Do not anything.
  848.     }
  849.     else
  850.     {
  851.         for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
  852.         {
  853.             if (GetAttributeType(i))
  854.             {
  855.                 const TPlayerItemAttribute& ia = GetAttribute(i);
  856.                 long sValue = ia.sValue;
  857. #ifdef __SASH_SYSTEM__
  858.                 if ((GetType() == ITEM_COSTUME) && (GetSubType() == COSTUME_SASH))
  859.                 {
  860.                     double dValue = sValue * GetSocket(SASH_ABSORPTION_SOCKET);
  861.                     dValue = (double)dValue / 100;
  862.                     dValue = (double)dValue + .5;
  863.                     sValue = (long)dValue;
  864.                     if ((ia.sValue > 0) && (sValue <= 0))
  865.                         sValue += 1;
  866.                 }
  867. #endif
  868.  
  869.                 if (ia.bType == APPLY_SKILL)
  870.                     m_pOwner->ApplyPoint(ia.bType, bAdd ? sValue : sValue ^ 0x00800000);
  871.                 else
  872.                     m_pOwner->ApplyPoint(ia.bType, bAdd ? sValue : -sValue);
  873.             }
  874.         }
  875.     }
  876.  
  877.     switch (m_pProto->bType)
  878.     {
  879.         case ITEM_PICK:
  880.         case ITEM_ROD:
  881.             {
  882.                 if (bAdd)
  883.                 {
  884.                     if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  885.                         m_pOwner->SetPart(PART_WEAPON, GetVnum());
  886.                 }
  887.                 else
  888.                 {
  889.                     if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  890.                         m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON));
  891.                 }
  892.             }
  893.             break;
  894.  
  895.         case ITEM_WEAPON:
  896.             {
  897. //#ifdef ENABLE_COSTUME_WEAPON
  898.                 if (0 != m_pOwner->GetWear(WEAR_COSTUME_WEAPON))
  899.                     break;
  900. //#endif
  901.                 if (bAdd)
  902.                 {
  903.                     if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  904.                     {
  905. #ifdef __CHANGELOOK_SYSTEM__
  906.                         DWORD dwRes = GetTransmutation() != 0 ? GetTransmutation() : GetVnum();
  907.                         m_pOwner->SetPart(PART_WEAPON, dwRes);
  908. #else
  909.                         m_pOwner->SetPart(PART_WEAPON, GetVnum());
  910. #endif
  911.                     }
  912.                 }
  913.                 else
  914.                 {
  915.                     if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  916.                         m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON));
  917.                 }
  918.             }
  919.             break;
  920.  
  921.         case ITEM_ARMOR:
  922.             {
  923.                 // 코스츔 body를 입고있다면 armor는 벗던 입던 상관 없이 비주얼에 영향을 주면 안 됨.
  924.                 if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
  925.                     break;
  926.  
  927. #ifdef ITEM_TALISMAN_EQUIPMENT
  928.                 if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD || GetSubType() == ARMOR_PENDANT)
  929. #else
  930.                 if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD)
  931. #endif
  932.                 {
  933.                     if (bAdd)
  934.                     {
  935.                         if (GetProto()->bSubType == ARMOR_BODY)
  936. #ifdef __CHANGELOOK_SYSTEM__
  937.                         {
  938.                             DWORD dwRes = GetTransmutation() != 0 ? GetTransmutation() : GetVnum();
  939.                             m_pOwner->SetPart(PART_MAIN, dwRes);
  940.                         }
  941. #else
  942.                             m_pOwner->SetPart(PART_MAIN, GetVnum());
  943. #endif
  944.                     }
  945.                     else
  946.                     {
  947.                         if (GetProto()->bSubType == ARMOR_BODY)
  948.                             m_pOwner->SetPart(PART_MAIN, m_pOwner->GetOriginalPart(PART_MAIN));
  949.                     }
  950.                 }
  951.             }
  952.             break;
  953.  
  954.         case ITEM_COSTUME:  // type 28
  955.             {
  956.                 DWORD toSetValue = this->GetVnum();
  957.                 EParts toSetPart = PART_MAX_NUM;
  958.  
  959.                 if (GetSubType() == COSTUME_MOUNT) //subType 2
  960.                 {
  961.                     toSetPart = PART_MOUNT;
  962.  
  963.                     if (false == bAdd)
  964.                     {
  965.                         const CItem* pMount = m_pOwner->GetWear(WEAR_COSTUME_MOUNT);
  966.                         toSetValue = (NULL != pMount) ? pMount->GetVnum() : m_pOwner->GetOriginalPart(PART_MOUNT);
  967.                     }
  968.                 }
  969.  
  970.                 else if (GetSubType() == COSTUME_BODY)
  971.                 {
  972.                     toSetPart = PART_MAIN;
  973.  
  974.                     if (false == bAdd)
  975.                     {
  976.                         const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
  977.                         toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);          
  978. #ifdef __CHANGELOOK_SYSTEM__
  979.                         if (pArmor)
  980.                             toSetValue = pArmor->GetTransmutation() != 0 ? pArmor->GetTransmutation() : pArmor->GetVnum();
  981. #endif
  982.                     }
  983. #ifdef __CHANGELOOK_SYSTEM__
  984.                     else
  985.                         toSetValue = GetTransmutation() != 0 ? GetTransmutation() : GetVnum();
  986. #endif
  987.                     }
  988.                    
  989.  
  990.                 else if (GetSubType() == COSTUME_HAIR)
  991.                 {
  992.                 toSetPart = PART_HAIR;
  993.                 if (!bAdd)
  994.                     toSetValue = 0;
  995.                 else
  996.                 {
  997. #ifdef __CHANGELOOK_SYSTEM__
  998.                     DWORD dwTransmutation = GetTransmutation();
  999.                     if (dwTransmutation != 0)
  1000.                     {
  1001.                         TItemTable* pItemTable = ITEM_MANAGER::instance().GetTable(dwTransmutation);
  1002.                         toSetValue = (pItemTable != NULL) ? pItemTable->alValues[3] : GetValue(3);
  1003.                     }
  1004.                     else
  1005.                         toSetValue = GetValue(3);
  1006. #else
  1007.                     toSetValue = GetValue(3);
  1008. #endif
  1009.                 }
  1010.                 }
  1011. #ifdef __SASH_SYSTEM__
  1012.                 else if (GetSubType() == COSTUME_SASH)
  1013.                 {
  1014.                     toSetValue -= 85000;
  1015.                     if (GetSocket(SASH_ABSORPTION_SOCKET) >= SASH_EFFECT_FROM_ABS)
  1016.                         toSetValue += 10000;
  1017.  
  1018.                     toSetValue = (bAdd == true) ? toSetValue : 0;
  1019.                     toSetPart = PART_SASH;
  1020.                 }
  1021. #endif
  1022.  
  1023. //#ifdef ENABLE_COSTUME_WEAPON
  1024.                 else if (GetSubType() == COSTUME_WEAPON_SWORD ||
  1025.                     GetSubType() == COSTUME_WEAPON_DAGGER ||
  1026.                     GetSubType() == COSTUME_WEAPON_BOW ||
  1027.                     GetSubType() == COSTUME_WEAPON_TWO_HANDED ||
  1028.                     GetSubType() == COSTUME_WEAPON_BELL ||
  1029.                     GetSubType() == COSTUME_WEAPON_FAN)
  1030.                 {
  1031.                     toSetPart = PART_WEAPON;
  1032.                     if (false == bAdd)
  1033.                     {
  1034.                         const CItem* pWeapon = m_pOwner->GetWear(WEAR_WEAPON);
  1035.                         toSetValue = (NULL != pWeapon) ? pWeapon->GetVnum() : m_pOwner->GetOriginalPart(PART_WEAPON);
  1036.  
  1037.                     }
  1038.                 }
  1039. //#endif
  1040.  
  1041.                 if (PART_MAX_NUM != toSetPart)
  1042.                 {
  1043.                     m_pOwner->SetPart((BYTE)toSetPart, toSetValue);
  1044.                     m_pOwner->UpdatePacket();
  1045.                 }
  1046.             }
  1047.             break;
  1048.  
  1049.         case ITEM_UNIQUE:
  1050.             {
  1051.                 if (0 != GetSIGVnum())
  1052.                 {
  1053.                     const CSpecialItemGroup* pItemGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(GetSIGVnum());
  1054.                     if (NULL == pItemGroup)
  1055.                         break;
  1056.                     DWORD dwAttrVnum = pItemGroup->GetAttrVnum(GetVnum());
  1057.                     const CSpecialAttrGroup* pAttrGroup = ITEM_MANAGER::instance().GetSpecialAttrGroup(dwAttrVnum);
  1058.                     if (NULL == pAttrGroup)
  1059.                         break;
  1060.                     for (itertype (pAttrGroup->m_vecAttrs) it = pAttrGroup->m_vecAttrs.begin(); it != pAttrGroup->m_vecAttrs.end(); it++)
  1061.                     {
  1062.                         m_pOwner->ApplyPoint(it->apply_type, bAdd ? it->apply_value : -it->apply_value);
  1063.                     }
  1064.                 }
  1065.             }
  1066.             break;
  1067.     }
  1068. }
  1069.  
  1070. bool CItem::IsEquipable() const
  1071. {
  1072.     switch (this->GetType())
  1073.     {
  1074.     case ITEM_COSTUME:
  1075.     case ITEM_ARMOR:
  1076.     case ITEM_WEAPON:
  1077.     case ITEM_ROD:
  1078.     case ITEM_PICK:
  1079.     case ITEM_UNIQUE:
  1080.     case ITEM_DS:
  1081.     case ITEM_SPECIAL_DS:
  1082.     case ITEM_RING:
  1083.     case ITEM_BELT:
  1084.         return true;
  1085.     }
  1086.  
  1087.     return false;
  1088. }
  1089.  
  1090. // return false on error state
  1091. bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
  1092. {
  1093.     if (!ch)
  1094.     {
  1095.         sys_err("EquipTo: nil character");
  1096.         return false;
  1097.     }
  1098.  
  1099.     // 용혼석 슬롯 index는 WEAR_MAX_NUM 보다 큼.
  1100.     if (IsDragonSoul())
  1101.     {
  1102.         if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
  1103.         {
  1104.             sys_err("EquipTo: invalid dragon soul cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetSubType(), bWearCell - WEAR_MAX_NUM);
  1105.             return false;
  1106.         }
  1107.     }
  1108.     else
  1109.     {
  1110.         if (bWearCell >= WEAR_MAX_NUM)
  1111.         {
  1112.             sys_err("EquipTo: invalid wear cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetWearFlag(), bWearCell);
  1113.             return false;
  1114.         }
  1115.     }
  1116.  
  1117.     if (ch->GetWear(bWearCell))
  1118.     {
  1119.         sys_err("EquipTo: item already exist (this: #%d %s cell: %d %s)", GetOriginalVnum(), GetName(), bWearCell, ch->GetWear(bWearCell)->GetName());
  1120.         return false;
  1121.     }
  1122.  
  1123.     if (GetOwner())
  1124.         RemoveFromCharacter();
  1125.  
  1126.     ch->SetWear(bWearCell, this); // 여기서 패킷 나감
  1127.  
  1128.     m_pOwner = ch;
  1129.     m_bEquipped = true;
  1130.     m_wCell = INVENTORY_MAX_NUM + bWearCell;
  1131.  
  1132.     DWORD dwImmuneFlag = 0;
  1133.  
  1134.     for (int i = 0 ; i < WEAR_MAX_NUM; i++)
  1135.     {
  1136.         LPITEM pItem = m_pOwner->GetWear(i);
  1137.         if (pItem)
  1138.         {
  1139.             SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->GetImmuneFlag());
  1140.         }
  1141.     }
  1142.  
  1143.     if (IsDragonSoul())
  1144.     {
  1145.         DSManager::instance().ActivateDragonSoul(this);
  1146.     }
  1147.     else
  1148.     {
  1149.         ModifyPoints(true);
  1150.         StartUniqueExpireEvent();
  1151.         if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
  1152.             StartTimerBasedOnWearExpireEvent();
  1153.  
  1154.         // ACCESSORY_REFINE
  1155.         StartAccessorySocketExpireEvent();
  1156.         // END_OF_ACCESSORY_REFINE
  1157.     }
  1158.  
  1159.     ch->BuffOnAttr_AddBuffsFromItem(this);
  1160.  
  1161.     m_pOwner->ComputeBattlePoints();
  1162.  
  1163.     m_pOwner->UpdatePacket();
  1164.  
  1165.     Save();
  1166.  
  1167.     return (true);
  1168. }
  1169.  
  1170. bool CItem::Unequip()
  1171. {
  1172.     if (!m_pOwner || GetCell() < INVENTORY_MAX_NUM)
  1173.     {
  1174.         // ITEM_OWNER_INVALID_PTR_BUG
  1175.         sys_err("%s %u m_pOwner %p, GetCell %d",
  1176.                 GetName(), GetID(), get_pointer(m_pOwner), GetCell());
  1177.         // END_OF_ITEM_OWNER_INVALID_PTR_BUG
  1178.         return false;
  1179.     }
  1180.  
  1181.     if (this != m_pOwner->GetWear(GetCell() - INVENTORY_MAX_NUM))
  1182.     {
  1183.         sys_err("m_pOwner->GetWear() != this");
  1184.         return false;
  1185.     }
  1186.  
  1187.     //신규 말 아이템 제거시 처리
  1188.     if (IsRideItem())
  1189.         ClearMountAttributeAndAffect();
  1190.  
  1191.     if (IsDragonSoul())
  1192.     {
  1193.         DSManager::instance().DeactivateDragonSoul(this);
  1194.     }
  1195.     else
  1196.     {
  1197.         ModifyPoints(false);
  1198.     }
  1199.  
  1200.     StopUniqueExpireEvent();
  1201.  
  1202.     if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
  1203.         StopTimerBasedOnWearExpireEvent();
  1204.  
  1205.     // ACCESSORY_REFINE
  1206.     StopAccessorySocketExpireEvent();
  1207.     // END_OF_ACCESSORY_REFINE
  1208.  
  1209.  
  1210.     m_pOwner->BuffOnAttr_RemoveBuffsFromItem(this);
  1211.  
  1212.     m_pOwner->SetWear(GetCell() - INVENTORY_MAX_NUM, NULL);
  1213.  
  1214.     DWORD dwImmuneFlag = 0;
  1215.  
  1216.     for (int i = 0 ; i < WEAR_MAX_NUM; i++)
  1217.     {
  1218.         LPITEM pItem = m_pOwner->GetWear(i);
  1219.         if (pItem)
  1220.         {
  1221.             SET_BIT(dwImmuneFlag, m_pOwner->GetWear(i)->GetImmuneFlag());
  1222.         }
  1223.     }
  1224.  
  1225.     m_pOwner->ComputeBattlePoints();
  1226.  
  1227.     m_pOwner->UpdatePacket();
  1228.  
  1229.     m_pOwner = NULL;
  1230.     m_wCell = 0;
  1231.     m_bEquipped = false;
  1232.  
  1233.     return true;
  1234. }
  1235.  
  1236. long CItem::GetValue(DWORD idx)
  1237. {
  1238.     assert(idx < ITEM_VALUES_MAX_NUM);
  1239.     return GetProto()->alValues[idx];
  1240. }
  1241.  
  1242. void CItem::SetExchanging(bool bOn)
  1243. {
  1244.     m_bExchanging = bOn;
  1245. }
  1246.  
  1247. void CItem::Save()
  1248. {
  1249.     if (m_bSkipSave)
  1250.         return;
  1251.  
  1252.     ITEM_MANAGER::instance().DelayedSave(this);
  1253. }
  1254.  
  1255. bool CItem::CreateSocket(BYTE bSlot, BYTE bGold)
  1256. {
  1257.     assert(bSlot < ITEM_SOCKET_MAX_NUM);
  1258.  
  1259.     if (m_alSockets[bSlot] != 0)
  1260.     {
  1261.         sys_err("Item::CreateSocket : socket already exist %s %d", GetName(), bSlot);
  1262.         return false;
  1263.     }
  1264.  
  1265.     if (bGold)
  1266.         m_alSockets[bSlot] = 2;
  1267.     else
  1268.         m_alSockets[bSlot] = 1;
  1269.  
  1270.     UpdatePacket();
  1271.  
  1272.     Save();
  1273.     return true;
  1274. }
  1275.  
  1276. void CItem::SetSockets(const long * c_al)
  1277. {
  1278.     thecore_memcpy(m_alSockets, c_al, sizeof(m_alSockets));
  1279.     Save();
  1280. }
  1281.  
  1282. void CItem::SetSocket(int i, long v, bool bLog)
  1283. {
  1284.     assert(i < ITEM_SOCKET_MAX_NUM);
  1285.     m_alSockets[i] = v;
  1286.     UpdatePacket();
  1287.     Save();
  1288.     if (bLog)
  1289.         LogManager::instance().ItemLog(i, v, 0, GetID(), "SET_SOCKET", "", "", GetOriginalVnum());
  1290. }
  1291.  
  1292. int CItem::GetGold()
  1293. {
  1294.     if (IS_SET(GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
  1295.     {
  1296.         if (GetProto()->dwGold == 0)
  1297.             return GetCount();
  1298.         else
  1299.             return GetCount() / GetProto()->dwGold;
  1300.     }
  1301.     else
  1302.         return GetProto()->dwGold;
  1303. }
  1304.  
  1305. int CItem::GetShopBuyPrice()
  1306. {
  1307.     return GetProto()->dwShopBuyPrice;
  1308. }
  1309.  
  1310. bool CItem::IsOwnership(LPCHARACTER ch)
  1311. {
  1312.     if (!m_pkOwnershipEvent)
  1313.         return true;
  1314.  
  1315.     return m_dwOwnershipPID == ch->GetPlayerID() ? true : false;
  1316. }
  1317.  
  1318. EVENTFUNC(ownership_event)
  1319. {
  1320.     item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  1321.  
  1322.     if ( info == NULL )
  1323.     {
  1324.         sys_err( "ownership_event> <Factor> Null pointer" );
  1325.         return 0;
  1326.     }
  1327.  
  1328.     LPITEM pkItem = info->item;
  1329.  
  1330.     pkItem->SetOwnershipEvent(NULL);
  1331.  
  1332.     TPacketGCItemOwnership p;
  1333.  
  1334.     p.bHeader   = HEADER_GC_ITEM_OWNERSHIP;
  1335.     p.dwVID = pkItem->GetVID();
  1336.     p.szName[0] = '\0';
  1337.  
  1338.     pkItem->PacketAround(&p, sizeof(p));
  1339.     return 0;
  1340. }
  1341.  
  1342. void CItem::SetOwnershipEvent(LPEVENT pkEvent)
  1343. {
  1344.     m_pkOwnershipEvent = pkEvent;
  1345. }
  1346.  
  1347. void CItem::SetOwnership(LPCHARACTER ch, int iSec)
  1348. {
  1349.     if (!ch)
  1350.     {
  1351.         if (m_pkOwnershipEvent)
  1352.         {
  1353.             event_cancel(&m_pkOwnershipEvent);
  1354.             m_dwOwnershipPID = 0;
  1355.  
  1356.             TPacketGCItemOwnership p;
  1357.  
  1358.             p.bHeader   = HEADER_GC_ITEM_OWNERSHIP;
  1359.             p.dwVID = m_dwVID;
  1360.             p.szName[0] = '\0';
  1361.  
  1362.             PacketAround(&p, sizeof(p));
  1363.         }
  1364.         return;
  1365.     }
  1366.  
  1367.     if (m_pkOwnershipEvent)
  1368.         return;
  1369.  
  1370.     if (true == LC_IsEurope())
  1371.     {
  1372.         if (iSec <= 10)
  1373.             iSec = 30;
  1374.     }
  1375.  
  1376.     m_dwOwnershipPID = ch->GetPlayerID();
  1377.  
  1378.     item_event_info* info = AllocEventInfo<item_event_info>();
  1379.     strlcpy(info->szOwnerName, ch->GetName(), sizeof(info->szOwnerName));
  1380.     info->item = this;
  1381.  
  1382.     SetOwnershipEvent(event_create(ownership_event, info, PASSES_PER_SEC(iSec)));
  1383.  
  1384.     TPacketGCItemOwnership p;
  1385.  
  1386.     p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
  1387.     p.dwVID = m_dwVID;
  1388.     strlcpy(p.szName, ch->GetName(), sizeof(p.szName));
  1389.  
  1390.     PacketAround(&p, sizeof(p));
  1391. }
  1392.  
  1393. int CItem::GetSocketCount()
  1394. {
  1395.     for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
  1396.     {
  1397.         if (GetSocket(i) == 0)
  1398.             return i;
  1399.     }
  1400.     return ITEM_SOCKET_MAX_NUM;
  1401. }
  1402.  
  1403. bool CItem::AddSocket()
  1404. {
  1405.     int count = GetSocketCount();
  1406.     if (count == ITEM_SOCKET_MAX_NUM)
  1407.         return false;
  1408.     m_alSockets[count] = 1;
  1409.     return true;
  1410. }
  1411.  
  1412. void CItem::AlterToSocketItem(int iSocketCount)
  1413. {
  1414.     if (iSocketCount >= ITEM_SOCKET_MAX_NUM)
  1415.     {
  1416.         sys_log(0, "Invalid Socket Count %d, set to maximum", ITEM_SOCKET_MAX_NUM);
  1417.         iSocketCount = ITEM_SOCKET_MAX_NUM;
  1418.     }
  1419.  
  1420.     for (int i = 0; i < iSocketCount; ++i)
  1421.         SetSocket(i, 1);
  1422. }
  1423.  
  1424. void CItem::AlterToMagicItem()
  1425. {
  1426.     int idx = GetAttributeSetIndex();
  1427.  
  1428.     if (idx < 0)
  1429.         return;
  1430.  
  1431.     //      Appeariance Second Third
  1432.     // Weapon 50        20     5
  1433.     // Armor  30        10     2
  1434.     // Acc    20        10     1
  1435.  
  1436.     int iSecondPct;
  1437.     int iThirdPct;
  1438.  
  1439.     if (g_iUseLocale)
  1440.     {
  1441.         switch (GetType())
  1442.         {
  1443.             case ITEM_WEAPON:
  1444.                 iSecondPct = 20;
  1445.                 iThirdPct = 5;
  1446.                 break;
  1447.  
  1448.             case ITEM_ARMOR:
  1449.             case ITEM_COSTUME:
  1450.                 if (GetSubType() == ARMOR_BODY)
  1451.                 {
  1452.                     iSecondPct = 10;
  1453.                     iThirdPct = 2;
  1454.                 }
  1455.                 else
  1456.                 {
  1457.                     iSecondPct = 10;
  1458.                     iThirdPct = 1;
  1459.                 }
  1460.                 break;
  1461.  
  1462.             default:
  1463.                 return;
  1464.         }
  1465.     }
  1466.     else
  1467.     {
  1468.         switch (GetType())
  1469.         {
  1470.             case ITEM_WEAPON:
  1471.                 iSecondPct = 30;
  1472.                 iThirdPct = 15;
  1473.                 break;
  1474.  
  1475.             case ITEM_ARMOR:
  1476.             case ITEM_COSTUME:
  1477.                 if (GetSubType() == ARMOR_BODY)
  1478.                 {
  1479.                     iSecondPct = 20;
  1480.                     iThirdPct = 10;
  1481.                 }
  1482.                 else
  1483.                 {
  1484.                     iSecondPct = 10;
  1485.                     iThirdPct = 5;
  1486.                 }
  1487.                 break;
  1488.  
  1489.             default:
  1490.                 return;
  1491.         }
  1492.     }
  1493.  
  1494.     // 100% 확률로 좋은 속성 하나
  1495.     PutAttribute(aiItemMagicAttributePercentHigh);
  1496.  
  1497.     if (number(1, 100) <= iSecondPct)
  1498.         PutAttribute(aiItemMagicAttributePercentLow);
  1499.  
  1500.     if (number(1, 100) <= iThirdPct)
  1501.         PutAttribute(aiItemMagicAttributePercentLow);
  1502. }
  1503.  
  1504. DWORD CItem::GetRefineFromVnum()
  1505. {
  1506.     return ITEM_MANAGER::instance().GetRefineFromVnum(GetVnum());
  1507. }
  1508.  
  1509. int CItem::GetRefineLevel()
  1510. {
  1511.     const char* name = GetName();
  1512.     char* p = const_cast<char*>(strrchr(name, '+'));
  1513.  
  1514.     if (!p)
  1515.         return 0;
  1516.  
  1517.     int rtn = 0;
  1518.     str_to_number(rtn, p+1);
  1519.  
  1520.     const char* locale_name = GetName();
  1521.     p = const_cast<char*>(strrchr(locale_name, '+'));
  1522.  
  1523.     if (p)
  1524.     {
  1525.         int locale_rtn = 0;
  1526.         str_to_number(locale_rtn, p+1);
  1527.         if (locale_rtn != rtn)
  1528.         {
  1529.             sys_err("refine_level_based_on_NAME(%d) is not equal to refine_level_based_on_LOCALE_NAME(%d).", rtn, locale_rtn);
  1530.         }
  1531.     }
  1532.  
  1533.     return rtn;
  1534. }
  1535.  
  1536. bool CItem::IsPolymorphItem()
  1537. {
  1538.     return GetType() == ITEM_POLYMORPH;
  1539. }
  1540.  
  1541. EVENTFUNC(unique_expire_event)
  1542. {
  1543.     item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  1544.  
  1545.     if ( info == NULL )
  1546.     {
  1547.         sys_err( "unique_expire_event> <Factor> Null pointer" );
  1548.         return 0;
  1549.     }
  1550.  
  1551.     LPITEM pkItem = info->item;
  1552.  
  1553.     if (pkItem->GetValue(2) == 0)
  1554.     {
  1555.         if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= 1)
  1556.         {
  1557.             sys_log(0, "UNIQUE_ITEM: expire %s %u", pkItem->GetName(), pkItem->GetID());
  1558.             pkItem->SetUniqueExpireEvent(NULL);
  1559.             ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
  1560.             return 0;
  1561.         }
  1562.         else
  1563.         {
  1564.             pkItem->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - 1);
  1565.             return PASSES_PER_SEC(60);
  1566.         }
  1567.     }
  1568.     else
  1569.     {
  1570.         time_t cur = get_global_time();
  1571.        
  1572.         if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= cur)
  1573.         {
  1574.             pkItem->SetUniqueExpireEvent(NULL);
  1575.             ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
  1576.             return 0;
  1577.         }
  1578.         else
  1579.         {
  1580.             // 게임 내에 시간제 아이템들이 빠릿빠릿하게 사라지지 않는 버그가 있어
  1581.             // 수정
  1582.             // by rtsummit
  1583.             if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur < 600)
  1584.                 return PASSES_PER_SEC(pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur);
  1585.             else
  1586.                 return PASSES_PER_SEC(600);
  1587.         }
  1588.     }
  1589. }
  1590.  
  1591. // 시간 후불제
  1592. // timer를 시작할 때에 시간 차감하는 것이 아니라,
  1593. // timer가 발화할 때에 timer가 동작한 시간 만큼 시간 차감을 한다.
  1594. EVENTFUNC(timer_based_on_wear_expire_event)
  1595. {
  1596.     item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  1597.  
  1598.     if ( info == NULL )
  1599.     {
  1600.         sys_err( "expire_event <Factor> Null pointer" );
  1601.         return 0;
  1602.     }
  1603.  
  1604.     LPITEM pkItem = info->item;
  1605.     int remain_time = pkItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) - processing_time/passes_per_sec;
  1606.     if (remain_time <= 0)
  1607.     {
  1608.         sys_log(0, "ITEM EXPIRED : expired %s %u", pkItem->GetName(), pkItem->GetID());
  1609.         pkItem->SetTimerBasedOnWearExpireEvent(NULL);
  1610.         pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, 0);
  1611.    
  1612.         // 일단 timer based on wear 용혼석은 시간 다 되었다고 없애지 않는다.
  1613.         if (pkItem->IsDragonSoul())
  1614.         {
  1615.             DSManager::instance().DeactivateDragonSoul(pkItem);
  1616.         }
  1617.         else
  1618.         {
  1619.             ITEM_MANAGER::instance().RemoveItem(pkItem, "TIMER_BASED_ON_WEAR_EXPIRE");
  1620.         }
  1621.         return 0;
  1622.     }
  1623.     pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
  1624.     return PASSES_PER_SEC (MIN (60, remain_time));
  1625. }
  1626.  
  1627. void CItem::SetUniqueExpireEvent(LPEVENT pkEvent)
  1628. {
  1629.     m_pkUniqueExpireEvent = pkEvent;
  1630. }
  1631.  
  1632. void CItem::SetTimerBasedOnWearExpireEvent(LPEVENT pkEvent)
  1633. {
  1634.     m_pkTimerBasedOnWearExpireEvent = pkEvent;
  1635. }
  1636.  
  1637. EVENTFUNC(real_time_expire_event)
  1638. {
  1639.     const item_vid_event_info* info = reinterpret_cast<const item_vid_event_info*>(event->info);
  1640.  
  1641.     if (NULL == info)
  1642.         return 0;
  1643.  
  1644.     const LPITEM item = ITEM_MANAGER::instance().FindByVID( info->item_vid );
  1645.  
  1646.     if (NULL == item)
  1647.         return 0;
  1648.  
  1649.     const time_t current = get_global_time();
  1650.  
  1651.     if (current > item->GetSocket(0))
  1652.     {
  1653.         switch (item->GetVnum())
  1654.         {
  1655.             if(item->IsNewMountItem())
  1656.             {
  1657.                 if (item->GetSocket(2) != 0)
  1658.                     item->ClearMountAttributeAndAffect();
  1659.             }
  1660.             break;
  1661.         }
  1662.  
  1663.         ITEM_MANAGER::instance().RemoveItem(item, "REAL_TIME_EXPIRE");
  1664.  
  1665.         return 0;
  1666.     }
  1667.  
  1668.     return PASSES_PER_SEC(1);
  1669. }
  1670.  
  1671. void CItem::StartRealTimeExpireEvent()
  1672. {
  1673.     if (m_pkRealTimeExpireEvent)
  1674.         return;
  1675.     for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  1676.     {
  1677.         if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType || LIMIT_REAL_TIME_START_FIRST_USE == GetProto()->aLimits[i].bType)
  1678.         {
  1679.             item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
  1680.             info->item_vid = GetVID();
  1681.  
  1682.             m_pkRealTimeExpireEvent = event_create( real_time_expire_event, info, PASSES_PER_SEC(1));
  1683.  
  1684.             sys_log(0, "REAL_TIME_EXPIRE: StartRealTimeExpireEvent");
  1685.  
  1686.             return;
  1687.         }
  1688.     }
  1689. }
  1690.  
  1691. bool CItem::IsRealTimeItem()
  1692. {
  1693.     if(!GetProto())
  1694.         return false;
  1695.     for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  1696.     {
  1697.         if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType)
  1698.             return true;
  1699.     }
  1700.     return false;
  1701. }
  1702.  
  1703. void CItem::StartUniqueExpireEvent()
  1704. {
  1705.     if (GetType() != ITEM_UNIQUE)
  1706.         return;
  1707.  
  1708.     if (m_pkUniqueExpireEvent)
  1709.         return;
  1710.  
  1711.     //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
  1712.     if (IsRealTimeItem())
  1713.         return;
  1714.  
  1715.     // HARD CODING
  1716.     if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
  1717.         m_pOwner->ShowAlignment(false);
  1718.  
  1719.     int iSec = GetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME);
  1720.  
  1721.     if (iSec == 0)
  1722.         iSec = 60;
  1723.     else
  1724.         iSec = MIN(iSec, 60);
  1725.  
  1726.     SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, 0);
  1727.  
  1728.     item_event_info* info = AllocEventInfo<item_event_info>();
  1729.     info->item = this;
  1730.  
  1731.     SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec)));
  1732. }
  1733.  
  1734. // 시간 후불제
  1735. // timer_based_on_wear_expire_event 설명 참조
  1736. void CItem::StartTimerBasedOnWearExpireEvent()
  1737. {
  1738.     if (m_pkTimerBasedOnWearExpireEvent)
  1739.         return;
  1740.  
  1741.     //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
  1742.     if (IsRealTimeItem())
  1743.         return;
  1744.  
  1745.     if (-1 == GetProto()->cLimitTimerBasedOnWearIndex)
  1746.         return;
  1747.  
  1748.     int iSec = GetSocket(0);
  1749.    
  1750.     // 남은 시간을 분단위로 끊기 위해...
  1751.     if (0 != iSec)
  1752.     {
  1753.         iSec %= 60;
  1754.         if (0 == iSec)
  1755.             iSec = 60;
  1756.     }
  1757.  
  1758.     item_event_info* info = AllocEventInfo<item_event_info>();
  1759.     info->item = this;
  1760.  
  1761.     SetTimerBasedOnWearExpireEvent(event_create(timer_based_on_wear_expire_event, info, PASSES_PER_SEC(iSec)));
  1762. }
  1763.  
  1764. void CItem::StopUniqueExpireEvent()
  1765. {
  1766.     if (!m_pkUniqueExpireEvent)
  1767.         return;
  1768.  
  1769.     if (GetValue(2) != 0) // 게임시간제 이외의 아이템은 UniqueExpireEvent를 중단할 수 없다.
  1770.         return;
  1771.  
  1772.     // HARD CODING
  1773.     if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
  1774.         m_pOwner->ShowAlignment(true);
  1775.  
  1776.     SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, event_time(m_pkUniqueExpireEvent) / passes_per_sec);
  1777.     event_cancel(&m_pkUniqueExpireEvent);
  1778.  
  1779.     ITEM_MANAGER::instance().SaveSingleItem(this);
  1780. }
  1781.  
  1782. void CItem::StopTimerBasedOnWearExpireEvent()
  1783. {
  1784.     if (!m_pkTimerBasedOnWearExpireEvent)
  1785.         return;
  1786.  
  1787.     int remain_time = GetSocket(ITEM_SOCKET_REMAIN_SEC) - event_processing_time(m_pkTimerBasedOnWearExpireEvent) / passes_per_sec;
  1788.  
  1789.     SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
  1790.     event_cancel(&m_pkTimerBasedOnWearExpireEvent);
  1791.  
  1792.     ITEM_MANAGER::instance().SaveSingleItem(this);
  1793. }
  1794.  
  1795. void CItem::ApplyAddon(int iAddonType)
  1796. {
  1797.     CItemAddonManager::instance().ApplyAddonTo(iAddonType, this);
  1798. }
  1799.  
  1800. int CItem::GetSpecialGroup() const
  1801. {
  1802.     return ITEM_MANAGER::instance().GetSpecialGroupFromItem(GetVnum());
  1803. }
  1804.  
  1805. //
  1806. // 악세서리 소켓 처리.
  1807. //
  1808. bool CItem::IsAccessoryForSocket()
  1809. {
  1810.     return (m_pProto->bType == ITEM_ARMOR && (m_pProto->bSubType == ARMOR_WRIST || m_pProto->bSubType == ARMOR_NECK || m_pProto->bSubType == ARMOR_EAR)) ||
  1811.         (m_pProto->bType == ITEM_BELT);             // 2013년 2월 새로 추가된 '벨트' 아이템의 경우 기획팀에서 악세서리 소켓 시스템을 그대로 이용하자고 함.
  1812. }
  1813.  
  1814. void CItem::SetAccessorySocketGrade(int iGrade)
  1815. {
  1816.     SetSocket(0, MINMAX(0, iGrade, GetAccessorySocketMaxGrade()));
  1817.  
  1818.     int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
  1819.  
  1820.     //if (test_server)
  1821.     //  iDownTime /= 60;
  1822.  
  1823.     SetAccessorySocketDownGradeTime(iDownTime);
  1824. }
  1825.  
  1826. void CItem::SetAccessorySocketMaxGrade(int iMaxGrade)
  1827. {
  1828.     SetSocket(1, MINMAX(0, iMaxGrade, ITEM_ACCESSORY_SOCKET_MAX_NUM));
  1829. }
  1830.  
  1831. void CItem::SetAccessorySocketDownGradeTime(DWORD time)
  1832. {
  1833.     SetSocket(2, time);
  1834.  
  1835.     if (test_server && GetOwner())
  1836.         GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s에서 소켓 빠질때까지 남은 시간 %d"), GetName(), time);
  1837. }
  1838.  
  1839. EVENTFUNC(accessory_socket_expire_event)
  1840. {
  1841.     item_vid_event_info* info = dynamic_cast<item_vid_event_info*>( event->info );
  1842.  
  1843.     if ( info == NULL )
  1844.     {
  1845.         sys_err( "accessory_socket_expire_event> <Factor> Null pointer" );
  1846.         return 0;
  1847.     }
  1848.  
  1849.     LPITEM item = ITEM_MANAGER::instance().FindByVID(info->item_vid);
  1850.  
  1851.     if (item->GetAccessorySocketDownGradeTime() <= 1)
  1852.     {
  1853. degrade:
  1854.         item->SetAccessorySocketExpireEvent(NULL);
  1855.         item->AccessorySocketDegrade();
  1856.         return 0;
  1857.     }
  1858.     else
  1859.     {
  1860.         int iTime = item->GetAccessorySocketDownGradeTime() - 60;
  1861.  
  1862.         if (iTime <= 1)
  1863.             goto degrade;
  1864.  
  1865.         item->SetAccessorySocketDownGradeTime(iTime);
  1866.  
  1867.         if (iTime > 60)
  1868.             return PASSES_PER_SEC(60);
  1869.         else
  1870.             return PASSES_PER_SEC(iTime);
  1871.     }
  1872. }
  1873.  
  1874. void CItem::StartAccessorySocketExpireEvent()
  1875. {
  1876.     if (!IsAccessoryForSocket())
  1877.         return;
  1878.  
  1879.     if (m_pkAccessorySocketExpireEvent)
  1880.         return;
  1881.  
  1882.     if (GetAccessorySocketMaxGrade() == 0)
  1883.         return;
  1884.  
  1885.     if (GetAccessorySocketGrade() == 0)
  1886.         return;
  1887.  
  1888.     int iSec = GetAccessorySocketDownGradeTime();
  1889.     SetAccessorySocketExpireEvent(NULL);
  1890.  
  1891.     if (iSec <= 1)
  1892.         iSec = 5;
  1893.     else
  1894.         iSec = MIN(iSec, 60);
  1895.  
  1896.     item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
  1897.     info->item_vid = GetVID();
  1898.  
  1899.     SetAccessorySocketExpireEvent(event_create(accessory_socket_expire_event, info, PASSES_PER_SEC(iSec)));
  1900. }
  1901.  
  1902. void CItem::StopAccessorySocketExpireEvent()
  1903. {
  1904.     if (!m_pkAccessorySocketExpireEvent)
  1905.         return;
  1906.  
  1907.     if (!IsAccessoryForSocket())
  1908.         return;
  1909.  
  1910.     int new_time = GetAccessorySocketDownGradeTime() - (60 - event_time(m_pkAccessorySocketExpireEvent) / passes_per_sec);
  1911.  
  1912.     event_cancel(&m_pkAccessorySocketExpireEvent);
  1913.  
  1914.     if (new_time <= 1)
  1915.     {
  1916.         AccessorySocketDegrade();
  1917.     }
  1918.     else
  1919.     {
  1920.         SetAccessorySocketDownGradeTime(new_time);
  1921.     }
  1922. }
  1923.        
  1924. bool CItem::IsRideItem()
  1925. {
  1926.     if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_RIDE == GetSubType())
  1927.         return true;
  1928.     if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_MOUNT_RIDE == GetSubType())
  1929.         return true;
  1930. #ifdef WJ_ENABLE_COSTUME_MOUNT
  1931.     if (ITEM_COSTUME == GetType() && COSTUME_MOUNT == GetSubType())
  1932.         return true;
  1933. #endif
  1934.     return false;
  1935. }
  1936.        
  1937. bool CItem::IsRamadanRing()
  1938. {
  1939.     if (GetVnum() == UNIQUE_ITEM_RAMADAN_RING)
  1940.         return true;
  1941.     return false;
  1942. }
  1943.  
  1944. void CItem::ClearMountAttributeAndAffect()
  1945. {
  1946.     LPCHARACTER ch = GetOwner();
  1947.  
  1948.     ch->RemoveAffect(AFFECT_MOUNT);
  1949.     ch->RemoveAffect(AFFECT_MOUNT_BONUS);
  1950.  
  1951.     ch->MountVnum(0);
  1952.  
  1953.     ch->PointChange(POINT_ST, 0);
  1954.     ch->PointChange(POINT_DX, 0);
  1955.     ch->PointChange(POINT_HT, 0);
  1956.     ch->PointChange(POINT_IQ, 0);
  1957. }
  1958.  
  1959. // fixme
  1960. // 이거 지금은 안쓴데... 근데 혹시나 싶어서 남겨둠.
  1961. // by rtsummit
  1962. bool CItem::IsNewMountItem()
  1963. {
  1964.     switch(GetVnum())
  1965.     {
  1966.         case 76000: case 76001: case 76002: case 76003:
  1967.         case 76004: case 76005: case 76006: case 76007:
  1968.         case 76008: case 76009: case 76010: case 76011:
  1969.         case 76012: case 76013: case 76014:
  1970.             return true;
  1971.     }
  1972.     return false;
  1973. }
  1974.  
  1975. void CItem::SetAccessorySocketExpireEvent(LPEVENT pkEvent)
  1976. {
  1977.     m_pkAccessorySocketExpireEvent = pkEvent;
  1978. }
  1979.  
  1980. void CItem::AccessorySocketDegrade()
  1981. {
  1982.     if (GetAccessorySocketGrade() > 0)
  1983.     {
  1984.         LPCHARACTER ch = GetOwner();
  1985.  
  1986.         if (ch)
  1987.         {
  1988.             ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s에 박혀있던 보석이 사라집니다."), GetName());
  1989.         }
  1990.  
  1991.         ModifyPoints(false);
  1992.         SetAccessorySocketGrade(GetAccessorySocketGrade()-1);
  1993.         ModifyPoints(true);
  1994.  
  1995.         int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
  1996.  
  1997.         if (test_server)
  1998.             iDownTime /= 60;
  1999.  
  2000.         SetAccessorySocketDownGradeTime(iDownTime);
  2001.  
  2002.         if (iDownTime)
  2003.             StartAccessorySocketExpireEvent();
  2004.     }
  2005. }
  2006.  
  2007. // ring에 item을 박을 수 있는지 여부를 체크해서 리턴
  2008. static const bool CanPutIntoRing(LPITEM ring, LPITEM item)
  2009. {
  2010.     //const DWORD vnum = item->GetVnum();
  2011.     return false;
  2012. }
  2013.  
  2014. bool CItem::CanPutInto(LPITEM item)
  2015. {
  2016.     if (item->GetType() == ITEM_BELT)
  2017.         return this->GetSubType() == USE_PUT_INTO_BELT_SOCKET;
  2018.  
  2019.     else if(item->GetType() == ITEM_RING)
  2020.         return CanPutIntoRing(item, this);
  2021.  
  2022.     else if (item->GetType() != ITEM_ARMOR)
  2023.         return false;
  2024.  
  2025.     DWORD vnum = item->GetVnum();
  2026.  
  2027.     struct JewelAccessoryInfo
  2028.     {
  2029.         DWORD jewel;
  2030.         DWORD wrist;
  2031.         DWORD neck;
  2032.         DWORD ear;
  2033.     };
  2034.     const static JewelAccessoryInfo infos[] = {
  2035.         { 50634, 14420, 16220, 17220 },
  2036.         { 50635, 14500, 16500, 17500 },
  2037.         { 50636, 14520, 16520, 17520 },
  2038.         { 50637, 14540, 16540, 17540 },
  2039.         { 50638, 14560, 16560, 17560 },
  2040.     };
  2041.    
  2042.     DWORD item_type = (item->GetVnum() / 10) * 10;
  2043.     for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++)
  2044.     {
  2045.         const JewelAccessoryInfo& info = infos[i];
  2046.         switch(item->GetSubType())
  2047.         {
  2048.         case ARMOR_WRIST:
  2049.             if (info.wrist == item_type)
  2050.             {
  2051.                 if (info.jewel == GetVnum())
  2052.                 {
  2053.                     return true;
  2054.                 }
  2055.                 else
  2056.                 {
  2057.                     return false;
  2058.                 }
  2059.             }
  2060.             break;
  2061.         case ARMOR_NECK:
  2062.             if (info.neck == item_type)
  2063.             {
  2064.                 if (info.jewel == GetVnum())
  2065.                 {
  2066.                     return true;
  2067.                 }
  2068.                 else
  2069.                 {
  2070.                     return false;
  2071.                 }
  2072.             }
  2073.             break;
  2074.         case ARMOR_EAR:
  2075.             if (info.ear == item_type)
  2076.             {
  2077.                 if (info.jewel == GetVnum())
  2078.                 {
  2079.                     return true;
  2080.                 }
  2081.                 else
  2082.                 {
  2083.                     return false;
  2084.                 }
  2085.             }
  2086.             break;
  2087.         }
  2088.     }
  2089.     if (item->GetSubType() == ARMOR_WRIST)
  2090.         vnum -= 14000;
  2091.     else if (item->GetSubType() == ARMOR_NECK)
  2092.         vnum -= 16000;
  2093.     else if (item->GetSubType() == ARMOR_EAR)
  2094.         vnum -= 17000;
  2095.     else
  2096.         return false;
  2097.  
  2098.     DWORD type = vnum / 20;
  2099.  
  2100.     if (type < 0 || type > 11)
  2101.     {
  2102.         type = (vnum - 170) / 20;
  2103.  
  2104.         if (50623 + type != GetVnum())
  2105.             return false;
  2106.         else
  2107.             return true;
  2108.     }
  2109.     else if (item->GetVnum() >= 16210 && item->GetVnum() <= 16219)
  2110.     {
  2111.         if (50625 != GetVnum())
  2112.             return false;
  2113.         else
  2114.             return true;
  2115.     }
  2116.     else if (item->GetVnum() >= 16230 && item->GetVnum() <= 16239)
  2117.     {
  2118.         if (50626 != GetVnum())
  2119.             return false;
  2120.         else
  2121.             return true;
  2122.     }
  2123.  
  2124.     return 50623 + type == GetVnum();
  2125. }
  2126.  
  2127. // PC_BANG_ITEM_ADD
  2128. bool CItem::IsPCBangItem()
  2129. {
  2130.     for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  2131.     {
  2132.         if (m_pProto->aLimits[i].bType == LIMIT_PCBANG)
  2133.             return true;
  2134.     }
  2135.     return false;
  2136. }
  2137. // END_PC_BANG_ITEM_ADD
  2138.  
  2139. bool CItem::CheckItemUseLevel(int nLevel)
  2140. {
  2141.     for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  2142.     {
  2143.         if (this->m_pProto->aLimits[i].bType == LIMIT_LEVEL)
  2144.         {
  2145.             if (this->m_pProto->aLimits[i].lValue > nLevel) return false;
  2146.             else return true;
  2147.         }
  2148.     }
  2149.     return true;
  2150. }
  2151.  
  2152. long CItem::FindApplyValue(BYTE bApplyType)
  2153. {
  2154.     if (m_pProto == NULL)
  2155.         return 0;
  2156.  
  2157.     for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
  2158.     {
  2159.         if (m_pProto->aApplies[i].bType == bApplyType)
  2160.             return m_pProto->aApplies[i].lValue;
  2161.     }
  2162.  
  2163.     return 0;
  2164. }
  2165.  
  2166. void CItem::CopySocketTo(LPITEM pItem)
  2167. {
  2168.     for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  2169.     {
  2170.         pItem->m_alSockets[i] = m_alSockets[i];
  2171.     }
  2172. }
  2173.  
  2174. int CItem::GetAccessorySocketGrade()
  2175. {
  2176.     return MINMAX(0, GetSocket(0), GetAccessorySocketMaxGrade());
  2177. }
  2178.  
  2179. int CItem::GetAccessorySocketMaxGrade()
  2180. {
  2181.     return MINMAX(0, GetSocket(1), ITEM_ACCESSORY_SOCKET_MAX_NUM);
  2182. }
  2183.  
  2184. int CItem::GetAccessorySocketDownGradeTime()
  2185. {
  2186.     return MINMAX(0, GetSocket(2), aiAccessorySocketDegradeTime[GetAccessorySocketGrade()]);
  2187. }
  2188.  
  2189. void CItem::AttrLog()
  2190. {
  2191.     const char * pszIP = NULL;
  2192.  
  2193.     if (GetOwner() && GetOwner()->GetDesc())
  2194.         pszIP = GetOwner()->GetDesc()->GetHostName();
  2195.  
  2196.     for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  2197.     {
  2198.         if (m_alSockets[i])
  2199.         {
  2200.             LogManager::instance().ItemLog(i, m_alSockets[i], 0, GetID(), "INFO_SOCKET", "", pszIP ? pszIP : "", GetOriginalVnum());
  2201.         }
  2202.     }
  2203.  
  2204.     for (int i = 0; i<ITEM_ATTRIBUTE_MAX_NUM; ++i)
  2205.     {
  2206.         int type    = m_aAttr[i].bType;
  2207.         int value   = m_aAttr[i].sValue;
  2208.  
  2209.         if (type)
  2210.             LogManager::instance().ItemLog(i, type, value, GetID(), "INFO_ATTR", "", pszIP ? pszIP : "", GetOriginalVnum());
  2211.     }
  2212. }
  2213.  
  2214. int CItem::GetLevelLimit()
  2215. {
  2216.     for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  2217.     {
  2218.         if (this->m_pProto->aLimits[i].bType == LIMIT_LEVEL)
  2219.         {
  2220.             return this->m_pProto->aLimits[i].lValue;
  2221.         }
  2222.     }
  2223.     return 0;
  2224. }
  2225.  
  2226. bool CItem::OnAfterCreatedItem()
  2227. {
  2228.     // 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
  2229.     if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
  2230.     {
  2231.         // Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
  2232.         if (0 != GetSocket(1))
  2233.         {
  2234.             StartRealTimeExpireEvent();
  2235.         }
  2236.     }
  2237.  
  2238.     return true;
  2239. }
  2240.  
  2241.  
  2242. bool CItem::IsDragonSoul()
  2243. {
  2244.     return GetType() == ITEM_DS;
  2245. }
  2246.  
  2247. int CItem::GiveMoreTime_Per(float fPercent)
  2248. {
  2249.     if (IsDragonSoul())
  2250.     {
  2251.         DWORD duration = DSManager::instance().GetDuration(this);
  2252.         int remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
  2253.         int given_time = fPercent * duration / 100;
  2254.         if (remain_sec == (int)duration)
  2255.             return false;
  2256.         if ((given_time + remain_sec) >= (int)duration)
  2257.         {
  2258.             SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
  2259.             return duration - remain_sec;
  2260.         }
  2261.         else
  2262.         {
  2263.             SetSocket(ITEM_SOCKET_REMAIN_SEC, given_time + remain_sec);
  2264.             return given_time;
  2265.         }
  2266.     }
  2267.     // 우선 용혼석에 관해서만 하도록 한다.
  2268.     else
  2269.         return 0;
  2270. }
  2271.  
  2272. #ifdef ENABLE_DS_CHANGE_ATTR
  2273. bool CItem::IsMythDragonSoul()
  2274.  
  2275. {
  2276.     bool bMyth = ((GetVnum() / 1000) % 10) == 5 ? true : false;
  2277.  
  2278.     return bMyth;
  2279. }
  2280. #endif
  2281.  
  2282. int CItem::GiveMoreTime_Fix(DWORD dwTime)
  2283. {
  2284.     if (IsDragonSoul())
  2285.     {
  2286.         DWORD duration = DSManager::instance().GetDuration(this);
  2287.         int remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
  2288.         if (remain_sec == (int)duration)
  2289.             return false;
  2290.         if ((dwTime + remain_sec) >= duration)
  2291.         {
  2292.             SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
  2293.             return duration - remain_sec;
  2294.         }
  2295.         else
  2296.         {
  2297.             SetSocket(ITEM_SOCKET_REMAIN_SEC, dwTime + remain_sec);
  2298.             return dwTime;
  2299.         }
  2300.     }
  2301.     // 우선 용혼석에 관해서만 하도록 한다.
  2302.     else
  2303.         return 0;
  2304. }
  2305.  
  2306.  
  2307. int CItem::GetDuration()
  2308. {
  2309.     if(!GetProto())
  2310.         return -1;
  2311.  
  2312.     for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  2313.     {
  2314.         if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType)
  2315.             return GetProto()->aLimits[i].lValue;
  2316.     }
  2317.    
  2318.     if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
  2319.         return GetProto()->aLimits[static_cast<unsigned char>(GetProto()->cLimitTimerBasedOnWearIndex)].lValue;
  2320.  
  2321.     return -1;
  2322. }
  2323.  
  2324. bool CItem::IsSameSpecialGroup(const LPITEM item) const
  2325. {
  2326.     // 서로 VNUM이 같다면 같은 그룹인 것으로 간주
  2327.     if (this->GetVnum() == item->GetVnum())
  2328.         return true;
  2329.  
  2330.     if (GetSpecialGroup() && (item->GetSpecialGroup() == GetSpecialGroup()))
  2331.         return true;
  2332.  
  2333.     return false;
  2334. }
Add Comment
Please, Sign In to add comment