daily pastebin goal
14%
SHARE
TWEET

Untitled

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