Advertisement
Guest User

Untitled

a guest
Apr 16th, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 52.01 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.  
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement