Advertisement
Guest User

Untitled

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