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. CItem::CItem(DWORD dwVnum)
  25. : 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),
  26. m_bExchanging(false), m_pkDestroyEvent(NULL), m_pkUniqueExpireEvent(NULL), m_pkTimerBasedOnWearExpireEvent(NULL), m_pkRealTimeExpireEvent(NULL),
  27. m_pkExpireEvent(NULL),
  28. m_pkAccessorySocketExpireEvent(NULL), m_pkOwnershipEvent(NULL), m_dwOwnershipPID(0), m_bSkipSave(false), m_isLocked(false),
  29. m_dwMaskVnum(0), m_dwSIGVnum (0), m_bIsChangingAttr(false)
  30. {
  31. memset( &m_alSockets, 0, sizeof(m_alSockets) );
  32. memset( &m_aAttr, 0, sizeof(m_aAttr) );
  33. }
  34. CItem::~CItem()
  35. {
  36. Destroy();
  37. }
  38. void CItem::Initialize()
  39. {
  40. CEntity::Initialize(ENTITY_ITEM);
  41. m_bWindow = RESERVED_WINDOW;
  42. m_pOwner = NULL;
  43. m_dwID = 0;
  44. m_bEquipped = false;
  45. m_dwVID = m_wCell = m_dwCount = m_lFlag = 0;
  46. m_pProto = NULL;
  47. m_bExchanging = false;
  48. memset(&m_alSockets, 0, sizeof(m_alSockets));
  49. memset(&m_aAttr, 0, sizeof(m_aAttr));
  50. m_pkDestroyEvent = NULL;
  51. m_pkOwnershipEvent = NULL;
  52. m_dwOwnershipPID = 0;
  53. m_pkUniqueExpireEvent = NULL;
  54. m_pkTimerBasedOnWearExpireEvent = NULL;
  55. m_pkRealTimeExpireEvent = NULL;
  56. m_pkAccessorySocketExpireEvent = NULL;
  57. m_bSkipSave = false;
  58. m_bIsChangingAttr = false;
  59. m_dwLastOwnerPID = 0;
  60. }
  61. void CItem::Destroy()
  62. {
  63. event_cancel(&m_pkDestroyEvent);
  64. event_cancel(&m_pkOwnershipEvent);
  65. event_cancel(&m_pkUniqueExpireEvent);
  66. event_cancel(&m_pkTimerBasedOnWearExpireEvent);
  67. event_cancel(&m_pkRealTimeExpireEvent);
  68. event_cancel(&m_pkAccessorySocketExpireEvent);
  69. CEntity::Destroy();
  70. if (GetSectree())
  71. GetSectree()->RemoveEntity(this);
  72. }
  73. EVENTFUNC(item_destroy_event)
  74. {
  75. item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  76. if ( info == NULL )
  77. {
  78. sys_err( "item_destroy_event> <Factor> Null pointer" );
  79. return 0;
  80. }
  81. LPITEM pkItem = info->item;
  82. if (pkItem->GetOwner())
  83. sys_err("item_destroy_event: Owner exist. (item %s owner %s)", pkItem->GetName(), pkItem->GetOwner()->GetName());
  84. pkItem->SetDestroyEvent(NULL);
  85. M2_DESTROY_ITEM(pkItem);
  86. return 0;
  87. }
  88. void CItem::SetDestroyEvent(LPEVENT pkEvent)
  89. {
  90. m_pkDestroyEvent = pkEvent;
  91. }
  92. void CItem::StartDestroyEvent(int iSec)
  93. {
  94. if (m_pkDestroyEvent)
  95. return;
  96. item_event_info* info = AllocEventInfo<item_event_info>();
  97. info->item = this;
  98. SetDestroyEvent(event_create(item_destroy_event, info, PASSES_PER_SEC(iSec)));
  99. }
  100. void CItem::EncodeInsertPacket(LPENTITY ent)
  101. {
  102. LPDESC d;
  103. if (!(d = ent->GetDesc()))
  104. return;
  105. const PIXEL_POSITION & c_pos = GetXYZ();
  106. struct packet_item_ground_add pack;
  107. pack.bHeader = HEADER_GC_ITEM_GROUND_ADD;
  108. pack.x = c_pos.x;
  109. pack.y = c_pos.y;
  110. pack.z = c_pos.z;
  111. pack.dwVnum = GetVnum();
  112. pack.dwVID = m_dwVID;
  113. //pack.count = m_dwCount;
  114. d->Packet(&pack, sizeof(pack));
  115. if (m_pkOwnershipEvent != NULL)
  116. {
  117. item_event_info * info = dynamic_cast<item_event_info *>(m_pkOwnershipEvent->info);
  118. if ( info == NULL )
  119. {
  120. sys_err( "CItem::EncodeInsertPacket> <Factor> Null pointer" );
  121. return;
  122. }
  123. TPacketGCItemOwnership p;
  124. p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
  125. p.dwVID = m_dwVID;
  126. strlcpy(p.szName, info->szOwnerName, sizeof(p.szName));
  127. d->Packet(&p, sizeof(TPacketGCItemOwnership));
  128. }
  129. }
  130. void CItem::EncodeRemovePacket(LPENTITY ent)
  131. {
  132. LPDESC d;
  133. if (!(d = ent->GetDesc()))
  134. return;
  135. struct packet_item_ground_del pack;
  136. pack.bHeader = HEADER_GC_ITEM_GROUND_DEL;
  137. pack.dwVID = m_dwVID;
  138. d->Packet(&pack, sizeof(pack));
  139. sys_log(2, "Item::EncodeRemovePacket %s to %s", GetName(), ((LPCHARACTER) ent)->GetName());
  140. }
  141. void CItem::SetProto(const TItemTable * table)
  142. {
  143. assert(table != NULL);
  144. m_pProto = table;
  145. SetFlag(m_pProto->dwFlags);
  146. }
  147. void CItem::UsePacketEncode(LPCHARACTER ch, LPCHARACTER victim, struct packet_item_use *packet)
  148. {
  149. if (!GetVnum())
  150. return;
  151. packet->header = HEADER_GC_ITEM_USE;
  152. packet->ch_vid = ch->GetVID();
  153. packet->victim_vid = victim->GetVID();
  154. packet->Cell = TItemPos(GetWindow(), m_wCell);
  155. packet->vnum = GetVnum();
  156. }
  157. void CItem::RemoveFlag(long bit)
  158. {
  159. REMOVE_BIT(m_lFlag, bit);
  160. }
  161. void CItem::AddFlag(long bit)
  162. {
  163. SET_BIT(m_lFlag, bit);
  164. }
  165. void CItem::UpdatePacket()
  166. {
  167. if (!m_pOwner || !m_pOwner->GetDesc())
  168. return;
  169. if (IsChangingAttr())
  170. return;
  171. TPacketGCItemUpdate pack;
  172. pack.header = HEADER_GC_ITEM_UPDATE;
  173. pack.Cell = TItemPos(GetWindow(), m_wCell);
  174. pack.count = m_dwCount;
  175. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  176. pack.alSockets[i] = m_alSockets[i];
  177. thecore_memcpy(pack.aAttr, GetAttributes(), sizeof(pack.aAttr));
  178. sys_log(2, "UpdatePacket %s -> %s", GetName(), m_pOwner->GetName());
  179. m_pOwner->GetDesc()->Packet(&pack, sizeof(pack));
  180. }
  181. DWORD CItem::GetCount()
  182. {
  183. if (GetType() == ITEM_ELK) return MIN(m_dwCount, INT_MAX);
  184. else
  185. {
  186. return MIN(m_dwCount, 200);
  187. }
  188. }
  189. bool CItem::SetCount(DWORD count)
  190. {
  191. if (GetType() == ITEM_ELK)
  192. {
  193. m_dwCount = MIN(count, INT_MAX);
  194. }
  195. else
  196. {
  197. m_dwCount = MIN(count, ITEM_MAX_COUNT);
  198. }
  199. if (count == 0 && m_pOwner)
  200. {
  201. if (GetSubType() == USE_ABILITY_UP || GetSubType() == USE_POTION || GetVnum() == 70020)
  202. {
  203. LPCHARACTER pOwner = GetOwner();
  204. WORD wCell = GetCell();
  205. RemoveFromCharacter();
  206. if (!IsDragonSoul())
  207. {
  208. LPITEM pItem = pOwner->FindSpecifyItem(GetVnum());
  209. if (NULL != pItem)
  210. {
  211. pOwner->ChainQuickslotItem(pItem, QUICKSLOT_TYPE_ITEM, wCell);
  212. }
  213. else
  214. {
  215. pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, wCell, 255);
  216. }
  217. }
  218. M2_DESTROY_ITEM(this);
  219. }
  220. else
  221. {
  222. if (!IsDragonSoul())
  223. {
  224. m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, m_wCell, 255);
  225. }
  226. M2_DESTROY_ITEM(RemoveFromCharacter());
  227. }
  228. return false;
  229. }
  230. UpdatePacket();
  231. Save();
  232. return true;
  233. }
  234. LPITEM CItem::RemoveFromCharacter()
  235. {
  236. if (!m_pOwner)
  237. {
  238. sys_err("Item::RemoveFromCharacter owner null");
  239. return (this);
  240. }
  241. LPCHARACTER pOwner = m_pOwner;
  242. if (m_bEquipped) // ÀåÂøµÇ¾ú´Â°¡?
  243. {
  244. Unequip();
  245. //pOwner->UpdatePacket();
  246. SetWindow(RESERVED_WINDOW);
  247. Save();
  248. return (this);
  249. }
  250. else
  251. {
  252. if (GetWindow() != SAFEBOX && GetWindow() != MALL)
  253. {
  254. if (IsDragonSoul())
  255. {
  256. if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  257. sys_err("CItem::RemoveFromCharacter: pos >= DRAGON_SOUL_INVENTORY_MAX_NUM");
  258. else
  259. pOwner->SetItem(TItemPos(m_bWindow, m_wCell), NULL);
  260. }
  261. else
  262. {
  263. TItemPos cell(INVENTORY, m_wCell);
  264. if (false == cell.IsDefaultInventoryPosition() && false == cell.IsBeltInventoryPosition()) // ¾Æ´Ï¸é ¼ÒÁöǰ¿¡?
  265. sys_err("CItem::RemoveFromCharacter: Invalid Item Position");
  266. else
  267. {
  268. pOwner->SetItem(cell, NULL);
  269. }
  270. }
  271. }
  272. m_pOwner = NULL;
  273. m_wCell = 0;
  274. SetWindow(RESERVED_WINDOW);
  275. Save();
  276. return (this);
  277. }
  278. }
  279. bool CItem::AddToCharacter(LPCHARACTER ch, TItemPos Cell)
  280. {
  281. assert(GetSectree() == NULL);
  282. assert(m_pOwner == NULL);
  283. WORD pos = Cell.cell;
  284. BYTE window_type = Cell.window_type;
  285. if (INVENTORY == window_type)
  286. {
  287. if (m_wCell >= INVENTORY_MAX_NUM && BELT_INVENTORY_SLOT_START > m_wCell)
  288. {
  289. sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
  290. return false;
  291. }
  292. }
  293. else if (DRAGON_SOUL_INVENTORY == window_type)
  294. {
  295. if (m_wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  296. {
  297. sys_err("CItem::AddToCharacter: cell overflow: %s to %s cell %d", m_pProto->szName, ch->GetName(), m_wCell);
  298. return false;
  299. }
  300. }
  301. if (ch->GetDesc())
  302. m_dwLastOwnerPID = ch->GetPlayerID();
  303. event_cancel(&m_pkDestroyEvent);
  304. ch->SetItem(TItemPos(window_type, pos), this);
  305. m_pOwner = ch;
  306. Save();
  307. return true;
  308. }
  309. LPITEM CItem::RemoveFromGround()
  310. {
  311. if (GetSectree())
  312. {
  313. SetOwnership(NULL);
  314. GetSectree()->RemoveEntity(this);
  315. ViewCleanup();
  316. Save();
  317. }
  318. return (this);
  319. }
  320. bool CItem::AddToGround(long lMapIndex, const PIXEL_POSITION & pos, bool skipOwnerCheck)
  321. {
  322. if (0 == lMapIndex)
  323. {
  324. sys_err("wrong map index argument: %d", lMapIndex);
  325. return false;
  326. }
  327. if (GetSectree())
  328. {
  329. sys_err("sectree already assigned");
  330. return false;
  331. }
  332. if (!skipOwnerCheck && m_pOwner)
  333. {
  334. sys_err("owner pointer not null");
  335. return false;
  336. }
  337. LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, pos.x, pos.y);
  338. if (!tree)
  339. {
  340. sys_err("cannot find sectree by %dx%d", pos.x, pos.y);
  341. return false;
  342. }
  343. //tree->Touch();
  344. SetWindow(GROUND);
  345. SetXYZ(pos.x, pos.y, pos.z);
  346. tree->InsertEntity(this);
  347. UpdateSectree();
  348. Save();
  349. return true;
  350. }
  351. bool CItem::DistanceValid(LPCHARACTER ch)
  352. {
  353. if (!GetSectree())
  354. return false;
  355. int iDist = DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY());
  356. if (iDist > 300)
  357. return false;
  358. return true;
  359. }
  360. bool CItem::CanUsedBy(LPCHARACTER ch)
  361. {
  362. // Anti flag check
  363. switch (ch->GetJob())
  364. {
  365. case JOB_WARRIOR:
  366. if (GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR)
  367. return false;
  368. break;
  369. case JOB_ASSASSIN:
  370. if (GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN)
  371. return false;
  372. break;
  373. case JOB_SHAMAN:
  374. if (GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN)
  375. return false;
  376. break;
  377. case JOB_SURA:
  378. if (GetAntiFlag() & ITEM_ANTIFLAG_SURA)
  379. return false;
  380. break;
  381. }
  382. return true;
  383. }
  384. int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
  385. {
  386. // ÄÚ½ºÃõ ¾ÆÀÌÅÛ(ITEM_COSTUME)Àº WearFlag ¾ø¾îµµ µÊ. (sub typeÀ¸·Î Âø¿ëÀ§Ä¡ ±¸ºĞ. ±ÍÂú°Ô ¶Ç wear flag ÁÙ Çʿ䰡 ÀÖ³ª..)
  387. // ¿ëÈ¥¼®(ITEM_DS, ITEM_SPECIAL_DS)µµ SUB_TYPEÀ¸·Î ±¸ºĞ. ½Å±Ô ¹İÁö, º§Æ®´Â ITEM_TYPEÀ¸·Î ±¸ºĞ -_-
  388. if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
  389. return -1;
  390. // ¿ëÈ¥¼® ½½·ÔÀ» WEAR·Î ó¸®ÇÒ ¼ö°¡ ¾ø¾î¼­(WEAR´Â ÃÖ´ë 32°³±îÁö °¡´ÉÇѵ¥ ¿ëÈ¥¼®À» Ãß°¡Çϸé 32°¡ ³Ñ´Â´Ù.)
  391. // Àκ¥Å丮ÀÇ Æ¯Á¤ À§Ä¡((INVENTORY_MAX_NUM + WEAR_MAX_NUM)ºÎÅÍ (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)±îÁö)¸¦
  392. // ¿ëÈ¥¼® ½½·ÔÀ¸·Î Á¤ÇÔ.
  393. // return ÇÒ ¶§¿¡, INVENTORY_MAX_NUMÀ» »« ÀÌÀ¯´Â,
  394. // º»·¡ WearCellÀÌ INVENTORY_MAX_NUM¸¦ »©°í return Çϱ⠶§¹®.
  395. if (GetType() == ITEM_DS || GetType() == ITEM_SPECIAL_DS)
  396. {
  397. if (iCandidateCell < 0)
  398. {
  399. return WEAR_MAX_NUM + GetSubType();
  400. }
  401. else
  402. {
  403. for (int i = 0; i < DRAGON_SOUL_DECK_MAX_NUM; i++)
  404. {
  405. if (WEAR_MAX_NUM + i * DS_SLOT_MAX + GetSubType() == iCandidateCell)
  406. {
  407. return iCandidateCell;
  408. }
  409. }
  410. return -1;
  411. }
  412. }
  413. else if (GetType() == ITEM_COSTUME)
  414. {
  415. if (GetSubType() == COSTUME_BODY)
  416. return WEAR_COSTUME_BODY;
  417. else if (GetSubType() == COSTUME_HAIR)
  418. return WEAR_COSTUME_HAIR;
  419. }
  420. else if (GetType() == ITEM_RING)
  421. {
  422. if (ch->GetWear(WEAR_RING1))
  423. return WEAR_RING2;
  424. else
  425. return WEAR_RING1;
  426. }
  427. else if (GetType() == ITEM_BELT)
  428. return WEAR_BELT;
  429. else if (GetWearFlag() & WEARABLE_BODY)
  430. return WEAR_BODY;
  431. else if (GetWearFlag() & WEARABLE_HEAD)
  432. return WEAR_HEAD;
  433. else if (GetWearFlag() & WEARABLE_FOOTS)
  434. return WEAR_FOOTS;
  435. else if (GetWearFlag() & WEARABLE_WRIST)
  436. return WEAR_WRIST;
  437. else if (GetWearFlag() & WEARABLE_WEAPON)
  438. return WEAR_WEAPON;
  439. else if (GetWearFlag() & WEARABLE_SHIELD)
  440. return WEAR_SHIELD;
  441. else if (GetWearFlag() & WEARABLE_NECK)
  442. return WEAR_NECK;
  443. else if (GetWearFlag() & WEARABLE_EAR)
  444. return WEAR_EAR;
  445. else if (GetWearFlag() & WEARABLE_ARROW)
  446. return WEAR_ARROW;
  447. else if (GetWearFlag() & WEARABLE_UNIQUE)
  448. {
  449. if (ch->GetWear(WEAR_UNIQUE1))
  450. return WEAR_UNIQUE2;
  451. else
  452. return WEAR_UNIQUE1;
  453. }
  454. // ¼öÁı Äù½ºÆ®¸¦ À§ÇÑ ¾ÆÀÌÅÛÀÌ ¹ÚÈ÷´Â°÷À¸·Î Çѹø ¹ÚÈ÷¸é Àı´ë –E¼ö ¾ø´Ù.
  455. else if (GetWearFlag() & WEARABLE_ABILITY)
  456. {
  457. if (!ch->GetWear(WEAR_ABILITY1))
  458. {
  459. return WEAR_ABILITY1;
  460. }
  461. else if (!ch->GetWear(WEAR_ABILITY2))
  462. {
  463. return WEAR_ABILITY2;
  464. }
  465. else if (!ch->GetWear(WEAR_ABILITY3))
  466. {
  467. return WEAR_ABILITY3;
  468. }
  469. else if (!ch->GetWear(WEAR_ABILITY4))
  470. {
  471. return WEAR_ABILITY4;
  472. }
  473. else if (!ch->GetWear(WEAR_ABILITY5))
  474. {
  475. return WEAR_ABILITY5;
  476. }
  477. else if (!ch->GetWear(WEAR_ABILITY6))
  478. {
  479. return WEAR_ABILITY6;
  480. }
  481. else if (!ch->GetWear(WEAR_ABILITY7))
  482. {
  483. return WEAR_ABILITY7;
  484. }
  485. else if (!ch->GetWear(WEAR_ABILITY8))
  486. {
  487. return WEAR_ABILITY8;
  488. }
  489. else
  490. {
  491. return -1;
  492. }
  493. }
  494. return -1;
  495. }
  496. void CItem::ModifyPoints(bool bAdd)
  497. {
  498. int accessoryGrade;
  499. // ¹«±â¿Í °©¿Ê¸¸ ¼ÒÄÏÀ» Àû¿ë½ÃŲ´Ù.
  500. if (false == IsAccessoryForSocket())
  501. {
  502. if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
  503. {
  504. // ¼ÒÄÏÀÌ ¼Ó¼º°­È­¿¡ »ç¿ëµÇ´Â °æ¿ì Àû¿ëÇÏÁö ¾Ê´Â´Ù (ARMOR_WRIST ARMOR_NECK ARMOR_EAR)
  505. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  506. {
  507. DWORD dwVnum;
  508. if ((dwVnum = GetSocket(i)) <= 2)
  509. continue;
  510. TItemTable * p = ITEM_MANAGER::instance().GetTable(dwVnum);
  511. if (!p)
  512. {
  513. sys_err("cannot find table by vnum %u", dwVnum);
  514. continue;
  515. }
  516. if (ITEM_METIN == p->bType)
  517. {
  518. //m_pOwner->ApplyPoint(p->alValues[0], bAdd ? p->alValues[1] : -p->alValues[1]);
  519. for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
  520. {
  521. if (p->aApplies[i].bType == APPLY_NONE)
  522. continue;
  523. if (p->aApplies[i].bType == APPLY_SKILL)
  524. m_pOwner->ApplyPoint(p->aApplies[i].bType, bAdd ? p->aApplies[i].lValue : p->aApplies[i].lValue ^ 0x00800000);
  525. else
  526. m_pOwner->ApplyPoint(p->aApplies[i].bType, bAdd ? p->aApplies[i].lValue : -p->aApplies[i].lValue);
  527. }
  528. }
  529. }
  530. }
  531. accessoryGrade = 0;
  532. }
  533. else
  534. {
  535. accessoryGrade = MIN(GetAccessorySocketGrade(), ITEM_ACCESSORY_SOCKET_MAX_NUM);
  536. }
  537. for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
  538. {
  539. if (m_pProto->aApplies[i].bType == APPLY_NONE)
  540. continue;
  541. long value = m_pProto->aApplies[i].lValue;
  542. if (m_pProto->aApplies[i].bType == APPLY_SKILL)
  543. {
  544. m_pOwner->ApplyPoint(m_pProto->aApplies[i].bType, bAdd ? value : value ^ 0x00800000);
  545. }
  546. else
  547. {
  548. if (0 != accessoryGrade)
  549. value += MAX(accessoryGrade, value * aiAccessorySocketEffectivePct[accessoryGrade] / 100);
  550. m_pOwner->ApplyPoint(m_pProto->aApplies[i].bType, bAdd ? value : -value);
  551. }
  552. }
  553. // Ãʽ´ŞÀÇ ¹İÁö, ÇÒ·ÎÀ© »çÅÁ, ÇູÀÇ ¹İÁö, ¿µ¿øÇÑ »ç¶ûÀÇ Ææ´øÆ®ÀÇ °æ¿ì
  554. // ±âÁ¸ÀÇ Çϵå ÄÚµùÀ¸·Î °­Á¦·Î ¼Ó¼ºÀ» ºÎ¿©ÇßÁö¸¸,
  555. // ±× ºÎºĞÀ» Á¦°ÅÇϰí special item group Å×ÀÌºí¿¡¼­ ¼Ó¼ºÀ» ºÎ¿©Çϵµ·Ï º¯°æÇÏ¿´´Ù.
  556. // ÇÏÁö¸¸ Çϵå ÄÚµùµÇ¾îÀÖÀ» ¶§ »ı¼ºµÈ ¾ÆÀÌÅÛÀÌ ³²¾ÆÀÖÀ» ¼öµµ À־ Ư¼öó¸® ÇØ³õ´Â´Ù.
  557. // ÀÌ ¾ÆÀÌÅÛµéÀÇ °æ¿ì, ¹Ø¿¡ ITEM_UNIQUEÀÏ ¶§ÀÇ Ã³¸®·Î ¼Ó¼ºÀÌ ºÎ¿©µÇ±â ¶§¹®¿¡,
  558. // ¾ÆÀÌÅÛ¿¡ ¹ÚÇôÀÖ´Â attribute´Â Àû¿ëÇÏÁö ¾Ê°í ³Ñ¾î°£´Ù.
  559. if (true == CItemVnumHelper::IsRamadanMoonRing(GetVnum()) || true == CItemVnumHelper::IsHalloweenCandy(GetVnum())
  560. || true == CItemVnumHelper::IsHappinessRing(GetVnum()) || true == CItemVnumHelper::IsLovePendant(GetVnum()))
  561. {
  562. // Do not anything.
  563. }
  564. else
  565. {
  566. for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
  567. {
  568. if (GetAttributeType(i))
  569. {
  570. const TPlayerItemAttribute& ia = GetAttribute(i);
  571. if (ia.bType == APPLY_SKILL)
  572. m_pOwner->ApplyPoint(ia.bType, bAdd ? ia.sValue : ia.sValue ^ 0x00800000);
  573. else
  574. m_pOwner->ApplyPoint(ia.bType, bAdd ? ia.sValue : -ia.sValue);
  575. }
  576. }
  577. }
  578. switch (m_pProto->bType)
  579. {
  580. case ITEM_PICK:
  581. case ITEM_ROD:
  582. {
  583. if (bAdd)
  584. {
  585. if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  586. m_pOwner->SetPart(PART_WEAPON, GetVnum());
  587. }
  588. else
  589. {
  590. if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  591. m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON));
  592. }
  593. }
  594. break;
  595. case ITEM_WEAPON:
  596. {
  597. if (bAdd)
  598. {
  599. if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  600. m_pOwner->SetPart(PART_WEAPON, GetVnum());
  601. }
  602. else
  603. {
  604. if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON)
  605. m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON));
  606. }
  607. }
  608. break;
  609. case ITEM_ARMOR:
  610. {
  611. // ÄÚ½ºÃõ body¸¦ ÀÔ°íÀÖ´Ù¸é armor´Â ¹ş´ø ÀÔ´ø »ó°ü ¾øÀÌ ºñÁÖ¾ó¿¡ ¿µÇâÀ» ÁÖ¸é ¾È µÊ.
  612. if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
  613. break;
  614. if (GetSubType() == ARMOR_BODY || GetSubType() == ARMOR_HEAD || GetSubType() == ARMOR_FOOTS || GetSubType() == ARMOR_SHIELD)
  615. {
  616. if (bAdd)
  617. {
  618. if (GetProto()->bSubType == ARMOR_BODY)
  619. m_pOwner->SetPart(PART_MAIN, GetVnum());
  620. }
  621. else
  622. {
  623. if (GetProto()->bSubType == ARMOR_BODY)
  624. m_pOwner->SetPart(PART_MAIN, m_pOwner->GetOriginalPart(PART_MAIN));
  625. }
  626. }
  627. }
  628. break;
  629. // ÄÚ½ºÃõ ¾ÆÀÌÅÛ ÀÔ¾úÀ» ¶§ ij¸¯ÅÍ parts Á¤º¸ ¼¼ÆÃ. ±âÁ¸ ½ºÅ¸ÀÏ´ë·Î Ãß°¡ÇÔ..
  630. case ITEM_COSTUME:
  631. {
  632. DWORD toSetValue = this->GetVnum();
  633. EParts toSetPart = PART_MAX_NUM;
  634. // °©¿Ê ÄÚ½ºÃõ
  635. if (GetSubType() == COSTUME_BODY)
  636. {
  637. toSetPart = PART_MAIN;
  638. if (false == bAdd)
  639. {
  640. // ÄÚ½ºÃõ °©¿ÊÀ» ¹ş¾úÀ» ¶§ ¿ø·¡ °©¿ÊÀ» ÀÔ°í ÀÖ¾ú´Ù¸é ±× °©¿ÊÀ¸·Î look ¼¼ÆÃ, ÀÔÁö ¾Ê¾Ò´Ù¸é default look
  641. const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
  642. toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
  643. }
  644. }
  645. // Çì¾î ÄÚ½ºÃõ
  646. else if (GetSubType() == COSTUME_HAIR)
  647. {
  648. toSetPart = PART_HAIR;
  649. // ÄÚ½ºÃõ Çì¾î´Â shape°ªÀ» item protoÀÇ value3¿¡ ¼¼ÆÃÇϵµ·Ï ÇÔ. Ưº°ÇÑ ÀÌÀ¯´Â ¾ø°í ±âÁ¸ °©¿Ê(ARMOR_BODY)ÀÇ shape°ªÀÌ ÇÁ·ÎÅäÀÇ value3¿¡ À־ Çì¾îµµ °°ÀÌ value3À¸·Î ÇÔ.
  650. // [NOTE] °©¿ÊÀº ¾ÆÀÌÅÛ vnumÀ» º¸³»°í Çì¾î´Â shape(value3)°ªÀ» º¸³»´Â ÀÌÀ¯´Â.. ±âÁ¸ ½Ã½ºÅÛÀÌ ±×·¸°Ô µÇ¾îÀÖÀ½...
  651. toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
  652. }
  653. if (PART_MAX_NUM != toSetPart)
  654. {
  655. m_pOwner->SetPart((BYTE)toSetPart, toSetValue);
  656. m_pOwner->UpdatePacket();
  657. }
  658. }
  659. break;
  660. case ITEM_UNIQUE:
  661. {
  662. if (0 != GetSIGVnum())
  663. {
  664. const CSpecialItemGroup* pItemGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(GetSIGVnum());
  665. if (NULL == pItemGroup)
  666. break;
  667. DWORD dwAttrVnum = pItemGroup->GetAttrVnum(GetVnum());
  668. const CSpecialAttrGroup* pAttrGroup = ITEM_MANAGER::instance().GetSpecialAttrGroup(dwAttrVnum);
  669. if (NULL == pAttrGroup)
  670. break;
  671. for (itertype (pAttrGroup->m_vecAttrs) it = pAttrGroup->m_vecAttrs.begin(); it != pAttrGroup->m_vecAttrs.end(); it++)
  672. {
  673. m_pOwner->ApplyPoint(it->apply_type, bAdd ? it->apply_value : -it->apply_value);
  674. }
  675. }
  676. }
  677. break;
  678. }
  679. }
  680. bool CItem::IsEquipable() const
  681. {
  682. switch (this->GetType())
  683. {
  684. case ITEM_COSTUME:
  685. case ITEM_ARMOR:
  686. case ITEM_WEAPON:
  687. case ITEM_ROD:
  688. case ITEM_PICK:
  689. case ITEM_UNIQUE:
  690. case ITEM_DS:
  691. case ITEM_SPECIAL_DS:
  692. case ITEM_RING:
  693. case ITEM_BELT:
  694. return true;
  695. }
  696. return false;
  697. }
  698. // return false on error state
  699. bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
  700. {
  701. if (!ch)
  702. {
  703. sys_err("EquipTo: nil character");
  704. return false;
  705. }
  706. // ¿ëÈ¥¼® ½½·Ô index´Â WEAR_MAX_NUM º¸´Ù Å­.
  707. if (IsDragonSoul())
  708. {
  709. if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
  710. {
  711. sys_err("EquipTo: invalid dragon soul cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetSubType(), bWearCell - WEAR_MAX_NUM);
  712. return false;
  713. }
  714. }
  715. else
  716. {
  717. if (bWearCell >= WEAR_MAX_NUM)
  718. {
  719. sys_err("EquipTo: invalid wear cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetWearFlag(), bWearCell);
  720. return false;
  721. }
  722. }
  723. if (ch->GetWear(bWearCell))
  724. {
  725. sys_err("EquipTo: item already exist (this: #%d %s cell: %d %s)", GetOriginalVnum(), GetName(), bWearCell, ch->GetWear(bWearCell)->GetName());
  726. return false;
  727. }
  728. if (GetOwner())
  729. RemoveFromCharacter();
  730. ch->SetWear(bWearCell, this); // ¿©±â¼­ ÆĞŶ ³ª°¨
  731. m_pOwner = ch;
  732. m_bEquipped = true;
  733. m_wCell = INVENTORY_MAX_NUM + bWearCell;
  734. DWORD dwImmuneFlag = 0;
  735. LPITEM item = NULL;
  736. for (int i = 0; i < WEAR_MAX_NUM; ++i)
  737. {
  738. if (item=m_pOwner->GetWear(i))
  739. {
  740. if (item->GetImmuneFlag() != 0)
  741. SET_BIT(dwImmuneFlag, item->GetImmuneFlag());
  742. if (item->GetAttributeCount() > 0)
  743. {
  744. if (item->HasAttr(APPLY_IMMUNE_STUN))
  745. SET_BIT(dwImmuneFlag, IMMUNE_STUN);
  746. if (item->HasAttr(APPLY_IMMUNE_SLOW))
  747. SET_BIT(dwImmuneFlag, IMMUNE_SLOW);
  748. if (item->HasAttr(APPLY_IMMUNE_FALL))
  749. SET_BIT(dwImmuneFlag, IMMUNE_FALL);
  750. }
  751. }
  752. }
  753. m_pOwner->SetImmuneFlag(dwImmuneFlag);
  754. if (IsDragonSoul())
  755. {
  756. DSManager::instance().ActivateDragonSoul(this);
  757. }
  758. else
  759. {
  760. ModifyPoints(true);
  761. StartUniqueExpireEvent();
  762. if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
  763. StartTimerBasedOnWearExpireEvent();
  764. // ACCESSORY_REFINE
  765. StartAccessorySocketExpireEvent();
  766. // END_OF_ACCESSORY_REFINE
  767. }
  768. ch->BuffOnAttr_AddBuffsFromItem(this);
  769. m_pOwner->ComputeBattlePoints();
  770. m_pOwner->UpdatePacket();
  771. Save();
  772. return (true);
  773. }
  774. bool CItem::Unequip()
  775. {
  776. if (!m_pOwner || GetCell() < INVENTORY_MAX_NUM)
  777. {
  778. // ITEM_OWNER_INVALID_PTR_BUG
  779. sys_err("%s %u m_pOwner %p, GetCell %d",
  780. GetName(), GetID(), get_pointer(m_pOwner), GetCell());
  781. // END_OF_ITEM_OWNER_INVALID_PTR_BUG
  782. return false;
  783. }
  784. if (this != m_pOwner->GetWear(GetCell() - INVENTORY_MAX_NUM))
  785. {
  786. sys_err("m_pOwner->GetWear() != this");
  787. return false;
  788. }
  789. //½Å±Ô ¸» ¾ÆÀÌÅÛ Á¦°Å½Ã ó¸®
  790. if (IsRideItem())
  791. ClearMountAttributeAndAffect();
  792. if (IsDragonSoul())
  793. {
  794. DSManager::instance().DeactivateDragonSoul(this);
  795. }
  796. else
  797. {
  798. ModifyPoints(false);
  799. }
  800. StopUniqueExpireEvent();
  801. if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
  802. StopTimerBasedOnWearExpireEvent();
  803. // ACCESSORY_REFINE
  804. StopAccessorySocketExpireEvent();
  805. // END_OF_ACCESSORY_REFINE
  806. m_pOwner->BuffOnAttr_RemoveBuffsFromItem(this);
  807. m_pOwner->SetWear(GetCell() - INVENTORY_MAX_NUM, NULL);
  808. DWORD dwImmuneFlag = 0;
  809. LPITEM item = NULL;
  810. for (int i = 0; i < WEAR_MAX_NUM; ++i)
  811. {
  812. if (item=m_pOwner->GetWear(i))
  813. {
  814. if (item->GetImmuneFlag() != 0)
  815. SET_BIT(dwImmuneFlag, item->GetImmuneFlag());
  816. if (item->GetAttributeCount() > 0)
  817. {
  818. if (item->HasAttr(APPLY_IMMUNE_STUN))
  819. SET_BIT(dwImmuneFlag, IMMUNE_STUN);
  820. if (item->HasAttr(APPLY_IMMUNE_SLOW))
  821. SET_BIT(dwImmuneFlag, IMMUNE_SLOW);
  822. if (item->HasAttr(APPLY_IMMUNE_FALL))
  823. SET_BIT(dwImmuneFlag, IMMUNE_FALL);
  824. }
  825. }
  826. }
  827. m_pOwner->SetImmuneFlag(dwImmuneFlag);
  828. m_pOwner->ComputeBattlePoints();
  829. m_pOwner->UpdatePacket();
  830. m_pOwner = NULL;
  831. m_wCell = 0;
  832. m_bEquipped = false;
  833. return true;
  834. }
  835. long CItem::GetValue(DWORD idx)
  836. {
  837. assert(idx < ITEM_VALUES_MAX_NUM);
  838. return GetProto()->alValues[idx];
  839. }
  840. void CItem::SetExchanging(bool bOn)
  841. {
  842. m_bExchanging = bOn;
  843. }
  844. void CItem::Save()
  845. {
  846. if (m_bSkipSave)
  847. return;
  848. ITEM_MANAGER::instance().DelayedSave(this);
  849. }
  850. bool CItem::CreateSocket(BYTE bSlot, BYTE bGold)
  851. {
  852. assert(bSlot < ITEM_SOCKET_MAX_NUM);
  853. if (m_alSockets[bSlot] != 0)
  854. {
  855. sys_err("Item::CreateSocket : socket already exist %s %d", GetName(), bSlot);
  856. return false;
  857. }
  858. if (bGold)
  859. m_alSockets[bSlot] = 2;
  860. else
  861. m_alSockets[bSlot] = 1;
  862. UpdatePacket();
  863. Save();
  864. return true;
  865. }
  866. void CItem::SetSockets(const long * c_al)
  867. {
  868. thecore_memcpy(m_alSockets, c_al, sizeof(m_alSockets));
  869. Save();
  870. }
  871. void CItem::SetSocket(int i, long v, bool bLog)
  872. {
  873. assert(i < ITEM_SOCKET_MAX_NUM);
  874. m_alSockets[i] = v;
  875. UpdatePacket();
  876. Save();
  877. if (bLog)
  878. LogManager::instance().ItemLog(i, v, 0, GetID(), "SET_SOCKET", "", "", GetOriginalVnum());
  879. }
  880. int CItem::GetGold()
  881. {
  882. if (IS_SET(GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
  883. {
  884. if (GetProto()->dwGold == 0)
  885. return GetCount();
  886. else
  887. return GetCount() / GetProto()->dwGold;
  888. }
  889. else
  890. return GetProto()->dwGold;
  891. }
  892. int CItem::GetShopBuyPrice()
  893. {
  894. return GetProto()->dwShopBuyPrice;
  895. }
  896. bool CItem::IsOwnership(LPCHARACTER ch)
  897. {
  898. if (!m_pkOwnershipEvent)
  899. return true;
  900. return m_dwOwnershipPID == ch->GetPlayerID() ? true : false;
  901. }
  902. EVENTFUNC(ownership_event)
  903. {
  904. item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  905. if ( info == NULL )
  906. {
  907. sys_err( "ownership_event> <Factor> Null pointer" );
  908. return 0;
  909. }
  910. LPITEM pkItem = info->item;
  911. pkItem->SetOwnershipEvent(NULL);
  912. TPacketGCItemOwnership p;
  913. p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
  914. p.dwVID = pkItem->GetVID();
  915. p.szName[0] = '\0';
  916. pkItem->PacketAround(&p, sizeof(p));
  917. return 0;
  918. }
  919. void CItem::SetOwnershipEvent(LPEVENT pkEvent)
  920. {
  921. m_pkOwnershipEvent = pkEvent;
  922. }
  923. void CItem::SetOwnership(LPCHARACTER ch, int iSec)
  924. {
  925. if (!ch)
  926. {
  927. if (m_pkOwnershipEvent)
  928. {
  929. event_cancel(&m_pkOwnershipEvent);
  930. m_dwOwnershipPID = 0;
  931. TPacketGCItemOwnership p;
  932. p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
  933. p.dwVID = m_dwVID;
  934. p.szName[0] = '\0';
  935. PacketAround(&p, sizeof(p));
  936. }
  937. return;
  938. }
  939. if (m_pkOwnershipEvent)
  940. return;
  941. if (true == LC_IsEurope())
  942. {
  943. if (iSec <= 10)
  944. iSec = 30;
  945. }
  946. m_dwOwnershipPID = ch->GetPlayerID();
  947. item_event_info* info = AllocEventInfo<item_event_info>();
  948. strlcpy(info->szOwnerName, ch->GetName(), sizeof(info->szOwnerName));
  949. info->item = this;
  950. SetOwnershipEvent(event_create(ownership_event, info, PASSES_PER_SEC(iSec)));
  951. TPacketGCItemOwnership p;
  952. p.bHeader = HEADER_GC_ITEM_OWNERSHIP;
  953. p.dwVID = m_dwVID;
  954. strlcpy(p.szName, ch->GetName(), sizeof(p.szName));
  955. PacketAround(&p, sizeof(p));
  956. }
  957. int CItem::GetSocketCount()
  958. {
  959. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
  960. {
  961. if (GetSocket(i) == 0)
  962. return i;
  963. }
  964. return ITEM_SOCKET_MAX_NUM;
  965. }
  966. bool CItem::AddSocket()
  967. {
  968. int count = GetSocketCount();
  969. if (count == ITEM_SOCKET_MAX_NUM)
  970. return false;
  971. m_alSockets[count] = 1;
  972. return true;
  973. }
  974. void CItem::AlterToSocketItem(int iSocketCount)
  975. {
  976. if (iSocketCount >= ITEM_SOCKET_MAX_NUM)
  977. {
  978. sys_log(0, "Invalid Socket Count %d, set to maximum", ITEM_SOCKET_MAX_NUM);
  979. iSocketCount = ITEM_SOCKET_MAX_NUM;
  980. }
  981. for (int i = 0; i < iSocketCount; ++i)
  982. SetSocket(i, 1);
  983. }
  984. void CItem::AlterToMagicItem()
  985. {
  986. int idx = GetAttributeSetIndex();
  987. if (idx < 0)
  988. return;
  989. // Appeariance Second Third
  990. // Weapon 50 20 5
  991. // Armor 30 10 2
  992. // Acc 20 10 1
  993. int iSecondPct;
  994. int iThirdPct;
  995. if (g_iUseLocale)
  996. {
  997. switch (GetType())
  998. {
  999. case ITEM_WEAPON:
  1000. iSecondPct = 20;
  1001. iThirdPct = 5;
  1002. break;
  1003. case ITEM_ARMOR:
  1004. case ITEM_COSTUME:
  1005. if (GetSubType() == ARMOR_BODY)
  1006. {
  1007. iSecondPct = 10;
  1008. iThirdPct = 2;
  1009. }
  1010. else
  1011. {
  1012. iSecondPct = 10;
  1013. iThirdPct = 1;
  1014. }
  1015. break;
  1016. default:
  1017. return;
  1018. }
  1019. }
  1020. else
  1021. {
  1022. switch (GetType())
  1023. {
  1024. case ITEM_WEAPON:
  1025. iSecondPct = 30;
  1026. iThirdPct = 15;
  1027. break;
  1028. case ITEM_ARMOR:
  1029. case ITEM_COSTUME:
  1030. if (GetSubType() == ARMOR_BODY)
  1031. {
  1032. iSecondPct = 20;
  1033. iThirdPct = 10;
  1034. }
  1035. else
  1036. {
  1037. iSecondPct = 10;
  1038. iThirdPct = 5;
  1039. }
  1040. break;
  1041. default:
  1042. return;
  1043. }
  1044. }
  1045. // 100% È®·ü·Î ÁÁÀº ¼Ó¼º Çϳª
  1046. PutAttribute(aiItemMagicAttributePercentHigh);
  1047. if (number(1, 100) <= iSecondPct)
  1048. PutAttribute(aiItemMagicAttributePercentLow);
  1049. if (number(1, 100) <= iThirdPct)
  1050. PutAttribute(aiItemMagicAttributePercentLow);
  1051. }
  1052. DWORD CItem::GetRefineFromVnum()
  1053. {
  1054. return ITEM_MANAGER::instance().GetRefineFromVnum(GetVnum());
  1055. }
  1056. int CItem::GetRefineLevel()
  1057. {
  1058. const char* name = GetBaseName();
  1059. char* p = const_cast<char*>(strrchr(name, '+'));
  1060. if (!p)
  1061. return 0;
  1062. int rtn = 0;
  1063. str_to_number(rtn, p+1);
  1064. const char* locale_name = GetName();
  1065. p = const_cast<char*>(strrchr(locale_name, '+'));
  1066. if (p)
  1067. {
  1068. int locale_rtn = 0;
  1069. str_to_number(locale_rtn, p+1);
  1070. if (locale_rtn != rtn)
  1071. {
  1072. sys_err("refine_level_based_on_NAME(%d) is not equal to refine_level_based_on_LOCALE_NAME(%d).", rtn, locale_rtn);
  1073. }
  1074. }
  1075. return rtn;
  1076. }
  1077. bool CItem::IsPolymorphItem()
  1078. {
  1079. return GetType() == ITEM_POLYMORPH;
  1080. }
  1081. EVENTFUNC(unique_expire_event)
  1082. {
  1083. item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  1084. if ( info == NULL )
  1085. {
  1086. sys_err( "unique_expire_event> <Factor> Null pointer" );
  1087. return 0;
  1088. }
  1089. LPITEM pkItem = info->item;
  1090. if (pkItem->GetValue(2) == 0)
  1091. {
  1092. if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= 1)
  1093. {
  1094. sys_log(0, "UNIQUE_ITEM: expire %s %u", pkItem->GetName(), pkItem->GetID());
  1095. pkItem->SetUniqueExpireEvent(NULL);
  1096. ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
  1097. return 0;
  1098. }
  1099. else
  1100. {
  1101. pkItem->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - 1);
  1102. return PASSES_PER_SEC(60);
  1103. }
  1104. }
  1105. else
  1106. {
  1107. time_t cur = get_global_time();
  1108. if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) <= cur)
  1109. {
  1110. pkItem->SetUniqueExpireEvent(NULL);
  1111. ITEM_MANAGER::instance().RemoveItem(pkItem, "UNIQUE_EXPIRE");
  1112. return 0;
  1113. }
  1114. else
  1115. {
  1116. // °ÔÀÓ ³»¿¡ ½Ã°£Á¦ ¾ÆÀÌÅÛµéÀÌ ºü¸´ºü¸´ÇÏ°Ô »ç¶óÁöÁö ¾Ê´Â ¹ö±×°¡ ÀÖ¾î
  1117. // ¼öÁ¤
  1118. // by rtsummit
  1119. if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur < 600)
  1120. return PASSES_PER_SEC(pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur);
  1121. else
  1122. return PASSES_PER_SEC(600);
  1123. }
  1124. }
  1125. }
  1126. // ½Ã°£ ÈĺÒÁ¦
  1127. // timer¸¦ ½ÃÀÛÇÒ ¶§¿¡ ½Ã°£ Â÷°¨ÇÏ´Â °ÍÀÌ ¾Æ´Ï¶ó,
  1128. // timer°¡ ¹ßÈ­ÇÒ ¶§¿¡ timer°¡ µ¿ÀÛÇÑ ½Ã°£ ¸¸Å­ ½Ã°£ Â÷°¨À» ÇÑ´Ù.
  1129. EVENTFUNC(timer_based_on_wear_expire_event)
  1130. {
  1131. item_event_info* info = dynamic_cast<item_event_info*>( event->info );
  1132. if ( info == NULL )
  1133. {
  1134. sys_err( "expire_event <Factor> Null pointer" );
  1135. return 0;
  1136. }
  1137. LPITEM pkItem = info->item;
  1138. int remain_time = pkItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) - processing_time/passes_per_sec;
  1139. if (remain_time <= 0)
  1140. {
  1141. sys_log(0, "ITEM EXPIRED : expired %s %u", pkItem->GetName(), pkItem->GetID());
  1142. pkItem->SetTimerBasedOnWearExpireEvent(NULL);
  1143. pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, 0);
  1144. // ÀÏ´Ü timer based on wear ¿ëÈ¥¼®Àº ½Ã°£ ´Ù µÇ¾ú´Ù°í ¾ø¾ÖÁö ¾Ê´Â´Ù.
  1145. if (pkItem->IsDragonSoul())
  1146. {
  1147. DSManager::instance().DeactivateDragonSoul(pkItem);
  1148. }
  1149. else
  1150. {
  1151. ITEM_MANAGER::instance().RemoveItem(pkItem, "TIMER_BASED_ON_WEAR_EXPIRE");
  1152. }
  1153. return 0;
  1154. }
  1155. pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
  1156. return PASSES_PER_SEC (MIN (60, remain_time));
  1157. }
  1158. void CItem::SetUniqueExpireEvent(LPEVENT pkEvent)
  1159. {
  1160. m_pkUniqueExpireEvent = pkEvent;
  1161. }
  1162. void CItem::SetTimerBasedOnWearExpireEvent(LPEVENT pkEvent)
  1163. {
  1164. m_pkTimerBasedOnWearExpireEvent = pkEvent;
  1165. }
  1166. EVENTFUNC(real_time_expire_event)
  1167. {
  1168. const item_vid_event_info* info = reinterpret_cast<const item_vid_event_info*>(event->info);
  1169. if (NULL == info)
  1170. return 0;
  1171. const LPITEM item = ITEM_MANAGER::instance().FindByVID( info->item_vid );
  1172. if (NULL == item)
  1173. return 0;
  1174. const time_t current = get_global_time();
  1175. if (current > item->GetSocket(0))
  1176. {
  1177. switch (item->GetVnum())
  1178. {
  1179. if(item->IsNewMountItem())
  1180. {
  1181. if (item->GetSocket(2) != 0)
  1182. item->ClearMountAttributeAndAffect();
  1183. }
  1184. break;
  1185. }
  1186. ITEM_MANAGER::instance().RemoveItem(item, "REAL_TIME_EXPIRE");
  1187. return 0;
  1188. }
  1189. return PASSES_PER_SEC(1);
  1190. }
  1191. void CItem::StartRealTimeExpireEvent()
  1192. {
  1193. if (m_pkRealTimeExpireEvent)
  1194. return;
  1195. for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  1196. {
  1197. if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType || LIMIT_REAL_TIME_START_FIRST_USE == GetProto()->aLimits[i].bType)
  1198. {
  1199. item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
  1200. info->item_vid = GetVID();
  1201. m_pkRealTimeExpireEvent = event_create( real_time_expire_event, info, PASSES_PER_SEC(1));
  1202. sys_log(0, "REAL_TIME_EXPIRE: StartRealTimeExpireEvent");
  1203. return;
  1204. }
  1205. }
  1206. }
  1207. bool CItem::IsRealTimeItem()
  1208. {
  1209. if(!GetProto())
  1210. return false;
  1211. for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  1212. {
  1213. if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType)
  1214. return true;
  1215. }
  1216. return false;
  1217. }
  1218. void CItem::StartUniqueExpireEvent()
  1219. {
  1220. if (GetType() != ITEM_UNIQUE)
  1221. return;
  1222. if (m_pkUniqueExpireEvent)
  1223. return;
  1224. //±â°£Á¦ ¾ÆÀÌÅÛÀÏ °æ¿ì ½Ã°£Á¦ ¾ÆÀÌÅÛÀº µ¿ÀÛÇÏÁö ¾Ê´Â´Ù
  1225. if (IsRealTimeItem())
  1226. return;
  1227. // HARD CODING
  1228. if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
  1229. m_pOwner->ShowAlignment(false);
  1230. int iSec = GetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME);
  1231. if (iSec == 0)
  1232. iSec = 60;
  1233. else
  1234. iSec = MIN(iSec, 60);
  1235. SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, 0);
  1236. item_event_info* info = AllocEventInfo<item_event_info>();
  1237. info->item = this;
  1238. SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec)));
  1239. }
  1240. // ½Ã°£ ÈĺÒÁ¦
  1241. // timer_based_on_wear_expire_event ¼³¸í ÂüÁ¶
  1242. void CItem::StartTimerBasedOnWearExpireEvent()
  1243. {
  1244. if (m_pkTimerBasedOnWearExpireEvent)
  1245. return;
  1246. //±â°£Á¦ ¾ÆÀÌÅÛÀÏ °æ¿ì ½Ã°£Á¦ ¾ÆÀÌÅÛÀº µ¿ÀÛÇÏÁö ¾Ê´Â´Ù
  1247. if (IsRealTimeItem())
  1248. return;
  1249. if (-1 == GetProto()->cLimitTimerBasedOnWearIndex)
  1250. return;
  1251. int iSec = GetSocket(0);
  1252. // ³²Àº ½Ã°£À» ºĞ´ÜÀ§·Î ²÷±â À§ÇØ...
  1253. if (0 != iSec)
  1254. {
  1255. iSec %= 60;
  1256. if (0 == iSec)
  1257. iSec = 60;
  1258. }
  1259. item_event_info* info = AllocEventInfo<item_event_info>();
  1260. info->item = this;
  1261. SetTimerBasedOnWearExpireEvent(event_create(timer_based_on_wear_expire_event, info, PASSES_PER_SEC(iSec)));
  1262. }
  1263. void CItem::StopUniqueExpireEvent()
  1264. {
  1265. if (!m_pkUniqueExpireEvent)
  1266. return;
  1267. if (GetValue(2) != 0) // °ÔÀӽð£Á¦ ÀÌ¿ÜÀÇ ¾ÆÀÌÅÛÀº UniqueExpireEvent¸¦ Áß´ÜÇÒ ¼ö ¾ø´Ù.
  1268. return;
  1269. // HARD CODING
  1270. if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
  1271. m_pOwner->ShowAlignment(true);
  1272. SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, event_time(m_pkUniqueExpireEvent) / passes_per_sec);
  1273. event_cancel(&m_pkUniqueExpireEvent);
  1274. ITEM_MANAGER::instance().SaveSingleItem(this);
  1275. }
  1276. void CItem::StopTimerBasedOnWearExpireEvent()
  1277. {
  1278. if (!m_pkTimerBasedOnWearExpireEvent)
  1279. return;
  1280. int remain_time = GetSocket(ITEM_SOCKET_REMAIN_SEC) - event_processing_time(m_pkTimerBasedOnWearExpireEvent) / passes_per_sec;
  1281. SetSocket(ITEM_SOCKET_REMAIN_SEC, remain_time);
  1282. event_cancel(&m_pkTimerBasedOnWearExpireEvent);
  1283. ITEM_MANAGER::instance().SaveSingleItem(this);
  1284. }
  1285. void CItem::ApplyAddon(int iAddonType)
  1286. {
  1287. CItemAddonManager::instance().ApplyAddonTo(iAddonType, this);
  1288. }
  1289. int CItem::GetSpecialGroup() const
  1290. {
  1291. return ITEM_MANAGER::instance().GetSpecialGroupFromItem(GetVnum());
  1292. }
  1293. //
  1294. // ¾Ç¼¼¼­¸® ¼ÒÄÏ Ã³¸®.
  1295. //
  1296. bool CItem::IsAccessoryForSocket()
  1297. {
  1298. return (m_pProto->bType == ITEM_ARMOR && (m_pProto->bSubType == ARMOR_WRIST || m_pProto->bSubType == ARMOR_NECK || m_pProto->bSubType == ARMOR_EAR)) ||
  1299. (m_pProto->bType == ITEM_BELT); // 2013³â 2¿ù »õ·Î Ãß°¡µÈ 'º§Æ®' ¾ÆÀÌÅÛÀÇ °æ¿ì ±âȹÆÀ¿¡¼­ ¾Ç¼¼¼­¸® ¼ÒÄÏ ½Ã½ºÅÛÀ» ±×´ë·Î ÀÌ¿ëÇÏÀÚ°í ÇÔ.
  1300. }
  1301. void CItem::SetAccessorySocketGrade(int iGrade)
  1302. {
  1303. SetSocket(0, MINMAX(0, iGrade, GetAccessorySocketMaxGrade()));
  1304. int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
  1305. //if (test_server)
  1306. // iDownTime /= 60;
  1307. SetAccessorySocketDownGradeTime(iDownTime);
  1308. }
  1309. void CItem::SetAccessorySocketMaxGrade(int iMaxGrade)
  1310. {
  1311. SetSocket(1, MINMAX(0, iMaxGrade, ITEM_ACCESSORY_SOCKET_MAX_NUM));
  1312. }
  1313. void CItem::SetAccessorySocketDownGradeTime(DWORD time)
  1314. {
  1315. SetSocket(2, time);
  1316. if (test_server && GetOwner())
  1317. GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s¿¡¼­ ¼ÒÄÏ ºüÁú¶§±îÁö ³²Àº ½Ã°£ %d"), GetName(), time);
  1318. }
  1319. EVENTFUNC(accessory_socket_expire_event)
  1320. {
  1321. item_vid_event_info* info = dynamic_cast<item_vid_event_info*>( event->info );
  1322. if ( info == NULL )
  1323. {
  1324. sys_err( "accessory_socket_expire_event> <Factor> Null pointer" );
  1325. return 0;
  1326. }
  1327. LPITEM item = ITEM_MANAGER::instance().FindByVID(info->item_vid);
  1328. if (item->GetAccessorySocketDownGradeTime() <= 1)
  1329. {
  1330. degrade:
  1331. item->SetAccessorySocketExpireEvent(NULL);
  1332. item->AccessorySocketDegrade();
  1333. return 0;
  1334. }
  1335. else
  1336. {
  1337. int iTime = item->GetAccessorySocketDownGradeTime() - 60;
  1338. if (iTime <= 1)
  1339. goto degrade;
  1340. item->SetAccessorySocketDownGradeTime(iTime);
  1341. if (iTime > 60)
  1342. return PASSES_PER_SEC(60);
  1343. else
  1344. return PASSES_PER_SEC(iTime);
  1345. }
  1346. }
  1347. void CItem::StartAccessorySocketExpireEvent()
  1348. {
  1349. if (!IsAccessoryForSocket())
  1350. return;
  1351. if (m_pkAccessorySocketExpireEvent)
  1352. return;
  1353. if (GetAccessorySocketMaxGrade() == 0)
  1354. return;
  1355. if (GetAccessorySocketGrade() == 0)
  1356. return;
  1357. int iSec = GetAccessorySocketDownGradeTime();
  1358. SetAccessorySocketExpireEvent(NULL);
  1359. if (iSec <= 1)
  1360. iSec = 5;
  1361. else
  1362. iSec = MIN(iSec, 60);
  1363. item_vid_event_info* info = AllocEventInfo<item_vid_event_info>();
  1364. info->item_vid = GetVID();
  1365. SetAccessorySocketExpireEvent(event_create(accessory_socket_expire_event, info, PASSES_PER_SEC(iSec)));
  1366. }
  1367. void CItem::StopAccessorySocketExpireEvent()
  1368. {
  1369. if (!m_pkAccessorySocketExpireEvent)
  1370. return;
  1371. if (!IsAccessoryForSocket())
  1372. return;
  1373. int new_time = GetAccessorySocketDownGradeTime() - (60 - event_time(m_pkAccessorySocketExpireEvent) / passes_per_sec);
  1374. event_cancel(&m_pkAccessorySocketExpireEvent);
  1375. if (new_time <= 1)
  1376. {
  1377. AccessorySocketDegrade();
  1378. }
  1379. else
  1380. {
  1381. SetAccessorySocketDownGradeTime(new_time);
  1382. }
  1383. }
  1384. bool CItem::IsRideItem()
  1385. {
  1386. if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_RIDE == GetSubType())
  1387. return true;
  1388. if (ITEM_UNIQUE == GetType() && UNIQUE_SPECIAL_MOUNT_RIDE == GetSubType())
  1389. return true;
  1390. return false;
  1391. }
  1392. bool CItem::IsRamadanRing()
  1393. {
  1394. if (GetVnum() == UNIQUE_ITEM_RAMADAN_RING)
  1395. return true;
  1396. return false;
  1397. }
  1398. void CItem::ClearMountAttributeAndAffect()
  1399. {
  1400. LPCHARACTER ch = GetOwner();
  1401. ch->RemoveAffect(AFFECT_MOUNT);
  1402. ch->RemoveAffect(AFFECT_MOUNT_BONUS);
  1403. ch->MountVnum(0);
  1404. ch->PointChange(POINT_ST, 0);
  1405. ch->PointChange(POINT_DX, 0);
  1406. ch->PointChange(POINT_HT, 0);
  1407. ch->PointChange(POINT_IQ, 0);
  1408. }
  1409. // fixme
  1410. // À̰ŠÁö±İÀº ¾È¾´µ¥... ±Ùµ¥ Ȥ½Ã³ª ½Í¾î¼­ ³²°ÜµÒ.
  1411. // by rtsummit
  1412. bool CItem::IsNewMountItem()
  1413. {
  1414. switch(GetVnum())
  1415. {
  1416. case 76000: case 76001: case 76002: case 76003:
  1417. case 76004: case 76005: case 76006: case 76007:
  1418. case 76008: case 76009: case 76010: case 76011:
  1419. case 76012: case 76013: case 76014:
  1420. return true;
  1421. }
  1422. return false;
  1423. }
  1424. void CItem::SetAccessorySocketExpireEvent(LPEVENT pkEvent)
  1425. {
  1426. m_pkAccessorySocketExpireEvent = pkEvent;
  1427. }
  1428. void CItem::AccessorySocketDegrade()
  1429. {
  1430. if (GetAccessorySocketGrade() > 0)
  1431. {
  1432. LPCHARACTER ch = GetOwner();
  1433. if (ch)
  1434. {
  1435. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s¿¡ ¹ÚÇôÀÖ´ø º¸¼®ÀÌ »ç¶óÁı´Ï´Ù."), GetName());
  1436. }
  1437. ModifyPoints(false);
  1438. SetAccessorySocketGrade(GetAccessorySocketGrade()-1);
  1439. ModifyPoints(true);
  1440. int iDownTime = aiAccessorySocketDegradeTime[GetAccessorySocketGrade()];
  1441. if (test_server)
  1442. iDownTime /= 60;
  1443. SetAccessorySocketDownGradeTime(iDownTime);
  1444. if (iDownTime)
  1445. StartAccessorySocketExpireEvent();
  1446. }
  1447. }
  1448. // ring¿¡ itemÀ» ¹ÚÀ» ¼ö ÀÖ´ÂÁö ¿©ºÎ¸¦ Ã¼Å©ÇØ¼­ ¸®ÅÏ
  1449. static const bool CanPutIntoRing(LPITEM ring, LPITEM item)
  1450. {
  1451. const DWORD vnum = item->GetVnum();
  1452. (void)vnum;
  1453. return false;
  1454. }
  1455. bool CItem::CanPutInto(LPITEM item)
  1456. {
  1457. if (item->GetType() == ITEM_BELT)
  1458. return this->GetSubType() == USE_PUT_INTO_BELT_SOCKET;
  1459. else if(item->GetType() == ITEM_RING)
  1460. return CanPutIntoRing(item, this);
  1461. else if (item->GetType() != ITEM_ARMOR)
  1462. return false;
  1463. DWORD vnum = item->GetVnum();
  1464. struct JewelAccessoryInfo
  1465. {
  1466. DWORD jewel;
  1467. DWORD wrist;
  1468. DWORD neck;
  1469. DWORD ear;
  1470. };
  1471. const static JewelAccessoryInfo infos[] = {
  1472. { 50634, 14420, 16220, 17220 },
  1473. { 50635, 14500, 16500, 17500 },
  1474. { 50636, 14520, 16520, 17520 },
  1475. { 50637, 14540, 16540, 17540 },
  1476. { 50638, 14560, 16560, 17560 },
  1477. };
  1478. DWORD item_type = (item->GetVnum() / 10) * 10;
  1479. for (unsigned int i = 0; i < sizeof(infos) / sizeof(infos[0]); i++)
  1480. {
  1481. const JewelAccessoryInfo& info = infos[i];
  1482. switch(item->GetSubType())
  1483. {
  1484. case ARMOR_WRIST:
  1485. if (info.wrist == item_type)
  1486. {
  1487. if (info.jewel == GetVnum())
  1488. {
  1489. return true;
  1490. }
  1491. else
  1492. {
  1493. return false;
  1494. }
  1495. }
  1496. break;
  1497. case ARMOR_NECK:
  1498. if (info.neck == item_type)
  1499. {
  1500. if (info.jewel == GetVnum())
  1501. {
  1502. return true;
  1503. }
  1504. else
  1505. {
  1506. return false;
  1507. }
  1508. }
  1509. break;
  1510. case ARMOR_EAR:
  1511. if (info.ear == item_type)
  1512. {
  1513. if (info.jewel == GetVnum())
  1514. {
  1515. return true;
  1516. }
  1517. else
  1518. {
  1519. return false;
  1520. }
  1521. }
  1522. break;
  1523. }
  1524. }
  1525. if (item->GetSubType() == ARMOR_WRIST)
  1526. vnum -= 14000;
  1527. else if (item->GetSubType() == ARMOR_NECK)
  1528. vnum -= 16000;
  1529. else if (item->GetSubType() == ARMOR_EAR)
  1530. vnum -= 17000;
  1531. else
  1532. return false;
  1533. DWORD type = vnum / 20;
  1534. if (type < 0 || type > 11)
  1535. {
  1536. type = (vnum - 170) / 20;
  1537. if (50623 + type != GetVnum())
  1538. return false;
  1539. else
  1540. return true;
  1541. }
  1542. else if (item->GetVnum() >= 16210 && item->GetVnum() <= 16219)
  1543. {
  1544. if (50625 != GetVnum())
  1545. return false;
  1546. else
  1547. return true;
  1548. }
  1549. else if (item->GetVnum() >= 16230 && item->GetVnum() <= 16239)
  1550. {
  1551. if (50626 != GetVnum())
  1552. return false;
  1553. else
  1554. return true;
  1555. }
  1556. return 50623 + type == GetVnum();
  1557. }
  1558. // PC_BANG_ITEM_ADD
  1559. bool CItem::IsPCBangItem()
  1560. {
  1561. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  1562. {
  1563. if (m_pProto->aLimits[i].bType == LIMIT_PCBANG)
  1564. return true;
  1565. }
  1566. return false;
  1567. }
  1568. // END_PC_BANG_ITEM_ADD
  1569. bool CItem::CheckItemUseLevel(int nLevel)
  1570. {
  1571. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  1572. {
  1573. if (this->m_pProto->aLimits[i].bType == LIMIT_LEVEL)
  1574. {
  1575. if (this->m_pProto->aLimits[i].lValue > nLevel) return false;
  1576. else return true;
  1577. }
  1578. }
  1579. return true;
  1580. }
  1581. long CItem::FindApplyValue(BYTE bApplyType)
  1582. {
  1583. if (m_pProto == NULL)
  1584. return 0;
  1585. for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
  1586. {
  1587. if (m_pProto->aApplies[i].bType == bApplyType)
  1588. return m_pProto->aApplies[i].lValue;
  1589. }
  1590. return 0;
  1591. }
  1592. void CItem::CopySocketTo(LPITEM pItem)
  1593. {
  1594. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1595. {
  1596. pItem->m_alSockets[i] = m_alSockets[i];
  1597. }
  1598. }
  1599. int CItem::GetAccessorySocketGrade()
  1600. {
  1601. return MINMAX(0, GetSocket(0), GetAccessorySocketMaxGrade());
  1602. }
  1603. int CItem::GetAccessorySocketMaxGrade()
  1604. {
  1605. return MINMAX(0, GetSocket(1), ITEM_ACCESSORY_SOCKET_MAX_NUM);
  1606. }
  1607. int CItem::GetAccessorySocketDownGradeTime()
  1608. {
  1609. return MINMAX(0, GetSocket(2), aiAccessorySocketDegradeTime[GetAccessorySocketGrade()]);
  1610. }
  1611. void CItem::AttrLog()
  1612. {
  1613. const char * pszIP = NULL;
  1614. if (GetOwner() && GetOwner()->GetDesc())
  1615. pszIP = GetOwner()->GetDesc()->GetHostName();
  1616. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1617. {
  1618. if (m_alSockets[i])
  1619. {
  1620. LogManager::instance().ItemLog(i, m_alSockets[i], 0, GetID(), "INFO_SOCKET", "", pszIP ? pszIP : "", GetOriginalVnum());
  1621. }
  1622. }
  1623. for (int i = 0; i<ITEM_ATTRIBUTE_MAX_NUM; ++i)
  1624. {
  1625. int type = m_aAttr[i].bType;
  1626. int value = m_aAttr[i].sValue;
  1627. if (type)
  1628. LogManager::instance().ItemLog(i, type, value, GetID(), "INFO_ATTR", "", pszIP ? pszIP : "", GetOriginalVnum());
  1629. }
  1630. }
  1631. int CItem::GetLevelLimit()
  1632. {
  1633. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  1634. {
  1635. if (this->m_pProto->aLimits[i].bType == LIMIT_LEVEL)
  1636. {
  1637. return this->m_pProto->aLimits[i].lValue;
  1638. }
  1639. }
  1640. return 0;
  1641. }
  1642. bool CItem::OnAfterCreatedItem()
  1643. {
  1644. // ¾ÆÀÌÅÛÀ» ÇÑ ¹øÀÌ¶óµµ »ç¿ëÇß´Ù¸é, ±× ÀÌÈÄ¿£ »ç¿ë ÁßÀÌÁö ¾Ê¾Æµµ ½Ã°£ÀÌ Â÷°¨µÇ´Â ¹æ½Ä
  1645. if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
  1646. {
  1647. // Socket1¿¡ ¾ÆÀÌÅÛÀÇ »ç¿ë Ƚ¼ö°¡ ±â·ÏµÇ¾î ÀÖÀ¸´Ï, ÇÑ ¹øÀÌ¶óµµ »ç¿ëÇÑ ¾ÆÀÌÅÛÀº ŸÀ̸Ӹ¦ ½ÃÀÛÇÑ´Ù.
  1648. if (0 != GetSocket(1))
  1649. {
  1650. StartRealTimeExpireEvent();
  1651. }
  1652. }
  1653. return true;
  1654. }
  1655. #ifdef __AUCTION__
  1656. // °æ¸ÅÀå
  1657. // window¸¦ °æ¸ÅÀåÀ¸·Î ÇÑ´Ù.
  1658. bool CItem::MoveToAuction()
  1659. {
  1660. LPCHARACTER owner = GetOwner();
  1661. if (owner == NULL)
  1662. {
  1663. sys_err ("Item those owner is not exist cannot regist in auction");
  1664. return false;
  1665. }
  1666. if (GetWindow() == AUCTION)
  1667. {
  1668. sys_err ("Item is already in auction.");
  1669. }
  1670. SetWindow(AUCTION);
  1671. owner->SetItem(m_bCell, NULL);
  1672. Save();
  1673. ITEM_MANAGER::instance().FlushDelayedSave(this);
  1674. return true;
  1675. }
  1676. void CItem::CopyToRawData (TPlayerItem* new_item)
  1677. {
  1678. if (new_item != NULL)
  1679. return;
  1680. new_item->id = m_dwID;
  1681. new_item->window = m_bWindow;
  1682. new_item->pos = m_bCell;
  1683. new_item->count = m_dwCount;
  1684. new_item->vnum = GetVnum();
  1685. thecore_memcpy (new_item->alSockets, m_alSockets, sizeof (m_alSockets));
  1686. thecore_memcpy (new_item->aAttr, m_aAttr, sizeof (m_aAttr));
  1687. new_item->owner = m_pOwner->GetPlayerID();
  1688. }
  1689. #endif
  1690. bool CItem::IsDragonSoul()
  1691. {
  1692. return GetType() == ITEM_DS;
  1693. }
  1694. int CItem::GiveMoreTime_Per(float fPercent)
  1695. {
  1696. if (IsDragonSoul())
  1697. {
  1698. DWORD duration = DSManager::instance().GetDuration(this);
  1699. unsigned int remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
  1700. unsigned int given_time = fPercent * duration / 100;
  1701. if (remain_sec == static_cast<signed long long>(duration))
  1702. return false;
  1703. if ((given_time + remain_sec) >= static_cast<signed long long>(duration))
  1704. {
  1705. SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
  1706. return duration - remain_sec;
  1707. }
  1708. else
  1709. {
  1710. SetSocket(ITEM_SOCKET_REMAIN_SEC, given_time + remain_sec);
  1711. return given_time;
  1712. }
  1713. }
  1714. // ¿ì¼± ¿ëÈ¥¼®¿¡ °üÇØ¼­¸¸ Çϵµ·Ï ÇÑ´Ù.
  1715. else
  1716. return 0;
  1717. }
  1718. int CItem::GiveMoreTime_Fix(DWORD dwTime)
  1719. {
  1720. if (IsDragonSoul())
  1721. {
  1722. DWORD duration = DSManager::instance().GetDuration(this);
  1723. unsigned int remain_sec = GetSocket(ITEM_SOCKET_REMAIN_SEC);
  1724. if (remain_sec == static_cast<signed long long>(duration))
  1725. return false;
  1726. if ((dwTime + remain_sec) >= duration)
  1727. {
  1728. SetSocket(ITEM_SOCKET_REMAIN_SEC, duration);
  1729. return duration - remain_sec;
  1730. }
  1731. else
  1732. {
  1733. SetSocket(ITEM_SOCKET_REMAIN_SEC, dwTime + remain_sec);
  1734. return dwTime;
  1735. }
  1736. }
  1737. // ¿ì¼± ¿ëÈ¥¼®¿¡ °üÇØ¼­¸¸ Çϵµ·Ï ÇÑ´Ù.
  1738. else
  1739. return 0;
  1740. }
  1741. int CItem::GetDuration()
  1742. {
  1743. if(!GetProto())
  1744. return -1;
  1745. for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  1746. {
  1747. if (LIMIT_REAL_TIME == GetProto()->aLimits[i].bType)
  1748. return GetProto()->aLimits[i].lValue;
  1749. }
  1750. if (-1 != GetProto()->cLimitTimerBasedOnWearIndex)
  1751. return GetProto()->aLimits[static_cast<unsigned char>(GetProto()->cLimitTimerBasedOnWearIndex)].lValue;
  1752. return -1;
  1753. }
  1754. bool CItem::IsSameSpecialGroup(const LPITEM item) const
  1755. {
  1756. // ¼­·Î VNUMÀÌ °°´Ù¸é °°Àº ±×·ìÀÎ °ÍÀ¸·Î °£ÁÖ
  1757. if (this->GetVnum() == item->GetVnum())
  1758. return true;
  1759. if (GetSpecialGroup() && (item->GetSpecialGroup() == GetSpecialGroup()))
  1760. return true;
  1761. return false;
  1762. }